Canvas and Drawables

Android framework API提供了一套2D绘画API绘制自己的图形到画布上或更改已有的Views定制外观。绘制2D图形,有两种方法:

  1. 从layout中把图形或动画绘制给一个View对象。在这个方法中,图形绘制操作由系统普通View图层绘制进程完成——我们只需要定义这个图形到View视图中。
  2. 直接绘制图形到画布上。这样需要个人调用onDraw()方法或者画布类的draw...()方法(例如drawPicture()方法),这样作我们仍然控制着动画。

方法1绘制一个View视图,是绘制不需要动态改变的以及非加强游戏的简单 图形的最佳选择。例如,当我们需要在一个静态应用中展示一个静态图形或一个实现定义的动画时需要绘制图形到View视图中。更多消息查看Drawables。

方法2,绘制到画布上,是应用需要重绘的很好选择。像视频游戏这类的应用需要自己绘制到画布上。而且,不止一个方法可以做到这一点:

  • 在UI Activity的同一个线程中,我们layout中创建了一个自定义View组件,调用invalidate()方法然后处理onDraw()回调。
  • 或者,在不同线程中,处理一个SurfaceView。一旦线程准备好了,立即把绘制工作交给画布。

Draw with a Canvas

当应用程序需要特别展示绘制或控制图形动画时,需要使用Canvas进行绘制。Canvas是一个表象或者说是一个接口使图形绘制到真正的平面上,这个类包含了所有的绘制调用函数。通过Canvas类,绘制工作在一个Bitmap上完成,这个Bitmap放置在窗口中。

在onDraw()回调的绘制事件中,提供出Canvas类,我们只需要回调的地方。同时当处理SurfaceView对象时,我们可以从SurfaceHolder.lockCanvas()中获取Canvas。然后必须定义绘制地点的Bitmap。对于Canvas来说,Bitmap必不可少。我们可以如下设置一个Canvas:

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

这样,Canvas则会绘制到定义的Bitmap上。绘制后,可以使用Canvas.drawBitmap(Bitmap, ...)方法把Bitmap搬移到另一个Canvas上。建议最终调用View.onDraw()或SurfaceHolder.lockCanvas()提供的Canvas绘制最后的图形。

Canvas类有自己的一套绘制函数,例如drawBitmap(...),drawRect(...),drawText(...)等等。其他可以使用的类也有draw()函数。例如,我们可能会把一些Drawable对象防止到Canvas上。Drawable有自己的draw()函数把Canvas作为一个参数使用。

On a View

如果应用不要求处理大量的数据或较快的帧频速度(比如象棋游戏,贪吃蛇游戏或其他慢动画应用),那么我们需要考虑创建自定义View组件在View.onDraw()使用Canvas绘制。这样作最方便的是安卓framework提供了事先定义的Canvas防止绘制调用。

开始时,继承View类并定义onDraw()回调方法。当View视图需要自己进行绘制时安卓framework会调用这个方法。这个继承的新类是我们通过Canvas进行所有调用的地方,Canvas类会通过onDraw()回调传递出来。

安卓framework只在必要的时候调用onDraw()。当应用准备绘制时,调用invalidate()使View准备进行刷新。这意味着我们希望View进行绘制并且紧接着调用onDraw()方法(未保证回调是瞬时的)。

在View组件的onDraw()方法中,使用给出的Canvas进行所有的绘制,使用多种Canvas.draw...()方法,或者其他类的draw()方法把Canvas作为参数。一旦onDraw()绘制完成,安卓框架将会使用Canvas绘制一个由系统处理的Bitmap。

Note:要使刷新在另外的进程而不是activit主进程中进行,必须调用postInvalidate()方法。

更多关于继承View类的信息,参阅Building Custom Components。

实例程序查看安卓sdk目录下的/samples/Snake/。

On a SurfaceView

SurfaceView是View的一个特殊子类,它在View图层中提供了一个专用的绘制表面。使用这个类的目的是在应用的第二个线程中提供一个绘制表面,这样应用在系统View图层绘制完毕前不需要等待。所以在第二线程中SurfaceView可以按照自己的步伐绘制到自己的Canvas是上。

开始,需要创建一个继承自SurfaceView的类。这个类同时需要实现SurfaceHolder.Callback。这个子类是一个接口,它提供我们底层Surface的信息,例如它创建,变化和销毁的时间。这些事件对于我们何时开始绘制,是否需要更具新的表面属性进行调整,以及何时停止绘制和可能杀死人物很重要。SurfaceView类也是定义第二线程的好地方,它会展开所有的绘制进程到Canvas上。

有别于直接操作Surface对象,我们通过使用SurfaceHolder进行替代。所以当SurfaceView初始化时,调用getHolder()获取SurfaceHolder。紧接着需要调用addCallback()通知SurfaceHolder我们需要接收SurfaceHolder回调(从SurfaceHolder.Callback中)。紧接着在继承SurfaceView的类中复写所有SurfaceHolder.Callback方法。

为了在第二线程中绘制,必须把Surface的句柄传递到进程并且用lockCanvas()取出进程。然后就可以在SurfaceHolder提供的Canvas上进行绘制了。一旦结束绘制,调用unlockCanvasAndPost(),并且把Canvas对象传递给它。每次重绘时,都需要进行这样的锁定和解锁操作。

Note:每次从SurfaceHolder取出Canvas传递的过程中,Canvas先前的状态都会被保留。为了图形的动画化能够准确,必须重绘所有的Surface。例如,我们调用drawColor()填充颜色或调用drawBitmap()设置背景图片会清楚先前的Canvas状态。否则,会留下先前绘制操作的痕迹。

示例应用,查看sdk中的/samples/LunarLander/或者查看Sample Code部分。

Drawables

安卓提供了绘制图形和图片的2D图形库。通用类报存在android.graphics.drawable包里。

这些文献讨论了Drawable对象绘制图形的基本应用和如何使用Drawable子类。使用Drawables做桢动画操作,查阅Drawable Animation。

一个Drawable对象表示“可被绘制的东西”。继承Drawable类定义了许多具体的图形drawable,包括BitmapDrawable, ShapeDrawable, PictureDrawable, LayerDrawable等。同时我们也可以继承这些类自定义Drawable对象。

有三中定义和初始化一个Drawable对象的方法:使用保存在工程资源里的图片;使用定义了Drawable属性的XML文件;使用类构造函数。下面讨论了前两种机制(对一个老鸟来说,使用构造器定义并不是什么难事)。

Creating from resource images

把图形添加到应用中的一个简便方法是指定工程资源中的一个图片文件。图片资源支持的格式有:PNG(优先使用),JPG(可以使用),GIF(不推荐使用)。在应用程序图标,LOGO,或游戏图形中推荐使用这种机制。

使用图片资源,我们需要作的仅仅是把图片添加到工程的res/drawable/文件夹中,然后我们就可以把它们应用到代码或XML layout中。不论哪种应用,推荐使用资源ID,ID不包括图片名称的后缀名(例如my_image.png的ID为my_image)。

Note:保存在res/drawable/中的图片资源在build过程中被aapt工具进行无损压缩。例如一个本色PNG图片不要求256色会被转换为一个8比特PNG图片。这样的结果是图片质量不失真,而占用的内存会减少。我们要明确这一点在build过程中,图片的二进制比特流会改变。如果我们打算用比特流形式读取一张图片以便转化为bitmap,那么应该把图片放在res/raw/文件夹中代替,这样它们就不会被压缩。

Example code

下述代码片段使用drawable资源里的图片创建了一个ImageView并添加到layout中。

LinearLayout mLineraLayout;
protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        mLinearLayout = new LinearLayout(this);
        ImageView i = new ImageView(this);
        i.setImageResource(R.drawable.my_image);
        i.setAdjustViewBounds(true);
        i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        mLinearLayout.addView(i);
         setContentView(mLinearLayout);
}

在一些应用中,可能会把图片资源作为一个Drawable对象使用。如下:
Resources res = mContext.getResources();
Drawable myImage = res.getDrawable(R.drawable.my_image);

Note:保存在工程里的每个独立资源不管我们如何初始化它,都只会保存一种状态。例如,我们使用同一图片资源初始化为两个Drawable对象,然后改变其中一个对象的属性(比如透明度),那么同时另一个Drawable对象的该属性也会改变。所以当一张图片资源的多个实例时,应该使用补间动画取代这种直接操作Drawable资源。

Example XML

下面的代码段展示了在XML layout中添加一个Drawable资源到ImageView控件。(红色的tint属性仅供娱乐)。

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tint="#55ff0000"
        android:src="@drawable/my_image"/>

更多使用工程资源的信息,查阅Resources and Assets。

Creating from resource XML

先在我们应该知悉了安卓开发用户接口的规则,因此,我们也应该明白了使用XML定义对象的强大的灵活性。这套规则从View到drawable都适用。如果想创建一个一开始不依赖于应用代码或与用户有交互的Drawable对象,那么在XML里定义该对象是不错的选择。即便有时候期望根据用户的选择改变Drawable对象属性,仍可以考虑在XML中定义对象,因为可以在初始化的时候修改属性。

定义的XML文件保存到res/drawable/文件夹中。然后调用Resources.getDrawable()取出和初始化该对象。具体查看下面的示例。

任何支持inflate()方法的Drawable子类都可以在XML中初始化然后由应用程序初始化。它们使用具体的XML属性辅助定义对象属性。查看每个Drawable子类API查看各自的XML信息。

Example

下面的示例定义了一个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文件中,下面的代码展示了如何初始化这个TransistionDrawable并把他作为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可以如下播放(时间1s):
transition.startTransition(1000);

Shape Drawable

ShapeDrawable对象适用于动态绘制一些二维图形。使用ShapeDrawable,我们可以绘制一些基础图形,并且可以把它们装饰为任何我们可以想象的样子。

ShapeDrawable继承自Drawable,所以任何使用Drawable的地方都可以使用它——可能是一个View视图的背景图,调用setBackgroundDrawable()。当然我们还可以绘制自定义View视图的形状添加到layout中。因为ShapeDrawable有它自己的draw()方法。我们可以创建一个View子类在View.onDraw()方法中绘制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);
        }
}

使用上述自定义View,我们可以在Activity中绘制上述形状。
CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState){
          super.onCreate(savedInstanceState);
          mCustomDrawableView = new CustomDrawableView(this);
          setContentView(mCustomDrawableView);
}

如果我们不想像上面那样在代码中绘制这个drawable,而是在一个XML layout中,那么CustomDrawable类必须复写View(Context, AttributeSet)构造器,这个构造器在从XML中填充初始化View时调用。他一个CustomDrawable元素添加到XML的方法如下:
<com.example.shapedrawable.CustomDrawableView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      />

ShapeDrawable类(像android.graphics.drawable包中的许多其他Drawable类一样)允许我们使用一些共有方法定义drawable属性。以及调配一些属性,比如透明度,颜色,线条抖动。

当然也可以使用XML定义一些基础drawable图形,更多信息,插卡Drawable Resources的关于Shape Drawables部分。

Nine-patch

NinePatchDrawable图形是可伸展bitmap图片,安卓系统会自动调整这种图片尺寸以适应View视图。使用这种图片的一个例子是标准安卓按钮的背景图片——按钮必须能够扩展以适应不同长度的字串。NinePatch drawable是一张标准PNG图片包括了一个额外的1像素点宽度的边界。它必须被保存为.9.png的后缀名,而且保存在res/drawable/文件夹中。

那个额外边界用来定义图片的可伸展区域以及静态区域。在一张图片左边侧和上边侧画一条1像素点宽的黑线(其它部分全透明或白色)表明这是一个可扩展部分。我们可以根据需求有许多可扩展部分:他们的相对大小保持不变,最大部分保持最大。

我们也可以定义在图片右侧和下侧画线定义一个可选择的drawable部分(padding线)。如果一个View对象把NinePatch图片设置为背景图片然后指定了View的文本。那么图片会自行伸展以让所有文本填充到指定的右侧和下侧区域中。如果不包括padding线,那么安卓系统会使用上侧和左侧线定义这个drawable区域。

要分清不同线的差别,左侧和上侧线定义了图片的哪些像素可以允许图片扩展。底侧和右侧线定义了图片内可以放置View内容的相对区域。

下面有一个使用NinePatch文件定义按钮的示例:

NinePatch图片左侧和上侧线定义了可伸展部分,底侧和右侧定义了绘制部分。在第一副图中,灰色线圈出了会被复写以伸展的区域。第二副图的粉色矩形区域表示View控件内容放置的地方。如果内容与区域不对应,图片会进行伸展。

绘制9-patch的工具是WYSIWYG图形编辑器。这个工具当定义的可伸展区域在复制像素点时有可能产生绘制问题是甚至会产生警告。

Example XML

下面的示例表明了如何添加一个NinePatch图片到一些按钮中(该NinePatch图片保存为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"/>

注意button控件的宽和高设置为wrap_content。

下面的两副图片是上面示例的结果。注意按钮的宽和高是如何随着文本进行改变的,背景图片进行了伸展以适应这一些。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值