前面的五篇文章已经完整的介绍了横向ListView的整个实现过程,这篇文章介绍的是将前面所完成的横向ListView转换成竖向的,及一个可以上/下拉回弹的ListView。
这篇文章也是这一系列文章的最后一篇。
横向转竖向比较容易步骤如下:
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