and*_*per 22 animation android drawable android-progressbar
Android有一个标准的ProgressBar,在不确定时会有一个特殊的动画.还有很多可用的进度视图库(这里).
在我搜索过的所有内容中,我找不到办法做一件非常简单的事情:
具有从颜色X到颜色Y的渐变,水平显示,并在X坐标中移动,以便X之前的颜色将变为颜色Y.
例如(只是一个插图),如果我有一个蓝色< - >红色的渐变,从边缘到边缘,它将如此:
我在StackOverflow上尝试了一些解决方案:
但遗憾的是,它们都是关于Android的标准ProgressBar视图,这意味着它有一种不同的方式来显示drawable的动画.
我也试过在Android Arsenal网站上找到类似的东西,但即使有很多不错的东西,我找不到这样的东西.
当然,我可以自己动画2个视图,每个视图都有自己的渐变(一个与另一个相反),但我确信有更好的方法.
有可能使用Drawable或它的动画,这使得渐变(或其他任何东西)以这种方式移动(当然重复)?
也许只是从ImageView扩展并在那里制作drawable动画?
是否也可以设置容器将用于重复可绘制的多少?我的意思是,在上面的例子中,它可能是从蓝色到红色,所以蓝色将在边缘,红色将在中间.
编辑:
好的,我已经取得了一些进展,但是我不确定这个动作是否正常,而且我认为它的速度不一致,以防万一CPU有点忙,因为它不考虑帧丢失.我所做的是将2个GradientDrawables一个接一个地绘制,如下:
class HorizontalProgressView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val speedInPercentage = 1.5f
private var xMovement: Float = 0.0f
private val rightDrawable: GradientDrawable = GradientDrawable()
private val leftDrawable: GradientDrawable = GradientDrawable()
init {
if (isInEditMode)
setGradientColors(intArrayOf(Color.RED, Color.BLUE))
rightDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT;
rightDrawable.orientation = GradientDrawable.Orientation.LEFT_RIGHT
rightDrawable.shape = GradientDrawable.RECTANGLE;
leftDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT;
leftDrawable.orientation = GradientDrawable.Orientation.RIGHT_LEFT
leftDrawable.shape = GradientDrawable.RECTANGLE;
}
fun setGradientColors(colors: IntArray) {
rightDrawable.colors = colors
leftDrawable.colors = colors
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val widthSize = View.MeasureSpec.getSize(widthMeasureSpec)
val heightSize = View.MeasureSpec.getSize(heightMeasureSpec)
rightDrawable.setBounds(0, 0, widthSize, heightSize)
leftDrawable.setBounds(0, 0, widthSize, heightSize)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.save()
if (xMovement < width) {
canvas.translate(xMovement, 0.0f)
rightDrawable.draw(canvas)
canvas.translate(-width.toFloat(), 0.0f)
leftDrawable.draw(canvas)
} else {
//now the left one is actually on the right
canvas.translate(xMovement - width, 0.0f)
leftDrawable.draw(canvas)
canvas.translate(-width.toFloat(), 0.0f)
rightDrawable.draw(canvas)
}
canvas.restore()
xMovement += speedInPercentage * width / 100.0f
if (isInEditMode)
return
if (xMovement >= width * 2.0f)
xMovement = 0.0f
invalidate()
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
horizontalProgressView.setGradientColors(intArrayOf(Color.RED, Color.BLUE))
Run Code Online (Sandbox Code Playgroud)
结果(它确实循环好,很难编辑视频):
所以现在我的问题是,即使UI线程有点忙,我该怎样做才能确保它的动画效果很好?
只是invalidate单凭这对我来说似乎不是一种可靠的方式.我认为它应该检查更多.也许它可以使用一些动画API而不是内插器.
我决定在 Kotlin 中放置“pskink”答案(起源在这里)。我写在这里只是因为其他解决方案要么不起作用,要么是解决方法而不是我问的问题。
class ScrollingGradient(private val pixelsPerSecond: Float) : Drawable(), Animatable, TimeAnimator.TimeListener {
private val paint = Paint()
private var x: Float = 0.toFloat()
private val animator = TimeAnimator()
init {
animator.setTimeListener(this)
}
override fun onBoundsChange(bounds: Rect) {
paint.shader = LinearGradient(0f, 0f, bounds.width().toFloat(), 0f, Color.WHITE, Color.BLUE, Shader.TileMode.MIRROR)
}
override fun draw(canvas: Canvas) {
canvas.clipRect(bounds)
canvas.translate(x, 0f)
canvas.drawPaint(paint)
}
override fun setAlpha(alpha: Int) {}
override fun setColorFilter(colorFilter: ColorFilter?) {}
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
override fun start() {
animator.start()
}
override fun stop() {
animator.cancel()
}
override fun isRunning(): Boolean = animator.isRunning
override fun onTimeUpdate(animation: TimeAnimator, totalTime: Long, deltaTime: Long) {
x = pixelsPerSecond * totalTime / 1000
invalidateSelf()
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
主活动.kt
val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200f, resources.getDisplayMetrics())
progress.indeterminateDrawable = ScrollingGradient(px)
Run Code Online (Sandbox Code Playgroud)
活动_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"
tools:context=".MainActivity">
<ProgressBar
android:id="@+id/progress" style="?android:attr/progressBarStyleHorizontal" android:layout_width="200dp"
android:layout_height="20dp" android:indeterminate="true"/>
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2080 次 |
| 最近记录: |