项目地址
概述
- 处理滑动到左边界和右边界时,不允许滑动。
- 页面滑动一半回弹,滑动一半以上自动切换下一界面。
- 当页面内存在ScrollView这类子控件,事件要正常分发,不允许自定义ViewPager拦截事件。
- 回弹与切换动画处理。
源码分析
- 初始化
public ViewPagerY(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
myScroll = new Scroller(context, new LinearInterpolator());
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(mContext));
}
- 设置资源,如图片id,布局,图片链接等
public void setRes(ArrayList<ResType> res) {
for (ResType mResType : res) {
if (mResType.getmType() == ResType.Type.IAMG) {
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageView.setImageResource((Integer) mResType.getRes());
this.addView(imageView);
}
if (mResType.getmType() == ResType.Type.URL) {
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
ImageLoader.getInstance().displayImage((String) mResType.getRes(), imageView);
this.addView(imageView);
}
if (mResType.getmType() == ResType.Type.LAYOUT) {
View view = LayoutInflater.from(mContext).inflate((Integer) mResType.getRes(), null);
this.addView(view);
}
}
}
public class ResType<T> {
public enum Type {
IAMG,
LAYOUT,
URL
}
private T mRes;
private Type mType;
public ResType(T res, Type mType) {
this.mRes = res;
this.mType = mType;
}
public T getRes() {
return mRes;
}
public Type getmType() {
return mType;
}
}
- ViewPagerY对子View的测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = getMeasuredHeight();
widht = getMeasuredWidth();
int wMeasureSpec = MeasureSpec.makeMeasureSpec(widht, MeasureSpec.EXACTLY);
int hMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).measure(wMeasureSpec, hMeasureSpec);
}
}
- ViewPagerY对子View进行布局
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
this.getChildAt(i).layout(i * widht, 0, i * widht + widht, height);
}
}
- 判断手势,如果手势为水平滑动就拦截, 否则就正常将事件分发给子View处理.
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean interceptChildeEvent = super.onInterceptTouchEvent(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mLastX = mDownX = interceptLastX = event.getX();
interceptLastY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
float slopX = moveX - interceptLastX;
float slopY = moveY - interceptLastY;
float slopAbsX = Math.abs(slopX);
float slopAbsY = Math.abs(slopY);
if ((slopAbsX > 0 || slopAbsY > 0) && (slopAbsX - slopAbsY) >= 6) {
interceptChildeEvent = true;
}
interceptLastX = moveX;
interceptLastY = moveY;
break;
}
return interceptChildeEvent;
}
- 处理页面滑动回弹的逻辑
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
float mMoveX = event.getX();
float mDiffX = mMoveX - mLastX;
mLastX = mMoveX;
if (event.getPointerId(event.getActionIndex()) == 0 && event.getPointerCount() == 1) {
int scrollX = getScrollX();
if (currentIndex == 0) {
if (mDiffX < 0) {
ViewPagerY.this.scrollBy((int) -mDiffX, 0);
} else {
float mDiffMargin = scrollX - mDiffX;
if (mDiffMargin >= 0) {
ViewPagerY.this.scrollBy((int) -mDiffX, 0);
} else {
ViewPagerY.this.scrollBy(-scrollX, 0);
}
}
}
if (currentIndex == getChildCount() - 1) {
if (mDiffX > 0) {
ViewPagerY.this.scrollBy((int) -mDiffX, 0);
} else {
float mDiffMargin = (((getChildCount() - 1) * widht) - scrollX) + mDiffX;
if (mDiffMargin >= 0) {
ViewPagerY.this.scrollBy((int) -mDiffX, 0);
} else {
ViewPagerY.this.scrollBy(-(((getChildCount() - 1) * widht) - scrollX), 0);
}
}
}
if (currentIndex != 0 && currentIndex != getChildCount() - 1) {
ViewPagerY.this.scrollBy((int) -mDiffX, 0);
}
}
break;
case MotionEvent.ACTION_UP:
float mUpX = event.getX();
if (mUpX - mDownX > getWidth() / 2) {
moveTo(currentIndex - 1);
} else if (mUpX - mDownX < -getWidth() / 2) {
moveTo(currentIndex + 1);
} else {
moveTo(currentIndex);
}
break;
}
return true;
}
- 页面切换逻辑
public void moveTo(int index) {
int duration = 0;
if (index < 0) {
index = 0;
} else if (index > getChildCount() - 1) {
index = getChildCount() - 1;
}
int count = currentIndex - index;
if (count != 0) {
duration = mDuration * count;
} else {
duration = mDuration;
}
currentIndex = index;
if (onPageChangeListener != null) {
onPageChangeListener.onPageSelect(currentIndex);
}
int distanceX = currentIndex * getWidth() - getScrollX();
myScroll.startScroll(getScrollX(), 0, distanceX, 0, Math.abs(duration));
invalidate();
}
@Override
public void computeScroll() {
if (myScroll.computeScrollOffset()) {
float currX = myScroll.getCurrX();
scrollTo((int) currX, 0);
invalidate();
}
}
效果图