带有进度条的按钮 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的主要内容,如果未能解决你的问题,请参考以下文章

在每个 TableViewcell 中播放带有进度条的音频

网页插入SWF视频,如何带有播放控制按钮、进度条等!

Android进度没有相应地工作

如何实现带有进度条的启动画面? - 安卓

如何使用 swift 显示带有进度条的 AVAudioPlayer?

进度条与拖动条的使用学习