注册

Android 实现自动滚动布局

前言


在平时的开发中,有时会碰到这样的场景,设计上布局的内容会比较紧凑,导致部分机型上某些布局中的内容显示不完全,或者在数据内容多的情况下,单行无法显示所有内容。这时如果要进行处理,无非就那几种方式:换行、折叠、缩小、截取内容、布局自动滚动等。而这里可以简单介绍下布局自动滚动的一种实现方式。


1. 布局自动滚动的思路


要实现滚动的效果,在Android中无非两种,吸附式的滚动或者顺滑式的滚动,吸附式就是类似viewpager换页的效果,如果需求上是要实现这样的效果,可以使用viewpager进行实现,这个类型比较简单,这里就不过多介绍。另一种是顺滑的,非常丝滑的缓慢移动的那种,要实现这种效果,可以使用RecyclerView或者ScrollView来实现。我这里主要使用ScrollView会简单点。


滑动的控件找到了,那要如何实现丝滑的自动滚动呢?我们都知道ScrollView能用scrollTo和scrollBy去让它滚动到某个位置,但如何去实现丝滑的效果?


这里就用到了属性动画, 我之前的文章也提到过属性动画的强大 juejin.cn/post/714419…


所以我这边会使用ScrollView和属性动画来实现这个效果


2. 最终效果


可以写个Demo来看看最终的效果


799d8a54-ed7d-4137-8a00-ad6bed2e2499.gif


这就是一个横向自动滚动的效果。


3. 代码实现


先写个接口定义自动滚动的行为


interface Autoscroll {

// 开始自动滚动
fun autoStart()

// 停止自动滚动
fun autoStop()

}

然后自定义一个View继承ScrollView,方便阅读,在代码中加了注释


// 自定义View继承HorizontalScrollView,我这里演示横向滚动的,纵向可以使用ScrollView
class HorizontalAutoscrollLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : HorizontalScrollView(context, attrs, defStyleAttr), Autoscroll {

// 一些流程上的变量,可以自己去定义,变量多的情况也可以使用builder模式
var isLoop = true // 滚动到底后,是否循环滚动
var loopDelay = 1000L // 滚动的时间
var duration = 1000L // 每一次滚动的间隔时间

private var offset: Int = 0
val loopHandler = Handler(Looper.getMainLooper())
var isAutoStart = false

private var animator: ValueAnimator? = null

override fun autoStart() {
// 需要计算滚动距离所以要把计算得代码写在post里面,等绘制完才拿得到宽度
post {
var childView = getChildAt(0)
childView?.let {
offset = it.measuredWidth - width
}

// 判断能否滑动,这里只判断了一个方向,如果想做两个方向的话,多加一个变量就行
if (canScrollHorizontally(1)) {
animator = ValueAnimator.ofInt(0, offset)
.setDuration(duration)
// 属性动画去缓慢改变scrollview的滚动位置,抽象上也可以说改变scrollview的属性
animator?.addUpdateListener {
val currentValue = it.animatedValue as Int
scrollTo(currentValue, 0)
}
animator?.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {

}

override fun onAnimationEnd(animation: Animator) {
// 动画结束后判断是否要重复播放
if (isLoop) {
loopHandler?.postDelayed({
if (isAutoStart) {
scrollTo(0, 0)
autoStart()
}
}, loopDelay)
}
}

override fun onAnimationCancel(animation: Animator) {

}

override fun onAnimationRepeat(animation: Animator) {

}

})
animator?.start()
isAutoStart = true
}

}
}

// 动画取消
override fun autoStop() {
animator?.cancel()
isAutoStart = false
loopHandler.removeCallbacksAndMessages(null)
}

}

能看到实现这个功能,写的代码不会很多。其中主要需要注意一些点:

(1)属性动画要熟,我这里只是简单的效果,但如果你对属性动画能熟练使用的话,你还可以做到加速、减速等效果

(2)页面关闭的时候要调用autoStop去关闭动画

(3)这里是用scrollTo去实现滚动的效果,scrollBy也可以,但是写法就不是这样了


从代码可以看出没什么难点,都是比较基础的知识,比较重要的知识就是属性动画,熟练的话做这种效果的上限就很高。其他的像这里为什么用post,为什么用scrollTo,这些就是比较基础的知识,就不扩展讲了。


最后看看使用的地方,先是Demo的布局


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.kylin.testproject.HorizontalAutoscrollLayout
android:id="@+id/auto_scroll"
android:layout_width="150dp"
android:layout_height="wrap_content">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="小日本"
/>

<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:scaleType="fitXY"
android:src="@drawable/a"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="排放核废水污染海洋"
/>

<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:scaleType="fitXY"
android:src="@drawable/b"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text=",必遭天谴!!"
/>

</LinearLayout>

</com.kylin.testproject.HorizontalAutoscrollLayout>

</LinearLayout>


然后在开始播放自动滚动(注意页面关闭的时候要手动停止)


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)

val autoScroll: HorizontalAutoscrollLayout = findViewById(R.id.auto_scroll)
autoScroll.duration = 3000
autoScroll.loopDelay = 2000
autoScroll.autoStart()
}

4. 总结


代码比较简单,而且都加上了注释,所以没有其他要说明的。

前段时间太忙,所以这几个月都没时间写文章。想了一下,这个还是要坚持,如果有时间的话抽出点时间一天写一点,得保持一个常更新的状态。


作者:流浪汉kylin
来源:juejin.cn/post/7309392585679110194

0 个评论

要回复文章请先登录注册