View事件体系学习(一)滑动

来源:互联网 发布:知行供应链 编辑:程序博客网 时间:2024/05/21 17:13

一、View 的滑动可以通过三种方法来实现:

  • 通过 View 本身提供的 scrollTo / scrollBy 方法来实现。
  • 通过动画给 View 施加平移效果来实现滑动。
  • 通过改变 View 的 LayoutParams 使得 View 重新布局从而实现滑动。

(一) scrollTo / scroll By

scrollTo:

这里写图片描述

scrollBy:

这里写图片描述

丛源码来看,scrollBy 调用了 scrollTo, 而最终 scrollTo 调用了 onScrollChanger() 方法。

在滑动过程中:

  • mScrollX 的值总是等于 View 左边缘和 View 内容左边缘在水平方向上的距离。
    mScrollY 的值总是等于 View 上边缘和 View 内容上边缘在竖直方向上的距离。

  • View 的边缘是指 View 的位置,由四个顶点组成,
    而View内容的边缘是指 View 中的内容的边缘。

  • scrollTo / scrollBy 只能改变 View 内容的位置而不能改变 View 在布局中的位置。

  • mScrollX 和 mScrollY 的单位为像素,并且当 View 左边缘在 View 内容左边缘的右边时,mScrollX 为正值,反之为负值;当 View 的上边缘在 View 内容的上边缘的下边时, mScrollY 为正值,反之为负值。

  • 从左向右化滑动,那么 mScrollX 为负值,反之为正值。 从上往下滑动,哪么 mScrollY 为负值,反之为正值。

(二)使用动画

使用动画来移动 View,主要是操作 View 的 translationX 和 translationY 属性,既可以采用传统的 View 动画,也可以采用属性动画,如果采用属性动画的话,需要注意兼容 3.0 以下的版本。

(三)改变布局参数

通过 view.getLayoutParams() 方法获得LayoutParams 对象,在该对象中,通过修改margin、width等属性来实现 View 的滑动效果。

总结:

  • scrollTo / scrollBy: 操作简单,适合对 view 内容的滑动。
    但是它只能滑动 view 的内容,不能滑动 view 的本身。

  • 动画:操作简单,主要适用于没有交互的 View 和实现复杂的动画效果。
    如果使用属性动画,哪么采用这种方式没有明显的缺点。

  • 改变布局参数:操作稍微复杂,适用于有交互的 View。

二、弹性滑动的实现:

(一)使用Scroller

先看代码:

private Scroller scroller = new Scroller(getContext());    public void smoothScroollTo(int destX,int dextY,int duration){        int scrollX = getScrollX();        int deltaX = destX - scrollX;        int scrollY = getScrollY();        int deltaY = dextY - scrollY;        scroller.startScroll(scrollX,scrollY,deltaX,deltaY,duration);        invalidate();    }    @Override    public void computeScroll() {        if (scroller.computeScrollOffset()){            scrollTo(scroller.getCurrX(),scroller.getCurrY());            postInvalidate();        }    }

有几个注意的地方:
1,必须重写 View 的 computeScroll() 方法。
2,scroller.startScroll()其实并没有使 View 进行滑动,而是保存了我们传递的几个参数:

  public void startScroll(int startX, int startY, int dx, int dy, int duration) {        mMode = SCROLL_MODE;        mFinished = false;        mDuration = duration;        mStartTime = AnimationUtils.currentAnimationTimeMillis();        mStartX = startX;        mStartY = startY;        mFinalX = startX + dx;        mFinalY = startY + dy;        mDeltaX = dx;        mDeltaY = dy;        mDurationReciprocal = 1.0f / (float) mDuration;    }

在保存好参数之后,我们需要调用 invalidate() 方法让 View 重绘,而在 View 重绘的 draw() 方法又会去调用 computeScroll 方法。

3,computeScrollOffset:

  public boolean computeScrollOffset() {        if (mFinished) {            return false;        }        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);        if (timePassed < mDuration) {            switch (mMode) {            case SCROLL_MODE:                final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);                mCurrX = mStartX + Math.round(x * mDeltaX);                mCurrY = mStartY + Math.round(x * mDeltaY);                break;            case FLING_MODE:                final float t = (float) timePassed / mDuration;                final int index = (int) (NB_SAMPLES * t);                float distanceCoef = 1.f;                float velocityCoef = 0.f;                if (index < NB_SAMPLES) {                    final float t_inf = (float) index / NB_SAMPLES;                    final float t_sup = (float) (index + 1) / NB_SAMPLES;                    final float d_inf = SPLINE_POSITION[index];                    final float d_sup = SPLINE_POSITION[index + 1];                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;                }                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));                // Pin to mMinX <= mCurrX <= mMaxX                mCurrX = Math.min(mCurrX, mMaxX);                mCurrX = Math.max(mCurrX, mMinX);                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));                // Pin to mMinY <= mCurrY <= mMaxY                mCurrY = Math.min(mCurrY, mMaxY);                mCurrY = Math.max(mCurrY, mMinY);                if (mCurrX == mFinalX && mCurrY == mFinalY) {                    mFinished = true;                }                break;            }        }        else {            mCurrX = mFinalX;            mCurrY = mFinalY;            mFinished = true;        }        return true;    }

该方法根据时间的流逝来计算出当前的 scrollX 和 scrollY 的值,返回 true 表示滑动未结束。

4, 使用 scroller 只能使内容进行滑动。

(二)通过动画

属性动画可以设置duration以及插值器来实现。

    ObjectAnimator animator = ObjectAnimator.ofFloat(myScrollView, "translationX", 0f, 360f);        animator.setDuration(3000);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.start();

具体的动画学习放在以后=。=

(三)使用延时策略
使用延时策略的核心思想是,通过发送一系列延时消息从而达到一种渐进式的效果,具体来说可以使用 Handler 或 View 的 postDelayed 方法,也可以使用线程的 sleep 方法。

原创粉丝点击