当前位置: 首页 > 编程笔记 >

android自定义ViewPager水平滑动弹性效果

刁远
2023-03-14
本文向大家介绍android自定义ViewPager水平滑动弹性效果,包括了android自定义ViewPager水平滑动弹性效果的使用技巧和注意事项,需要的朋友参考一下

android ViewPager是一个经常要用到的组件,但android系统本身为我们提供的ViewPager是没有任何效果的,只能是一页一页的滑动,这样会让人感觉很死板,在看一些知名大公司的App时,看到了他们的ViewPager在滑动到最开始或者最后的时候是有一个弹性效果的,使用起来感觉非常的好,于是乎就是百度搜了一下,在StackOverflow中看到一篇文章就是讲如何实现这个效果的。

先看下效果图:滑动到最后一页时仍然可以拉动……

代码如下:

package com.example.myviewpager; 
 
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.nineoldandroids.animation.Animator; 
import com.nineoldandroids.animation.Animator.AnimatorListener; 
import com.nineoldandroids.animation.ObjectAnimator; 
 
public class BounceBackViewPager extends ViewPager 
{ 
 
 /** 
  * maximum z distance to translate child view 
  */ 
 final static int DEFAULT_OVERSCROLL_TRANSLATION = 500; 
 
 /** 
  * 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_bounce, 
    DEFAULT_OVERSCROLL_TRANSLATION); 
  mOverscrollAnimationDuration = a.getInt(R.styleable.BounceBackViewPager_overscroll_animation_duration_bounce, 
    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; 
 } 
} 

html" target="_blank">定义属性如下:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍Android自定义ViewPager实现纵向滑动翻页效果,包括了Android自定义ViewPager实现纵向滑动翻页效果的使用技巧和注意事项,需要的朋友参考一下 抖音几乎已经成为了我们日常生活中使用比较频繁的App,无聊之时或工作之后可以刷一刷短视频来供我们娱乐与放松。看到抖音的视屏切换效果,觉得用ViewPager可以做出一样的效果。想一想之前用的ViewPager都是横向切换

  • 本文向大家介绍android自定义View滑动删除效果,包括了android自定义View滑动删除效果的使用技巧和注意事项,需要的朋友参考一下 View滑动删除效果图 实现功能 1、可以向左滑动,右侧出现删除 2、向左滑动如果删除出现一大半,松手打开删除,反之关闭删除 3、应用场景           微信消息的删除功能 实现原理 1、外面是一个ListView 2、条目是一个自定义控件继承Vie

  • 我试图创建一个进度条,当它水平前进时,进度条本身会以垂直旋转的方式进行动画。我通过以下方式成功地使用了我的进度绘图功能: 这是我的画: 但我希望它在前进的过程中有一个微妙的滚动效果。所以看起来垂直线在向后移动。你明白了吗?非常感谢您的帮助。谢谢 编辑:我尝试创建一个动画列表作为我的进度绘图,但我仍然不能看到动画。动画列表可以在进度项目的剪辑中吗?

  • 本文向大家介绍Android自定义View实现弹性小球效果,包括了Android自定义View实现弹性小球效果的使用技巧和注意事项,需要的朋友参考一下 照例先看效果图 自定义代码示例 总结 以上就是Android自定义View实现弹性小球效果的全部内容,希望对大家开发Android能带来一定的帮助,如果有疑问大家可以留言交流。谢谢大家对呐喊教程的支持。

  • 本文向大家介绍android viewpager实现竖屏滑动效果,包括了android viewpager实现竖屏滑动效果的使用技巧和注意事项,需要的朋友参考一下 Viewpager 横向滑动效果系统就自带了很多种,比如这个 效果 那如果做成竖屏的这种效果呢 。我百度过很多,效果都不是很好,有的代码特别多而且存在很多问题。我结合了以前别人的代码现在来教大家个简单的实现过程。 首先自定义Viewpa

  • 本文向大家介绍Android使用Scroller实现弹性滑动效果,包括了Android使用Scroller实现弹性滑动效果的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android使用Scroller实现弹性滑动展示的具体代码,供大家参考,具体内容如下 scrollTo、scrollBy View内部为了实现滑动提供了这两个方法,但是使用这两个方法滑动的效果是瞬间的不够平滑,如何