Canvas and Drawables
原文:http://developer.android.com/guide/topics/graphics/2d-graphics.html
知识点小节:http://www.cnblogs.com/jsaint/articles/3428014.html
Canvas and Drawables
Android framework(框架) Apis 提供了 一系列的2D画图Apis,通过这些Api你可以指定你自己制定的图片在canvas上或者是修改已存在的views定制它们的外形与视觉感受。当在画2d图像的时候,你通常会在二者之中选其一:
a.画你的图像或者是动画在你layout的中某个View对象。这种方式,你的图像绘制是由系统普通的View hierarchy drawing process(图像层级进程),你简单的定义图像在某个View中。
b.直接在canvas上绘制你的图像。这种方式,你调用相应类型的onDraw()方法(传递给你canvas),或者canvans draw()方式的一种(像是drawPicture()).在这这些的时候,你也可以控制任何的动画。
A方式在view上绘制图像,是你最佳的选择当你只是想简单的绘制图像不需要动态的改变以及加强视觉效果。举个例子,当你想要展示一张静态或者预先定义好的animation,你需要将你的图像在某个View中绘制。
当你的app需要定期重新绘制图像是,b方式在canvans上绘制会更好一些。App像是一个video游戏需要在canvas上绘制自己。然而,存在多种方式做这件事情:
在相同的thread像是你的UI activity,在你layout中,你创建的通用(custom)View组件,调用invalidate()以及处理onDraw()的回调。
或者在一个独立的thread中,你管理SurfaceView以及执行在canvans上的绘制想你的capable(?)线程一样快.(你不需要请求invalidate())
Draw with a Canvas
当你正在编写一个app时,在你想要执行一个特殊的绘制或者是控制图片的动画时,你应该通过canvans去绘制。Canvas 对于你来说像是一个接口或者是一个假象(pretense or interface),是你图像绘制的实际表面--- canvas拥有你绘制调用。通过canvas,你的绘制实际是将在潜在的bitMap中执行,它将在被放进窗口中。
你通过onDraw()回调方式绘制时,为你提供了canvas以及你只需要将的绘制调用放在它上面。当你处理一个SurfaceView对象时,你也可以通过SurfaceHolder.lockCanvas()获取canvas。(以上情景在接下来的文章均将展开讨论)。然而,如果你需要创建一个新的canvans,你必须定义一个Bitmap,这个bitmap将绘制。Canvans通常需要一个Bitmap.你可以创建一个新的canvans像是这样:
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
现在你的canvas可以在被定义的bitmap的基础上进行绘制了。在canvans上绘制bitmap,你可以带着你的bitmap在另一个canvas绘制通过Canvans.drawBitmap(Bitmap,.....)中的方法中的一种。在View.onDraw或者是SurfaceHolder.lockCanvas()中提供的canvas上绘制你的最终的图像,推荐这种方式。
Canvas类有它自己一系列的绘制方式,你可以使用的像是drawBitmap(...).drawRect(...),drawText(....)以及其他。其他类中也有draw()函数。举个例子,你可以拥有一些drawable对象,你想要将这些对象放在Canvans显示。Drawable 有自己的draw()函数将你的canvas作为一个参数传入。
On the View
如果你的app不需要大量的处理或者是frame-rate 速度(可能是下棋软件、贪吃蛇或者其他慢速动画的app),你应该考虑创建一个传统(custom)View组件以及在View.onDraw上通过Canvas绘制。最为便捷的方面是android framework 会提供给你一个预定义的canvas,你可以使用canvas调用你的绘制。
一开始,继承View类(或者是它的子类)以及定义onDraw()回调函数。这个函数会被android framewok 请求当你的View绘制自己的时候。在这里,你可以通过回传过来的Canvas,执行所有你想要的函数去绘制。
Android framework只会在必要的时候调用onDraw()。每次你的app准备去绘制的时候,你必须请求你的View 无效,通过调用invalidate()的方式。这表明你想要的View被绘制以及Android会调用onDraw() (虽然不能保证这个回调会立即被执行)。
在View组件onDraw()里面,通过使用被传入的Canvas绘制,使用不同的Canvas.draw()函数或者是其他类型draw()函数将canvas作为一个变量。当你onDraw()完成的时候,android
Framework会使用你的canvas绘制一个将被系统处理Bitmap。
注意:如果在非主Activity 线程中(UI线程)请求失效,你必须调用postInvalidate()
对于继承View的展开,在这里
http://developer.android.com/guide/topics/ui/custom-components.html
On a SurfaceView
surfaceView 是view的一个特殊子类,这个类可以提供专有的绘制surface(表面?)在View层级内。目的就是提供给app第二线程一个绘制平面(surface).这样app不需要等待到系统的View层级绘制完成。第二进程通过索引sufaceView就可以在自己的canvans上进行绘制了。
一开始,你需要创建一个新的类继承surfaceView..这个类同时需要implement SurFaceHolder.Callback.这个子类是一个接口,这个接口会通知你回传一些关于信息基础(underling)Surface,像是当它被创建,改变或是消除。这些事件非常重要,你可以知道当你会开始绘制时,是否需要对于依赖的新surface配置进行适配以及当你停止绘制的时候需要干掉一些任务。在surfaceView类的中,定义你的第二进行类是不错的选择。
替代直接处理surface对象,你应该通过surfaceHolder处理它。这样的话,当你surfaceView 初始化后,通过调用 getHolder()获取surfaceHolder.之后你应该通知surfaceHolder你想要接受surfaceHolder回调通过调用addCallback的方式。在你的SurfaceVIew中重载SurfaceHolder.Callback.
为了在你的第二进程中的Surface Canvas上绘制,你必须传递你的SurfaceHandler给进程以及使用lockCanvas()来接受canvas.你可以通过SurfaceHolder获取canvas以及在canvas上进行绘制。当你完成在canvas上的绘制时,调用unlickCavansAndPost(),将它传递给canvas对象。Surface 将绘制canvas当你舍弃的时候。执行这一系列的lock与unlock操作每当你想要重新绘制时。
注意:当你从surfaceHolder中接受到canvas时,canvas之前的状态将会保留。为了使得动画运行,你必须要重新绘制整个surface。举个例子,你需要清空之前canvas的状态,可以填充color调用drawColor()或者是设置一个背景图片。此外你需要查看你之前的绘制执行的记录。
Drawables
Android提供传统的2D图像lib用于绘制基本图形与图像。在android.graphics.drawable包中,你可以发现用于2维图片绘制的公用类。
本篇文档讨论使用Drawable对象绘制图片以及如何使用drawable子类们的基础知识。对于使用drawablesc逐帧绘制动画的信息,可见Drawable Animation(http://developer.android.com/guide/topics/graphics/drawable-animation.html)
Drawable是对“可以被绘制(drawn)的东西”的抽象。你可以发现drawable类的子类定义了一些特殊类型的可绘制图片,包括BitmapDrawable,ShapeDrawable,PictureDrawable,LayerDrawable以及其他。当然,你也可以继承这些子类定义你的传统Drawable 对象拥有特殊的行为。
存在三种方法定义以及实例化一个drawable:使用一张图像保存在你的工程资源中;
使用xml文件定义drawable 配置;或者是使用普通的类构造。以下,我们将分别讨论前二种(使用类构造不是新东西对于一个有经验的开发者).
Creating from resource images
一个简单的方法添加图片到你的app是从你的工程资源中引用一个图片文件。支持的文件类型是PNG(首选),JPG(可接受)以及GIF(不鼓励).这种方式显然应当优先用于app 图标,商标,或者其他图片像是那些用于游戏中的图片。
为了使用图片资源,只是将添加你的文件到你的工程res/drawable/目录下。在那里,你可以在你的代码或者xml layout中使用它。无论哪种方法,你通过resource ID使用,这个id就是文件的名字去掉文件类型的扩展。(e.g:my_image.png被my_image索引)。
注意点:在build过程中,appt工具可能将放在res/drawable中的图片资源进行图像的无损压缩。举个列子,一张true-color PNG不需要比256更多的颜色,可能通过color调色盘被转换成8-bit PNG.这样会影响到图片质量,但是需要的内存更少。注意放在这个目录的图片2进制文件可能改变在build中。如果你计划读取一个bit stream为了将它转换为bitmap,将你的图片资源放在res/raw/文件中,那样图片不会被优化。
Example code
以下代码展示如何构建一个ImageView来使用存在于drawable资源中图片以及将它添加到layout中。
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); }
Example Xml
以下的Xml片段展示如何在xml layout 将一个资源drawable添加到imageView中。
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#55ff0000"
android:src="@drawable/my_image"/>
Creating from resource xml
到目前为止,你应该对android 开发用户界面的原则有了一定了解。因此,你明白在xml定义对象的灵活与强大。This philosophy caries over from Views to Drawables(不明白).如果存在你想要创建的一个drawable 对象,这个对象起初不依赖于你的app代码定义的变量或者用户交互,那么在xml中定义这个drawable是不错的选择。甚至当用户使用你的app时,如果你希望你的drawable改变自身的性质(properties),你应该考虑在xml中定义对象,这样的化你可以在drawable实例化的时候改变它的属性。
一旦当你在xml中定义你的drawabl时,将文件保存在你的app下res/drawable目录下。
之后通过调用Resources.getDrawable()的方式传递xml文件中资源id,检索以及实例化对象.
一个Drawable 子类支持inflate()方法可以在xml中被定义以及被你的app实例化。每个Drawable支持xml inflation(膨胀?)可以利用指定的xml属性帮助定义对象的性质(见类文档所有的性质).见Drawable子类文档如何在xml中定义自身。
Example
Xml定义 TransitionDrawable
<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中,接下来的代码将会实例化TransitionDrawable 以及将它设为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);
之后,这个TransitionDrawable 运行1s:
transition.startTransition(1000);
Shape Drawable
当你想要动态绘制一些2维图像时,一个ShapeDrawable对象可能会符合你的需求。通过ShapeDrawble,你可以
以程序的方式绘制原始图形以及设计可能的任何图形。
ShapeDrawable是Drawable类型的扩展,所以你可以使用ShapeDrable在哪些drawable被需要的地方----可能是一个View的background,通过setBackgroundDrawable()设置。当然,你也可以在绘制你的图形在它自己的custiom View,你可以将这个view添加到layout中。因为shapeDrawable有自己draw()方法,你可以创建View的子类当View.onDraw()时绘制ShapeDrawable.以下对View类基本的扩展,绘制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,给定颜色以及图形的边界。如果你不设定边界,图形将不被绘制,如果不给定颜色,默认为黑色。
Custom View的定义,你可以通过任意你想要的方式去绘制。以下的列子,我们在Activity中绘制程序化的绘制图形:
CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView); }
如果你想要通过xml layout 绘制custom drawable而不是在activity中,CustomDrawableView类必须重载View(Context,AttributeSet)构造函数,这个函数在从xml中实例化View时将被调用。在XML中添加CustomDrawbaleView:
<com.example.shapedrawable.CustomDrawableView
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
ShapeDrawable类(像其他drawable类型在android.graphics.drawable包中)允许你通过 drawable的公共函数定义各种性质。你可能会想要一些性质调整包括alpha透明度、颜色过滤器,犹豫,透明度和颜色。
你也可以定义原始的drawable shapes在xml中。更多信息详见Drawable Resources.
Nine-patch
NinePatchDrawable 图像是一种可拉伸的bitmap图像,android会自动调整其大小使其适应对应View内容(该View将NinePatchDrawable设置为背景)。使用样例将NinePatch作为android标准buttons的背景,buttons必须延伸适应不同strings的长度。NinePatch drawable 是一种标准的PNG图像包含额外像素宽度的边界。它必须被保存为.9.png的扩展以及保存在res/drawable目录下。
NinePatchDrawable的边间用于定义图片的可延展以及静态区域。你通过在边界的左边或者是顶部绘制一个或多个1像素宽度的黑色直线说明这是可延展区域(其他边界像素点需要全透明或者是白色的)。你可以使用多个可延展区域,它们相对大小保持不变,所以最大的区域任然保持最大。
你可以通过在右边或者是底部直线上绘制一条线来定义可选择drawable区域。如果一个View对象设置NinePatch做为背景以及制定View文本,它将会延展自身所以所有的文本将会向内适应(fit inside)通过右边以及底部直线指定的直线。如果padding直线不被包含,Android使用左边以及顶部的lines定义可绘制区域。
为了申明不同lines之间的区别,左边以及顶部的lines定义哪些图像的像素点可以用于复制来延展图像。而右边以及底部的lines定义在图像内的相对区域可用于内容的填充(文字等)。
(图片 http://developer.android.com/images/ninepatch_raw.png )
上面图像的NinePatch使用左边以及顶部的lines定义可延展区域以及使用底部与右边lines定义可以绘制区域。在上图中顶部图片,灰色点线确认图像可复制区域用于延展图像。粉色矩形在底下图片中确认可被View内容填充的区域。如果内容不能适应这个区域,图像将被拉伸。
Draw 9-patch 工具提供一种极端简易的方式创建你的NinePatch 图像,使用WYSIWYG图像编辑器。
它甚至会提供警告如果你定义的可延展区域在像素复制时存在一定风险。
Example Xml
这里有一些layout xml 样例展示如何添加NinePatch图像到buttons(NinePatch保存于res/drawable/my_button_backgroud.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"/>
注意width 以及height设置为wrap_contetn使button灵活的适应文本。
以下两个buttons在xml中定义。注意根据text的不同导致buttons不同的witdh以及height,以及背景图片适应buttons的调整。
http://developer.android.com/images/ninepatch_examples.png
Canvas and Drawables
Android framework(框架) Apis 提供了 一系列的2D画图Apis,通过这些Api你可以指定你自己制定的图片在canvas上或者是修改已存在的views定制它们的外形与视觉感受。当在画2d图像的时候,你通常会在二者之中选其一:
a.画你的图像或者是动画在你layout的中某个View对象。这种方式,你的图像绘制是由系统普通的View hierarchy drawing process(图像层级进程),你简单的定义图像在某个View中。
b.直接在canvas上绘制你的图像。这种方式,你调用相应类型的onDraw()方法(传递给你canvas),或者canvans draw()方式的一种(像是drawPicture()).在这这些的时候,你也可以控制任何的动画。
A方式在view上绘制图像,是你最佳的选择当你只是想简单的绘制图像不需要动态的改变以及加强视觉效果。举个例子,当你想要展示一张静态或者预先定义好的animation,你需要将你的图像在某个View中绘制。
当你的app需要定期重新绘制图像是,b方式在canvans上绘制会更好一些。App像是一个video游戏需要在canvas上绘制自己。然而,存在多种方式做这件事情:
在相同的thread像是你的UI activity,在你layout中,你创建的通用(custom)View组件,调用invalidate()以及处理onDraw()的回调。
或者在一个独立的thread中,你管理SurfaceView以及执行在canvans上的绘制想你的capable(?)线程一样快.(你不需要请求invalidate())
Draw with a Canvas
当你正在编写一个app时,在你想要执行一个特殊的绘制或者是控制图片的动画时,你应该通过canvans去绘制。Canvas 对于你来说像是一个接口或者是一个假象(pretense or interface),是你图像绘制的实际表面--- canvas拥有你绘制调用。通过canvas,你的绘制实际是将在潜在的bitMap中执行,它将在被放进窗口中。
你通过onDraw()回调方式绘制时,为你提供了canvas以及你只需要将的绘制调用放在它上面。当你处理一个SurfaceView对象时,你也可以通过SurfaceHolder.lockCanvas()获取canvas。(以上情景在接下来的文章均将展开讨论)。然而,如果你需要创建一个新的canvans,你必须定义一个Bitmap,这个bitmap将绘制。Canvans通常需要一个Bitmap.你可以创建一个新的canvans像是这样:
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
现在你的canvas可以在被定义的bitmap的基础上进行绘制了。在canvans上绘制bitmap,你可以带着你的bitmap在另一个canvas绘制通过Canvans.drawBitmap(Bitmap,.....)中的方法中的一种。在View.onDraw或者是SurfaceHolder.lockCanvas()中提供的canvas上绘制你的最终的图像,推荐这种方式。
Canvas类有它自己一系列的绘制方式,你可以使用的像是drawBitmap(...).drawRect(...),drawText(....)以及其他。其他类中也有draw()函数。举个例子,你可以拥有一些drawable对象,你想要将这些对象放在Canvans显示。Drawable 有自己的draw()函数将你的canvas作为一个参数传入。
On the View
如果你的app不需要大量的处理或者是frame-rate 速度(可能是下棋软件、贪吃蛇或者其他慢速动画的app),你应该考虑创建一个传统(custom)View组件以及在View.onDraw上通过Canvas绘制。最为便捷的方面是android framework 会提供给你一个预定义的canvas,你可以使用canvas调用你的绘制。
一开始,继承View类(或者是它的子类)以及定义onDraw()回调函数。这个函数会被android framewok 请求当你的View绘制自己的时候。在这里,你可以通过回传过来的Canvas,执行所有你想要的函数去绘制。
Android framework只会在必要的时候调用onDraw()。每次你的app准备去绘制的时候,你必须请求你的View 无效,通过调用invalidate()的方式。这表明你想要的View被绘制以及Android会调用onDraw() (虽然不能保证这个回调会立即被执行)。
在View组件onDraw()里面,通过使用被传入的Canvas绘制,使用不同的Canvas.draw()函数或者是其他类型draw()函数将canvas作为一个变量。当你onDraw()完成的时候,android
Framework会使用你的canvas绘制一个将被系统处理Bitmap。
注意:如果在非主Activity 线程中(UI线程)请求失效,你必须调用postInvalidate()
对于继承View的展开,在这里
http://developer.android.com/guide/topics/ui/custom-components.html
On a SurfaceView
surfaceView 是view的一个特殊子类,这个类可以提供专有的绘制surface(表面?)在View层级内。目的就是提供给app第二线程一个绘制平面(surface).这样app不需要等待到系统的View层级绘制完成。第二进程通过索引sufaceView就可以在自己的canvans上进行绘制了。
一开始,你需要创建一个新的类继承surfaceView..这个类同时需要implement SurFaceHolder.Callback.这个子类是一个接口,这个接口会通知你回传一些关于信息基础(underling)Surface,像是当它被创建,改变或是消除。这些事件非常重要,你可以知道当你会开始绘制时,是否需要对于依赖的新surface配置进行适配以及当你停止绘制的时候需要干掉一些任务。在surfaceView类的中,定义你的第二进行类是不错的选择。
替代直接处理surface对象,你应该通过surfaceHolder处理它。这样的话,当你surfaceView 初始化后,通过调用 getHolder()获取surfaceHolder.之后你应该通知surfaceHolder你想要接受surfaceHolder回调通过调用addCallback的方式。在你的SurfaceVIew中重载SurfaceHolder.Callback.
为了在你的第二进程中的Surface Canvas上绘制,你必须传递你的SurfaceHandler给进程以及使用lockCanvas()来接受canvas.你可以通过SurfaceHolder获取canvas以及在canvas上进行绘制。当你完成在canvas上的绘制时,调用unlickCavansAndPost(),将它传递给canvas对象。Surface 将绘制canvas当你舍弃的时候。执行这一系列的lock与unlock操作每当你想要重新绘制时。
注意:当你从surfaceHolder中接受到canvas时,canvas之前的状态将会保留。为了使得动画运行,你必须要重新绘制整个surface。举个例子,你需要清空之前canvas的状态,可以填充color调用drawColor()或者是设置一个背景图片。此外你需要查看你之前的绘制执行的记录。
Drawables
Android提供传统的2D图像lib用于绘制基本图形与图像。在android.graphics.drawable包中,你可以发现用于2维图片绘制的公用类。
本篇文档讨论使用Drawable对象绘制图片以及如何使用drawable子类们的基础知识。对于使用drawablesc逐帧绘制动画的信息,可见Drawable Animation(http://developer.android.com/guide/topics/graphics/drawable-animation.html)
Drawable是对“可以被绘制(drawn)的东西”的抽象。你可以发现drawable类的子类定义了一些特殊类型的可绘制图片,包括BitmapDrawable,ShapeDrawable,PictureDrawable,LayerDrawable以及其他。当然,你也可以继承这些子类定义你的传统Drawable 对象拥有特殊的行为。
存在三种方法定义以及实例化一个drawable:使用一张图像保存在你的工程资源中;
使用xml文件定义drawable 配置;或者是使用普通的类构造。以下,我们将分别讨论前二种(使用类构造不是新东西对于一个有经验的开发者).
Creating from resource images
一个简单的方法添加图片到你的app是从你的工程资源中引用一个图片文件。支持的文件类型是PNG(首选),JPG(可接受)以及GIF(不鼓励).这种方式显然应当优先用于app 图标,商标,或者其他图片像是那些用于游戏中的图片。
为了使用图片资源,只是将添加你的文件到你的工程res/drawable/目录下。在那里,你可以在你的代码或者xml layout中使用它。无论哪种方法,你通过resource ID使用,这个id就是文件的名字去掉文件类型的扩展。(e.g:my_image.png被my_image索引)。
注意点:在build过程中,appt工具可能将放在res/drawable中的图片资源进行图像的无损压缩。举个列子,一张true-color PNG不需要比256更多的颜色,可能通过color调色盘被转换成8-bit PNG.这样会影响到图片质量,但是需要的内存更少。注意放在这个目录的图片2进制文件可能改变在build中。如果你计划读取一个bit stream为了将它转换为bitmap,将你的图片资源放在res/raw/文件中,那样图片不会被优化。
Example code
以下代码展示如何构建一个ImageView来使用存在于drawable资源中图片以及将它添加到layout中。
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); }
Example Xml
以下的Xml片段展示如何在xml layout 将一个资源drawable添加到imageView中。
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#55ff0000"
android:src="@drawable/my_image"/>
Creating from resource xml
到目前为止,你应该对android 开发用户界面的原则有了一定了解。因此,你明白在xml定义对象的灵活与强大。This philosophy caries over from Views to Drawables(不明白).如果存在你想要创建的一个drawable 对象,这个对象起初不依赖于你的app代码定义的变量或者用户交互,那么在xml中定义这个drawable是不错的选择。甚至当用户使用你的app时,如果你希望你的drawable改变自身的性质(properties),你应该考虑在xml中定义对象,这样的化你可以在drawable实例化的时候改变它的属性。
一旦当你在xml中定义你的drawabl时,将文件保存在你的app下res/drawable目录下。
之后通过调用Resources.getDrawable()的方式传递xml文件中资源id,检索以及实例化对象.
一个Drawable 子类支持inflate()方法可以在xml中被定义以及被你的app实例化。每个Drawable支持xml inflation(膨胀?)可以利用指定的xml属性帮助定义对象的性质(见类文档所有的性质).见Drawable子类文档如何在xml中定义自身。
Example
Xml定义 TransitionDrawable
<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中,接下来的代码将会实例化TransitionDrawable 以及将它设为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);
之后,这个TransitionDrawable 运行1s:
transition.startTransition(1000);
Shape Drawable
当你想要动态绘制一些2维图像时,一个ShapeDrawable对象可能会符合你的需求。通过ShapeDrawble,你可以
以程序的方式绘制原始图形以及设计可能的任何图形。
ShapeDrawable是Drawable类型的扩展,所以你可以使用ShapeDrable在哪些drawable被需要的地方----可能是一个View的background,通过setBackgroundDrawable()设置。当然,你也可以在绘制你的图形在它自己的custiom View,你可以将这个view添加到layout中。因为shapeDrawable有自己draw()方法,你可以创建View的子类当View.onDraw()时绘制ShapeDrawable.以下对View类基本的扩展,绘制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,给定颜色以及图形的边界。如果你不设定边界,图形将不被绘制,如果不给定颜色,默认为黑色。
Custom View的定义,你可以通过任意你想要的方式去绘制。以下的列子,我们在Activity中绘制程序化的绘制图形:
CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView); }
如果你想要通过xml layout 绘制custom drawable而不是在activity中,CustomDrawableView类必须重载View(Context,AttributeSet)构造函数,这个函数在从xml中实例化View时将被调用。在XML中添加CustomDrawbaleView:
<com.example.shapedrawable.CustomDrawableView
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
ShapeDrawable类(像其他drawable类型在android.graphics.drawable包中)允许你通过 drawable的公共函数定义各种性质。你可能会想要一些性质调整包括alpha透明度、颜色过滤器,犹豫,透明度和颜色。
你也可以定义原始的drawable shapes在xml中。更多信息详见Drawable Resources.
Nine-patch
NinePatchDrawable 图像是一种可拉伸的bitmap图像,android会自动调整其大小使其适应对应View内容(该View将NinePatchDrawable设置为背景)。使用样例将NinePatch作为android标准buttons的背景,buttons必须延伸适应不同strings的长度。NinePatch drawable 是一种标准的PNG图像包含额外像素宽度的边界。它必须被保存为.9.png的扩展以及保存在res/drawable目录下。
NinePatchDrawable的边间用于定义图片的可延展以及静态区域。你通过在边界的左边或者是顶部绘制一个或多个1像素宽度的黑色直线说明这是可延展区域(其他边界像素点需要全透明或者是白色的)。你可以使用多个可延展区域,它们相对大小保持不变,所以最大的区域任然保持最大。
你可以通过在右边或者是底部直线上绘制一条线来定义可选择drawable区域。如果一个View对象设置NinePatch做为背景以及制定View文本,它将会延展自身所以所有的文本将会向内适应(fit inside)通过右边以及底部直线指定的直线。如果padding直线不被包含,Android使用左边以及顶部的lines定义可绘制区域。
为了申明不同lines之间的区别,左边以及顶部的lines定义哪些图像的像素点可以用于复制来延展图像。而右边以及底部的lines定义在图像内的相对区域可用于内容的填充(文字等)。
(图片 http://developer.android.com/images/ninepatch_raw.png )
上面图像的NinePatch使用左边以及顶部的lines定义可延展区域以及使用底部与右边lines定义可以绘制区域。在上图中顶部图片,灰色点线确认图像可复制区域用于延展图像。粉色矩形在底下图片中确认可被View内容填充的区域。如果内容不能适应这个区域,图像将被拉伸。
Draw 9-patch 工具提供一种极端简易的方式创建你的NinePatch 图像,使用WYSIWYG图像编辑器。
它甚至会提供警告如果你定义的可延展区域在像素复制时存在一定风险。
Example Xml
这里有一些layout xml 样例展示如何添加NinePatch图像到buttons(NinePatch保存于res/drawable/my_button_backgroud.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"/>
注意width 以及height设置为wrap_contetn使button灵活的适应文本。
以下两个buttons在xml中定义。注意根据text的不同导致buttons不同的witdh以及height,以及背景图片适应buttons的调整。
http://developer.android.com/images/ninepatch_examples.png
浙公网安备 33010602011771号