使用 appcompat v7 更改 EditText 底线颜色

Posted

技术标签:

【中文标题】使用 appcompat v7 更改 EditText 底线颜色【英文标题】:Changing EditText bottom line color with appcompat v7 【发布时间】:2014-12-21 20:24:41 【问题描述】:

我正在使用 appcompat v7 在 android 5 及更低版本上获得一致的外观。它工作得很好。但是我无法弄清楚如何更改 EditTexts 的底线颜色和强调色。可能吗?

我尝试定义自定义android:editTextStyle(参见下文),但我只成功更改了完整的背景颜色或文本颜色,但没有更改底线或强调色。是否有特定的属性值可供使用?我必须通过android:background 属性使用自定义可绘制图像吗?不能用hexa指定颜色吗?

 <style name="Theme.App.Base" parent="Theme.AppCompat.Light.DarkActionBar">
     <item name="android:editTextStyle">@style/Widget.App.EditText</item>
 </style>

 <style name="Widget.App.EditText" parent="Widget.AppCompat.EditText">
     ???
 </style>

根据 android API 21 来源,带有材料设计的 EditTexts 似乎使用 colorControlActivatedcolorControlNormal。因此,我尝试在之前的样式定义中覆盖这些属性,但没有效果。可能 appcompat 不使用它。不幸的是,我找不到带有材料设计的最新版本的 appcompat 的来源。

【问题讨论】:

定义编辑文本的主题 感谢您的建议,但我已经这样做了。我已经更新了我的问题以显示我已经尝试过做的事情。我的问题是关于在主题样式中使用的属性来更改 edittext 底线颜色。理想情况下,我正在寻找一种可以直接以十六进制指定颜色的解决方案。 这些答案都不适用于 4.3。您有可行的解决方案吗? 显然我不得不扩展AppCompatEditText 【参考方案1】:

最后,我找到了解决方案。它只是在你的应用主题定义中覆盖colorControlActivatedcolorControlHighlightcolorControlNormal 的值,而不是你的edittext 样式。然后,考虑将此主题用于您想要的任何活动。下面是一个例子:

<style name="Theme.App.Base" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorControlNormal">#c5c5c5</item>
    <item name="colorControlActivated">@color/accent</item>
    <item name="colorControlHighlight">@color/accent</item>
</style>

【讨论】:

我看到菜单汉堡包、后退按钮和滚动条的颜色已更改为 colorControlNormal。 这会改变底线的颜色,但也会改变所有其他控件,如复选框、单选按钮等。它还会改变整个应用程序/活动中的每个 EditText。如果您想更改单个 EditText 的底线(就像我一样),那么您必须覆盖该 EditText 的 android:background 属性。 AFAIK 没有其他方法。 如果您使用的是 AppCompat v22 支持库,您可以在 EditText 中指定主题,例如:android:theme="@style/Theme.App.Base。这将确保样式不会影响布局中您不想更改的其他视图。 没有在 Jelly Bean (4.2) 上工作,但在 Lollipop 上工作 活动应该继承自AppCompatActivity。如果它继承自Activity,它将无法工作。【参考方案2】:

我觉得这需要一个答案,以防有人只想更改一个编辑文本。我是这样做的:

editText.getBackground().mutate().setColorFilter(ContextCompat.getColor(context, R.color.your_color), PorterDuff.Mode.SRC_ATOP);

【讨论】:

但是我如何才能重置为默认背景,在 Lollipop 上调用 editText.getBackground().resetColorFilter() 后出现了很多错误? 小心!添加这可能会导致在所有应用程序中更改 editText 的颜色。在 Nexus 5 上测试。操作系统 6.0.1。 @AlexPerevozchykov 你可能是对的。尝试在 .getBackground() 之后添加 .mutate()。应该这样做。 @hordurh 是的,就是这样,我早一点收到了这个建议,drawables 共享一个池,所以在改变之前我们需要改变它 如果我使用edittext,它是有效的,但这种方法不适用于棒棒糖上的app compat edittext。你知道我该如何解决这个问题吗?【参考方案3】:

虽然Laurents solution 是正确的,但它有一些缺点,如 cmets 中所述,因为不仅EditText 的底线被着色,而且ToolbarCheckBoxes 等的后退按钮也被着色.

幸运的是v22.1appcompat-v7 引入了一些新的可能性。现在可以将特定主题仅分配给一个视图。直接来自Changelog:

不推荐使用 app:theme 来设置工具栏的样式。 您现在可以在所有 API 级别 7 和更高级别的设备上使用 android:theme 工具栏,并且 android:theme 在 API 级别 11 上支持 所有小部件和更高的设备。

因此,我们不是在全局主题中设置所需的颜色,而是创建一个新主题并将其仅分配给EditText

示例:

<style name="MyEditTextTheme">
    <!-- Used for the bottom line when not selected / focused -->
    <item name="colorControlNormal">#9e9e9e</item>
    <!-- colorControlActivated & colorControlHighlight use the colorAccent color by default -->
</style>

<EditText
    android:layout_
    android:layout_
    android:theme="@style/MyEditTextTheme"/>

【讨论】:

我认为没有必要。 colorControlNormal 不带 android 前缀使用 appcompat 方法为小部件着色,而带前缀则回退到系统方法,这仅在 API 21+ 设备中可用。 嗯,我在我的棒棒糖设备上进行了测试,它不会染成自定义颜色,除非您也使用 android 命名空间以 v21 样式实现它。 我正在使用22.2.0 版本的 AppCompat 但这个技巧不起作用:( 使用 #000000 代替 colorControlNormal 为我工作。 非常适合只更改应用程序中的一个编辑文本! (正是我需要的!谢谢)【参考方案4】:

这可以通过以下方式在 XML 中更改:

对于参考 API >= 21 兼容性使用:

android:backgroundTint="@color/blue"

对于向后 API

app:backgroundTint="@color/blue"

【讨论】:

是的,但这仅适用于 android API 版本 21+(kitkat 和 lolipop)。人们可能会尝试创建一种向后兼容的解决方案。 只需使用backgroundTint="@color/blue" 而不是android:backgroundTint="@color/blue" 以获得向后兼容的支持 @KishanVaghela,不要使用android:backgroundTint="@color/blue",而是使用app:backgroundTint="@color/blue" 来支持棒棒糖之前的设备,感谢您的评论! @blueware 如果你想在风格上使用它,那么我们不需要使用“app”。 如果app:backgroundTint="&lt;your color&gt;"下方出现红色下划线,则添加tools:ignore="MissingPrefix"【参考方案5】:

这里是API 及以上的解决方案

Drawable drawable = yourEditText.getBackground(); // get current EditText drawable 
drawable.setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP); // change the drawable color

if(Build.VERSION.SDK_INT > 16) 
    yourEditText.setBackground(drawable); // set the new drawable to EditText
else
    yourEditText.setBackgroundDrawable(drawable); // use setBackgroundDrawable because setBackground required API 16

希望对你有帮助

【讨论】:

@CoolMind 抱歉回复晚了。我已经在支持库24.2.125.1.125.2.0 中再次检查了设备 21 的代码,它仍然有效。请查看这个简单的演示 drive.google.com/file/d/0B_poNaia6t8kSzU3bDFVazRSSDA/…。我不知道为什么这段代码不适合你,所以请告诉我。谢谢 @Renjith 抱歉回复晚了,请查看我上面的评论 如何使用此代码将颜色重置为默认值?【参考方案6】:

公认的答案是基于样式的东西,但最有效的做法是在您的 AppTheme 样式中添加 colorAccent 属性,如下所示:

<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:editTextStyle">@style/EditTextStyle</item>
</style>

<style name="EditTextStyle" parent="Widget.AppCompat.EditText"/>

colorAccent 属性用于整个应用程序的小部件着色,因此应该用于保持一致性

【讨论】:

@Tomasz 它不需要 API 21+,因为父主题是 AppCompat,它下降到 API 7 呃。谢谢你,我错误地使用了name="android:colorAccent"【参考方案7】:

如果您使用appcompat-v7:22.1.0+,您可以使用DrawableCompat 为您的小部件着色

    public static void tintWidget(View view, int color) 
        Drawable wrappedDrawable = DrawableCompat.wrap(view.getBackground());
        DrawableCompat.setTint(wrappedDrawable.mutate(), getResources().getColor(color));
        view.setBackgroundDrawable(wrappedDrawable);
    

【讨论】:

这救命稻草真棒,可惜不为人知 请向下移动并查看我对设计库 23.2.0 的回答。这个方法现在没用。【参考方案8】:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <item name="colorControlNormal">@color/colorAccent</item>
    <item name="colorControlActivated">@color/colorAccent</item>
    <item name="colorControlHighlight">@color/colorAccent</item>

</style>

【讨论】:

有效!正如问题所问,它应该在风格/主题中得到解决,这应该是正确的答案。 我同意。这应该是正确的答案,因为它是一个全球解决方案 如果不同的控件需要不同的颜色,这很不方便。【参考方案9】:

用途:

<EditText
    app:backgroundTint="@color/blue"/>

这将不仅支持棒棒糖之前的设备 +21

【讨论】:

@powder366,你能发布你的应用主题吗? @powder366,试试这个:&lt;style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"&gt; 它应该可以工作【参考方案10】:

您的问题的一个快速解决方案是在 yourappspackage/build/intermediates/exploded-aar/com.android.support/appcompat-v7/res/drawable/ 中查找 abc_edit_text_material.xml 并将该 xml 文件复制到您的可绘制文件夹中.然后,您可以在此选择器中更改 9 个补丁文件的颜色,以符合您的偏好。

【讨论】:

【参考方案11】:

只需在EditText 中添加android:backgroundTint 属性非常简单。

android:backgroundTint="@color/blue"
android:backgroundTint="#ffffff"
android:backgroundTint="@color/red"


 <EditText
     android:layout_
     android:layout_
     android:backgroundTint="#ffffff"/>

【讨论】:

API 级别 21 以上的backgroundTint ViewCompat.setBackgroundTintList(editText, ColorStateList.valueOf(Color.YELLOW)) app:backgroundTint="@color/blue"worps上的所有API级别。虽然无论出于何种原因,所选xd span>时仍然转到不同的颜色 【参考方案12】:

这是支持设计库中TextInputLayout 的部分源代码(已更新为版本 23.2.0),它改变了EditText 的底线以更简单的方式着色:

private void updateEditTextBackground() 
    ensureBackgroundDrawableStateWorkaround();

    final Drawable editTextBackground = mEditText.getBackground();
    if (editTextBackground == null) 
        return;
    

    if (mErrorShown && mErrorView != null) 
        // Set a color filter of the error color
        editTextBackground.setColorFilter(
                AppCompatDrawableManager.getPorterDuffColorFilter(
                        mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
    
    ...

如果您想以编程方式更改颜色,上述所有代码现在在 23.2.0 中似乎都变得无用了。

如果你想支持所有平台,这是我的方法:

/**
 * Set backgroundTint to @link View across all targeting platform level.
 * @param view the @link View to tint.
 * @param color color used to tint.
 */
public static void tintView(View view, int color) 
    final Drawable d = view.getBackground();
    final Drawable nd = d.getConstantState().newDrawable();
    nd.setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(
            color, PorterDuff.Mode.SRC_IN));
    view.setBackground(nd);

【讨论】:

什么是 AppCompatDrawableManager? setBackground 需要 API 16。【参考方案13】:

我也被这个问题困扰太久了。

我需要一个适用于 v21 以上和以下版本的解决方案。

我终于发现了一个非常简单但可能并不理想但有效的解决方案:只需在 EditText 属性中将背景颜色设置为transparent

<EditText
    android:background="@android:color/transparent"/>

我希望这可以节省一些时间。

【讨论】:

这是改变整个背景颜色,我们只想改变下划线颜色。 @shahzain ali EditText 的下划线是背景。如果您将其设置为null,它就消失了。这就是为什么 backgroundTint 会起作用的原因(但它在激活时不会改变颜色)【参考方案14】:

对我来说,我修改了 AppTheme 和值 colors.xml colorControlNormal 和 colorAccent 都帮助我更改了 EditText 边框颜色。以及光标和“|”在 EditText 中时。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorControlNormal">@color/yellow</item>
    <item name="colorAccent">@color/yellow</item>
</style>

这里是colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="yellow">#B7EC2A</color>
</resources>

我取出了@null 的android:textCursorDrawable 属性,该属性放在了editText 样式中。当我尝试使用它时,颜色不会改变。

【讨论】:

这应该是答案 工作就像一个魅力。谢谢【参考方案15】:

您可以将 edittext 的背景设置为在左、右和顶部带有减号填充的矩形来实现此目的。这是xml示例:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:top="-1dp"
        android:left="-1dp"
        android:right="-1dp"
        android:bottom="1dp"
        >
        <shape android:shape="rectangle">
            <stroke android: android:color="#6A9A3A"/>
        </shape>
    </item>
</layer-list>

如果您想为焦点编辑文本提供不同的宽度和颜色,请用选择器替换形状。

【讨论】:

【参考方案16】:

经过 2 天的努力,我找到了一个可行的解决方案来解决这个问题,下面的解决方案非常适合那些只想更改少量编辑文本、通过 java 代码更改/切换颜色以及想要克服不同行为问题的人由于使用 setColorFilter() 方法,在操作系统版本上。

    import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatDrawableManager;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import com.newco.cooltv.R;

public class RqubeErrorEditText extends AppCompatEditText 

  private int errorUnderlineColor;
  private boolean isErrorStateEnabled;
  private boolean mHasReconstructedEditTextBackground;

  public RqubeErrorEditText(Context context) 
    super(context);
    initColors();
  

  public RqubeErrorEditText(Context context, AttributeSet attrs) 
    super(context, attrs);
    initColors();
  

  public RqubeErrorEditText(Context context, AttributeSet attrs, int defStyleAttr) 
    super(context, attrs, defStyleAttr);
    initColors();
  

  private void initColors() 
    errorUnderlineColor = R.color.et_error_color_rule;

  

  public void setErrorColor() 
    ensureBackgroundDrawableStateWorkaround();
    getBackground().setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(
        ContextCompat.getColor(getContext(), errorUnderlineColor), PorterDuff.Mode.SRC_IN));
  

  private void ensureBackgroundDrawableStateWorkaround() 
    final Drawable bg = getBackground();
    if (bg == null) 
      return;
    
    if (!mHasReconstructedEditTextBackground) 
      // This is gross. There is an issue in the platform which affects container Drawables
      // where the first drawable retrieved from resources will propogate any changes
      // (like color filter) to all instances from the cache. We'll try to workaround it...
      final Drawable newBg = bg.getConstantState().newDrawable();
      //if (bg instanceof DrawableContainer) 
      //  // If we have a Drawable container, we can try and set it's constant state via
      //  // reflection from the new Drawable
      //  mHasReconstructedEditTextBackground =
      //      DrawableUtils.setContainerConstantState(
      //          (DrawableContainer) bg, newBg.getConstantState());
      //
      if (!mHasReconstructedEditTextBackground) 
        // If we reach here then we just need to set a brand new instance of the Drawable
        // as the background. This has the unfortunate side-effect of wiping out any
        // user set padding, but I'd hope that use of custom padding on an EditText
        // is limited.
        setBackgroundDrawable(newBg);
        mHasReconstructedEditTextBackground = true;
      
    
  

  public boolean isErrorStateEnabled() 
    return isErrorStateEnabled;
  

  public void setErrorState(boolean isErrorStateEnabled) 
    this.isErrorStateEnabled = isErrorStateEnabled;
    if (isErrorStateEnabled) 
      setErrorColor();
      invalidate();
     else 
      getBackground().mutate().clearColorFilter();
      invalidate();
    
  

在xml中使用

<com.rqube.ui.widget.RqubeErrorEditText
            android:id="@+id/f_signup_et_referral_code"
            android:layout_
            android:layout_
            android:layout_alignParentTop="true"
            android:layout_toEndOf="@+id/referral_iv"
            android:layout_toRightOf="@+id/referral_iv"
            android:ems="10"
            android:hint="@string/lbl_referral_code"
            android:imeOptions="actionNext"
            android:inputType="textEmailAddress"
            android:textSize="@dimen/text_size_sp_16"
            android:theme="@style/EditTextStyle"/>

在样式中添加线条

<style name="EditTextStyle" parent="android:Widget.EditText">
    <item name="android:textColor">@color/txt_color_change</item>
    <item name="android:textColorHint">@color/et_default_color_text</item>
    <item name="colorControlNormal">@color/et_default_color_rule</item>
    <item name="colorControlActivated">@color/et_engagged_color_rule</item>
  </style>

切换颜色的java代码

myRqubeEditText.setErrorState(true);
myRqubeEditText.setErrorState(false);

【讨论】:

【参考方案17】:

在 Activit.XML 中添加代码

<EditText
        android:layout_
        android:layout_
        android:inputType="textPersonName"
        android:ems="10"
        android:id="@+id/editText"
        android:hint="Informe o usuário"
        android:backgroundTint="@android:color/transparent"/>

BackgroundTint=color 哪里有你想要的颜色

【讨论】:

【参考方案18】:

我用这个方法用PorterDuff改变线条的颜色,没有其他drawable。

public void changeBottomColorSearchView(int color) 
    int searchPlateId = mSearchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
    View searchPlate = mSearchView.findViewById(searchPlateId);
    searchPlate.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);

【讨论】:

是否存在类似的标识符来访问简单 EditText 的底线?【参考方案19】:

如果您想在不使用应用颜色的情况下更改底线,请在您的主题中使用这些行:

<item name="android:editTextStyle">@android:style/Widget.EditText</item>
<item name="editTextStyle">@android:style/Widget.EditText</item>

我不知道其他解决方案。

【讨论】:

【参考方案20】:

我对这个问题感到非常困惑。我已经尝试了这个线程和其他线程中的所有内容,但无论我做什么,我都无法将下划线的颜色更改为默认蓝色以外的任何颜色。

我终于弄清楚发生了什么。我在创建新实例时(错误地)使用了android.widget.EditText(但我的其余组件来自 appcompat 库)。我应该使用android.support.v7.widget.AppCompatEditText。我用new AppCompatEditText(this) 替换了new EditText(this) 问题立即解决了。事实证明,如果您实际使用AppCompatEditText,它只会尊重您主题中的accentColor(如上面几个cmets 所述),无需额外配置。

【讨论】:

【参考方案21】:

这是最简单、最高效/可重用/适用于所有 API 像这样创建一个自定义的 EditText 类:

public class EditText extends android.widget.EditText 
    public EditText(Context context) 
        super(context);
        init();
    

    public EditText(Context context, AttributeSet attrs) 
        super(context, attrs);
        init();
    

    public EditText(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
        init();
    

    private void init() 
        getBackground().mutate().setColorFilter(ContextCompat.getColor(getContext(), R.color.colorAccent), PorterDuff.Mode.SRC_ATOP);
    

然后像这样使用它:

 <company.com.app.EditText
        android:layout_
        android:layout_/>

【讨论】:

【参考方案22】:

要动态改变 EditText 背景,可以使用ColorStateList。

int[][] states = new int[][] 
    new int[]  android.R.attr.state_enabled, // enabled
    new int[] -android.R.attr.state_enabled, // disabled
    new int[] -android.R.attr.state_checked, // unchecked
    new int[]  android.R.attr.state_pressed  // pressed
;

int[] colors = new int[] 
    Color.BLACK,
    Color.RED,
    Color.GREEN,
    Color.BLUE
;

ColorStateList colorStateList = new ColorStateList(states, colors);

致谢:This SO answer about ColorStateList is awesome。

【讨论】:

用什么方法呢?设置背景色调列表?它需要 API 21。 setSupportBackgroundTintList 用于较旧的 API 版本。【参考方案23】:

为 API 级别 21 以下添加 app:backgroundTint。否则使用 android:backgroundTint

API 级别 21 以下。

<EditText
     android:id="@+id/edt_name"
     android:layout_
     android:layout_
     android:textColor="#0012ff"
     app:backgroundTint="#0012ff"/>

API 级别 21 以上。

<EditText
     android:id="@+id/edt_name"
     android:layout_
     android:layout_
     android:textColor="#0012ff"
     android:backgroundTint="#0012ff"/>

【讨论】:

【参考方案24】:

您可以只使用 backgroundTint 来更改编辑文本的底线颜色

 android:backgroundTint="#000000"

示例:

 <EditText
          android:id="@+id/title1"
          android:layout_
          android:layout_
          android:backgroundTint="#000000" />

【讨论】:

【参考方案25】:

请根据您的需要修改此方法。这对我有用!

private boolean validateMobilenumber() 
        if (mobilenumber.getText().toString().trim().isEmpty() || mobilenumber.getText().toString().length() < 10) 
            input_layout_mobilenumber.setErrorEnabled(true);
            input_layout_mobilenumber.setError(getString(R.string.err_msg_mobilenumber));
           // requestFocus(mobilenumber);
            return false;
         else 
            input_layout_mobilenumber.setError(null);
            input_layout_mobilenumber.setErrorEnabled(false);
            mobilenumber.setBackground(mobilenumber.getBackground().getConstantState().newDrawable());
        

【讨论】:

以上是关于使用 appcompat v7 更改 EditText 底线颜色的主要内容,如果未能解决你的问题,请参考以下文章

在 AppCompat 21 中使用 Light.DarkActionBar 主题更改 ActionBar 标题文本颜色

Android 支持库 v7 缺少 appcompat

带有 appcompat 库 v7 的 ActionBar(ava.lang.IllegalStateException:您需要使用 Theme.AppCompat 主题)

在 Appcompat 21 中更改工具栏颜色

建议:使用 tools:overrideLibrary="android.support.v7.appcompat" 强制使用

缺少来自android appcompat v7-21.0.0的样式