使用scrollTo、scrollBy、Scroller实现滚动动画

在上一节讲解了layoutoffsetlayoutParam的使用,本节说明scrollToscrollByScroller

1、scrollToscrollBy

view体系中,可以使用scrollToscrollBy移动view的位置,他们两个的区别也很简单。

  • scrollTo(x, y)view 移动到一个具体的坐标点
  • scrollBy(x, y) 将view在现有坐标基础上进行增量移动

scrollBy本质上是内部调用的scrollTo实现。

public void scrollBy(int x, int y) {
  scrollTo(mScrollX + x, mScrollY + y);
}

看到这里是不是感觉会了,想要宠宠欲动了,尝试之后发现view在scrollToscrollBy的时候并没有发生移动。这是因为scrollByscrollTo作用的对象是view的内容。如果你想要view移动,则需要通过view的父类viewGroup来触发移动。

(view.parent as ViewGroup).scrollBy(x, y)

再次尝试,你就会发现发生了移动,但是当你设置移动scrollBy(20, 20),视图本身的移动却与你想要的相反了。其实出现这种情况的原因是,移动操作作用的是父布局,你可以理解为移动的是背景幕布,当幕布移动的时候,视觉上你的位置其实就是和幕布相反的。

所以就会出现这样的结果:

  • 当你在scrollBy/scrollTo设置负数的时候,content其实是沿着正方向移动
  • 当你在scrollBy/scrollTo设置正数的时候,content其实是沿着负方向移动

下面移动一个简单的实例:

class ScrollerByOrToView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) {

    private var mLastX = 0F
    private var mLastY = 0F

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                this.performClick()
                mLastX = event.x
                mLastY = event.y
            }
            MotionEvent.ACTION_MOVE -> {
                val offsetX = event.x - mLastX
                val offsetY = event.y - mLastY
                (parent as ViewGroup).scrollBy(-offsetX.toInt(), -offsetY.toInt())
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                (parent as ViewGroup).scrollTo(0, 0)
            }
        }
        return true
    }
}
<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical">

   <org.fireking.basic.animator.basic.widget.ScrollerByOrToView
       android:id="@+id/scrollTouchView"
       android:layout_width="90dp"
       android:layout_height="90dp"
       android:background="#ff723d"
       android:gravity="center"
       android:text="Touch"
       android:textColor="@android:color/white"
       android:textSize="12dp" />

   <TextView
       android:layout_width="90dp"
       android:layout_height="90dp"
       android:background="#80008800"
       android:gravity="center"
       android:text="我是一个参照物,我和滚动布局在同一个父容器"
       android:textColor="@android:color/white"
       android:textSize="12dp" />

</LinearLayout>

在这里插入图片描述

2、scroller

使用scrollByscrollTo帮我们完成很多移动动画效果,但是使用的过程中,发现移动时瞬间完成的,这样明显是很丑陋的。

这个时候,就需要用到scroller登场了,使用scroller可以实现平滑移动效果。

下面简单介绍下scroller使用

  • 初始化Scroller
//两个参数分别是上下文对象 和 插值器
//Scroller(Context context, Interpolator interpolator)
private var mScroller: Scroller = Scroller(context, AccelerateDecelerateInterpolator())
  • 使用startScroll(int startX, int startY, int dx, int dy, int duration)方法开始平滑移动
val viewGroup = parent as ViewGroup
//5个参数分别是移动起始位置,移动偏移量,移动动画持续时长
mScroller.startScroll(
        viewGroup.scrollX,
        viewGroup.scrollY,
        -viewGroup.scrollX,
        -viewGroup.scrollY,
        1000
    )
  • 重写override fun computeScroll()方法

这个方法中会首先判断动画是否结束,没有结束的话,则需要调用scrollTo进行移动,而移动的距离则是mScroller.currXmScroller.currY。同时需要调用invalidate

 override fun computeScroll() {
     super.computeScroll()
     if (mScroller.computeScrollOffset()) {
         (parent as ViewGroup).scrollTo(mScroller.currX, mScroller.currY)
         invalidate()
     }
 }

最后是一个简单的例子。

class ScrollerView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) {

    private var mLastX = 0F
    private var mLastY = 0F

    private var mScroller: Scroller = Scroller(context, AccelerateDecelerateInterpolator())

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                this.performClick()
                mLastX = event.x
                mLastY = event.y
            }
            MotionEvent.ACTION_MOVE -> {
                val offsetX = event.x - mLastX
                val offsetY = event.y - mLastY
                (parent as ViewGroup).scrollBy(-offsetX.toInt(), -offsetY.toInt())
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                val viewGroup = parent as ViewGroup
                mScroller.startScroll(
                    viewGroup.scrollX,
                    viewGroup.scrollY,
                    -viewGroup.scrollX,
                    -viewGroup.scrollY,
                    1000
                )
                invalidate()
            }
        }
        return true
    }

    override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            (parent as ViewGroup).scrollTo(mScroller.currX, mScroller.currY)
            invalidate()
        }
    }
}
<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <org.fireking.basic.animator.basic.widget.ScrollerView
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:background="#9f723d"
                android:gravity="center"
                android:text="Touch"
                android:textColor="@android:color/white"
                android:textSize="12dp" />

            <TextView
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:background="#80008800"
                android:gravity="center"
                android:text="我是一个参照物,我和滚动布局在同一个父容器"
                android:textColor="@android:color/white"
                android:textSize="12dp" />
        </LinearLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end"
            android:text="我和滚动布局的父布局平级,\n用来区分平移。\n使用scrollBy和scrollTo滑动,\n移动的是所在的父容器"
            android:textColor="@color/black"
            android:textSize="12dp" />
    </FrameLayout>

在这里插入图片描述
拖动移动一段距离放手之后,布局会平滑的移动到初始位置。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值