首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >android:前台属性/ setForeground()方法不适用于Button元素

问android:前台属性/ setForeground()方法不适用于Button元素
EN

Stack Overflow用户
提问于 2018-06-21 18:02:30
回答 2查看 1.8K关注 0票数 3

自Android 23以来,android:foreground XML属性(以及相应的setForeground() 方法 )应该可用于所有视图,而不仅仅是以前的FrameLayout实例。

然而,由于某种原因,每当我创建一个从TextView ->视图继承的Button实例时,我似乎都无法显示前景。

下面是一个不起作用的示例按钮定义,它显示了前景:

代码语言:javascript
复制
    <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风格的定义:

代码语言:javascript
复制
    <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>

我已经确认,在样式中或在foreground定义中设置<Button>属性不会改变任何事情,无论前景如何都不能显示。背景显示正确,就像文本一样,它只是缺少的前景。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-21 18:02:30

在逐个删除样式元素并重新测试之后,我将问题缩小到在样式中包含android:singleLine属性。

删除该属性使得使用我的样式的任何TextViews或按钮都能正确地显示前景可按需要绘制。在定义了TextView.java的singleLine的实现中,我仍然很难确定设置这个属性是如何导致find被忽略的,但是如果我发现了这个答案,我会更新这个答案。

我知道对singleLine的使用是不可取的,但不幸的是,我仍然需要singleLine / ellipsize属性组合提供的功能,这些属性在用maxLines使用替换时是不可用的。

编辑:写了我上面的答案后,我决定做一些更多的调查,并发现了一些更多的细节。

首先,我创建了一个从AppCompatButton扩展的自定义视图,这样我就可以尝试重新实现singleLine / ellipsize提供的功能(即,通过用空格替换换行符来在单行上显示文本,然后在文本离开视图时添加省略号)。

通过阅读TextView源代码,我发现了当singleLine属性设置为true时调用的一段代码:

代码语言:javascript
复制
private void applySingleLine(boolean singleLine, boolean applyTransformation,
        boolean changeMaxLines) {
    mSingleLine = singleLine;
    if (singleLine) {
        setLines(1);
        setHorizontallyScrolling(true);
        if (applyTransformation) {
            setTransformationMethod(SingleLineTransformationMethod.getInstance());
        }
    } 
    ...
}

因此,我尝试提取这些行并添加到我自己的实现中:

代码语言:javascript
复制
    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);
    }
}

但是,当这段代码运行时,我在前面看到了同样的问题,在这个问题上,前景图形将不再可见。

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

下面是我的最后一个自定义Button类,它简单地查看maxLines属性,并在将maxLines设置为1时模拟旧的maxLines功能,从而避免了方法调用,这将阻止from显示。万一有用..。

代码语言:javascript
复制
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:

代码语言:javascript
复制
<declare-styleable name="Button">
    <attr name="android:maxLines" format="integer" />
</declare-styleable>
票数 1
EN

Stack Overflow用户

发布于 2019-09-12 06:39:14

正如基思setHorizontallyScrolling(true)所说,滚动会使前景消失。人们可以很容易地再现这个问题。

但是为什么水平滚动会影响前景呢?

设置水平(或垂直滚动)会告诉TextView它包含的区域比它的布局边界更大。

如果您打印scrollX / scrollY值,通常它不会是零,而是一个非常大的数字,即使内容不能被用户滚动。

另一方面,前台是用来滚动内容的,因此它基本上是从画布的(0, 0) (而不是可见内容的左上角)开始绘制的。所以它被拉得离实际的视野很远。您可以为此打开View.java的onDrawForeground源代码。

我能做什么

  • 在设置setHorizontallyScrolling(false)属性或任何包含滚动的内容后,通过调用singleline来禁用滚动。注意不要启用滚动,尝试初始化/更新视图。
  • 翻译前景绘图,例如通过添加setBounds和scrollY来更新边界
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50974994

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档