垂直方向的viewpager,网上也有些许实现。大多是自定义ViewGoup的,这样的话就要自己做view复用的事情了。
但我思考了下发现listview不也可以做这事情吗!!于是就尝试着去实现了下,发现还真可以,效果也棒棒的。。。。。
看效果是不是跟ViewPager没区别,也有回滚和快速切换。哈哈、、、最主要的是代码没几行。
有下面几个问题需要解决
1.怎么让item占满整个屏幕
2.怎么滚动listview(listview滚动跟scrollview还是有区别的)
3.兼容到2.2(虽然4以下的手机基本见不到了,好多公司还是要兼容到2.2的)
1.怎么让item占满整个屏幕
刚开始我考虑使用onMeasure里面做下手机,但发现没效果,后看了下源码`
private void measureScrapChild(View child, int position, int widthMeasureSpec) {
LayoutParams p = (LayoutParams) child.getLayoutParams();
if (p == null) {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
child.setLayoutParams(p);
}
p.viewType = mAdapter.getItemViewType(position);
p.forceAdd = true;
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
mListPadding.left + mListPadding.right, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
就是这几句代码,如果不设置LayoutParams那么测量方式都是UNSPECIFIED
所以onMeasure这里通过几种测量方式的改变来做是做不了,只能忘LayoutParams方向动手。
要设置LayoutParams可以在getview的时候设置下,也是可以的。但能不能再onmeasure之前设置呢?这样就可以不用每次都设置了,也是可以的,但是就是有个问题,如果listview不是全屏怎么办?要怎么取到listview的高度?暂时没有想到方法,如果有方法的请告知。。感激不尽啊。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
childView.getLayoutParams().height=200;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
上面就是在Onmeasure里面做的测试代码
所以最后还是决定在getview里面做
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 只是测试 不考虑性能
View v = new View(VerticalViewPagerActivity.this);
v.setBackgroundColor((int) (Color.RED * Math.random()));
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
displayMetrics.heightPixels);
v.setLayoutParams(params);
return v;
}
是不是也很easy啊,没什么可说的,是吧。
2.怎么滚动listview
这个滚动使用Scroller也是可以的,做法应该不难,这里我采用的是Animation,动画来做的
// 动画辅助scroller
scrollAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
// TODO Auto-generated method stub
super.applyTransformation(interpolatedTime, t);
int deltaY = (int) (interpolatedTime * scrollDest - haseScrollValue);
if (Math.abs(deltaY) == Math.abs(scrollDest)) {
deltaY = 0;
}
//listview 滚动辅助类 在v4包里
listViewAutoScrollHelper.scrollTargetBy(0, deltaY);
haseScrollValue += deltaY;
}
};
当然使用属性动画是最简单的 ,但是3.0以下不支持,要导入第三方兼容库,对方法数是一个挑战。
最后就是滑动了。
在down 和move事件都可以交给listview来做,我们要处理的就是up事件。
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (downY == 0) {
downY = ev.getY();
}
break;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int initialVelocity = (int) velocityTracker.getXVelocity();
final int destY = (int) (ev.getY() - downY);
if (Math.abs(initialVelocity) > mMinimumVelocity
&& Math.abs(destY) > mTouchSlop) {// 一定要滚动到下一页
final View childView = getChildAt(0);
if (childView == null)
return true;
if (destY > 0) {// 向下滚
switchPager(childView.getTop());
} else {// 向上滚
switchPager(childView.getBottom());
}
} else {// 根据临界值判断是否要滚动
checkScrollReset();
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
downY = 0;
return true;
}
return super.onTouchEvent(ev);
}
就是最基本的滚动操作了。把down和move都交给listview自己处理,up事件咱来处理,就是有viewpager的滑动效果了。
好了,垂直滚动的viewpager就完成了。
源代码