0%

View滑动

View滑动

view滑动可通过下面几种方法:

  • layout
  • offsetLeftAndRight
  • offsetTopAndBottom
  • LayoutParams
  • Animation
  • Scroller

示意图

view_slide01

view_slide02:


layout

通过layout方法让view移动到指定的坐标位置

val HORIZONTAL_OFFSET = 100f.dp
val VERTICAL_OFFSET = 100f.dp
class SlideByLayoutActivity : BaseSlideActivity() {
override fun slide() {
slideView.layout(
HORIZONTAL_OFFSET,
VERTICAL_OFFSET,
HORIZONTAL_OFFSET + slideView.width,
VERTICAL_OFFSET + slideView.height
)
}
}

offsetLeftAndRight

通过view的offetLeftAndRight方法滑动到指定位置

override fun slide() {
slideView.offsetLeftAndRight(HORIZONTAL_OFFSET)
}

offsetTopAndBottom

通过view的offetTopAndBottom方法滑动到指定位置

override fun slide() {
slideView.offsetTopAndBottom(-VERTICAL_OFFSET)
}

LayoutParams

通过LayoutParams滑动到指定位置

override fun slide() {
val layoutParams = slideView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.leftMargin = HORIZONTAL_OFFSET
layoutParams.topMargin = VERTICAL_OFFSET
slideView.layoutParams = layoutParams
}

Animation

通过位移动画滑动到指定位置,注意位移动画只是视觉移动View并不会真正发生移动,如果View有点击事件,还是响应原来的点击区域

override fun slide() {
val translateAnimation = TranslateAnimation(
0f,
(HORIZONTAL_OFFSET - slideView.left).toFloat(),
0f,
(VERTICAL_OFFSET - slideView.top).toFloat()
)
translateAnimation.duration = 500
translateAnimation.fillAfter = true
slideView.startAnimation(translateAnimation)
}

Scroller

通过layout,layoutparams,offsetLeftAndRight方法对view滑动是比较生硬的,可以使用Scroller实现平滑移动
实现原理:
Scroller的用法有固定模板
1.自定义View重写computeScroll实现滑动逻辑
2.提供对外调用的滑动方法,初始化scroller
自定义View并重写computeScroll方法,computeScroll会在View的onDraw方法中被调用,computeScroll实现细节是获取当前时刻scroller滑动的最新位置并调用View的Parent的scrollTo方法滑动并调用postInvalidate方法重绘触发下一次computeScroll循环直到滑动到指定位置。
然后需要提供一个对外暴露的滑动方法内部初始化Scroller并调用startScroll方法启动Scroller接着调用invalidate触发computeScroll方法。

class SlideView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
View(context, attrs) {
private var scroller: Scroller = Scroller(context)
override fun computeScroll() {
if (scroller.computeScrollOffset()) {
(parent as View).scrollTo(scroller.currX, scroller.currY)
postInvalidate()
}
}

fun startSmooth(delX: Int, delY: Int) {
val destX = delX - scrollX
scroller.startScroll(scrollX, 0, destX, delY, 2000)
invalidate()
}
}

解惑Scroller:
1.为什么是调用Parent的scrollTo?
2.为什么滑动方向跟期望是相反的?

为什么是调用Parent的scrollTo?
我们很直观的会认为应该调用View的scrollTo方法发现View位置并没有发生变化,这是因为scrollTo移动的是View的内容Content,如果的TextView调用scrollTo你会发现文本内容发生了移动


为什么滑动方向跟期望是相反的?
当我们想要x轴放心移动100像素值时,实际结果恰好相反向x轴负方向发生了移动,这是为什么呢
借鉴《Android群英传》的一张图来解释

我们可以把View看做是镂空的下面是内容content就像画布一样,当我们调用scrollTo时是镂空的部分在移动,这个移动是相对于content的位移,相当于content并没有移动移动的是镂空的部分,我们想要button右移的时候,镂空的部分需要向左移动,这样大家应该可以更好的理解了。

Github代码地址:ViewSlide

参考:
《Android群英传》