带有进度条的按钮 android
Posted
技术标签:
【中文标题】带有进度条的按钮 android【英文标题】:Button with progress bar android 【发布时间】:2021-05-29 10:54:36 【问题描述】:我正在尝试在 android 中创建一个带有进度条的自定义按钮。
按钮应该有两种状态: 正常和正在加载。
在正常状态下它应该显示一个文本,而在加载状态下它应该显示一个居中的圆形进度指示器而不是文本! 当按钮状态返回“正常”状态时,它应该再次显示文本。
为了实现这一点,我考虑过创建一个从 RelativeLayout 构建的自定义视图 在其中有一个 TextView 和一个 Circular 进度指示器,并根据状态更改它们在代码中的可见性。
这个想法和逻辑很有效。
请参考我的带有进度指示器的按钮图片:
但是,当我想将选择器应用于此视图时,问题就来了, 我为每个按钮创建了一个样式和一个选择器,但它只是在禁用时没有为视图设置正确的背景。
RelativeLayout 在其 xml 中没有可用的 enabled
属性,因此我必须添加一个可样式化的 attr 并使用 isEnabled = false
或类似的东西在代码中更改其状态。
这使得它在 did 中被禁用,但背景保持启用状态(选择器不起作用)。
这是我的“按钮”源代码:
class ProgressButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr)
private val progressBar: LottieAnimationView
private val buttonTextView: TextView
init
val root = LayoutInflater.from(context).inflate(R.layout.progress_button, this, true)
buttonTextView = root.findViewById(R.id.button_text)
progressBar = root.findViewById(R.id.progress_indicator)
loadAttr(attrs, defStyleAttr)
private fun loadAttr(attrs: AttributeSet?, defStyleAttr: Int)
val arr = context.obtainStyledAttributes(
attrs,
R.styleable.ProgressButton,
defStyleAttr,
0
)
val buttonText = arr.getString(R.styleable.ProgressButton_text)
val loading = arr.getBoolean(R.styleable.ProgressButton_loading, false)
val enabled = arr.getBoolean(R.styleable.ProgressButton_enabled, true)
isEnabled = enabled
arr.recycle()
buttonTextView.text = buttonText
setLoading(loading)
fun setLoading(loading: Boolean)
if(loading)
buttonTextView.visibility = View.GONE
progressBar.visibility = View.VISIBLE
else
buttonTextView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
这是它的布局:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_>
<TextView
android:id="@+id/button_text"
android:layout_
android:layout_
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceButton"
android:text="OK" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/progress_indicator"
android:layout_
android:layout_
android:layout_centerInParent="true"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lottile_button_loader" />
</RelativeLayout>
这是一个带有选择器的背景:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/components_corner_radius" />
<solid android:color="@color/button_black_bg_selector" />
</shape>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/black" android:state_enabled="true" />
<item android:color="@color/buttons_black_pressed" android:state_pressed="true" />
<item android:color="@color/buttons_black_disabled" android:state_enabled="false" />
<item android:color="@color/black" />
这是样式和主题:
<style name="Theme.Widget.ProgressButton" parent="">
<item name="android:textAppearanceButton">@style/TextAppearance.Body.White</item>
</style>
<style name="Widget.ProgressButton.Black" parent="@style/Theme.Widget.ProgressButton">
<item name="android:colorControlHighlight">@color/buttons_black_pressed</item>
<item name="android:background">@drawable/progress_button_black</item>
</style>
最后,这是我在片段布局 xml 中使用它的方式:
<com.example.widgets.ProgressButton
android:id="@+id/button_black_loading"
android:theme="@style/Widget.ProgressButton.Black". //This is where it gets its style and theme
android:layout_
android:layout_
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:loading="true"/>
我们将不胜感激。
【问题讨论】:
【参考方案1】:最后我发现了一种模式,它似乎可以在自定义视图使用 xml 中使用单个样式行(例如片段或活动布局)。
我为每个按钮定义了类似的样式块,如下所示:
<style name="Theme.Widget.Button.Black" parent="">
<item name="android:textAppearanceButton">@style/TextAppearance.BlackButton</item> //This will set the theme for the button internal TextView
<item name="android:colorControlHighlight">@color/buttons_black_pressed</item> //This will set the highlight color for ripple effect
</style>
<style name="Widget.Button.Black" parent="">
**<item name="android:theme">@style/Theme.Widget.Button.Black</item>** //Note this theme attribute which takes that above styling and applying it as a theme!!
<item name="android:background">@drawable/button_black</item> //A shape with selector drawable
</style>
背景可绘制:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight"> //This comes from the theme for the ripple effect
<item android:drawable="@drawable/button_black_shape"/> //The selector
</ripple>
可绘制的背景形状:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/components_corner_radius" />
<solid android:color="@color/button_black_bg_selector" />
</shape>
选择器:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/black" android:state_enabled="true" />
<item android:color="@color/buttons_black_pressed" android:state_pressed="true" />
<item android:color="@color/buttons_black_disabled" android:state_enabled="false" />
<item android:color="@color/black" />
</selector>
最后像这样在片段 XML 中使用按钮:
<com.sample.widgets.ProgressButton
android:id="@+id/button_black_enabled"
android:layout_
android:layout_
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:enabled="true"
app:text="OK"
style="@style/Widget.Button.Black"/> //The style brings a theme also!
【讨论】:
【参考方案2】:添加选择器后,您需要更改ProgressButton
的状态我在下面添加基本代码应该可以工作。
选择器应该是这样的:-
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/black" android:state_enabled="true" />
<item android:drawable="@color/buttons_black_pressed" android:state_pressed="true" />
<item android:drawable="@color/buttons_black_disabled" android:state_enabled="false" />
和ProgressButton.kt
class ProgressButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr)
private val progressBar: LottieAnimationView
private val buttonTextView: TextView
init
val root = LayoutInflater.from(context).inflate(R.layout.progress_button, this, true)
buttonTextView = root.findViewById(R.id.button_text)
progressBar = root.findViewById(R.id.progress_indicator)
loadAttr(attrs, defStyleAttr)
private fun loadAttr(attrs: AttributeSet?, defStyleAttr: Int)
// this line can be removed if you are setting selector in xml
setBackgroundResource(R.drawable.button_selector)
setLoading(true)
fun setLoading(loading: Boolean)
if (loading)
buttonTextView.visibility = View.GONE
progressBar.visibility = View.VISIBLE
else
buttonTextView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
isEnabled = !loading
【讨论】:
谢谢,我确实在 XML 中设置了它,我用包含选择器的可绘制对象设置了背景。然后在我使用按钮的布局中,我将其主题设置为该样式。 是的,我后来看到了。在上面的答案中使用选择器。我没有看到在这里使用源自Theme.Widget.ProgressButton
的样式的意义。您可以直接使用选择器并使用isEnabled = !loading
更改状态。
那么如何设置不同的选择器(使用不同的颜色),如您所见,我想要蓝色、绿色、黑色等按钮。
如果您想在运行时更改它或只是在 xml 中设置它,只需创建不同的选择器并在运行时使用 setBackgroundResource
设置它们。我在这里没有看到问题。是什么牵着你?
谢谢!!看起来直接将背景可绘制(带有选择器的形状)放在xml工作!但我不明白为什么通过样式放置相同的可绘制背景不起作用?有什么区别?以上是关于带有进度条的按钮 android的主要内容,如果未能解决你的问题,请参考以下文章