Android API Guides---Canvas and Drawables

来源:互联网 发布:淘宝商品资质图片 编辑:程序博客网 时间:2024/04/30 01:27

Canvas and Drawables

Android的框架API提供了一组二维绘图API,让您呈现自己的自定义图形到画布或修改现有的视图来定制自己的外观和感觉的。当绘制2D图形,你会通常以两种方式做到这一点:
画出你的图形或动画到从布局视图对象。在这种方式下,图形的绘制是由系统的正常查看层次拉丝工艺处理 - 您只需定义图形去查看里面。
直接画出你的图形到画布上。这样一来,你亲自调用相应的类的OnDraw()方法(它传递你的Canvas),或帆布之一绘制...()方法(如画绘画())。这样一来,你也是任何动画的控制权。
选项​​“a”引到View,是您最佳的选择,当你想绘制简单的图形不需要动态改变,是不是性能密集型游戏的一部分。例如,当你想显示静态图形或预定义的动画,一个原本静态的应用程序中,你应该绘制图形到一个视图。阅读绘图资源以获取更多信息。
选项​​“B”,绘制到一个Canvas,不如当应用程序需要定期重新绘制本身。应用,如视频游戏,应借鉴到自身的画布。然而,有这样做不止一种方法:
在同一个线程你的UI活动,其中创建在布局自定义视图组件,将无效(),然后处理的onDraw()回调。
或者,在一个单独的线程,其中你管理一个SurfaceView并执行提请画布一样快,你的线程能够(你不需要申请无效())。
用帆布画
当你写的,你想进行专业的作图和/或控制图形的动画的应用程序,你应该通过一个绘图画布这样做。画布为你工作的幌子,或接口,实际表面,在其图形将被吸引 - 它拥有所有的“画图”的电话。通过画布,图形实际上是在一个基本的位图,它被放置在窗口中执行。
在你的的onDraw()回调方法中借鉴的情况下,画布是为你,你只需要放置在其上绘图的电话。您还可以获取来自SurfaceHolder.lockCanvas一个Canvas(),具有SurfaceView对象打交道时。 (这两种情况都在下面的章节中讨论)。但是,如果你需要创建一个新的画布,那么你必须定义在其绘图将被实际执行位图。位图总是需要一个Canvas。您可以设置一个新的Canvas是这样的:

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);Canvas c = new Canvas(b);
现在你的画布将绘制到定义位图。与画布后,它绘制后,你就可以带着你的位图到另一个画布与Canvas.drawBitmap之一(位图,...)方法。它建议最终通过)由View.onDraw()或SurfaceHolder.lockCanvas(提供给你一个Canvas(见下文)绘制图形决赛。


Canvas类都有自己的一套绘图方法,你可以用,像drawBitmap(...),drawRect中(...)的drawText(...)的,等等。您可能还可以使用其他类有画()方法。例如,你可能有你想要把画布上的一些拖拉的对象。可绘制有自己的draw()方法,把你的画布作为参数。


在一个视图


如果您的应用程序不需要处理或帧速率的速度(也许是一盘棋,一条蛇游戏,或另一种慢慢动画的应用程序)的显著量,那么你应该考虑创建一个自定义视图组件和在Canvas绘图View.onDraw()。这样做的最方便的方面是,Android框架将为您提供一个预先定义的画布,你会把你的图纸电话。


要启动,延长View类(或其后代),并定义的onDraw()回调方法。这种方法将被Android框架调用来请求您的视图中绘制本身。在这里,您将执行所有通话透过画布,这是通过的onDraw()回调传递给你画。


Android框架只会调用的onDraw()是必要的。每次您的应用程序准备绘制,你必须要求你查看调用无效无效()。这表示您想绘制您的视图,然后Android将会调用你的onDraw()方法(虽然不能保证回调将是瞬间)。


您的内部View组件的OnDraw(),使用提供给您的所有绘图画布,用各种Canvas.draw ...()方法,或其他类的draw()是把你的画布作为参数的方法。一旦你的onDraw()完成后,Android框架会使用你的画布绘制由系统处理的位图。


注:为了从与您的主要活动的线程的线程上请求无效,必须调用postInvalidate()。


有关扩展视图类信息,请阅读构建自定义组件。


对于一个示例应用程序,请参见贪吃蛇游戏,在SDK示例文件夹:<您-SDK目录> /样本/蛇/。


在一个SurfaceView


该SurfaceView观是一种特殊的子类,提供了查看层次结构中的专用绘图表面。其目的是该图的表面提供到一个应用程序的辅助线程,以使应用程序不需要等到系统的视图层次是准备绘制。相反,具有参照SurfaceView辅助线程可在其自己的速度绘制到其自身的画布。


首先,你需要创建一个扩展SurfaceView一个新的类。类也应该实现SurfaceHolder.Callback。子类是一个接口,会通知你有关下垫面,当创建,更改或销毁等信息。让你知道当你可以开始绘制,是否需要根据新的表面特性进行调整,以及何时停止绘制并有可能杀死一些任务,这些事件是非常重要的。里面你SurfaceView类也是定义您的辅助线程类,它将执行所有的绘图程序到你的画布的好地方。


而不是直接处理Surface物件,你应该通过SurfaceHolder处理。所以,当您SurfaceView初始化,通过调用getHolder得到SurfaceHolder()。那么你应该通知你想调用的addCallback接收(从SurfaceHolder.Callback)SurfaceHolder回调SurfaceHolder()(传递这一点)。然后重写你的每一个SurfaceView类中SurfaceHolder.Callback方法。


为了从你的第二个线程中吸取到表面画布,你必须通过你的线程和SurfaceHandler检索与lockCanvas画布()。您现在可以通过SurfaceHolder给您的画布在其上做你需要的绘图。一旦你完成的绘图画布,调用unlockCanvasAndPost(),它传递你的Canvas对象。表面现在将绘制画布你离开它。执行锁定并要重绘每次解锁画布的这个序列。


注:在每一个与你擦肩而过检索来自SurfaceHolder画布,画布的以前的状态将被保留。为了正确动画图形,你必须重新绘制整个表面。例如,您可以通过与drawColor(颜色与drawBitmap填充)或设置背景图片清除画布的前一个状态()。否则,你会发现你以前进行图纸的痕迹。


对于一个示例应用程序,看到月球着陆游戏,在SDK示例文件夹:<您-SDK目录> /样本/ LunarLander /。或者,浏览示例代码部分的来源。


可绘


Android提供了绘制图形和图像的自定义2D图形库。该android.graphics.drawable包是在这里您可以找到用于以二维绘图的公共类。


该文件讨论了使用拖拉的对象绘制图形,以及如何使用可绘制类的子类夫妇的基本知识。有关使用绘图资源做帧一帧动画信息,请参见可绘制动画。


可拉伸是一般的抽象“的东西,可以得出”。你会发现,绘制对象类扩展定义各种特定种类绘制的图形,包括BitmapDrawable,ShapeDrawable,PictureDrawable,LayerDrawable,还有几个的。当然,你也可以扩展这些定义以独特的方式表现自己的自定义拖拉的对象。


有三种方法来定义和实例化一个绘制对象:使用保存在您的项目资源图像;使用定义的可绘制属性的XML文件;或使用正常类的构造函数。下面,我们将讨论各自的前两个技术(使用构造是一个有经验的开发人员毫无新意)。


从资源映像创建


一个简单的方法,以图形添加到您的应用程序是由您的项目资源引用的图像文件。支持的文件类型为PNG(首选),JPG(可接受的)和G​​IF(灰心)。这种技术显然是优选的用于应用程序的图标,徽标或其他图形,如在一个游戏中使用。


使用图像资源,只需添加文件到您的项目的RES /绘制/目录下。从那里,你可以从你的代码或XML布局引用它。无论哪种方式,它是利用一个资源ID,这是不带文件类型扩展名(例如,my_image.png引用作为my_image)的文件名称为。


注:/置于RES /绘制的图像资源可以通过在构建过程中AAPT工具无损图像压缩自动优化。例如,一个真​​彩色的PNG,不需要超过256种颜色可以用颜色调色板转换成一个8位的PNG。这将导致相等质量的图像,但它需要较少的存储器英寸所以,要知道,放在这个目录下的图像二进制文件可以在生成过程中发生改变。如果你计划,以将其转换为位图读取图像作为比特流,把你的照片在res /生/文件夹而不是,在那里他们将不会被优化。


示例代码


下面的代码片段演示了如何构建,从绘图资源使用的图像的ImageView的,并把它添加到布局。

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);}
在其他情况下,你可能要处理图像资源作为可绘制对象。要做到这一点,创建像这样的一个资源绘制对象:

Resources res = mContext.getResources();Drawable myImage = res.getDrawable(R.drawable.my_image);
注:项目中的每个独特的资源可以只维护一个状态,无论你可能有多少种不同的对象实例化它。例如,如果你从相同的图像资源实例2拖拉的对象,然后更改属性(如Alpha)的可绘之一,那么它也将影响其他。因此,与一个图像资源的多个实例打交道时,而不是直接转化绘制对象,您应该执行补间动画。


示例XML


下面的XML片段展示了如何将资源可绘制在XML布局添加到一个ImageView的(有一些红色色调只是为了好玩)。

<ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:tint="#55ff0000"        android:src="@drawable/my_image"/>
有关使用项目资源的更多信息,请阅读资源和资产。


从资源XML创建


现在,你应该熟悉开发用户界面的Andr​​oid的原则。因此,你明白的力量和灵活性于XML定义对象所固有的。这一理念从视图来绘制资源龋齿过来。如果有一个可绘制对象,您想创建,这是最初不依赖于你的应用程序代码或用户交互定义,然后定义在XML中可绘制变量是一个不错的选择。即使你希望你的可绘制到用户的使用应用程序的体验过程中改变其属性,你应该考虑在XML中定义的对象,一旦被实例化,你可以随时修改属性。


一旦你定义XML中的可绘制,保存在你的项目的RES /绘制/目录下的文件。然后,检索和调用Resources.getDrawable()实例化对象,将其传递XML文件的资源ID。 (请参见下面的例子。)


支持充气()方法的可绘制子类可以在XML定义和您的应用程序实例化。支持XML通胀利用特定的XML属性来帮助定义对象属性每个绘制对象(请参阅类的引用,看看这是什么意思)。请参阅有关如何在XML定义它信息的每个可绘制子类文档。





下面是一些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 /绘制/扩展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);
然后,这种转变可以向前跑(1秒)带:

transition.startTransition(1000);
请参阅有关每个支持的XML属性的更多信息,上面所列的可绘制类。
形状绘制对象
当你要动态地画一些二维图形,一个图形对象可绘制可能会满足您的需求。其形状可绘制,您可以通过编程绘制基本形状,并以任何方式想象他们的风格。
一个ShapeDrawable是绘制对象的扩展,所以你可以使用一个地方可绘制预期 - 也许是()视图的背景,与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);  }}
在构造函数中,一个形状绘制对象被定义为一个椭圆形。它然后给出一个颜色和形状的边界被设定。如果您没有设置界限,则形状将无法绘制,而如果你不设置颜色,它会默认为黑色。
通过自定义视图定义,可以得出任何你喜欢的方式。与上面的例子中,我们可以在活动编程绘制形状:

CustomDrawableView mCustomDrawableView;protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  mCustomDrawableView = new CustomDrawableView(this);  setContentView(mCustomDrawableView);}
如果您想从XML布局,而不是从活动得出这个自定义绘制,然后自定义绘制对象类必须重写视图(背景下,的AttributeSet)构造,通过通胀率从XML实例化一个视图时被调用。然后自定义绘制对象元素添加到XML,像这样:

<com.example.shapedrawable.CustomDrawableView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        />
该ShapeDrawable类(像android.graphics.drawable包许多其他类型的可绘制)允许您与公共方法定义绘制的各种属性。您可能需要调整一些特性包括Alpha透明度,彩色滤光片,抖动,不透明度和颜色。
您也可以使用XML定义原始绘制形状。欲了解更多信息,请参阅有关绘图资源文件中可绘制形状的部分。
九宫格


一个NinePatchDrawable图形是一个可拉伸的位图图像,它的Andr​​oid会自动调整以适应你所把它作为背景查看的内容。一个例子使用九补丁是标准的Andr​​oid按键使用的背景 - 按钮必须延伸,以适应不同长度的字符串。阿九补丁绘是一个标准的PNG图像,其中包括一个额外的1个像素宽的边框。它必须与扩展.9.png被保存,并保存到你的项目的RES /绘制/目录下。
边界用于定义图像的伸缩性和静止区域。你表明通过绘制一个(或多个)中的边界的左侧和顶部部分可拉伸部分1个像素宽的黑线(多个)(其他边界像素应该是充分透明的或白色)。只要你想,你可以有很多伸展部分:其相对规模保持不变,所以最大的部分始终保持最大的。
您还可以通过画线的右侧和底部行定义图像(有效,填充线)的一个可选的可绘制部分。如果一个视图对象设置NinePatch为背景,然后指定查看的文本,这将让所有的文字只能由右侧和底部线(如果有)指定的区域内适合舒展自己。如果不包括填充线,Android使用左侧和顶部行定义该可拉伸区域。
澄清不同行之间的差异,左侧和顶部行定义该图像的像素被允许以拉伸图像被复制。底部和右侧行定义了图像内的相对面积,该视图中的内容被允许之内。
这里是用来定义按钮样品NinePatch文件:
此NinePatch定义与左,顶线和与底部和右线被拉伸区域的一个拉伸区域。在顶部图像中,点状线确定将为了拉伸图像被复制的图像的区域。底图像中的粉红色矩形标识该视图中的内容被允许的区域。如果内容不在该区域适合,则图像将被拉伸,使得他们这样做。
绘图9补丁工具提供了一个非常方便的方法来创建你的NinePatch的图像,使用所见即所得的图形编辑器。它甚至提出了警告,如果您为拉伸区域定义的区域是在生产图纸文物为像素复制的结果的风险。
示例XML
以下是演示如何将NinePatch图像添加到几个按钮的一些示例XML布局。 (该NinePatch图像保存为RES /绘制/ 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和九补丁图像呈现的两个按钮。通知按钮的宽度和高度如何与文本变化,并且背景图像延伸来容纳。


0 0