如何添加自定义按钮状态

Posted

技术标签:

【中文标题】如何添加自定义按钮状态【英文标题】:How to add a custom button state 【发布时间】:2011-05-19 04:11:54 【问题描述】:

例如,默认按钮在其状态和背景图像之间具有以下依赖关系:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_window_focused="false" android:state_enabled="false"
        android:drawable="@drawable/btn_default_normal_disable" />
    <item android:state_pressed="true" 
        android:drawable="@drawable/btn_default_pressed" />
    <item android:state_focused="true" android:state_enabled="true"
        android:drawable="@drawable/btn_default_selected" />
    <item android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_focused="true"
        android:drawable="@drawable/btn_default_normal_disable_focused" />
    <item
        android:drawable="@drawable/btn_default_normal_disable" />
</selector>

如何定义我自己的自定义状态(例如android:state_custom),然后我可以使用它来动态更改我的按钮视觉外观?

【问题讨论】:

我想要 EditText 视图的额外状态,以确定两个密码框何时匹配以显示一个小复选标记。 【参考方案1】:

@(Ted Hopp) 指出的解决方案可行,但需要稍作修正:在选择器中,项目状态需要一个“app:”前缀,否则充气器将无法正确识别命名空间,并且会静默失败;至少这是发生在我身上的事情。

请允许我在这里报告整个解决方案,并提供更多详细信息:

首先,创建文件“res/values/attrs.xml”:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="food">
        <attr name="state_fried" format="boolean" />
        <attr name="state_baked" format="boolean" />
    </declare-styleable>
</resources>

然后定义您的自定义类。例如,它可能是从类“Button”派生的类“FoodButton”。您将必须实现一个构造函数;实现这个,这似乎是充气机使用的:

public FoodButton(Context context, AttributeSet attrs) 
    super(context, attrs);

在派生类之上:

private static final int[] STATE_FRIED = R.attr.state_fried;
private static final int[] STATE_BAKED = R.attr.state_baked;

还有,你的状态变量:

private boolean mIsFried = false;
private boolean mIsBaked = false;

还有几个二传手:

public void setFried(boolean isFried) mIsFried = isFried;
public void setBaked(boolean isBaked) mIsBaked = isBaked;

然后重写函数“onCreateDrawableState”:

@Override
protected int[] onCreateDrawableState(int extraSpace) 
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    if (mIsFried) 
        mergeDrawableStates(drawableState, STATE_FRIED);
    
    if (mIsBaked) 
        mergeDrawableStates(drawableState, STATE_BAKED);
    
    return drawableState;

最后,这个难题中最微妙的部分;定义将用作小部件背景的 StateListDrawable 的选择器。这是文件“res/drawable/food_button.xml”:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
    app:state_baked="true"
    app:state_fried="false"
    android:drawable="@drawable/item_baked" />
<item
    app:state_baked="false"
    app:state_fried="true"
    android:drawable="@drawable/item_fried" />
<item
    app:state_baked="true"
    app:state_fried="true"
    android:drawable="@drawable/item_overcooked" />
<item
    app:state_baked="false"
    app:state_fried="false"
    android:drawable="@drawable/item_raw" />
</selector>

注意“app:”前缀,而对于标准的 android 状态,您会使用前缀“android:”。 XML 命名空间对于 inflater 的正确解释至关重要,并且取决于您在其中添加属性的项目类型。如果是应用程序,请将 com.mydomain.mypackage 替换为您的应用程序的实际包名称(应用程序名称除外)。如果它是一个库,则必须使用“http://schemas.android.com/apk/res-auto”(并且使用的是 R17 或更高版本的工具),否则会出现运行时错误。

几点说明:

看来您不需要调用“refreshDrawableState”函数,至少在我的情况下解决方案效果很好

为了在布局 xml 文件中使用您的自定义类,您必须指定完全限定名称(例如 com.mydomain.mypackage.FoodButton)

您可以将标准状态(例如 android:pressed、android:enabled、android:selected)与自定义状态混合,以表示更复杂的状态组合

【讨论】:

更新:如果自定义类派生自 TextView 而不是 Button,则似乎需要调用 refreshDrawableState,否则不会更新小部件外观。呼叫应放在二传手。我没有尝试过其他课程。在 froyo 设备上进行的测试。 refreshDrawableState 绝对重要。我不确定何时真正需要它。但在我的情况下,以编程方式设置状态时需要它。我猜它可能是在 onTouchEvent 中自动从 View 类中调用的。我最好在 setSelected 方法中添加它。 但是如何使用不是boolean 的自定义状态呢?还是选择器只对布尔值进行操作? 它是如何工作的?我的意思是,属性如何更新为状态真/假?谁更新它?只有当局部变量为真时,合并drawablestate才会更新属性的状态或值?究竟哪个代码会更新 R.attr.state_fried? 似乎现在我们可以在任何地方使用xmlns:app="http://schemas.android.com/apk/res-auto",而不仅仅是在库中。 ***.com/a/30620868/6182136【参考方案2】:

This thread 展示了如何向按钮等添加自定义状态。 (如果您在浏览器中看不到新的 Google 群组,请查看帖子 here 的副本。)

【讨论】:

+1 非常感谢,泰德!现在问题的根源已经消失,所以我没有得到实际的实施。但是,如果我的客户再次回到这里,我会尝试你指给我的方式。 看起来和我需要的完全一样,但是我的自定义状态的状态列表drawables没有改变我一定错过了什么...... 你在调用 refreshDrawableState() 吗? 链接失效了。 @Mitch -- 好吧,那太糟糕了。我会看看能不能找到一些替代链接。如果没有,我会删除这个答案,因为它基本上没有用。同时,接受的答案包含所需的所有信息。【参考方案3】:

请不要忘记在 UI 线程中调用 refreshDrawableState

mHandler.post(new Runnable() 
    @Override
    public void run() 
        refreshDrawableState();
    
);

我花了很多时间才弄清楚为什么我的按钮没有改变它的状态,即使一切看起来都正确。

【讨论】:

我应该在何处或何时发布此处理程序?

以上是关于如何添加自定义按钮状态的主要内容,如果未能解决你的问题,请参考以下文章

HTML 如何实现自定义按钮

如何向 UIActivityViewController 添加自定义按钮?

iOS 导航栏-返回按钮-自定义

如何在现有的 webview android 中添加自定义按钮?

Finereport可以自定义一个导出按钮么

Vimeo 嵌入:自定义播放按钮工作。如何添加暂停按钮?