为什么android:foreground属性不起作用?

时间:2018-09-14 09:43:01

标签: android xml android-layout

看看这个小型的Android应用程序:

MainActivity.java:

package io.github.gsaga.toucheventtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

activity_main:     

<ImageView android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:foreground="@drawable/ic_launcher_background"
    xmlns:android="http://schemas.android.com/apk/res/android" />

android:foreground指向的图像未显示,但是如果我将foreground中的src更改为backgroundactivity_main.xml,则会显示该图像。此代码似乎遵循此处描述的说明:

https://developer.android.com/reference/android/view/View.html#attr_android:foreground

为什么android:foreground标签在上面的代码中不起作用?

注意:

minSdkVersion19,我正在Android 5.1API level 22)上运行此应用程序

4 个答案:

答案 0 :(得分:15)

简短回答

这是由于自API级别23开始存在于Android中的一个错误。


有关行为的更多详细信息

以下是所有XML属性以及与通过FrameLayout引入的具有API级别的视图级别的可绘制对象设置视图相关的相应方法的列表。但是,这些后来又移至API级别23中的View中。

╔════════════════════════════╦═════════════════════════════════════════════════╦═════════════╗
║       XML attribute        ║                     Method                      ║   Added in  ║
║                            ║                                                 ║ (API level) ║
╠════════════════════════════╬═════════════════════════════════════════════════╬═════════════╣
║ android:foreground         ║ setForeground(Drawable)                         ║ 1           ║
╠════════════════════════════╬═════════════════════════════════════════════════╬═════════════╣
║ android:foregroundGravity  ║ setForegroundGravity(int gravity)               ║ 1           ║
╠════════════════════════════╬═════════════════════════════════════════════════╬═════════════╣
║ android:foregroundTint     ║ setForegroundTintMode(PorterDuff.Mode tintMode) ║ 21          ║
╠════════════════════════════╬═════════════════════════════════════════════════╬═════════════╣
║ android:foregroundTintMode ║ setForegroundTintMode(PorterDuff.Mode tintMode) ║ 21          ║
╚════════════════════════════╩═════════════════════════════════════════════════╩═════════════╝
  • Android文档说,在API 1中添加了setForeground(Drawable),在API级别21中将setForegroundTintList (ColorStateList tint)setForegroundTintMode (PorterDuff.Mode tintMode)添加到了View。这是错误的。直到API 23为止FrameLayout都存在。

  • 在API级别<23中,即使不是必需的,您也会收到警告。您可以抑制它。参见this


现在看看这些属性如何在不同版本上工作。

╔═══════════╦══════════════════╦══════════════════╗
║ API level ║      By code     ║     Using XML    ║
╠═══════════╬══════════════════╬══════════════════╣
║ <23       ║ FrameLayout only ║ FrameLayout only ║
╠═══════════╬══════════════════╬══════════════════╣
║ >=23      ║ FrameLayout only ║ All views        ║
╚═══════════╩══════════════════╩══════════════════╝


错误原因

当这些属性在API级别23中移至View时,它们对其进行了一些奇怪的修改,这可以称为错误。从XML加载属性时,它会检查View是否为FrameLayout,而该case R.styleable.View_foreground: if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { setForeground(a.getDrawable(attr)); } break; 在我们可用于同一目的的方法中不存在。

View构造函数,API级别23:

let arr = ["Orebro", "Sundsvall", "Hudriksvall", "Goteborg"];
    
console.log(arr.sort((a,b)=>b.length-a.length)[0])

答案 1 :(得分:5)

要在android:foreground上使用Android 5.1,即API level 22,则表示您未正确使用android:foreground

顾名思义,您可以在诸如叠加层之类的任何内容的顶部/前景上设置可绘制对象,即可以在FrameLayout中放置一些视图,以便可以使用android:foreground。在此FrameLayout中添加您的ImageView

Documentation

  

定义可绘制对象绘制内容。这可以用作   重叠。前景可绘制对象参与填充   重力设置为填充时的内容。

下面是用法示例:

<FrameLayout
    android:id="@+id/share"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:foreground="@drawable/ic_launcher_background>

    // your ImageView here
    <ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

</FrameLayout>

注意: 对于API level > 23,它可以不使用FrameLayout

我希望这会对您有所帮助。

答案 2 :(得分:1)

就像VicJordan所建议的那样,names一次只能与android:foreground一起使用(API <23)。但是,对于API 23+,看来FrameLayout适用于任何视图类型。请参见 View.java 源中的this选择:

android:foreground

这是case R.styleable.View_foreground: if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { setForeground(a.getDrawable(attr)); } 在API 28上使用以下布局的示例:

android:foreground

enter image description here

但是,在API 22上,我们看到了以下内容:

enter image description here

无前景图像。因此,<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:foreground="@drawable/ic_launcher_foreground" android:src="@android:drawable/ic_delete" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> 仅在API级别为23+时有效。我同意这并没有真正记录在案,但这只是事实。

更新:API 23似乎与android:foreground有关,因此,假设android:foreground在API 24+上可用于一般视图。

第二次更新:还遇到了其他几篇有关android:foreground herehere的相同问题的文章。在对第二个问题的公认答案中,CommonsWare将其标识为“文档错误”。

答案 3 :(得分:1)

另一种解决方案是用<ripple>包装图片,将其设置为ImageView的{​​{1}},然后将backgroundtint设置为“隐藏” tintMode图片,以便可以看到上面有波纹的背景图片。

src
<!-- In your layout file -->

<ImageView
    android:adjustViewBounds="true"
    android:background="@drawable/image_with_ripple"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:src="@drawable/image"
    android:tint="@android:color/transparent"
    android:tintMode="src_in" />

不仅可在API 21+上使用,而且如果您的图像具有圆角-或者是另一种非矩形形状(例如星形或心形图标),则保持其边界,而不是填充视图的矩形边界,这在某些情况下可以提供更好的外观。

有关动画GIF的信息,请参见this Medium article,以了解该技术与使用<!-- drawable/image_with_ripple.xml --> <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?colorControlHighlight"> <item android:drawable="@drawable/image" /> </ripple> <FrameLayout>属性的比较。