Ant*_*nit 2 android loading android-progressbar progress-bar material-components-android
使用Material Design 库中的TextInputLayout,我们可以使用各种结束图标模式进行密码编辑、文本清除和自定义模式。此外,如果我们使用任何样式,它将自动应用显示打开和关闭 V 形的特殊结束图标模式。Widget.MaterialComponents.TextInputLayout.*.ExposedDropdownMenu
各种图标模式示例:
鉴于结束图标的各种用例,我们决定在 中使用加载指示器InputTextLayout,使其看起来像这样:
应该如何着手实施呢?
Ant*_*nit 23
可以简单地设置使用自定义可绘制代替结束图标,如下所示:
textInputLayout.endIconMode = TextInputLayout.END_ICON_CUSTOM
textInputLayout.endIconDrawable = progressDrawable
Run Code Online (Sandbox Code Playgroud)
有问题的部分是获取可绘制的加载指示器。
没有可用于加载指示器的公共可绘制资源。
有android.R.drawable.progress_medium_material但它被标记为私有并且无法在代码中解析。将资源及其所有依赖的私有资源复制到大约 6 个文件中(2 个可绘制对象 + 2 个动画师 + 2 个插值器)。这可以工作,但感觉很像黑客。
我们可以用它ProgressBar来检索它的indeterminateDrawable. 这种方法的问题在于 drawable 与ProgressBar. 指示器仅在ProgressBar可见时动画,为一个视图着色也会为另一个视图中的指示器着色,并且可能还有其他奇怪的行为。
在类似的情况下,我们可以使用Drawable.mutate()获取 drawable 的新副本。不幸的indeterminateDrawable是 已经发生了变异,因此mutate()什么也不做。
真正将可绘制对象与 分离的方法ProgressBar是调用indeterminateDrawable.constantState.newDrawable(). 有关更多见解,请参阅文档。
无论如何,这仍然感觉像是一个黑客。
尽管可绘制资源被标记为私有,但我们可以解析某些主题属性以获得可绘制的系统默认加载指示器。主题定义progressBarStyle了引用样式的属性ProgressBar。此样式内部是indeterminateDrawable引用主题可绘制的属性。在代码中,我们可以像这样解析可绘制对象:
fun Context.getProgressBarDrawable(): Drawable {
val value = TypedValue()
theme.resolveAttribute(android.R.attr.progressBarStyleSmall, value, false)
val progressBarStyle = value.data
val attributes = intArrayOf(android.R.attr.indeterminateDrawable)
val array = obtainStyledAttributes(progressBarStyle, attributes)
val drawable = array.getDrawableOrThrow(0)
array.recycle()
return drawable
}
Run Code Online (Sandbox Code Playgroud)
太好了,现在我们有了一个无需黑客即可绘制的本机加载指示器!
现在,如果您将 drawable 插入此代码
textInputLayout.endIconMode = TextInputLayout.END_ICON_CUSTOM
textInputLayout.endIconDrawable = progressDrawable
Run Code Online (Sandbox Code Playgroud)
你会发现它没有显示任何东西。
实际上,它确实正确显示了可绘制对象,但真正的问题是它没有被动画化。碰巧在动画开始时,drawable 被折叠成一个不可见的点。
对我们来说不幸的是,我们无法将 drawable 转换为其真实类型,AnimationScaleListDrawable因为它在com.android.internal.graphics.drawablepackage.json 中。幸运的是,我们可以键入它Animatable和start()它:
(drawable as? Animatable)?.start()
Run Code Online (Sandbox Code Playgroud)
TextInputLayout接收/失去焦点时会发生另一种意外行为。在这种情况下,它会根据定义的颜色为 drawable 着色layout.setEndIconTintList()。如果您没有明确指定色调列表,它会将可绘制对象着色为?colorPrimary。但是在我们设置 drawable 的那一刻,它仍然是有色的,?colorAccent并且在一个看似随机的时刻它会改变颜色。
出于这个原因,我建议双方着色layout.endIconTintList并drawable.tintList用相同的ColorStateList。如:
fun Context.fetchPrimaryColor(): Int {
val array = obtainStyledAttributes(intArrayOf(android.R.attr.colorPrimary))
val color = array.getColorOrThrow(0)
array.recycle()
return color
}
...
val states = ColorStateList(arrayOf(intArrayOf()), intArrayOf(fetchPrimaryColor()))
layout.setEndIconTintList(states)
drawable.setTintList(states)
Run Code Online (Sandbox Code Playgroud)
最终我们得到这样的东西:
与android.R.attr.progressBarStyle(中)和android.R.attr.progressBarStyleSmall分别。
您可以使用ProgressIndicator材料组件库提供的。
在您的布局中只需使用:
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textinputlayout"
...>
<com.google.android.material.textfield.TextInputEditText
.../>
</com.google.android.material.textfield.TextInputLayout>
Run Code Online (Sandbox Code Playgroud)
然后定义ProgressIndicator使用:
ProgressIndicatorSpec progressIndicatorSpec = new ProgressIndicatorSpec();
progressIndicatorSpec.loadFromAttributes(
this,
null,
R.style.Widget_MaterialComponents_ProgressIndicator_Circular_Indeterminate);
progressIndicatorSpec.circularInset = 0; // Inset
progressIndicatorSpec.circularRadius =
(int) dpToPx(this, 10); // Circular radius is 10 dp.
IndeterminateDrawable progressIndicatorDrawable =
new IndeterminateDrawable(
this,
progressIndicatorSpec,
new CircularDrawingDelegate(),
new CircularIndeterminateAnimatorDelegate());
Run Code Online (Sandbox Code Playgroud)
最后将可绘制对象应用到 TextInputLayout:
textInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM);
textInputLayout.setEndIconDrawable(progressIndicatorDrawable);
Run Code Online (Sandbox Code Playgroud)
转换为dp的是util方法:
public static float dpToPx(@NonNull Context context, @Dimension(unit = Dimension.DP) int dp) {
Resources r = context.getResources();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
}
Run Code Online (Sandbox Code Playgroud)
您可以轻松自定义circularRadius和indicatorColors以及 中定义的所有其他属性ProgressIndicator:
progressIndicatorSpec.indicatorColors = getResources().getIntArray(R.array.progress_colors);
progressIndicatorSpec.growMode = GROW_MODE_OUTGOING;
Run Code Online (Sandbox Code Playgroud)
用这个数组:
<integer-array name="progress_colors">
<item>@color/...</item>
<item>@color/....</item>
<item>@color/....</item>
</integer-array>
Run Code Online (Sandbox Code Playgroud)
注意:它至少需要版本1.3.0-alpha02.