Multiple-View ViewPager-如何实现Viewpager控件的一个页面展示多个page以及回弹效果


链接地址:http://commonsware.com/blog/2012/08/20/multiple-view-viewpager-options.html

该文章讲述了三种实现方法,其中重载 getPageWidth方法可以有效实现需要的效果;  @Overridepublic float getPageWidth(int position) { return(0.5f);}

其余两种方法都会出现最左侧或者最右侧出现灰色区域的情况,无法继续实现回弹效果;

回弹效果的实现见http://stackoverflow.com/questions/13759862/android-viewpager-how-to-achieve-the-bound-effect


经过对上面链接代码的修改之后,可以在一个viewpager实现一个页面展示多个page的同时,最后一个页面和第一个页面都具备回弹效果!详情可见代码:

BounceBackViewPager.java

package com.example.viewpagerdemo;


import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Camera;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;

public class BounceBackViewPager extends ViewPager {

/**
 * maximum z distance to translate child view   ---滚动平移量
 */
final static int DEFAULT_OVERSCROLL_TRANSLATION = 150;

/**
 * duration of overscroll animation in ms      ---滚动平移时间
 */
final private static int DEFAULT_OVERSCROLL_ANIMATION_DURATION = 400;

@SuppressWarnings("unused")
private final static String DEBUG_TAG = ViewPager.class.getSimpleName();
private final static int INVALID_POINTER_ID = -1;

private static final String TAG = null;

/**
 * 
 * @author renard, extended by Piotr Zawadzki
 * 
 */
private class OverscrollEffect {
    private float mOverscroll;
    private Animator mAnimator;

    /**
     * @param deltaDistance [0..1] 0->no overscroll, 1>full overscroll
     */
    public void setPull(final float deltaDistance) {
        mOverscroll = deltaDistance;
        invalidateVisibleChilds(mLastPosition);
    }

    /**
     * called when finger is released. starts to animate back to default position
     */
    private void onRelease() {
        if (mAnimator != null && mAnimator.isRunning()) {
            mAnimator.addListener(new AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    startAnimation(0);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }
            });
            mAnimator.cancel();
        } else {
            startAnimation(0);
        }
    }

    private void startAnimation(final float target) {
        mAnimator = ObjectAnimator.ofFloat(this, "pull", mOverscroll, target);//初始化pull动画
        mAnimator.setInterpolator(new DecelerateInterpolator());
        //The time interpolator used in calculating the elapsed fraction of the animation
        final float scale = Math.abs(target - mOverscroll);
        mAnimator.setDuration((long) (mOverscrollAnimationDuration * scale));//持续时间
        mAnimator.start();
    }

    private boolean isOverscrolling() {
        if (mScrollPosition == 0 && mOverscroll < 0) {
            return true;
        }
        final boolean isLast = (getAdapter().getCount() - 1) == mScrollPosition;
        if (isLast && mOverscroll > 0) {
            return true;
            
        }
        return false;
    }

}

final private OverscrollEffect mOverscrollEffect = new OverscrollEffect();
final private Camera mCamera = new Camera();

private OnPageChangeListener mScrollListener;
private float mLastMotionX;
private int mActivePointerId;
private int mScrollPosition;
private float mScrollPositionOffset;
final private int mTouchSlop;

private float mOverscrollTranslation;
private int mOverscrollAnimationDuration;

public BounceBackViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    setStaticTransformationsEnabled(true);
    final ViewConfiguration configuration = ViewConfiguration.get(context);
    mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
    super.setOnPageChangeListener(new MyOnPageChangeListener());
    init(attrs);
}

private void init(AttributeSet attrs) {
    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.BounceBackViewPager);
    mOverscrollTranslation = a.getDimension(R.styleable.BounceBackViewPager_overscroll_translation, DEFAULT_OVERSCROLL_TRANSLATION);
    mOverscrollAnimationDuration = a.getInt(R.styleable.BounceBackViewPager_overscroll_animation_duration, DEFAULT_OVERSCROLL_ANIMATION_DURATION);
    a.recycle();
}

public int getOverscrollAnimationDuration() {
    return mOverscrollAnimationDuration;
}

public void setOverscrollAnimationDuration(int mOverscrollAnimationDuration) {
    this.mOverscrollAnimationDuration = mOverscrollAnimationDuration;
}

public float getOverscrollTranslation() {
    return mOverscrollTranslation;
}

public void setOverscrollTranslation(int mOverscrollTranslation) {
    this.mOverscrollTranslation = mOverscrollTranslation;
}

@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
    mScrollListener = listener;
};

private void invalidateVisibleChilds(final int position) {
     for (int i = 0; i < getChildCount(); i++) {
     getChildAt(i).invalidate();//刷新view视图的函数

     }
}

private int mLastPosition = 0;

private class MyOnPageChangeListener implements OnPageChangeListener {

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (mScrollListener != null) {
            mScrollListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
        mScrollPosition = position;
        mScrollPositionOffset = positionOffset;
        mLastPosition = position;
        invalidateVisibleChilds(position);
    }

    @Override
    public void onPageSelected(int position) {

        if (mScrollListener != null) {
            mScrollListener.onPageSelected(position);
        }
    }

    @Override
    public void onPageScrollStateChanged(final int state) {

        if (mScrollListener != null) {
            mScrollListener.onPageScrollStateChanged(state);
        }
        if (state == SCROLL_STATE_IDLE) {
            mScrollPositionOffset = 0;
        }
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    try {
        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            mLastMotionX = ev.getX();
            //Log.e("x1","Set Error! "+ mLastMotionX );
            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
            break;
        }
        case MotionEventCompat.ACTION_POINTER_DOWN: {
            final int index = MotionEventCompat.getActionIndex(ev);
            final float x = MotionEventCompat.getX(ev, index);
            mLastMotionX = x;
            //Log.e("x2","Set Error! "+ mLastMotionX );
            mActivePointerId = MotionEventCompat.getPointerId(ev, index);
            break;
        }
        }
        return super.onInterceptTouchEvent(ev);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        return false;
    } catch (ArrayIndexOutOfBoundsException e) {
        e.printStackTrace();
        return false;
    }
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    try {
        return super.dispatchTouchEvent(ev);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        return false;
    } catch (ArrayIndexOutOfBoundsException e) {
        e.printStackTrace();
        return false;
    }
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean callSuper = false;

    final int action = ev.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN: {
        callSuper = true;
        mLastMotionX = ev.getX();
        //Log.e("x3","Set Error! "+ mLastMotionX );
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        break;
    }
    case MotionEventCompat.ACTION_POINTER_DOWN: {
        callSuper = true;
        final int index = MotionEventCompat.getActionIndex(ev);
        final float x = MotionEventCompat.getX(ev, index);
        mLastMotionX = x;
        //Log.e("x4","Set Error! "+ mLastMotionX );
        mActivePointerId = MotionEventCompat.getPointerId(ev, index);
        break;
    }
    case MotionEvent.ACTION_MOVE: {
        if (mActivePointerId != INVALID_POINTER_ID) {
            // Scroll to follow the motion event
            final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            final float x = MotionEventCompat.getX(ev, activePointerIndex);
            final float deltaX = mLastMotionX - x;//手指滑动的距离
            //Log.e("x","Set Error! "+ mLastMotionX + " " + x + " " + deltaX);
            final float oldScrollX = getScrollX();
            final int width = getWidth();
            final int widthWithMargin = width + getPageMargin();
            final int lastItemIndex = getAdapter().getCount() - 1;
            final int currentItemIndex = getCurrentItem();
            final float leftBound = Math.max(0, (currentItemIndex - 1) * widthWithMargin);
            final float rightBound = Math.min(currentItemIndex + 1, lastItemIndex) * widthWithMargin;
            final float scrollX = oldScrollX + deltaX;
            if (mScrollPositionOffset == 0) {
                if (scrollX < leftBound) {
                    if (leftBound == 0) {
                        final float over = deltaX + mTouchSlop;
                        //Log.e("leftBound","Set Error!"+leftBound + " " + deltaX);
                        mOverscrollEffect.setPull(over / width);
                    }
                } else{
                    if (rightBound == lastItemIndex * widthWithMargin) {
                        final float over = deltaX + mTouchSlop;
                        //Log.e("rightBound","Set Error!"+rightBound+ " " + deltaX);
                        mOverscrollEffect.setPull(over / width);
                        
                    }
                }
            } else {
                //mLastMotionX = x;
            	 final float over = deltaX + mTouchSlop;    
                 mOverscrollEffect.setPull(over / width);
                //Log.e("x5","Set Error! "+ mLastMotionX );
            }
        } else {
            mOverscrollEffect.onRelease();
        }
        break;
    }
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL: {
        callSuper = true;
        mActivePointerId = INVALID_POINTER_ID;
        mOverscrollEffect.onRelease();
        break;
    }
    case MotionEvent.ACTION_POINTER_UP: {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastMotionX = ev.getX(newPointerIndex);
            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
            callSuper = true;
        }
        break;
    }
    }

    if (mOverscrollEffect.isOverscrolling() && !callSuper) {
        return true;
    } else {
        return super.onTouchEvent(ev);
    }
}

@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
    if (child.getWidth() == 0) {
        return false;
    }
    //final int position = child.getLeft() / child.getWidth();
    //final boolean isFirstOrLast = position == 0 || (position == getAdapter().getCount() - 1);
    //if (mOverscrollEffect.isOverscrolling()) {
        final float dx = getWidth() / 2;
        final int dy = getHeight() / 2;
        t.getMatrix().reset();
        final float translateX =(float) mOverscrollTranslation * (mOverscrollEffect.mOverscroll > 0 ? Math.min(mOverscrollEffect.mOverscroll, 1) : Math.max(mOverscrollEffect.mOverscroll, -1));
        Log.d(TAG, mOverscrollEffect.mOverscroll+"t");
        mCamera.save();
        mCamera.translate(-translateX, 0, 0);
        mCamera.getMatrix(t.getMatrix());
        mCamera.restore();
        t.getMatrix().preTranslate(-dx, -dy);
        t.getMatrix().postTranslate(dx, dy);
        if (getChildCount() == 1) {
            this.invalidate();
        } else {
            child.invalidate();
        }
        return true;
    //}
    //return false;
}
}

AwesomePagerActivity.java

package com.example.viewpagerdemo;

import java.util.ArrayList;
import java.util.List;

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;

import android.os.Bundle;
import android.os.Parcelable;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;

public class AwesomePagerActivity extends Activity {
    
	private BounceBackViewPager awesomePager;

	private Context cxt;
	private AwesomePagerAdapter awesomeAdapter;
	
	private LayoutInflater mInflater;
	private List<View> mListViews;
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    	
        cxt = this;
        mListViews = new ArrayList<View>();
        mInflater = getLayoutInflater();
        mListViews.add(mInflater.inflate(R.layout.page01, null));
        mListViews.add(mInflater.inflate(R.layout.page02, null));
        mListViews.add(mInflater.inflate(R.layout.page03, null));
        mListViews.add(mInflater.inflate(R.layout.page04, null));
        awesomeAdapter = new AwesomePagerAdapter();
        awesomePager = (BounceBackViewPager) findViewById(R.id.awesomepager);
        awesomePager.setAdapter(awesomeAdapter);
        awesomePager.setPageMargin(15);
        
        
    }
    
    private class AwesomePagerAdapter extends PagerAdapter{

		
		@Override
		public int getCount() {
			return mListViews.size();
		}
		
//		@Override
//		public float getPageWidth(int position) 
//		{ return(0.3f); } 

	    /**
	     * 从指定的position创建page
	     *
	     * @param container ViewPager容器
	     * @param position The page position to be instantiated.
	     * @return 返回指定position的page,这里不需要是一个view,也可以是其他的视图容器.
	     */
		@Override
		public Object instantiateItem(View collection, int position) {

			
			((ViewPager) collection).addView(mListViews.get(position),0);
			mListViews.get(position).setBackgroundColor(Color.argb(255, position * 50, position * 10, position * 50));
			return mListViews.get(position);
		}

	    /**
	     * <span style="font-family:'Droid Sans';">从指定的position销毁page</span>
	     * 
	     * 
	     *<span style="font-family:'Droid Sans';">参数同上</span>
	     */
		@Override
		public void destroyItem(View collection, int position, Object view) {
			((ViewPager) collection).removeView(mListViews.get(position));
		}

		
		
		@Override
		public boolean isViewFromObject(View view, Object object) {
			return view==(object);
		}

		@Override
		public void finishUpdate(View arg0) {}
		

		@Override
		public void restoreState(Parcelable arg0, ClassLoader arg1) {}

		@Override
		public Parcelable saveState() {
			return null;
		}

		@Override
		public void startUpdate(View arg0) {}
    	
    }
    
    
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值