android - 材质滑块和范围滑块工具提示并不总是可见
问题描述
我想让工具提示值始终可见,并且工具提示的文本应该是背景透明的。我尝试了https://github.com/material-components/material-components-android/blob/master/docs/components/Slider.md但没有办法让工具提示始终可见
<com.google.android.material.slider.Slider
android:id="@+id/slider_sound_sensitivity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:valueFrom="0.0"
android:valueTo="100.0"
android:layout_marginTop="@dimen/_8sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.508"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txt_sound_sensitivity" />
<com.google.android.material.slider.RangeSlider
android:id="@+id/range_humidity_in_percentage"
style="@style/Myslider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:valueFrom="0.0"
android:valueTo="100.0"
android:layout_marginTop="@dimen/_16sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txt_humidity_in_percentage"
app:values="@array/initial_slider_values" />
解决方案
目前根据Sliders - Material Design Documentation,没有公共 API 可以使用该app:labelBehavior
属性保持 Tooltip 始终可见。下面我将描述一种使用反射的可能解决方案。
创建 Slider/RangeSlider 的子类并覆盖该
onDraw(@NonNull Canvas canvas)
方法并调用该setSliderTooltipAlwaysVisible(Slider slider)
方法以保持 Tooltip 始终可见,如下所示:对于滑块:
public class MyCustomSlider extends Slider { public MyCustomSlider(@NonNull Context context) { super(context); init(); } public MyCustomSlider(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public MyCustomSlider(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ //in case this View is inside a ScrollView you can listen to OnScrollChangedListener to redraw the View getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { invalidate(); } }); } @Override protected void onDraw(@NonNull Canvas canvas) { super.onDraw(canvas); setSliderTooltipAlwaysVisible(this); } public static void setSliderTooltipAlwaysVisible(Slider slider){ try { Class<?> baseSliderCls = Slider.class.getSuperclass(); if (baseSliderCls != null) { Method ensureLabelsAddedMethod = baseSliderCls.getDeclaredMethod("ensureLabelsAdded"); ensureLabelsAddedMethod.setAccessible(true); ensureLabelsAddedMethod.invoke(slider); } } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } } }
对于 RangeSlider:
public class MyCustomRangeSlider extends RangeSlider { public MyCustomRangeSlider(@NonNull Context context) { super(context); init(); } public MyCustomRangeSlider(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public MyCustomRangeSlider(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ //in case this View is inside a ScrollView you can listen to OnScrollChangedListener to redraw the View getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { invalidate(); } }); } @Override protected void onDraw(@NonNull Canvas canvas) { super.onDraw(canvas); setSliderTooltipAlwaysVisible(this); } public static void setSliderTooltipAlwaysVisible(RangeSlider slider){ try { Class<?> baseSliderCls = RangeSlider.class.getSuperclass(); if (baseSliderCls != null) { Method ensureLabelsAddedMethod = baseSliderCls.getDeclaredMethod("ensureLabelsAdded"); ensureLabelsAddedMethod.setAccessible(true); ensureLabelsAddedMethod.invoke(slider); } } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } } }
这里的关键是在调用
private void ensureLabelsAdded()
后使用反射调用 BaseSlider 类的私有方法super.onDraw(canvas)
。在您的 xml 中使用上述自定义滑块,如下所示:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <my.package.name.MyCustomSlider style="@style/Widget.App.Slider" app:labelBehavior="floating" android:id="@+id/slider_sound_sensitivity" android:layout_width="0dp" android:layout_height="wrap_content" android:valueFrom="0.0" android:valueTo="100.0" android:layout_marginTop="@dimen/_8sdp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> <my.package.name.MyCustomRangeSlider style="@style/Widget.App.Slider" app:labelBehavior="floating" android:id="@+id/range_humidity_in_percentage" android:layout_width="0dp" android:layout_height="wrap_content" android:valueFrom="0.0" android:valueTo="100.0" android:layout_marginTop="@dimen/_16sdp" app:layout_constraintTop_toBottomOf="@+id/slider_sound_sensitivity" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:values="@array/initial_slider_values" /> </androidx.constraintlayout.widget.ConstraintLayout>
style="@style/Widget.App.Slider"
您在 styles.xml 文件中定义的自定义样式在哪里,如下所示:
<style name="Widget.App.Slider" parent="Widget.MaterialComponents.Slider">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.Slider</item>
<item name="labelStyle">@style/Widget.App.Tooltip</item>
</style>
<style name="ThemeOverlay.App.Slider" parent="">
<item name="colorPrimary">@android:color/holo_red_light</item>
<item name="colorOnSurface">@android:color/holo_red_light</item>
</style>
<style name="Widget.App.Tooltip" parent="Widget.MaterialComponents.Tooltip">
<item name="android:textAppearance">@style/TextAppearance.App.Tooltip</item>
<!--This is the Tooltip Background Color. In case you don't want a background change it to @android:color/transparent -->
<item name="backgroundTint">@android:color/holo_orange_light</item>
</style>
<style name="TextAppearance.App.Tooltip" parent="TextAppearance.MaterialComponents.Tooltip">
<item name="android:textColor">@android:color/holo_blue_light</item>
</style>
从上面的 xml 中,您可以通过更改 backgroundTint 颜色将工具提示背景更改为透明颜色: <item name="backgroundTint">@android:color/transparent</item>
。
带有透明背景的工具提示的结果始终可见:
带有工具提示的结果在非透明背景下始终可见:
推荐阅读
- automation - Node.js puppeteer - 转换获取 URL
- c# - 如何将JSON反序列化为具有继承类的对象c#WebAPI Post请求
- flutter - Flutter - sharedpreferences getString 方法
- intellij-idea - 在 Intellij Idea 2020.1 中找不到 Git 本地更改
- iis - 我在哪里设置最大查询字符串长度?
- vbscript - 为什么即使我结束了 if 语句,我也会收到“预期语句”错误?
- java - 我希望我的循环以java中的给定数字结束
- c - 在这种情况下如何使用 snprintf 而不是 strcpy?
- flask-sqlalchemy - Flask SqlAlchemy 读取锁定一行
- c++ - 我们可以将结构作为另一个结构中变量的数据类型吗?在 C++ 中