android viewpager 弹性效果的实现,首页往左拉弹回,尾页往右拉弹回

这个实现,我今天找了蛮久,最后决定用的方法是这个:

http://stackoverflow.com/questions/13759862/android-viewpager-how-to-achieve-the-bound-effect

直接按照上面的方法用这个就ok了,我实验了一下效果还非常不错.网上所说的多加两个空白页的方法纯属娱乐感觉.

BounceBackViewPager 

直接在这里贴出吧

package com.lindo.collector.widget;

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.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;

import com.lindo.collector.R;

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;

	/**
	 *
	 * @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);
	        mAnimator.setInterpolator(new DecelerateInterpolator());
	        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();

	     }
	    //this.invalidate();
	    // final View child = getChildAt(position);
	    // final View previous = getChildAt(position - 1);
	    // final View next = getChildAt(position + 1);
	    // if (child != null) {
	    // child.invalidate();
	    // }
	    // if (previous != null) {
	    // previous.invalidate();
	    // }
	    // if (next != null) {
	    // next.invalidate();
	    // }
	}

	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();
	            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;
	            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();
	        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;
	        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;
	            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;
	                        mOverscrollEffect.setPull(over / width);
	                    }
	                } else if (scrollX > rightBound) {
	                    if (rightBound == lastItemIndex * widthWithMargin) {
	                        final float over = scrollX - rightBound - mTouchSlop;
	                        mOverscrollEffect.setPull(over / width);
	                    }
	                }
	            } else {
	                mLastMotionX = x;
	            }
	        } 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() && isFirstOrLast) {
	        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));
	        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;
	}
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="BounceBackViewPager">
    <!--
    determines the maximum amount of translation along the z-axis during the overscroll.
    Default is 150.
    -->
    <attr name="overscroll_translation" format="dimension" />

    <!-- Duration of animation when user releases the over scroll. Default is 400 ms. -->
    <attr name="overscroll_animation_duration" format="integer" />
</declare-styleable>
</resources>

就是用这个

BounceBackViewPager 
然后在styles 里面加上上面的resources代码
时间: 2024-10-30 04:21:01

android viewpager 弹性效果的实现,首页往左拉弹回,尾页往右拉弹回的相关文章

Android ListView弹性效果的实现方法_Android

关于在Android中实现ListView的弹性效果,有很多不同的方法,网上一搜,也有很多,下面贴出在项目中经常用到的两种实现ListView弹性效果的方法(基本上拿来就可以用),供大家参考: 第一种比较简单,好容易理解,只是动态改变了ListView在Y轴上的可移动距离,代码如下: import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; impor

Android ListView弹性效果的实现方法

关于在Android中实现ListView的弹性效果,有很多不同的方法,网上一搜,也有很多,下面贴出在项目中经常用到的两种实现ListView弹性效果的方法(基本上拿来就可以用),供大家参考: 第一种比较简单,好容易理解,只是动态改变了ListView在Y轴上的可移动距离,代码如下: import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; impor

Android ViewPager画廊效果详解及实例

Android ViewPager 画廊效果 从上面的图片可以看到,当添加多张图片的时候,能够在下方形成一个画廊的效果,我们左右拉动图片来看我们添加进去的图片,效果是不是好了很多呢?下面来看看怎么实现吧! 上面的效果类似Android里面ViewPage的效果,但是跟ViewPager有所不同,ViewPager每次只能显示一张图片. 其实我们是利用到了View的clipChildren属性,我们在这里要把ViewPager以及它的父窗体都设置为false,如下: android:clipChi

Android编程ViewPager回弹效果实例分析_Android

本文实例讲述了Android编程ViewPager回弹效果.分享给大家供大家参考,具体如下: 其实在我们很多应用中都看到当ViewPager滑到第一页或者最后一页的时候,如果再滑动的时候,就会有一个缓冲的过程,也就是回弹效果.之前在研究回弹效果的时候,也顺便实现了ViewPager的回弹效果,其实也很简单,一下是实现代码,注释比较少: package com.freesonfish.viewpager_2; import android.content.Context; import andro

Android编程ViewPager回弹效果实例分析

本文实例讲述了Android编程ViewPager回弹效果.分享给大家供大家参考,具体如下: 其实在我们很多应用中都看到当ViewPager滑到第一页或者最后一页的时候,如果再滑动的时候,就会有一个缓冲的过程,也就是回弹效果.之前在研究回弹效果的时候,也顺便实现了ViewPager的回弹效果,其实也很简单,一下是实现代码,注释比较少: package com.freesonfish.viewpager_2; import android.content.Context; import andro

Android ViewPager实现无限循环轮播广告位Banner效果

现在一些app通常会在头部放一个广告位,底部放置一行小圆圈指示器,指示广告位当前的页码,轮播展示一些图片,这些图片来自于网络.这个广告位banner是典型的android ViewPager实现,但是如果自己实现这样的ViewPager,要解决一系列琐碎的问题,比如: (1)这个广告位ViewPager要支持无限循环轮播,例如,有3张图片,A,B,C,当用户滑到最后C时候再滑就要滑到A,反之亦然. (2)ViewPager要实现自动播放,比如每个若干秒如2秒,自动切换播放到下一张图片. (3)通

android 2种效果求实现方法。。。有截图。。。

问题描述 android 2种效果求实现方法...有截图... ** 可以左右滑动,里面是文字,还可以上下滑动文字...我只做过图片的... ** ----------------------分割线----------------------------- 注意看图片边角(小半圆)...是怎么实现的,我已经确认过了图片是方形的,应该是覆盖了... 我不知道怎么覆盖的... 解决方案 android-support-v4.jar中的viewpager,里面是scrollview.覆盖,用relat

android viewpager切换fragment显示问题

问题描述 android viewpager切换fragment显示问题 项目中viewpager的第二个fragment添加有动画效果,可是viewpager采用预加载的机制,导致如果在第一个fragment等了5s(比如已在第二个fragment设定动画效果持续时间为5s),再切换到第二个fragment时候会没有动画效果,该怎么办? 解决方案 你可以重写第二个fragment的 @Override public void setUserVisibleHint(boolean isVisib

android tab切换效果如图???求实现思路

问题描述 android tab切换效果如图???求实现思路 解决方案 Android实现Tab切换效果总结 解决方案二: 其实这个效果分块解释,这样的效果不难.上面的四个按钮要做style,选择和非选择要有相应的图片背景就ok了. 解决方案三: 谢谢,我真正想问的是 上边 白色 和 灰色倾斜的的圆角只能用图片?? 解决方案四: 上边的白色和灰色,用图片实现比较快,而且方便.也可以做动画什么的. 解决方案五: 上边的是使用图片显示,下面使用Viewpager就行了.