如果您需要在应用中显示静态图片,可以使用 Drawable
类及其子类绘制形状和
图片。Drawable
是
可以绘制的东西。各种子类有助于处理特定图片
您可以扩展这些场景,以定义您自己的可绘制对象
行为方式独特的应用
除了使用类构造函数之外,还可以通过另外两种方法定义和实例化 Drawable
:
- 扩充保存在项目中的图片资源(位图文件)。
- 扩充用于定义可绘制属性的 XML 资源。
注意: 您可能更喜欢使用矢量可绘制对象,它定义了一个具有一组 以及相关的颜色信息。这样便可使用矢量可绘制对象 可以针对不同的尺寸进行缩放,而不会有损图片质量有关详情,请参阅矢量 可绘制对象概览。
通过资源图片创建可绘制对象
您可以通过引用来自应用的图片文件 项目资源。支持的文件类型包括 PNG(首选)、JPG(可接受)、 和 GIF(不推荐)。应用图标、徽标和其他图形(例如使用的图像) 非常适合采用这种方法。
如需使用图片资源,请将您的文件添加到 res/drawable/
目录进入您的项目后,您就可以引用该图片
从代码或 XML 布局中获取。无论采用哪种方式,都会引用
资源 ID,即不含文件类型扩展名的文件名。对于
例如,请使用 my_image
指代 my_image.png
。
注意:放置在
res/drawable/
目录可以使用
在构建期间由 aapt
工具进行无损图像压缩
过程。例如,不需要超过 256 种颜色的真彩色 PNG
可以使用调色板转换为 8 位 PNG。这会生成
但需要的内存更少因此,图片二进制文件
放置到此目录中的所有资源在构建时可能会发生变化。如果您打算阅读
比特流格式的图片,以便将其转换为位图,那么请将您的图片放入
res/raw/
文件夹,其中 aapt
工具不支持
修改它们。
以下代码段演示了如何构建使用ImageView
从可绘制资源创建的图片并将其添加到布局中:
Kotlin
private lateinit var constraintLayout: ConstraintLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Instantiate an ImageView and define its properties val i = ImageView(this).apply { setImageResource(R.drawable.my_image) contentDescription = resources.getString(R.string.my_image_desc) // set the ImageView bounds to match the Drawable's dimensions adjustViewBounds = true layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) } // Create a ConstraintLayout in which to add the ImageView constraintLayout = ConstraintLayout(this).apply { // Add the ImageView to the layout. addView(i) } // Set the layout as the content view. setContentView(constraintLayout) }
Java
ConstraintLayout constraintLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a ConstraintLayout in which to add the ImageView constraintLayout = new ConstraintLayout(this); // Instantiate an ImageView and define its properties ImageView i = new ImageView(this); i.setImageResource(R.drawable.my_image); i.setContentDescription(getResources().getString(R.string.my_image_desc)); // set the ImageView bounds to match the Drawable's dimensions i.setAdjustViewBounds(true); i.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // Add the ImageView to the layout and set the layout as the content view. constraintLayout.addView(i); setContentView(constraintLayout); }
在其他情况下,您可能需要将图片资源作为 Drawable
对象进行处理,如下所示
示例:
Kotlin
val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)
Java
Resources res = context.getResources(); Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);
警告:项目中的每个唯一资源
只能维持一种状态,不管有多少个不同的对象,
实例化。例如,如果您实例化同一图片资源中的两个 Drawable
对象,并
更改一个对象的属性(例如 alpha),那么这也会影响
另一个。处理一个图片资源的多个实例时,应改为
直接转换 Drawable
对象,您应该执行
补间
动画。
以下 XML 代码段展示了如何在 XML 布局中向 ImageView
添加可绘制资源:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/my_image" android:contentDescription="@string/my_image_desc" />
如需详细了解如何使用项目资源,请参阅资源。
注意:使用图片资源作为可绘制对象的来源时, 确保图像的尺寸适合各种像素密度。如果 图片不正确,它们将被放大以适应,这可能会导致可绘制对象出现伪影。 有关详情,请参阅支持不同的 像素密度。
通过 XML 资源创建可绘制对象
如果存在 Drawable
对象,该对象最初并不依赖于
代码或用户互动,那么在 XML 中定义 Drawable
是不错的选择。均匀
如果您希望 Drawable
在用户互动期间更改其属性
应用,则应考虑在 XML 中定义对象,因为您可以在之后修改属性,
该对象已被实例化。
在 XML 中定义 Drawable
后,将文件保存在
res/drawable/
目录中。以下示例展示了
定义了
TransitionDrawable
资源,该资源继承自 Drawable
:
<!-- res/drawable/expand_collapse.xml --> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/image_expand"/> <item android:drawable="@drawable/image_collapse"/> </transition>
然后,通过调用以下代码来检索和实例化该对象
Resources#getDrawable()
并传递 XML 文件的资源 ID。不限
Drawable
子类
支持 inflate()
方法的应用,可在 XML 中定义并实例化
。
每个支持 XML 膨胀的可绘制对象类都使用特定的 XML 属性
帮助定义对象属性以下代码将
TransitionDrawable
并将其设置为
ImageView
对象:
Kotlin
val transition= ResourcesCompat.getDrawable( context.resources, R.drawable.expand_collapse, null ) as TransitionDrawable val image: ImageView = findViewById(R.id.toggle_image) image.setImageDrawable(transition) // Description of the initial state that the drawable represents. image.contentDescription = resources.getString(R.string.collapsed) // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000) // After the transition is complete, change the image's content description // to reflect the new state.
Java
Resources res = context.getResources(); TransitionDrawable transition = (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null); ImageView image = (ImageView) findViewById(R.id.toggle_image); image.setImageDrawable(transition); // Description of the initial state that the drawable represents. image.setContentDescription(getResources().getString(R.string.collapsed)); // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000); // After the transition is complete, change the image's content description // to reflect the new state.
如需详细了解所支持的 XML 属性,请参阅 。
形状可绘制对象
ShapeDrawable
对象是个不错的选择
需要动态绘制二维图形时。您可以
以编程方式在 ShapeDrawable
对象上绘制基元形状
并应用您的应用所需的样式。
ShapeDrawable
是 Drawable
的子类。因此,您可以使用
ShapeDrawable
任何需要 Drawable
的地方。对于
例如,您可以使用 ShapeDrawable
对象设置背景
方法是将视图传递给视图的 setBackgroundDrawable()
方法。您还可以将形状作为
自定义视图,并将其添加到应用的布局中。
由于 ShapeDrawable
有自己的 draw()
方法,因此您可以创建
View
的子类,用于绘制 ShapeDrawable
如 onDraw()
事件期间发生的事件,
以下代码示例:
Kotlin
class CustomDrawableView(context: Context) : View(context) { private val drawable: ShapeDrawable = run { val x = 10 val y = 10 val width = 300 val height = 50 contentDescription = context.resources.getString(R.string.my_view_desc) ShapeDrawable(OvalShape()).apply { // If the color isn't set, the shape uses black as the default. paint.color = 0xff74AC23.toInt() // If the bounds aren't set, the shape can't be drawn. setBounds(x, y, x + width, y + height) } } override fun onDraw(canvas: Canvas) { drawable.draw(canvas) } }
Java
public class CustomDrawableView extends View { private ShapeDrawable drawable; public CustomDrawableView(Context context) { super(context); int x = 10; int y = 10; int width = 300; int height = 50; setContentDescription(context.getResources().getString( R.string.my_view_desc)); drawable = new ShapeDrawable(new OvalShape()); // If the color isn't set, the shape uses black as the default. drawable.getPaint().setColor(0xff74AC23); // If the bounds aren't set, the shape can't be drawn. drawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { drawable.draw(canvas); } }
您可以使用代码示例中的 CustomDrawableView
类
就像使用任何其他自定义视图一样。例如,您可以
以编程方式将其添加到应用中的 activity,如下所示
示例:
Kotlin
private lateinit var customDrawableView: CustomDrawableView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) customDrawableView = CustomDrawableView(this) setContentView(customDrawableView) }
Java
CustomDrawableView customDrawableView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); customDrawableView = new CustomDrawableView(this); setContentView(customDrawableView); }
如果您想在 XML 布局中使用自定义视图,则
CustomDrawableView
类必须替换 View(Context, AttributeSet)
构造函数,系统会在该类
从 XML 扩充而来。以下示例展示了如何声明
XML 布局中的 CustomDrawableView
:
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
ShapeDrawable
类与许多其他类一样
android.graphics.drawable
软件包中的可绘制对象类型,可让您
使用公共方法定义对象的各种属性。一些示例
例如透明度、色彩滤镜
抖动、不透明度和颜色
您还可以使用 XML 资源定义基元可绘制形状。有关 信息,请参阅 中的形状可绘制对象 可绘制资源类型。
NinePatch 可绘制对象
NinePatchDrawable
图形是
可用作视图背景的可拉伸位图图像。Android 设备
自动调整图形大小以适应视图内容。一个
NinePatch 图像示例是标准 Android
按钮——按钮必须拉伸以适应各种长度的字符串。答
NinePatch 图形是标准 PNG 图片,包含一个额外的 1 像素边框。
必须使用 9.png
扩展名保存在
res/drawable/
目录中。
使用边框定义图片的可拉伸区域和静态区域。 您可以通过绘制一个(或多个)1 像素宽的部分来指定可拉伸部分 边框左侧和顶部的黑线(其他边框像素) 应为完全透明或白色)。您可以设置任意数量的可拉伸部分 。可拉伸部分的相对尺寸保持不变, 最大的部分始终是最大的部分。
您还可以定义图片的可选可绘制部分(实际上,
添加内边距线)。如果
View
对象将 NinePatch 图形设置为其背景
然后指定视图的文本,它会拉伸自身,以便所有文本
仅占据由右侧和底部线条指定的区域(如果有的话)。
如果没有添加内边距行,Android 会使用左侧和顶部的行
定义这个可绘制区域
为了明确区分各线条,左侧和顶部的线条定义 允许复制图片的哪些像素 图片。底线和右边线定义了图片中的相对区域, 视图的内容会被占用。
图 1 显示了定义按钮的 NinePatch 图形示例:
此 NinePatch 图形定义了一个可拉伸区域,该区域左侧和顶部均位于右侧 绘制区域包含底部和右侧的线条。在上面的图片中 灰色虚线表示图片被复制的区域 以便拉伸图像底部图片中的粉色矩形标识 允许视图内容的区域。如果内容 系统就会拉伸图片,使其适合这个区域
Draw 9-patch 工具提供 使用 WYSIWYG(所见即所得)图形创建 NinePatch 图像的便捷方式 编辑器。如果您针对可拉伸区域定义的区域 区域因像素而产生的绘制伪影的风险 复制。
以下示例布局 XML 演示了如何添加 NinePatch 图形
几个按钮NinePatch 图像将保存到
res/drawable/my_button_background.9.png
。
<Button android:id="@+id/tiny" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:text="Tiny" android:textSize="8sp" android:background="@drawable/my_button_background"/> <Button android:id="@+id/big" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerInParent="true" android:text="Biiiiiiig text!" android:textSize="30sp" android:background="@drawable/my_button_background"/>
请注意,layout_width
和 layout_height
属性设为 wrap_content
,让按钮整齐地显示。
文本。
图 2 显示了通过 XML 和 NinePatch 图像渲染的两个按钮 如上图所示请注意按钮的宽度和高度如何随文本变化, 而背景图片会拉伸以适应该屏幕。
自定义可绘制对象
如果您想创建一些自定义可绘制对象,可以通过扩展 Drawable
类(或其任何子类)来实现。
最重要的实现方法是 draw(Canvas)
因为这提供了 Canvas
对象,您在提供
您的绘图说明。
以下代码展示了 Drawable
的一个简单子类
:
Kotlin
class MyDrawable : Drawable() { private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) } override fun draw(canvas: Canvas) { // Get the drawable's bounds val width: Int = bounds.width() val height: Int = bounds.height() val radius: Float = Math.min(width, height).toFloat() / 2f // Draw a red circle in the center canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint) } override fun setAlpha(alpha: Int) { // This method is required } override fun setColorFilter(colorFilter: ColorFilter?) { // This method is required } override fun getOpacity(): Int = // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE PixelFormat.OPAQUE }
Java
public class MyDrawable extends Drawable { private final Paint redPaint; public MyDrawable() { // Set up color and text size redPaint = new Paint(); redPaint.setARGB(255, 255, 0, 0); } @Override public void draw(Canvas canvas) { // Get the drawable's bounds int width = getBounds().width(); int height = getBounds().height(); float radius = Math.min(width, height) / 2; // Draw a red circle in the center canvas.drawCircle(width/2, height/2, radius, redPaint); } @Override public void setAlpha(int alpha) { // This method is required } @Override public void setColorFilter(ColorFilter colorFilter) { // This method is required } @Override public int getOpacity() { // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE return PixelFormat.OPAQUE; } }
然后,您可以将可绘制对象添加到任意位置,例如添加到
ImageView
,如下所示:
Kotlin
val myDrawing = MyDrawable() val image: ImageView = findViewById(R.id.imageView) image.setImageDrawable(myDrawing) image.contentDescription = resources.getString(R.string.my_image_desc)
Java
MyDrawable mydrawing = new MyDrawable(); ImageView image = findViewById(R.id.imageView); image.setImageDrawable(mydrawing); image.setContentDescription(getResources().getString(R.string.my_image_desc));
在 Android 7.0(API 级别 24)及更高版本中,您还可以定义自定义可绘制对象的实例 与 XML 相关联:
- 将完全限定类名用作 XML 元素名称。对于此方法,自定义的
可绘制对象类必须是顶级公共类:
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- 使用
drawable
作为 XML 标记名称并指定完全限定类 name。此方法可用于公共顶级类和 公共静态内部类:<drawable xmlns:android="http://schemas.android.com/apk/res/android" class="com.myapp.MyTopLevelClass$MyDrawable" android:color="#ffff0000" />
向可绘制对象添加色调
在 Android 5.0(API 级别 21)及更高版本中,您可以对定义为以下元素的位图和九宫格着色:
alpha 蒙版。您可以使用颜色资源或解析为颜色的主题属性为其着色
资源(例如 ?android:attr/colorPrimary
)。这类素材资源通常由您自己
并自动为其上色以符合您的主题。
您可以为 BitmapDrawable
、NinePatchDrawable
或 VectorDrawable
着色
与 setTint()
方法搭配使用。您可以
还使用 android:tint
和
android:tintMode
属性。
从图片中萃取突出颜色
Android 支持库包含 Palette
类,可让您从图片中提取突出颜色。
您可以将可绘制对象作为 Bitmap
加载,并将其传递给 Palette
以访问其颜色。
有关详情,请参阅选择颜色
Palette API