android:foreground属性/setForeground()方法不适用于Button元素 [英] android:foreground attribute / setForeground() method does not work with Button elements

查看:77
本文介绍了android:foreground属性/setForeground()方法不适用于Button元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为 Android 23,即 android:foreground XML属性(以及相应的 setForeground()

Since Android 23, the android:foreground XML attribute (and corresponding setForeground() method) should be available to all Views, and not just FrameLayout instances as was previously the case.

但是,由于某种原因,每当我创建一个从TextView-> View继承的Button实例时,我似乎根本看不到要显示的前景.

Yet, for some reason, whenever I create a Button instance which inherits from TextView -> View, I can't seem to get a foreground to show at all.

这是一个无效的示例按钮定义,显示为前景:

Here is an example button definition that doesn't work appear to show the foreground:

    <Button
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginEnd="10dp"
      android:text="Primary Full Width"
      style="@style/Button.Primary" />

这是 Button.Primary 样式的定义:

    <style name="Button.Primary" parent="Widget.AppCompat.Button">
      <item name="android:background">@drawable/button_primary_background_selector</item>
      <item name="android:foreground">@drawable/button_primary_foreground_selector</item>
      <item name="android:textAppearance">@style/TextAppearance.FF.Button</item>
      <item name="android:minHeight">80dp</item>
      <item name="android:height">80dp</item>
      <item name="android:minWidth">200dp</item>
      <item name="android:defaultWidth">288dp</item>
      <item name="android:maxWidth">400dp</item>
      <item name="android:focusable">true</item>
      <item name="android:clickable">true</item>
      <item name="android:gravity">center_vertical|center_horizontal</item>
      <item name="android:paddingStart">70dp</item>
      <item name="android:paddingEnd">70dp</item>
      <item name="android:stateListAnimator">@null</item>
      <item name="android:singleLine">true</item>
      <item name="android:ellipsize">end</item>
      <item name="android:drawablePadding">10dp</item>
</style>

我已经确认,在样式中或在< Button> 定义中设置 foreground 属性不会更改任何内容,无论如何前景都不会显示.背景和文字一样正确显示,只是缺少前景.

I've confirmed that setting the foreground attribute in the style or in the <Button> definition does not change anything, the foreground fails to show regardless. The background shows correctly, as does the text, it's just the foreground that's missing.

我还尝试将前景设置为纯色,而不是可绘制的状态选择器,但没有成功.

I've also tried setting the foreground to a solid color instead of a state selector drawable, with no success.

推荐答案

一个接一个地删除样式元素并重新测试之后,我将问题缩小为在 android:singleLine 属性中包含样式.

After removing the style elements one by one and retesting, I narrowed down the issue to the inclusion of the android:singleLine attribute in the style.

删除此属性后,所有使用我的样式的TextViews或Buttons都将根据需要正确显示前景可绘制对象.查看 TextView.java在定义了 singleLine 的地方,我仍在努力确定设置此属性如何导致前景被忽略,但是如果发现的话,我将更新此答案.

Removing this attribute made it so any TextViews or Buttons using my style would properly show the foreground drawable as desired. Looking through the implementation of TextView.java where singleLine is defined, I'm still struggling to determine how setting this attribute causes foregrounds to be ignored, but I will update this answer if I find out.

我知道不赞成使用 singleLine ,但不幸的是,我仍然需要 singleLine / ellipsize 属性的组合所提供的功能,用 maxLines 用法替换时不可用.

I know that use of singleLine is deprecated but unfortunately I still need the functionality provided by the combination of the singleLine / ellipsize attributes which are not available when replacing with maxLines usage.

编辑:在写完上述答案后,我决定进行更多调查,并发现更多细节.

After writing out my answer above, I decided to do some more investigation and uncovered a few more details.

首先,我创建了一个自AppCompatButton扩展的自定义视图,因此我可以尝试重新实现所提供的功能 singleLine / ellipsize (即,在单个通过用空格替换换行符,然后在文本超出视图范围的情况下添加省略号来替换行).

First, I created a custom view that extended from AppCompatButton so I could attempt to re-implement the functionality singleLine / ellipsize provided (namely, showing text on a single line by replacing newline characters with spaces and then also adding ellipsis if the text ran off the view).

通读

Reading through the TextView source code, I found a section of code that is called when the singleLine attribute is set to true:

private void applySingleLine(boolean singleLine, boolean applyTransformation,
        boolean changeMaxLines) {
    mSingleLine = singleLine;
    if (singleLine) {
        setLines(1);
        setHorizontallyScrolling(true);
        if (applyTransformation) {
            setTransformationMethod(SingleLineTransformationMethod.getInstance());
        }
    } 
    ...
}

所以我尝试提取这些行并将其添加到我自己的实现中:

So I tried extracting those lines and adding to my own implementation:

    private void updateMaxlinesLocally(int maxLines) {
    if (maxLines == 1) {
        Log.d("Button", "max lines was 1, setting to single line equivalent");
        setLines(1);
        setHorizontallyScrolling(true);

 setTransformationMethod(SingleLineTransformationMethod.getInstance());
        // reset any text that may have already been set
        setText(getText());
    } else {
        Log.d("Button", "max lines was  : " + maxLines);
    }
}

但是当这段代码运行时,我看到了以前的前景可绘制对象不再可见的相同问题.

But when this code ran, I saw the same issue from before where foreground drawables would no longer be visible.

经过进一步测试,我能够将问题缩小到 setHorizo​​ntallyScrolling(true)方法调用.如果我在自定义实现中只注释了这一行,则可以保留之前拥有的 singleLine / ellipsize 功能,前景可绘制对象将按预期显示!缩小到该方法仍然无法帮助我找出TextView基本实现的根本原因,但是如果有人对此有任何详细信息,请随时评论更多信息.

After further testing, I was able to narrow down the issue to the setHorizontallyScrolling(true) method call. If I commented just this line out of my custom implementation, I'm able to preserve the singleLine / ellipsize functionality I had before and foreground drawables show as expected! Narrowing it down to that method still didn't help me figure out the root cause in the TextView base implementation, but if anyone has any details on that, feel free to comment with more information.

这是我最后的自定义Button类,它仅查看 maxLines 属性,并在 maxLines 设置为1时模拟旧的 singleLine 功能.,避免了会阻止前景显示的方法调用.万一有用的话...

Here is my final custom Button class which simply looks at the maxLines attribute and simulates the old singleLine functionality when maxLines is set to 1, avoiding the method call that would prevent foregrounds from showing. In case it's useful...

public class Button extends AppCompatButton {

public Button(Context context) {
    super(context);
    init(context, null, 0);
}

public Button(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs, 0);
}

public Button(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
}

@Override
public void setMaxLines(int maxLines) {
    super.setMaxLines(maxLines);
    updateMaxlinesLocally(maxLines);
}

private void init(Context context, AttributeSet attributeSet, int defStyleAttr) {
    int[] set = {
            android.R.attr.maxLines
    };
    TypedArray a = context.obtainStyledAttributes(
            attributeSet, R.styleable.Button);
    int maxLines = a.getInt(R.styleable.Button_android_maxLines, -1);
    a.recycle();
    updateMaxlinesLocally(maxLines);
}

private void updateMaxlinesLocally(int maxLines) {
    if (maxLines == 1) {
        Log.d("Button", "max lines was 1, setting to single line equivalent");
        setLines(1);
        // The act of setting horizontally scrolling to true is what disables foregrounds from
        // showing...
//            setHorizontallyScrolling(true);
        setTransformationMethod(SingleLineTransformationMethod.getInstance());
        // reset any text that may have already been set
        setText(getText());
    } else {
        Log.d("Button", "max lines was  : " + maxLines);
    }
}

}

并来自attrs.xml:

and from attrs.xml:

<declare-styleable name="Button">
    <attr name="android:maxLines" format="integer" />
</declare-styleable>

这篇关于android:foreground属性/setForeground()方法不适用于Button元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆