【问题标题】:android:foreground attribute / setForeground() method does not work with Button elementsandroid:foreground 属性 / setForeground() 方法不适用于 Button 元素
【发布时间】:2018-06-21 18:02:30
【问题描述】:

由于Android 23android:foreground XML 属性(和相应的setForeground()method)应该对所有视图可用,而不仅仅是以前的 FrameLayout 实例。

然而,出于某种原因,每当我创建一个继承自 TextView -> View 的 Button 实例时,我似乎根本无法显示前景。

这是一个显示前景的按钮定义示例:

    <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>

我已经确认在样式或&lt;Button&gt; 定义中设置foreground 属性不会改变任何内容,无论如何前景都无法显示。背景显示正确,文本也正确显示,只是缺少前景。

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

【问题讨论】:

    标签: android button textview android-xml


    【解决方案1】:

    正如 Keith setHorizontallyScrolling(true) 所说,滚动会使前景消失。可以很容易地重现该问题。

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

    设置水平(或垂直滚动​​)告诉TextView 它包含的区域大于其布局范围。

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

    另一方面,前景被设计为随着内容滚动,所以它基本上是从画布的(0, 0)开始绘制的,而不是可见内容的左上角。所以它离实际的视图边界很远。你可以打开View.java获取onDrawForeground的源代码。

    我能做什么

    • 在设置singleline 属性或任何暗示滚动的内容后调用setHorizontallyScrolling(false) 禁用滚动。请注意不要在尝试初始化/更新视图时启用滚动。
    • 翻译前景drawable,例如通过添加 scrollXscrollYsetBounds 更新边界

    【讨论】:

      【解决方案2】:

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

      删除此属性后,任何使用我的样式的 TextViews 或 Buttons 都可以根据需要正确显示前景可绘制对象。通过定义singleLineTextView.java 的实现,我仍在努力确定设置此属性如何导致前景被忽略,但如果我发现我会更新这个答案。

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

      编辑:在上面写下我的答案后,我决定进行更多调查并发现更多细节。

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

      通读TextView source code,发现singleLine属性设置为true时调用的一段代码:

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

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

          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 时模拟旧的 singleLine 功能,避免了会阻止前景显示的方法调用。万一有用的话……

      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:

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

      【讨论】:

        猜你喜欢
        • 2022-11-15
        • 1970-01-01
        • 1970-01-01
        • 2021-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-19
        • 2015-01-09
        相关资源
        最近更新 更多