android带反弹效果ScrollView

xiaoxiao2021-02-28  109

自已写的一个带反弹效果的ScrollView,供参考 package cn.bassy.library.widget;    import android.content.Context;  import android.util.AttributeSet;  import android.view.MotionEvent;  import android.view.View;  import android.view.animation.OvershootInterpolator;  import android.widget.LinearLayout;  import android.widget.ScrollView;  import android.widget.Scroller;   / **   * 概述:滑动反弹组件   *     * 创建:2017-3-30   *     *   * @author Bassy Wain   */  public class BounceScrollView extends LinearLayout {      private static final String TAG = "BounceScrollView";        private enum PullAction {          PullDown, PullUp, None      }        / **       * 内容视图       */      private ScrollView mContentLayout;      / **       * 子View       */      private View mChildView;        / **       * 反弹效果       */      private Scroller mScroller;        / **       * 记录触摸按下位置       */      private float mTouchDownY;        / **       * 下拉偏移量与展示头部布局高度之间的比率,控制手势偏移与View偏移的比例       */      private static final float mPullRatio = 2.5f;        / **       * 当前操作类型       */      private PullAction mPullAction = PullAction.None;          public BounceScrollView(Context context) {          super(context);          init(context, null);      }        public BounceScrollView(Context context, AttributeSet attrs) {          super(context, attrs);          init(context, attrs);      }        public BounceScrollView(Context context, AttributeSet attrs, int defStyleAttr) {          super(context, attrs, defStyleAttr);          init(context, attrs);      }        private void init(Context context, AttributeSet attrs) {          setClickable(true);//设置为可点击,否则无法滚动            mScroller = new Scroller(context, new OvershootInterpolator());//带弹性效果          mContentLayout = createContentLayout(context);          addView(mContentLayout);      }        private ScrollView createContentLayout(Context context) {          ScrollView sv = new ScrollView(context);          sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));          return sv;      }        @Override      public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {          if (child == mContentLayout) {              //内容视图交给父类处理              super.addView(child, index, params);          } else {              //其它情况,交给ContentLayout处理              mContentLayout.addView(child, index, params);              mChildView = mContentLayout.getChildAt(0);          }      }        @Override      public boolean dispatchTouchEvent(MotionEvent ev) {            switch (ev.getActionMasked()) {              case MotionEvent.ACTION_DOWN: {                  //记录第一个手指的按下位置                  mTouchDownY = ev.getY();                  break;              }              case MotionEvent.ACTION_MOVE: {                  //对上拉和下拉进行计算和移动                  final float deltaY = mTouchDownY - ev.getY();                    mPullAction = (deltaY < 0) ? (PullAction.PullDown) :                          (deltaY > 0 ? PullAction.PullUp : PullAction.None);                    if (canPull()) {                      mScroller.abortAnimation();                      scrollTo(getScrollX(), (int) (deltaY / mPullRatio));                      if (mChildView != null) {                          mChildView.clearFocus();//清空子View的ACTION_DOWN状态                      }                  } else {                      mTouchDownY = ev.getY();                  }                  break;              }              case MotionEvent.ACTION_UP: {                  //回弹                  mPullAction = PullAction.None;                  smoothScrollTo(getScrollX(), 0);                  break;              }              default:          }          return super.dispatchTouchEvent(ev);      }        private boolean canPull() {            if (mChildView == null) {              //子视图为空              return true;          } else if (mPullAction == PullAction.PullDown && mContentLayout.getScrollY() <= 0) {              //ScrollView滚动位置在开始位置并且操作为下拉              return true;          } else if (mPullAction == PullAction.PullDown && getScrollY() > 0) {              //ScrollView先经过上拉拉出了一段距离(正数),再进行下拉操作,此时需要恢复位置              return true;          } else if (mPullAction == PullAction.PullUp &&                  (mContentLayout.getHeight() >= mChildView.getHeight())) {              //ScrollView的高度大于或等于子View的高度,此时允许上拉              return true;          } else if (mPullAction == PullAction.PullUp &&                  (mContentLayout.getHeight() + mContentLayout.getScrollY() >=                          mChildView.getHeight())) {              //ScrollView的高度 + ScrollView的滚动高度 >= 子View的高度(说明已经滚动到底部)              return true;          } else if (mPullAction == PullAction.PullUp && getScrollY() < 0) {              //ScrollView先经过下拉拉出了一段距离(负数),再进行上拉操作,此时需要恢复位置              return true;          } else {              return false;          }      }          / **       * 平滑滚动到指定位置       *       * @param toX 目标水平位置       * @param toY 目标垂直位置       */      private void smoothScrollTo(int toX, int toY) {            mScroller.abortAnimation();          mScroller.forceFinished(true);            int fromX = getScrollX();          int fromY = getScrollY();            mScroller.startScroll(fromX, fromY, toX - fromX, toY - fromY, 300);          invalidate();//要求重绘(即调用draw,该方法会调用computeScroll)      }        @Override      public void computeScroll() {          if (mScroller.computeScrollOffset()) {              scrollTo(mScroller.getCurrX(), mScroller.getCurrY());              invalidate();//要求重绘(即调用draw,该方法会调用computeScroll)          }      }  } 

转载请注明原文地址: https://www.6miu.com/read-49421.html

最新回复(0)