美文网首页Android
Android View的滑动和滑动冲突

Android View的滑动和滑动冲突

作者: 漆先生 | 来源:发表于2022-03-09 22:47 被阅读0次

    一、View的滑动

    可以通过三种方式实现滑动。

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

    1.使用scrollTo和scrollBy

        public void scrollTo(int x, int y) {
            if (mScrollX != x || mScrollY != y) {
                int oldX = mScrollX;
                int oldY = mScrollY;
                mScrollX = x;
                mScrollY = y;
                invalidateParentCaches();
                onScrollChanged(mScrollX, mScrollY, oldX, oldY);
                if (!awakenScrollBars()) {
                    postInvalidateOnAnimation();
                }
            }
        }
    
        public void scrollBy(int x, int y) {
            scrollTo(mScrollX + x, mScrollY + y);
        }
    

    scrollBy实际调用了scrollTo,实现了相对于当前位置的相对滑动。scrollTo实现了基于所传递参数的绝对滑动。
    scrollTo和scrollBy只能改变View的内容位置,而不能改变View在布局中的位置。
    mScrollX的值暂时等于View左边缘和View内容左边缘在水平方向的距离,内容在View的左边,为正值,反之为负值
    mScrollY的值总是等于View上边缘和View内容上边缘在竖直方向的距离,内容在View的上边,为正值,反之为负值

    2.使用动画

    使用动画来移动移动View,主要是操作View的translationX和translationY属性。可以选择传动的View动画,也可以选择属性动画。

    加载xml动画100ms把View移动到右下角100个像素,新位置只是View的影像,点击目标view会触发click。

    <?xml version="1.0" encoding="utf-8"?>
    <!--fillAfter = true设置停留在动画后的音像-->
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:fillAfter="true"
        android:zAdjustment="normal">
        <translate
            android:duration="100"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:interpolator="@android:anim/linear_interpolator"
            android:toXDelta="100"
            android:toYDelta="100" />
    </set>
    
    val animation = AnimationUtils.loadAnimation(this@MainActivity, R.anim.translate_100)
    v.startAnimation(animation)
    

    属性动画,将View右移动100像素,点击目标View,不会触发click。

    ObjectAnimator.ofFloat(v, "translationX", 0f, 100f).setDuration(100).start()
    

    3.改变布局参数

    修改LayoutPrams的值达到滑动效果,右移100px

    val params: ViewGroup.MarginLayoutParams =
        textView.layoutParams as ViewGroup.MarginLayoutParams
    params.leftMargin += 100
    v.requestLayout()
    //v.layoutParams = params
    

    4.对比总结

    • scrollTo和scrollBy:操作简单,View提供的原生方法,适合View内容的滑动。不影响元素的单击事件。缺点是只能移动内容,不能移动View本身。
    • 动画:属性动画没有明显缺点,如果是使用xml动画,不能改变View本身的属性。如果动画元素不需要响应用户的交互,使用动画来做滑动比较合适。并且还能实现复杂的效果。
    • 改变布局参数:使用麻烦一点,没有明显缺点,适用于动画元素是一些具有交互性的View。

    二、弹性滑动

    1.使用Scroller

        public void smoothScrollTo(int destX, int destY) {
            int scrollX = getScrollX();
            int scrollY = getScrollY();
            mScroller.startScroll(scrollX, scrollY, destX, destY, 1000);
            invalidate();
        }
    
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrX());
                postInvalidate();
            }
        }
    
        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;
        }
    

    startScroll是无法让View滑动的,因为它内部并没有做滑动相关的事情。startScroll方法下面有一个invalidate方法,会导致View重绘,在View的onDraw方法就会去调用computeScroll方法,computeScroll在View中是一个空的实现。我们在实现时,又去向scroller获取当前的scrollX和scrollY,再用scrollTo方法实现滚动,接着又调用postInvalidate方法进行第二次重绘,如此反复,就完成了滑动的整个过程。

    2.通过动画

    动画本身就是一个渐进的过程,天然的具有弹性效果,如上面的属性动画。

    ObjectAnimator.ofFloat(v, "translationX", 0f, 100f).setDuration(100).start()
    

    3.使用延迟策略

    核心思想是通过发送一系列的延迟消息从而达到渐进时的效果。可以使用Handler或者View的postDelayed方法,也可以使用线程的sleep方法。

    三、View的滑动冲突

    1.常见的滑动冲突场景

    • 外部滑动方向和内部滑动方向不一致
    • 外部滑动方向和内部滑动方向一致
    • 以上两种情况嵌套

    2.滑动冲突的解决方式

    • 外部拦截法,父容器需要此事件就拦截,不需要就不拦截。重写父容器的onInterceptTouch
      Event方法就行。
    • 内部拦截法,父容器不拦截任何事件,所有事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理。需要配合requestDisallowInterceptTouchEvent方法使用。

    相关文章

      网友评论

        本文标题:Android View的滑动和滑动冲突

        本文链接:https://www.haomeiwen.com/subject/reptdrtx.html