横向转竖向比较容易步骤如下:
1.把相应的left、right、width、height的值改成top、bottom、height、width的值
2.将addAndMeasureChild()方法改为以下代码:
private void addAndMeasureChild(View child, int viewIndex) {
LayoutParams params = child.getLayoutParams();
params = params==null ? new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT):params;
addViewInLayout(child, viewIndex, params, true);
child.measure(MeasureSpec.makeMeasureSpec(getWidth()-getPaddingLeft()-getPaddingRight(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.UNSPECIFIED));
}
3.修改ScrollBar的调用,把mScrollBar.showHorizontal()改成mScrollBar.showVertical()
if(canShowScrollBar) {
//布局完所有的视图之后添加上滚动条的显示
addAndMeasureChild(mScrollBar, getChildCount());
if (adapter != null) {
mScrollBar.showVertical(this, firstItemIndex, lastItemIndex, adapter.getCount(), headViewHeight, footViewHeight);
} else {
mScrollBar.showVertical(this, 0, 0, 0, headViewHeight, footViewHeight);
}
}
以下是完整代码:
package com.hss.os.horizontallistview.history_version;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.Scroller;
import com.hss.os.horizontallistview.ScrollBar;
import java.util.LinkedList;
import java.util.Queue;
/**
* Created by sxyx on 2017/8/11.
*/
public class VerticalListView extends AdapterView<ListAdapter> {
private Queue<View> cacheView = new LinkedList<>();//列表项缓存视图
private ListAdapter adapter = null;
private GestureDetector mGesture;
private int firstItemIndex = 0;//显示的第一个子项的下标
private int lastItemIndex = -1;//显示的最后的一个子项的下标
private int scrollValue=0;//列表已经发生有效滚动的位移值
private int hasToScrollValue=0;//接下来列表发生滚动所要达到的位移值
private int maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
private int minScrollValue=Integer.MIN_VALUE;//列表发生滚动所能达到的最小位移值(值为0表示不能发生类似下拉刷新的操作,负值表示可以)
private int displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)
private Scroller mScroller;
private int firstItemTopEdge=0;//第一个子项的左边界
private int lastItemBottomEdge=0;//最后一个子项的右边界
private View headView;
private View footView;
private boolean hasHeadView=false;
private boolean hasFootView=false;
private ScrollBar mScrollBar;
private int headViewHeight=0;//头视图宽度
private int footViewHeight=0;//尾视图宽度
private boolean canShowScrollBar=true;//是否需要显示滚动条
private boolean canPullUp=true;//可以下拉
private boolean canPullDown=true;//可以上拉
public VerticalListView(Context context) {
super(context);
init(context);
}
public VerticalListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public VerticalListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public VerticalListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context){
mGesture = new GestureDetector(getContext(), mOnGesture);
mScroller=new Scroller(context);
mScrollBar=new ScrollBar(context);
}
private void initParams(){
mScroller.forceFinished(true);//避免在滑动过程中变换视图内容时,出现列表无法滚动的情况
removeAllViewsInLayout();
if(adapter!=null&&lastItemIndex<adapter.getCount())
hasToScrollValue=scrollValue;//保持显示位置不变
else hasToScrollValue=0;//滚动到列表头
scrollValue=0;//列表已经发生有效滚动的位移值
firstItemIndex = 0;//显示的第一个子项的下标
lastItemIndex = -1;//显示的最后的一个子项的下标
maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
// 列表发生滚动所能达到的最小位移值(值为0表示不能发生类似下拉刷新的操作,负值表示可以)
if(!isCanPullDown()) minScrollValue = 0;
else minScrollValue = Integer.MIN_VALUE;
displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)
firstItemTopEdge=0;//第一个子项的左边界
lastItemBottomEdge=0;//最后一个子项的右边界
if(hasHeadView||hasFootView) {
if (hasHeadView) {
scrollValue = headView.getMeasuredHeight();
headView.layout(0, 0, 0, 0);
setHeadView(headView);
}
if (hasFootView) {
footView.layout(0, 0, 0, 0);
setFootView(footView);
}
}else requestLayout();
}
private DataSetObserver mDataObserver = new DataSetObserver() {
@Override
public void onChanged() {
//执行Adapter数据改变时的逻辑
initParams();
}
@Override
public void onInvalidated() {
//执行Adapter数据失效时的逻辑
initParams();
}
};
@Override
public ListAdapter getAdapter() {
return adapter;
}
@Override
public void setAdapter(ListAdapter adapter) {
if(adapter!=null){
adapter.registerDataSetObserver(mDataObserver);
}
if(this.adapter!=null){
this.adapter.unregisterDataSetObserver(mDataObserver);
}
this.adapter=adapter;
requestLayout();
}
@Override
public View getSelectedView() {
return null;
}
@Override
public void setSelection(int i) {
}
private void addAndMeasureChild(View child, int viewIndex) {
LayoutParams params = child.getLayoutParams();
params = params==null ? new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT):params;
addViewInLayout(child, viewIndex, params, true);
child.measure(MeasureSpec.makeMeasureSpec(getWidth()-getPaddingLeft()-getPaddingRight(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.UNSPECIFIED));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//在执行布局之前需要先移除滚动条,以免影响其它视图的显示运算
mScrollBar.remove(this);
//需要先布局列表项再根据余下的空间布局列表头尾
//布局列表项
/*
1.计算这一次整体滚动偏移量
2.根据偏移量提取需要缓存视图
3.根据偏移量显示新的列表项
4.根据整体偏移值整顿所有列表项位置
5.计算最大滚动位移值,记录已经发生有效滚动的位移值
6.根据显示的最终效果,判断是否要居中显示
*/
int dx=calculateScrollValue();
removeNonVisibleItems(dx);
showListItem(dx);
adjustItems();
//布局列表头、尾
adjustHeadAndFootView(dx);
calculateMaxScrollValue();
if(canShowScrollBar) {
//布局完所有的视图之后添加上滚动条的显示
addAndMeasureChild(mScrollBar, getChildCount());
if (adapter != null) {
mScrollBar.showVertical(this, firstItemIndex, lastItemIndex, adapter.getCount(), headViewHeight, footViewHeight);
} else {
mScrollBar.showVertical(this, 0, 0, 0, headViewHeight, footViewHeight);
}
}
//继续滚动
if(!mScroller.isFinished()){
//在onLayout中requestLayout()方法必须按以下形式调用,否则没有效果
post(new Runnable(){
@Override
public void run() {
requestLayout();
}
});
}else if(isRemoveFootView){//表示所有的计算都已经完成
isRemoveFootView=false;
//这是修补因移除尾视图而出现列表头空白的bug
int startIndex=0;
if(canShowScrollBar) startIndex=1;
if(getChildCount()>startIndex){
if(getChildAt(0).getTop()>getShowStartEdge()){
//表示列表头有出现空白
hasToScrollValue += getChildAt(0).getTop()-getShowStartEdge();
//在onLayout中requestLayout()方法必须按以下形式调用,否则没有效果
post(new Runnable(){
@Override
public void run() {
requestLayout();
}
});
}
}
}
}
/**
* 计算这一次整体滚动偏移量
* @return
*/
private int calculateScrollValue(){
int dx=0;
if(mScroller.computeScrollOffset()){
hasToScrollValue = mScroller.getCurrY();
}
if(hasToScrollValue <= minScrollValue){
hasToScrollValue = minScrollValue;
mScroller.forceFinished(true);
}
if(hasToScrollValue >= maxScrollValue) {
hasToScrollValue = maxScrollValue;
mScroller.forceFinished(true);
}
dx=hasToScrollValue-scrollValue;
scrollValue=hasToScrollValue;
return -dx;
}
/**
* 计算最大滚动值
*/
private void calculateMaxScrollValue(){
if(getListItemCount()>0) {
if(lastItemIndex==adapter.getCount()-1) {//已经显示了最后一项
if(getChildAt(getChildCount() - 1).getBottom()>=getShowEndEdge()) {
setMaxScrollValue(scrollValue + getChildAt(getChildCount() - 1).getBottom() - getShowEndEdge());
}else{
setMaxScrollValue(0);
}
}else{
setMaxScrollValue(Integer.MAX_VALUE);
}
}else{
if(adapter!=null&&adapter.getCount()>0){
// 修补bug:当尾视图足够宽能够占据所有可视区域时,
// maxScrollValue的值没有改变,而导致滚动出现空白区域
setMaxScrollValue(scrollValue + getChildAt(getChildCount() - 1).getBottom() - getShowEndEdge());
}else {
if (getChildCount() > 0
&& getChildAt(getChildCount() - 1).getBottom() >= getShowEndEdge()) {
setMaxScrollValue(scrollValue + getChildAt(getChildCount() - 1).getBottom() - getShowEndEdge());
}else{
setMaxScrollValue(0);
}
}
}
}
/**
* 根据偏移量提取需要缓存视图
* @param dx
*/
private void removeNonVisibleItems(int dx) {
if(getListItemCount()>0) {
//移除列表头
View child = getChildAt(getStartItemIndex());
while (getListItemCount()>0&&child != null && child.getBottom() + dx <= getShowStartEdge()) {
displayOffset += child.getMeasuredHeight();
cacheView.offer(child);
removeViewInLayout(child);
firstItemIndex++;
child = getChildAt(getStartItemIndex());
}
//移除列表尾
child = getChildAt(getEndItemIndex());
while (getListItemCount()>0&&child != null && child.getTop() + dx >= getShowEndEdge()) {
cacheView.offer(child);
removeViewInLayout(child);
lastItemIndex--;
child = getChildAt(getEndItemIndex());
}
}
}
/**
* 根据偏移量显示新的列表项
* @param dx
*/
private void showListItem(int dx) {
if(adapter==null)return;
int firstItemEdge = getFirstItemTopEdge()+dx;
int lastItemEdge = getLastItemBottomEdge()+dx;
displayOffset+=dx;//计算偏移量
//显示列表头视图
while(firstItemEdge > getShowStartEdge() && firstItemIndex-1 >= 0) {
firstItemIndex--;//往前显示一个列表项
View child = adapter.getView(firstItemIndex, cacheView.poll(), this);
addAndMeasureChild(child, getStartItemIndex());
firstItemEdge -= child.getMeasuredHeight();
displayOffset -= child.getMeasuredHeight();
}
//显示列表未视图
while(lastItemEdge < getShowEndEdge() && lastItemIndex+1 < adapter.getCount()) {
lastItemIndex++;//往后显示一个列表项
View child = adapter.getView(lastItemIndex, cacheView.poll(), this);
addAndMeasureChild(child, getEndItemIndex()+1);
lastItemEdge += child.getMeasuredHeight();
}
}
/**
* 调整各个item的位置
*/
private void adjustItems() {
if(getListItemCount() > 0){
int top = displayOffset+getShowStartEdge();
int left = getPaddingLeft();
int endIndex = getEndItemIndex();
int startIndex = getStartItemIndex();
int childWidth,childHeight;
for(int i=startIndex;i<=endIndex;i++){
View child = getChildAt(i);
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
child.layout(left, top, left + childWidth, top + childHeight);
top += childHeight;
}
firstItemTopEdge=getChildAt(getStartItemIndex()).getTop();
lastItemBottomEdge=getChildAt(getEndItemIndex()).getBottom();
}
}
/**
* 调整列表头、尾
*/
private void adjustHeadAndFootView(int dx){
headViewHeight=footViewHeight=0;
if(hasHeadView){
int top,bottom;
if(getListItemCount()>0){
bottom=firstItemTopEdge;
}else{
bottom=headView.getBottom()+dx;
}
top=bottom-headView.getMeasuredHeight();
headView.layout(getPaddingLeft(), top, headView.getMeasuredWidth()+getPaddingLeft(), bottom);
headViewHeight=headView.getMeasuredHeight();
}
if(hasFootView){
int top,bottom;
if(getListItemCount()>0){
top=getChildAt(getEndItemIndex()).getBottom();
}else{
//添加headView.getRight()>=getShowStartEdge()条件用于修补原先的bug
if(hasHeadView&&headView.getBottom()>=getShowStartEdge())
top=headView.getBottom();
else {
if(footView.getTop()==0&&dx==0){//第一次赋值
top=getShowStartEdge();
}else{
top=footView.getTop()+dx;
}
//调整以修补显示bug
if(hasHeadView) {//重新调整headView的位置
headView.layout(getPaddingLeft(),top-headView.getMeasuredWidth(), headView.getMeasuredWidth() + getPaddingLeft(),top);
}
}
}
bottom=top+footView.getMeasuredHeight();
footView.layout(getPaddingLeft(), top, footView.getMeasuredWidth()+getPaddingLeft(),bottom);
footViewHeight=footView.getMeasuredHeight();
}
}
//以下八个方法为概念性封装方法,有助于往后的扩展和维护
/**
* 获得列表视图中item View的总数
* @return
*/
private int getListItemCount(){
int itemCount=getChildCount();
if(hasHeadView)itemCount-=1;
if(hasFootView)itemCount-=1;
return itemCount;
}
/**
* 获得列表视图中第一个item View下标
* @return
*/
private int getStartItemIndex(){
if(hasHeadView) return 1;
return 0;
}
/**
* 获得列表视图中最后一个item View下标
* @return
*/
private int getEndItemIndex(){
if(hasFootView) return getChildCount()-2;
return getChildCount()-1;
}
/**
* 获得列表视图中第一个item View上边界值
* @return
*/
private int getFirstItemTopEdge(){
if(getListItemCount()>0) {
return firstItemTopEdge;
}else{
if(hasHeadView) return headView.getBottom();
else return getShowStartEdge();
}
}
/**
* 获得列表视图中最后一个item View下边界值
* @return
*/
private int getLastItemBottomEdge(){
if(getListItemCount()>0) {
return lastItemBottomEdge;
}else{
if(hasFootView) return footView.getTop();
else return getShowStartEdge();
}
}
/**
* 取得视图可见区域的左边界
* @return
*/
private int getShowStartEdge(){
return getPaddingTop();
}
/**
* 取得视图可见区域的右边界
* @return
*/
private int getShowEndEdge(){
return getHeight()-getPaddingBottom();
}
/**
* 取得视图可见区域的高度
* @return
*/
private int getShowHeight(){
return getHeight()-getPaddingTop()-getPaddingBottom();
}
public void setMaxScrollValue(int maxScrollValue) {
if(isCanPullUp()&&maxScrollValue!=Integer.MAX_VALUE) {
if(isSpringBack){//在执行回弹操作
this.maxScrollValue = Integer.MAX_VALUE;
}else if(mScroller.isFinished()){//手动执行滚动操作
this.maxScrollValue = Integer.MAX_VALUE;
}else{
if(maxScrollValue<0)this.maxScrollValue=0;
else this.maxScrollValue = maxScrollValue;
}
}else{
if(maxScrollValue<0)this.maxScrollValue=0;
else this.maxScrollValue = maxScrollValue;
}
}
public void setHeadView(View view){
if(view!=null) {
int headBottom=-1;
int height=0;
if (hasHeadView&&headView!=null) {
headBottom=headView.getBottom();
height=headView.getHeight();
removeViewInLayout(headView);
}
hasHeadView = true;
headView=view;
addAndMeasureChild(headView, 0);
if(getListItemCount()>0) {//有列表内容
if (headBottom == -1) {
//新增列表头
if (firstItemIndex == 0) {//第一个显示的是第一个列表项
//滚动整个列表,让其显示完整列表头(让列表往回滚)
scrollValue = headView.getMeasuredHeight()
+ getShowStartEdge() - firstItemTopEdge;
hasToScrollValue=0;
} else {//不是显示第一个列表项
//不滚动列表项,增加历史滚动值
hasToScrollValue += headView.getMeasuredHeight();
scrollValue = hasToScrollValue;
}
} else {
//替换列表头
hasToScrollValue += headView.getMeasuredHeight()-height;
}
}
setMaxScrollValue(Integer.MAX_VALUE);
requestLayout();
}
}
public void removeHeadView(){
if(hasHeadView&&headView!=null){
hasHeadView=false;
int top=headView.getTop();
int height=headView.getMeasuredHeight();
removeViewInLayout(headView);
if(headView.getBottom()>=getShowStartEdge()) {//列表头有显示
scrollValue = -(height+top-getShowStartEdge());
hasToScrollValue=0;
}else{
scrollValue-=height;
hasToScrollValue-=height;
}
requestLayout();
}else{
hasHeadView=false;
}
}
public void setFootView(View view){
if(view!=null) {
if (hasFootView&&footView!=null) {
removeViewInLayout(footView);
}
hasFootView=true;
footView=view;
addAndMeasureChild(footView, -1);
requestLayout();
}
}
private boolean isRemoveFootView=false;
public void removeFootView(){
if(hasFootView&&footView!=null){
hasFootView=false;
int top=footView.getTop();
mScroller.forceFinished(true);//用于修补由于快速华东的过程中移除尾视图而出现bug
removeViewInLayout(footView);
if(top<getShowEndEdge()) {//表示需要回退
hasToScrollValue -= getShowEndEdge()-top;
isRemoveFootView=true;
}
requestLayout();
}else{
hasFootView=false;
}
}
/**
* 在onTouchEvent处理事件,让子视图优先消费事件
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if(dealTouchEvent(event)) return true;
return mGesture.onTouchEvent(event);
}
private GestureDetector.OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
mScroller.forceFinished(true);//点击时停止滚动
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
minScrollValue=0;//在快速滑动时,不能出现类似下拉刷新的操作
mScroller.fling(0, scrollValue, 0, (int)-velocityY, 0, 0, 0, maxScrollValue);
requestLayout();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if(isCanPullDown()) {
minScrollValue = Integer.MIN_VALUE;//手动滑动时可以出现类似下拉刷新的操作
}else{
minScrollValue = 0;
}
synchronized(VerticalListView.this){
hasToScrollValue += (int)calDistanceVal(distanceY);
}
requestLayout();
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
int startIndex=0;
if(canShowScrollBar) startIndex=1;
for(int i=0;i<getChildCount();i++){
View child = getChildAt(i);
if(child==mScrollBar) break;
if (isEventWithinView(e, child)) {
if(hasHeadView&&i==0){
//点击列表头
if(OnHeadViewClickListener!=null)
OnHeadViewClickListener.onClick(child);
}else if(hasFootView&&i==getChildCount()-(1+startIndex)){
//点击列表尾
if(OnFootViewClickListener!=null)
OnFootViewClickListener.onClick(child);
}else {
int position=firstItemIndex + i;
if(hasHeadView) position--;
if (getOnItemClickListener() != null) {
getOnItemClickListener().onItemClick(VerticalListView.this, child, position, adapter.getItemId(position));
}
if (getOnItemSelectedListener() != null) {
getOnItemSelectedListener().onItemSelected(VerticalListView.this, child, position, adapter.getItemId(position));
}
}
break;
}
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
int startIndex=0;//这个值用于处理滚动条的影响
if(canShowScrollBar) startIndex=1;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if(child==mScrollBar) return;
if (isEventWithinView(e, child)) {
if(hasHeadView&&i==0){
//长按列表头
if(OnHeadViewLongClickListener!=null)
OnHeadViewLongClickListener.onLongClick(child);
}else if(hasFootView&&i==getChildCount()-(1+startIndex)){
//长按列表尾
if(OnFootViewLongClickListener!=null)
OnFootViewLongClickListener.onLongClick(child);
} else {
int position=firstItemIndex + i;
if(hasHeadView) position--;
if (getOnItemLongClickListener() != null) {
getOnItemLongClickListener().onItemLongClick(VerticalListView.this, child, position, adapter.getItemId(position));
}
}
break;
}
}
}
private boolean isEventWithinView(MotionEvent e, View child) {
Rect viewRect = new Rect();
int[] childPosition = new int[2];
child.getLocationOnScreen(childPosition);
int left = childPosition[0];
int right = left + child.getWidth();
int top = childPosition[1];
int bottom = top + child.getHeight();
viewRect.set(left, top, right, bottom);
return viewRect.contains((int) e.getRawX(), (int) e.getRawY());
}
};
private boolean isEventDownIntercept=false;
private boolean isSpringBack=false;
private boolean isCanPullDownInthis=true;
/**
* 在手势解析器之前拦截事件
* @param event
* @return
*/
private boolean dealTouchEvent(MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
isCanPullDownInthis=true;
int startIndex=0;
if(canShowScrollBar) startIndex=1;
if(getChildCount()==startIndex){
isCanPullDownInthis=false;
}else{
if(getChildAt(getChildCount()-(1+startIndex)).getBottom()<getShowEndEdge()){
isCanPullDownInthis=false;
}
}
isEventDownIntercept=springBack();
if (isEventDownIntercept) return true;
break;
case MotionEvent.ACTION_MOVE:
return isEventDownIntercept;
case MotionEvent.ACTION_UP:
return springBack();
}
return false;
}
/**
* 采用阻尼式算法,重新提取移动值
* @param distanceVal
* @return
*/
private float calDistanceVal(float distanceVal){
if(!isCanPullDownInthis&&distanceVal>0){
return 0;
}
int startIndex=0;//这个值用于处理滚动条的影响
if(canShowScrollBar) startIndex=1;
if(getChildCount()>startIndex){
int dis=getChildAt(0).getTop()-getShowStartEdge();
if(dis>0){//执行头部拉伸阻尼式计算
if(distanceVal>=0) distanceVal = distanceVal/2;
else {
float sc = 1 - dis / (getShowHeight() * 0.4f);
sc = sc < 0 ? 0 : sc;
distanceVal = distanceVal * sc;
}
if(onPullDownListener!=null)
onPullDownListener.onScroll(distanceVal);
}else {
dis = getShowEndEdge() - getChildAt(getChildCount() - (1 + startIndex)).getBottom();
if (dis > 0 && getFirstItemTopEdge() < getShowStartEdge()) {
//执行尾部拉伸阻尼式计算
if (distanceVal <= 0) distanceVal = distanceVal / 2;
else {
float sc = 1 - dis / (getShowHeight() * 0.4f);
sc = sc < 0 ? 0 : sc;
distanceVal = distanceVal * sc;
}
if (onPullUpListener != null)
onPullUpListener.onScroll(distanceVal);
}
}
}
return distanceVal;
}
/**
* 执行回滚操作
* @return
*/
private boolean springBack(){
isSpringBack=false;
int startIndex=0;
if(canShowScrollBar) startIndex=1;
if(getChildCount()>startIndex){
int dis=getChildAt(0).getTop()-getShowStartEdge();
if(dis>0){//执行头部回滚操作
mScroller.startScroll(0, scrollValue, 0, dis, 500);
isSpringBack=true;
requestLayout();
if(onPullDownListener!=null
&&(dis>getShowHeight()/5||dis>120))
onPullDownListener.onPullEvent();
return true;
}
dis=getShowEndEdge()-getChildAt(getChildCount()-(1+startIndex)).getBottom();
if(dis>0&&getFirstItemTopEdge()<getShowStartEdge()){
//执行尾部回滚操作
mScroller.startScroll(0, scrollValue, 0, -dis, 500);
isSpringBack=true;
requestLayout();
if(onPullUpListener!=null
&&(dis>getShowHeight()/5||dis>120))
onPullUpListener.onPullEvent();
return true;
}
}
return false;
}
private OnPullListener onPullDownListener = null;
private OnPullListener onPullUpListener = null;
private OnClickListener OnHeadViewClickListener;
private OnClickListener OnFootViewClickListener;
private OnLongClickListener OnHeadViewLongClickListener;
private OnLongClickListener OnFootViewLongClickListener;
public void setOnPullDownListener(OnPullListener onPullDownListener) {
this.onPullDownListener = onPullDownListener;
}
public void setOnPullUpListener(OnPullListener onPullUpListener) {
this.onPullUpListener = onPullUpListener;
}
public void setOnHeadViewClickListener(OnClickListener onHeadViewClickListener) {
OnHeadViewClickListener = onHeadViewClickListener;
}
public void setOnFootViewClickListener(OnClickListener onFootViewClickListener) {
OnFootViewClickListener = onFootViewClickListener;
}
public void setOnHeadViewLongClickListener(OnLongClickListener onHeadViewLongClickListener) {
OnHeadViewLongClickListener = onHeadViewLongClickListener;
}
public void setOnFootViewLongClickListener(OnLongClickListener onFootViewLongClickListener) {
OnFootViewLongClickListener = onFootViewLongClickListener;
}
public interface OnPullListener{
/**
* 滚动时执行
* @param dis 移动的位移值
*/
void onScroll(float dis);
/**
* 事件确认(类似下拉刷新事件触发)
*/
void onPullEvent();
}
public synchronized void scrollTo(int x) {
mScroller.startScroll(hasToScrollValue, 0, x - hasToScrollValue, 0);
requestLayout();
}
public boolean isCanShowScrollBar() {
return canShowScrollBar;
}
public void setCanShowScrollBar(boolean canShowScrollBar) {
this.canShowScrollBar = canShowScrollBar;
}
public boolean isCanPullDown() {
return canPullDown;
}
public void setCanPullDown(boolean canPullDown) {
this.canPullDown = canPullDown;
}
public boolean isCanPullUp() {
return canPullUp;
}
public void setCanPullUp(boolean canPullUp) {
this.canPullUp = canPullUp;
}
}