Android开发指南-二维图形

系统 2022 0

ninepatch_example 二维图形 2D Graphics

Android 提供一个定制的 2D 图形库,用来绘制图形图像和制作动画。你将从 android.graphics.drawable android.view.animation 包中找到这些通用类。

本文简单介绍如何在 Android 应用程序中进行画图。我们将讨论使用 Drawable 对象画图的基础知识,如何使用几个 Drawable 子类,以及如何创建动画,一个图形的补间动画或者一系列图形的连续动画(就像电影胶卷一样)。

可绘制物 Drawables

一个 Drawable 是一个“某些可以被绘制的物体”的一般抽象。你将发现这个 Drawable 类扩展了多种具体可绘制图形类,包括 BitmapDrawable , ShapeDrawable , PictureDrawable , LayerDrawable , 等等。 当然,你还可以扩展这些类来定义你自己的具有独特行为的可绘制对象。

有三种方式来定义和实例化一个 Drawable :使用一个保存在你的项目资源中的图像;使用一个定义了 Drawable 属性的 XML 文件;或者使用通常的类构造函数。下面,我们将挨个讨论前面两种方法(对于一个经验丰富的开发人员而言,使用构造函数没什么新意)。

从资源图像中创建 Creating from resource images

一个为你的应用程序增加图形的简单方法是通过引用项目资源中的一个图片文件。支持的图片文件格式有 PNG (推荐的), JPG (可接受的)和 GIF (不鼓励的)。 这个技术将显然推荐使用在应用程序图标, logo ,或者其它类似使用于游戏中的图形。

为了使用一个图片资源,只要把你的文件添加到你项目的 res/drawable/ 目录即可。从那里,你可以在代码或 XML 布局中进行引用。任何一种方式,都是通过资源 ID 来引用,资源 ID 是不带扩展后缀的文件名(比如, my_image.png 通过 my_image 来引用 )

注意 : 图像资源被放在 res/drawable / 里。也许会通过 aapt 工具进行无损图像压缩而被自动优化。比如,一个不需要多于 256 色的真彩色 PNG 图片可能会被转换成一个带有调色板的 8 PNG 。这产生了相同质量但占用更少内存的图片。因此需要意识到该目录下的二进制图像可能会在编译期间被改变。如果你想以比特流读取一个图片并转换为一个位图,那么需要把你的图片文件放在 res/raw/ 目录,这里的文件不会被优化。

示例代码 Example code

下面的代码片断说明了如何构造一个 ImageView ,从 drawable 资源中使用并添加到布局中。

LinearLayout mLinearLayout;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// Create a LinearLayout in which to add the ImageView

mLinearLayout = new LinearLayout(this);

// Instantiate an ImageView and define its properties

ImageView i = new ImageView(this);

i.setImageResource(R.drawable.my_image);

i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions

i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

// Add the ImageView to the layout and set the layout as the content view

mLinearLayout.addView(i);

setContentView(mLinearLayout);

}

在其它情况下,你可能想把你的图片资源当作一个可绘制 Drawable 对象。为此,你可以这样做 :

Resources res = mContext.getResources();

Drawable myImage = res.getDrawable(R.drawable.my_image);

注意 : 每个你项目里的唯一资源只能维护一个状态,而无论你为它实例化了多少个不同对象。比如,如果你从相同的图像资源实例化两个可绘制对象,然后改变其中之一的属性(比如 alpha ),那它也将作用于另一个。所以当处理一个图片资源的多个实例时,你应该实施一个 tween animation ,而不是直接转换这个可绘制对象。

示例 XML

下面的 XML 片断显示了如何添加一个可绘制资源到一个 XML 布局中的 ImageView 里(为了有趣些,添加一些红色渲染)。

<ImageView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:tint="#55ff0000"

android:src="@drawable/my_image"/>

更多关于使用项目资源的信息,请阅读资源和资产 Resources and Assets

从资源 XML 中创建 Creating from resource XML

到目前为止,你应该对 Android 用户界面 User Interface 开发原理比较熟悉。 因此,你应该了解在 XML 中定义对象所固有的能力和灵活性。这个理念从视图延伸到可绘制对象。如果你想创建一个可绘制( Drawable )对象,而它并不初始依赖于你代码中的变量或者用户交互,那么在 XML 里面定义它是个好的选择。即便你预期这个可绘制对象在用户使用你的应用程序时将会改变其属性,你也应该考虑在 XML 里面定义它,因为一旦被实例化后,你就可以修改它的属性。

一旦你在 XML 中定义了你的可绘制对象,把这个文件保存到你项目中的 res/drawable/ 目录下。然后,通过传递资源 ID 参数调用 Resources.getDrawable() 获取并实例化这个对象。 (参见 example below .

任何支持 inflate() 方法的可绘制对象( Drawable )子类可以在 XML 里定义并由你的应用程序实例化。每个支持 XML 扩充的可绘制对象利用特定的 XML 属性来帮助定义对象属性(参见类参考了解这些属性)。查阅每个可绘制对象子类的类描述文档,以获知如何在 XML 中定义它。

例子 Example

下面是一些定义了一个 TransitionDrawable 对象的 XML 语句:

<transition xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/image_expand">

<item android:drawable="@drawable/image_collapse">

</transition>

当把这个 XML 保存为 res/drawable/expand_collapse.xml 文件后,下面的代码将用来实例化它并把它设置为一个 ImageView 的内容:

Resources res = mContext.getResources();

TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.expand_collapse);

ImageView image = (ImageView) findViewById(R.id.toggle_image);

image.setImageDrawable(transition);

然后通过下面的方法让这个 transition 运转起来(每 1 秒转变一次):

transition.startTransition(1000);

请参考上面所列的可绘制对象( Drawable )类以了解更多它们所支持的 XML 属性。

可绘制形状 ShapeDrawable

当你想动态的画一些二维图形时, ShapeDrawable 对象可能会满足你的要求。 通过一个 ShapeDrawable ,你可以绘制原始图形和以任何想象得到的方式设计它们。

ShapeDrawable Drawable 的一个扩展类,因此你能使用在任何可用 Drawable 的地方 - 也许是视图背景,用 setBackgroundDrawable() 方法来设置。当然,你还能以它自己的视图来绘制图形,并添加到你的布局中只要你乐意。因为 ShapeDrawable 有它自己的 draw() 方法,你可以创建一个视图子类在 View.onDraw() 方法中绘制这个 ShapeDrawable 下面这个视图类的一个基本扩展就是这么做的,把 ShapeDrawable 作为一个视图来绘制。

public class CustomDrawableView extends View {

private ShapeDrawable mDrawable;

public CustomDrawableView(Context context) {

super(context);

int x = 10;

int y = 10;

int width = 300;

int height = 50;

mDrawable = new ShapeDrawable(new OvalShape());

mDrawable.getPaint().setColor(0xff74AC23);

mDrawable.setBounds(x, y, x + width, y + height);

}

protected void onDraw(Canvas canvas) {

mDrawable.draw(canvas);

}

}

在构造函数里, ShapeDrawable 被定义为一个 OvalShape 。然后设置颜色和边界。如果你不设置边界,那么这个图形将不被绘制,不过如果你不设置颜色的话,它会设置成缺省的黑色。

通过这个定制视图,它能以任何你想要的方式绘制。通过上面的例子,我们能在一个活动中以编程的方式绘制这个图形:

CustomDrawableView mCustomDrawableView;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mCustomDrawableView = new CustomDrawableView(this);

setContentView(mCustomDrawableView);

}

如果你希望从 XML 布局中而不是活动中绘制这个自定义可绘制对象,那么这个 CustomDrawable 类必须重写 View(Context, AttributeSet) 构造函数,这个当通过 XML 扩充来实例化一个视图时被调用。然后为这个 XML 添加一个 CustomDrawable 元素,如下:

<com.example.shapedrawable.CustomDrawableView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

/>

这个 ShapeDrawable 类(像很多其他在 android.graphics.drawable 包中的可绘制对象类型一样)允许你通过公共的方法来定义这个可绘制对象的各种属性。有一些属性,你可能会做一些调整,比如 alpha 透明度,颜色过滤器,抖动,模糊度和颜色。

可绘制九宫格

一个 NinePatchDrawable 图形是一个可拉伸位图图像, Android 会自动调整来容纳视图的内容,你可以用来作为背景。一个使用九宫格的例子是 Android 按钮背景 - 按钮必须延伸以适应各种长度的字符串。一个九宫格可绘制对象是一个标准的 PNG 图像,并包含一个附加的单像素宽的边界。它必须以扩展名 .9.png 保存,并存放到 res/drawable/ 目录。

这个边界用来定义这个图像的可拉伸和静态区域。通过在边界的左边和上面部分绘画单像素宽的一个或多条黑线来指示一个可拉伸区。(你能有任意多的可拉伸区)。这些可拉伸区的相对尺寸保持一样,因此最大的区域总是保持最大。

你也可以通过在右边和下面画线来定义这个图片(事实上,这些填充线)的一个可选的可绘制区。如果一个视图对象设置这个九宫格为其背景然后指定这个视图的文本,它将自我调整以使得文本适应在刚才通过右边和下面的画线指定的区域里面(如果被包含进来)。如果这些填充线未被包含, Android 使用左边和上面的线来定义可绘制区域。

为了阐明不同线的区别,左边和上面定义了哪些图像像素允许被复制来拉伸这个图像。下面和右边的线则定义了这个图像中的相对区域,这个区域可允许视图内容显示于其中。

下面是一个用来定义一个按钮的九宫格文件例子:

nighpatch_raw

这个九宫格通过左边和上面的线条定义了一个可拉伸区域以及通过下面和右边的线条定义了一个可绘制区域。在图中上半部分,灰色的虚线标示了可以被复制来拉伸图像的区域。而下半部分的粉红虚线框标示了允许显示视图内容的区域。如果内容不能适应这个区域,那么这个图像将被拉伸来适应它。

Draw 9-patch 工具提供了一个非常方便的方法来创建你的九宫格图像,使用一个所见即所得的图像编辑器。它甚至会在你的可拉伸区域会产生人工痕迹时(复制像素的副效果)提出告警。

示例 XMLExample XML

下面是一些示例布局 XML 来说明怎么添加一个九宫格图像到几个按钮中。(这个九宫格图像被保存为 res/drawable/my_button_background.9.png

<Button 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 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"/>

注意宽度和高度被设置为 "wrap_content" ,这样按钮可以整齐得体的适合文本。

下面两个按钮以 XML 和上面显示的九宫格图像进行绘制。注意按钮的高度和宽度如何根据文本大小进行相应调整,以及背景图片自动拉伸来容纳它。

补间动画 Tween Animation

一个补间动画可以在视图对象的内容上执行一系列的简单变换(位置,尺寸,旋转和透明度)。因此,如果你有一个文本视图 TextView 对象,你可以移动,旋转,扩展或者收缩这个文本。如果它有一个背景图像,也将随着文本一起变换。动画包 animation package 提供了所有补间动画需要使用的类。

一系列动画指令定义了这个补间动画,通过 XML 或者代码。就像定义一个布局一样, XML 文件是推荐使用的方法,因为它比硬编码这个动画要更容易阅读,可复用和可交换。在下面的例子中,我们使用 XML 。(为了学习更多关于在你的应用程序中定义一个动画方面的知识,请参考 AnimationSet 类和其他 Animation 子类。)

动画指令定义你想要发生的变换,什么时候发生以及多长时间。变换可以是顺序的或者是同时发生的 - 比如,你可以让一个 TextView 的内容从左到右移动,然后旋转 180 度,或者你让它同时移动和旋转。每个变换采用一组特定参数(尺寸变化的起动以及结束尺寸,旋转的起动和结束角度,等等),和一组通用参数(比如,起动时间和持续时间)。要使若干变换同时发生,可以为它们设定相同的起动时间;要让它们顺序发生,计算起动时间为前置变换起动时间加上持续时间。

这个动画 XML 文件归属于 res/anim/ 目录。该文件必须有一个单独的根元素:这将会是一个单独的 <alpha> , <scale> , <translate> , <rotate> , 插值器( interpolator )元素 , 或包含这些元素组的 <set> 元素(可能含有另一个 <set> 元素)。缺省情况下,所有的动画指令都是同时发生的。要让它们顺序发生,你必须指定 startOffset 属性,如下例所示:

下面来自 ApiDemos XML 文件被用来拉伸,然后同时旋转一个视图对象。

<set android:shareInterpolator="false">

<scale

android:interpolator="@android:anim/accelerate_decelerate_interpolator"

android:fromXScale="1.0"

android:toXScale="1.4"

android:fromYScale="1.0"

android:toYScale="0.6"

android:pivotX="50%"

android:pivotY="50%"

android:fillAfter="false"

android:duration="700" />

<set android:interpolator="@android:anim/decelerate_interpolator">

<scale

android:fromXScale="1.4"

android:toXScale="0.0"

android:fromYScale="0.6"

android:toYScale="0.0"

android:pivotX="50%"

android:pivotY="50%"

android:startOffset="700"

android:duration="400"

android:fillBefore="false" />

<rotate

android:fromDegrees="0"

android:toDegrees="-45"

android:toYScale="0.0"

android:pivotX="50%"

android:pivotY="50%"

android:startOffset="700"

android:duration="400" />

</set>

</set>

屏幕坐标(未在本例中使用)是基于左上角的 (0,0) ,向下和向右时坐标值增加。

margin: 0cm 0cm 12pt; line

Android开发指南-二维图形


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论