美图秀秀开发2D绘图
时间:2021-02-11 16:52:14 来源:勤学考试网 本文已影响 人
10.美图秀秀---开发2D绘图
浪费时间是所有支出中最奢侈最昂贵的。
——富兰克林
已经讲解了有关布局和各种可用的Android View类的知识,可以使屏幕设计变得简洁而高效。现
在考虑一些底层的问题,探讨如何在屏幕上绘制对象。本章讨论Android内建的2维绘制特性,包括
在创建自定义View类中使用Canvas和Paint在屏幕上进行图形和文本的绘制等,还将讨论在屏幕上显
示动画的各种方法。
10.1.屏幕绘图基础
Android可以在屏幕上绘制各种诸如PNG和JPG这样的图像,以及文本和基本图像。可以使用各
种颜色、样式和渐变来绘制它们,还可以使用标准的图像变换方法来对它们进行修改。我们甚至还可
以让这些可绘制的对象动起来,以制造生动的效果。
在Android下进行2D绘图需要Canvas类的支持,它位于"android.graphics.Canvas"包下,直译过来
为画布的意思,用于完成在View上的绘图,即使用"android.view.View"类的onDraw的方法。在Android SDK种支持多种图形效果,例如基本的图形元素(直线、圆形、弧度等),设置位图的透明度,画位图、旋转位图等等。
10.1.1.Canvas类
绘制图形通常在android.view.View或其子类的onDraw方法中进行。该方法的定义如下:
--------------------------------------------------------------------------------------------------------------------------------- protected void onDraw(Canvas canvas);
--------------------------------------------------------------------------------------------------------------------------------- 其中Canvas对象提供了大量绘图方法,这些方法主要包含绘制一条路径、区域、贴图、画点、画线、渲染文本,这些都是绘制图形的基本元素,如果绘制更为复杂的图形,可以采用组合的这些元素
的方式来完成,下面看看绘制图形的基本方法:
1、绘制像素
--------------------------------------------------------------------------------------------------------------------------------- public native void drawPoint(float x, float y, Paint paint); //画一个像素点
public native void drawPoint(float[] pts, int offset, int count, Paint paint); //画多个像素点public void drawPoint(float[] pts, Paint paint); //画多个像素点
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●x:像素点的横坐标
●y:像素点的纵坐标
●paint:描述像素点属性的Paint对象,可以设置坐标点像素的大小,颜色等属性。绘制其他图形
元素的Paint对象与绘制像素点的Paint对象的含义相同。在绘制具体的图形元素是可以根据实际情况设置Paint对象。
●pts:drawPoint方法可一次性画多个像素点,pts参数表示多个像素点的坐标。该数组元素必须是
偶数,两个一组为一个像素点的坐标。
●offset:drawPoint方法可以取pts数组中的一部分连续元素作为像素点的坐标,因此需要通过
offser参数来指定取得数组中连续元素的第一个元素位置,也就是元素的偏移量,从0开始。
●count:获得数组元素的个数。count必须为偶数(两个元素为一个像素点坐标)。
需要注意的是:offset可以从任意点取值。
2、绘制直线
--------------------------------------------------------------------------------------------------------------------------------- public void drawLine(float start_x, float start_y, float stop_x, float stop_y, Paint paint);
//画一条直线
public native void drawLine (float[] pts, int offset, int count, Paint paint);//画多条直线
public void drawLine (float[] pts, Paint paint); //画多条直线
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●start_x:直线开始端的横坐标
●start_y:直线开始端的纵坐标
●stop_x:直线结束端的横坐标
●stop_y:直线结束端的纵坐标
●pts:表示绘制多条直线的端点坐标集合,4个数组元素(两个为开始端点坐标,两个为结束端点
坐标)为一组,表述一条直线。
●offset:pts数组元素的偏移量。
●count:获得pts数组元素的个数。count必须为4的倍数。
3、绘制圆形
--------------------------------------------------------------------------------------------------------------------------------- public void drawCircle (float cx, float cy,float radius, Paint paint);
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●cx:圆心的横坐标。
●cx:圆心的横坐标。
●radius:圆的半径。
4、绘制弧
--------------------------------------------------------------------------------------------------------------------------------- public void drawArc(RectF oval,float startAngle, float sweepAngle,boolean useCenter, Paint paint); --------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●oval:弧的外切矩形坐标。需要设置该矩形的左上角和右下角的坐标,也就是oval.left、oval.top、
oval.right和oval.bottom。
●startAngle:弧的起始角度。
●sweepAngle:弧的结束角度。如果sweepAngle- startAngle大于等于360,drawArc画的就是一个圆
或者椭圆(如果oval指定的坐标画出来的是一个长方形,则drawArc画出来的为椭圆)。
●useCenter:如果该参数值为true,在画弧度时弧的两个端点会连接圆心;如果该参数值为false,
则只会画弧。
5、绘制文本
--------------------------------------------------------------------------------------------------------------------------------- public native void drawText(String text,float x, float y, Paint paint); //画text指定的文本。文本中的每一个字符的起始坐标由pos数组中的值决定。
public void drawPosText (String text, float[] pos, Paint paint); //画text指定的文本。
文本中的每一个字符的起始坐标由pos数组中的值决定,并且可以选择text中的某一段连续的字符绘制。
public void drawPosText (char[] text,int index,int count,float[] pos, Paint paint);
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●text:drawText方法中的text参数表示要绘制的文本,drawPosText方法中的text参数表示要绘制
的文本,但是每个字符的坐标需要单独指定,如果未指定某个字符的坐标系统会抛出异常。
●x:绘制文本的起始点的横坐标。
●y:绘制文本的起始点的纵坐标。
●index:选定的字符集合在text数组中的索引。
●count:选定的字符集合中的字符数。
从上面可以看出Canvas绘制类比较简单同时很灵活,实现一般的方法通常没有问题,同时可以叠加的处理设计出一些效果,若把Canvas当做绘画师来看,那么Paint就是绘画的工具,比如画笔、画刷、颜料等等。
在Android设备上处理图形最常用到的就是在一个View上画一些图片、形状或者自定义的文本内容,这里都可以使用Canvas来实现的。你可以获取View中的Canvas对象,绘制一些自定义形状,然后调用View.invalidate方法让View重新刷新,然后绘制一个新的形状,这样达到2D动画效果。下面就主要来了解下Canvas的使用方法。
Canvas对象的获取方式有两种:
1、通过重写View.onDraw方法,View中的Canvas对象被当做参数传递过来,操作Canvas图像效果会直接反应在View中。
2、创建一个Canvas对象直接在View中使用。
上面说了这么多,那么来实战一下,用点和线画一个优美的网格,创建一个名为DrawPoints的项目,修改MainActivity中的代码,如下所示:
--------------------------------------------------------------------------------------------------------------------------------- publicclass MainActivity extends Activity {
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
privatestaticclass SampleView extends View {
private Paint mPaint = new Paint();
privatefloat[] mPts;
privatestaticfinalfloat SIZE = 300;
privatestaticfinalint SEGS = 32;
privatestaticfinalint X = 0;
privatestaticfinalint Y = 1;
privatevoid buildPoints() {
finalint ptCount = (SEGS + 1) * 2;
mPts = newfloat[ptCount * 2];
float value = 0;
finalfloat delta = SIZE / SEGS;
for (int i = 0; i <= SEGS; i++) {
mPts[i*4 + X] = SIZE - value;
mPts[i*4 + Y] = 0;
mPts[i*4 + X + 2] = 0;
mPts[i*4 + Y + 2] = value;
value += delta;
}
}
public SampleView(Context context) {
super(context);
buildPoints(); //画点
}
@Override protectedvoid onDraw(Canvas canvas) {
Paint paint = mPaint;
canvas.translate(10, 10);
canvas.drawColor(Color.WHITE);
paint.setColor(Color.RED);
paint.setStrokeWidth(0);
canvas.drawLines(mPts, paint);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
canvas.drawPoints(mPts, paint);
}
}
}
--------------------------------------------------------------------------------------------------------------------------------- 在DrawPoints类的onCreate()方法中直接加载SampleView对象,SampleView是view的派生类,在SampleView的onDraw()方法中直接画点的操作,记得在AndroidManifest文件中对DrawPoints进行
图10.1 DrawPoints运行图
10.1.2.Paint类
Paint类顾名思义就是画笔类,在绘图过程中画笔主要保存了颜色,样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。Paint代表了Canvas上的画笔、画刷、颜料。下面看看Paint类常用方法。
1、绘制颜色
--------------------------------------------------------------------------------------------------------------------------------- public void setARGB(int a, int r, int g, int b)//设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
public voidsetAlpha(int a)//设置alpha透明度
--------------------------------------------------------------------------------------------------------------------------------- 注意的是这里的a值是0~255的范围,不是小数。
2、使用抗锯齿
--------------------------------------------------------------------------------------------------------------------------------- public void setAntiAlias(boolean aa) //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。图形设置后会平滑一些;
---------------------------------------------------------------------------------------------------------------------------------
3、图像抖动处理
--------------------------------------------------------------------------------------------------------------------------------- public void setDither(boolean dither); //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
---------------------------------------------------------------------------------------------------------------------------------
4、设置MaskFilter
--------------------------------------------------------------------------------------------------------------------------------- public void setMaskFilter(MaskFilter maskfilter);
--------------------------------------------------------------------------------------------------------------------------------- 系统提供了MaskFilter类,它可以为Paint配置边缘效果。对MaskFilter的扩展可以对一个Paint 边缘的alpha通道应用转换。
Android系统包含了下面两种MaskFilter:
●BlurMaskFilter:指定了一个模糊的样式和半径来处理Paint的边缘。
●EmbossMaskFilter:指定了光源的方向和环境光强度来添加浮雕效果。
5、颜色过滤器
--------------------------------------------------------------------------------------------------------------------------------- public void setColorFilter(ColorFilter colorfilter); //设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
--------------------------------------------------------------------------------------------------------------------------------- MaskFilter是对一个Paint的alpha通道的转换,而ColorFilter则是对每一个RGB通道应用转换。所有由ColorFilter所派生的类在执行它们的转换时,都会忽略alpha通道。
6、绘制路径的效果
--------------------------------------------------------------------------------------------------------------------------------- public void setPathEffect(PathEffect effect); //设置绘制路径的效果,如点画线等---------------------------------------------------------------------------------------------------------------------------------
PathEffect是用来控制绘制轮廓(线条)的方式。Android包含了多种PathEffect,具体如下:
●CornerPathEffect:可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。
●DashPathEffect:可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点),还可以指定任
意的虚/实线段的重复模式。
●DiscretePathEffect:与DashPathEffect相似,但是添加了随机性。当绘制它的时候,需要指定每一
段的长度和与原始路径的偏离度。
●PathDashPathEffect:这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。
如果使用下面两种PathEffect,会在一个Paint中组合使用出多种Path Effect效果,具体如下。
●SumPathEffect:顺序地在一条路径中添加两种效果,这样每一种效果都可以应用到原始路径中。
●ComposePathEffect:将两种效果组合起来应用,先使用第一种效果,然后在这种效果的基础上应
用第二种效果。
使用setPathEffect方法可以把PathEffect效果应用到Paint对象中,代码如下:
--------------------------------------------------------------------------------------------------------------------------------- paint.setPathEffect(new CornerPathEffect(10));
---------------------------------------------------------------------------------------------------------------------------------
7、图像重叠
--------------------------------------------------------------------------------------------------------------------------------- public void setXfermode(Xfermode xfermode);//设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
--------------------------------------------------------------------------------------------------------------------------------- 通过修改Paint的Xfermode来影响在Canvas已有的图像上面绘制新的颜色的方式。在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint是完全不透明的,那么它将完全遮挡住下面的Paint;如果它是部分透明的,那么它将会被染上下面的颜色。Xfermode类提供了不同的几种模式选择:
●AvoidXfermode:指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。●PixelXorXfermode:当覆盖已有的颜色时,应用一个简单的像素XOR操作。
●PorterDuffXfermode:可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已
有的Canvas图像进行交互。
下面使用PorterDuffXfermode实现橡皮擦功能,代码如下:
--------------------------------------------------------------------------------------------------------------------------------- Xfermode xFermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
paint.setXfermode(xFermode);
---------------------------------------------------------------------------------------------------------------------------------
8、Porter-Duff规则
计算机的颜色的表示,简单来说是RGB,再加上个Alpha透明度。计算机颜色以RGB三原色来编
码(255,255,255)为白色,每种颜色取值范围是0-255。但对于porter-duff除了三原色外、还定义
了透明度Alpha,Alpha表示透明度,范围为0-255。可以查看java-doc的AlphaComposite类,其中可
以看到(A,R,G,B)表示颜色。下面是Android提供的Xfermode类图像合成的16种规则模式:
--------------------------------------------------------------------------------------------------------------------------------- private static final Xfermode[] sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
new PorterDuffXfermode(PorterDuff.Mode.SRC),
new PorterDuffXfermode(PorterDuff.Mode.DST),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.XOR),
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
};
---------------------------------------------------------------------------------------------------------------------------------
Porter-Duff每个显示的效果具体如图10.2所示:
图10.2 Porter-Duff 16个显示的效果
10.1.3.Color类
Android中使用4个数字来表示颜色,分别是alpha、红(red)、绿(green)、蓝(blue)四个颜色值(ARGB)。每个数字取值0-255,因此一个颜色可以用一个整数来表示。为了运行效率,Android编码时
用整数Color类实例来表示颜色。红、绿、蓝三个值是就是代表颜色的取值,而Alpha代表的是透明度。最低值为0,表示颜色完全透明,而此时RGB是什么取值都不重要了。Alpha最高可取值为255,表示
颜色完全不透明。如果需要颜色透明、半透明,那么可以取值0-255中间的一些值,这常常用在前端
图层绘制时。
Android提供多种创建或表示颜色的方法,下面逐一看看:
1、使用Color类的常量,如:
--------------------------------------------------------------------------------------------------------------------------------- Int color = Color.BULE; // 创建一个蓝色、
---------------------------------------------------------------------------------------------------------------------------------
2、如果知道ARGB的取值,那么可以使用Color类的静态方法argb创建一个颜色:
--------------------------------------------------------------------------------------------------------------------------------- Int color = Color.argb(127,255,0,255);// 半透明的紫色
---------------------------------------------------------------------------------------------------------------------------------
3、使用XML资源文件来表示颜色。这是一个扩展性比较好的方式,便于今后可以方便的修改颜色值。
---------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------- 定义了一个名为mycolor颜色,在别的地方就可以引用mycolor来获取该颜色值。可以使用ResourceManager类中的getColor来获取该颜色。Java样例代码如下:
--------------------------------------------------------------------------------------------------------------------------------- Int color = getResources().getColor(R.color.mycolor);
--------------------------------------------------------------------------------------------------------------------------------- 这与第二种方法得到的值是一样的。getResources()返回当前类加载器路径上的所有资源以及父类加载器上的所有资源。
10.1.4.Path类
Android提供了一个Path类,顾名思义这个类可以设置曲线路径轨迹。任何无规则的曲线实际上都是由若干条线段组成,而线段的定义为两点之间最短的一条线。path类就可以记录这两点之间的轨迹,那么若干个Path就是需要绘制的无规则曲线。
path类设置轨迹路径的方法,如下:
--------------------------------------------------------------------------------------------------------------------------------- public void quadTo(float x1, float y1, float x2, float y2):
public void MoveTo(float dx, float dy);
public void lineTo(float x, float y) :
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
●quadTo:方法是当我们画弧线时会形成平滑的曲线,该曲线又称为"贝塞尔曲线"(Bezier curve),其
中,x1,y1为控制点的坐标值,x2,y2为终点的坐标值
●lineTo:方法是两点连成一线的绘制线路,是和MoveTo方法结合起来使用的,起点使用MoveTo
方法,结束时使用lineTO方法。
为了设置一条比较圆滑好看的曲线,需要对游戏画笔进行一些设置。创建一个画笔:
--------------------------------------------------------------------------------------------------------------------------------- mPaint = new Paint(); //创建画笔
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true); //设置画笔抗锯齿
mPaint.setStyle(Paint.Style.STROKE); //画笔的类型
mPaint.setStrokeCap(Paint.Cap.ROUND); //设置画笔变为圆滑状
mPaint.setStrokeWidth(5); //设置线的宽度
--------------------------------------------------------------------------------------------------------------------------------- 词条解释:
mPaint.setStyle(Paint.Style.STROKE);设置画笔的风格android提供了三种风格Paint.Style.STROKE、Paint.Style.FILL、Paint.Style.FILL_AND_STROKE 分别为空心、实心、实心与空心。如果不设置的话默认为Paint.Style.FILL,在这里必需设置成空心,因为如果一旦设置成实心或者实心与空心,那么画笔会把path路径中间包住,这样就不是曲线线段了。
截止现在我们已经了解了Canvas类、Paint类、Color类和Path类,那么下面我们就所学过的知识点来看看Android SDK提供的例子ApiDemos中graphics/FingerPaint.java,它就是可以用你的手指在屏幕上绘制图形,学习一下FingerPaint的代码,如下所示:
--------------------------------------------------------------------------------------------------------------------------------- publicclass FingerPaint extends GraphicsActivity
implements ColorPickerDialog.OnColorChangedListener {
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
mPaint = new Paint();/创建画笔渲染对象
mPaint.setAntiAlias(true);//设置抗锯齿,让绘画比较平滑
mPaint.setDither(true);//设置递色
mPaint.setColor(0xFFFF0000);//设置画笔的颜色
mPaint.setStyle(Paint.Style.STROKE);//画笔的类型有三种
mPaint.setStrokeJoin(Paint.Join.ROUND);//默认类型是MITER(1.BEVEL2.MITER3.ROUND)
mPaint.setStrokeCap(Paint.Cap.ROUND);//默认类型是BUTT(1.BUTT2.ROUND3.SQUARE)
mPaint.setStrokeWidth(12);
mEmboss = new EmbossMaskFilter(newfloat[] { 1, 1, 1 },
0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
publicvoid colorChanged(int color) {
mPaint.setColor(color);
}
publicclass MyView extends View {
privatestaticfinalfloat MINP = 0.25f;
privatestaticfinalfloat MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context c) {
super(c);
mPath = new Path();//创建画笔路径
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
@Override
protectedvoid onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);//绘制固定大小的bitmap对象
mCanvas = new Canvas(mBitmap);//将固定的bitmap对象嵌入到canvas对象中
}
@Override
protectedvoid onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
privatefloat mX, mY;
privatestaticfinalfloat TOUCH_TOLERANCE = 4;
privatevoid touch_start(float x, float y) {
mPath.reset();/将上次的路径保存起来,并重置新的路径。
mPath.moveTo(x, y);//设置新的路径的开始
mX = x;
mY = y;
}
privatevoid touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
privatevoid touch_up() {
mPath.lineTo(mX, mY);//从最后一个指定的xy点绘制一条线,如果没有用moveTo方法,那么起始点表示(0,0)点。
mCanvas.drawPath(mPath, mPaint);//手指离开屏幕后,绘制创建的“所有”路径。
// kill this so we don"t double draw
mPath.reset();
}
@Override
publicboolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:/手指开始按压屏幕,这个动作包含了初始化位置
touch_start(x, y);
invalidate();//刷新画布,重新运行onDraw()方法
break;
case MotionEvent.ACTION_MOVE:/手指按压屏幕时,位置的改变触发,这个方法在ACTION_DOWN和ACTION_UP之间。
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP://手指离开屏幕,不再按压屏幕
touch_up();
invalidate();
break;
}
returntrue;
}
}
--------------------------------------------------------------------------------------------------------------------------------- 在ACTION_DOWN事件中通过moveTo()方法设置触摸屏幕点为轨迹的起始点,在ACTION_MOVE 事件中设置曲线的轨迹使用mPath.quadTo()方法记录每次移动产生的一个曲线线段,然后将所有的曲
线线段绘制在屏幕中,最后在ACTION_UP事件中将调用mPath.lineTo()方法结束绘制轨迹。绘制中调用mCanvas.drawPath()方法将onTouchEvent中记录的路径曲线绘制在屏幕当中。下面我们在Activity中加入Menu,用于控制整个画笔,代码如下:
--------------------------------------------------------------------------------------------------------------------------------- privatestaticfinalint COLOR_MENU_ID = Menu.FIRST;
privatestaticfinalint EMBOSS_MENU_ID = Menu.FIRST + 1;
privatestaticfinalint BLUR_MENU_ID = Menu.FIRST + 2;
privatestaticfinalint ERASE_MENU_ID = Menu.FIRST + 3;
privatestaticfinalint SRCATOP_MENU_ID = Menu.FIRST + 4;
@Override
publicboolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut("4", "s");
menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut("5", "z");
menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut("5", "z");
menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut("5", "z");
returntrue;
}
@Override
publicboolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
returntrue;
}
@Override
publicboolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
returntrue;
case BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
returntrue;
case ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));//擦除模式
returntrue;
case SRCATOP_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.SRC_ATOP));
mPaint.setAlpha(0x80);
returntrue;
}
returnsuper.onOptionsItemSelected(item);
}
}
--------------------------------------------------------------------------------------------------------------------------------- 运行效果如图10.3所示:
图10.3 FingerPaint运行图
10.1.5.Drawable类
Drawable通常指可以作画的资源抽象.Android中Drawable类主要针对位图或纯色的可视元素,
如按钮、视图背景等。
一般是将资源文件放置在res/drawable文件夹下面,然后通过资源文件引用这个文件,支持的文
件类型有PNG、 JPG和GIF,例如显示应用程序的图标,也可以用来显示LOGO等。Android中可以有
多种方法加载drawable中的资源文件,下面以图像(image)为例举例加载的两种方法
1、下面的代码片段描述:使用drawable中的资源创建一个ImageView,然后将它添加到layout中,具体代码如下:
---------------------------------------------------------------------------------------------------------------------------------
public LinearLayout mLinearLayout;
protectedvoid 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); // 设置ImageView与Drawable的宽高比相同
i.setLayoutParams(new http://www.wendangku.net/doc/4de798144531b90d6c85ec3a87c24028905f8552.htmlyoutParams(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);
}
--------------------------------------------------------------------------------------------------------------------------------- 词条解释
●R.drawable.my_image:表示引用的资源编号,选择的文件只要去掉后缀就可以(例如:
my_image.png 引用它是就是my_image)。
上述代码也可以直接获取Drawable对象,LinearLayout直接加载的,代码如下:
--------------------------------------------------------------------------------------------------------------------------------- LinearLayout mLinearLayout= new LinearLayout(this);
Resources res = mContext.getResources();
Drawable myImage = res.getDrawable(R.drawable.my_image);
mLinearLayout.setBackgroundDrawable(myImage);
---------------------------------------------------------------------------------------------------------------------------------
2、或者直接在layout xml文件中添加资源Drawable到ImageView控件中,代码如下.
---------------------------------------------------------------------------------------------------------------------------------
xmlns:tools="http://www.wendangku.net/doc/4de798144531b90d6c85ec3a87c24028905f8552.html/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:tint="#55ff0000" android:src="@drawable/my_image"/>
--------------------------------------------------------------------------------------------------------------------------------- 上面我们讲解了如何使用Drawable类加载图像资源,当然绘图资源不仅限于此,比如颜色、形状等绘图相关的资源,都可以使用Drawable类去加载。
10.2.使用文字
Android提供几种默认的字体和样式。应用程序也可以使用自定义的字体,这需要将字体文件作为其一个组件(asset)包含进应用程序,并且像使用资源那样使用AssetManager载入字体。
Android系统默认支持三种字体,分别为:“Sans Serif”,“Serif”,“monospace”。这三个字体由android.graphic.typeface字体类提供,具体内容如下:
●Serif:有衬线字体,意思是在字的笔画开始、结束的地方有额外的装饰,而且笔画的粗细会有所
不同。
●Sans Serif:没有这些额外的装饰,而且笔画的粗细差不多。serif字体容易识别,它强调了每个字
母笔画的开始和结束,因此易读性比较高,Sans Serif则比较醒目。Sans Serif强调每一个字母,Serif更强调于一个单词。
●Monospaced:等宽字体,每个字体宽度是一致的。
创建项目TypefaceDemo,来展现上面三种字体的的区别,对于设置TextView的字体可以通过TextView的setTypeface方法来指定一个Typeface对象,下面我们通过两种方式来设置字体,第一种通过在Java代码中设置TextView的setTypeface()方法来实现,第二种在Layout XML文件中使用android:typeface 属性来设置,
首先通过在Java代码中使用TextView的setTypeface方法来设置字体,MainActvity中的onCreate()方法中的具体代码如下:
---------------------------------------------------------------------------------------------------------------------------------
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(http://www.wendangku.net/doc/4de798144531b90d6c85ec3a87c24028905f8552.htmlyout.activity_main);.....
monospace_TV = (TextView) findViewById(R.id.monospace);
sans_serif_TV = (TextView) findViewById(R.id.sans);
serif_TV = (TextView) findViewById(R.id.serif);
...
monospace_TV.setTextSize(24.0f);
sans_serif_TV.setTextSize(24.0f);
serif_TV.setTextSize(24.0f);
monospace_TV.setText("MONOSPACE");
sans_serif_TV.setText("SANS_SERIF");
serif_TV.setText("SERIF");
...
monospace_TV.setTypeface(Typeface.MONOSPACE);
sans_serif_TV.setTypeface(Typeface.SANS_SERIF);
serif_TV.setTypeface(Typeface.SERIF);
...
monospace_TV.setTextColor(Color.red);
serif_TV.setTextColor(Color. GRAY);
}
--------------------------------------------------------------------------------------------------------------------------------- 那么我们看看activity_main.xml的代码,如下所示:
---------------------------------------------------------------------------------------------------------------------------------
android:layout_width="fill_parent" android:layout_height="fill_parent"> ... android:id="@+id/sans" android:text="Hello,World"> ... android:id="@+id/serif" android:text="Hello,World"> ... android:id="@+id/monospace" android:text="Hello,World">
--------------------------------------------------------------------------------------------------------------------------------- 运行程序,显示如图10.4所示:
图10.4 TypefaceDemo运行图
下面使用第二种方法,通过使用XML来设置字体,使用XML来实现上面对字体的设置,activity_main.xml代码修改如下:
---------------------------------------------------------------------------------------------------------------------------------
android:layout_width="fill_parent" android:layout_height="fill_parent"> ... android:id="@+id/sans" android:text="Hello,World" android:textSize="24sp" android:typeface="sans" android:textColor="#000"> ... android:id="@+id/serif" android:text="Hello,World" android:textSize="24sp" android:typeface="serif" android:textColor="#00f"> ... android:id="@+id/monospace" android:text="Hello,World" android:textSize="24sp" android:typeface="monospace" android:textColor="#f00">
--------------------------------------------------------------------------------------------------------------------------------- 我们在activity_main.xml中修改了字体,那么在MainActivity中就不需要再设置字体,下面是MainActivity的代码:
--------------------------------------------------------------------------------------------------------------------------------- @Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(http://www.wendangku.net/doc/4de798144531b90d6c85ec3a87c24028905f8552.htmlyout.activity_main);.....
monospace_TV = (TextView) findViewById(R.id.monospace);
sans_serif_TV = (TextView) findViewById(R.id.sans);
serif_TV = (TextView) findViewById(R.id.serif);
}
--------------------------------------------------------------------------------------------------------------------------------- 运行程序,如图10.5所示:
图10.5 TypefaceDemo运行图
10.3.使用位图
位图图像(bitmap), 亦称为点阵图像或绘制图像,是由称作像素的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增大单个像素,从而使线条和形状显得参差不齐。然而,如果从稍远的位置观看它,位图图像的颜色和形状又显得是连续的,那么如何在Android系统中使用位图呢?下面首先来获取位图。
一. 从资源中获取位图
将位图资源保存在Resource中,从中获取位图有两种方法:1、通过资源ID获取Drawable;在XML文件中使用位图,代码如下:
--------------------------------------------------------------------------------------------------------------------------------- android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/myimage" /> --------------------------------------------------------------------------------------------------------------------------------- 二、通过资源ID获取资源文件的数据流。通过Resource的函数,代码如下: --------------------------------------------------------------------------------------------------------------------------------- InputStreamopenRawResource(int id) --------------------------------------------------------------------------------------------------------------------------------- 获取得到资源文件的数据流后,通过如下两种方法来获取Bitmap,如下: i、BitmapFactory类获取资源文件的数据流,下面使用BitmapFactory来获取图像对象,代码如下: --------------------------------------------------------------------------------------------------------------------------------- // 获取资源文件的引用res Resources res = getResources(); // 获取图形资源文件 Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable. myimage); --------------------------------------------------------------------------------------------------------------------------------- ii、BitmapDrawable类获取资源文件的数据流,下面使用BitmapDrawable来获取图像对象,代码如下: --------------------------------------------------------------------------------------------------------------------------------- //通过openRawResource获取一个inputStream对象 InputStream inputStream = getResources().openRawResource(R.drawable. myimage); //通过一个InputStream创建一个BitmapDrawable对象 BitmapDrawable drawable = new BitmapDrawable(inputStream); //通过BitmapDrawable对象获得Bitmap对象 Bitmap bitmap = drawable.getBitmap(); --------------------------------------------------------------------------------------------------------------------------------- 三. 获取位图的信息 要获取位图信息,比如位图大小、是否包含透明度、颜色格式等,这些信息在Bitmap的函数中可以获取到。在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,Bitmap还提供了compress()接口来压缩图片, Android SDK只支持PNG、JPG 格式的压缩。 四. 显示位图 显示位图需要使用核心类Canvas,可以直接通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。 五. 位图缩放 将一个位图按照需求重画一遍,代码如下: --------------------------------------------------------------------------------------------------------------------------------- drawBitmap(Bitmap source, Rect src, Rect dst, Paint paint) --------------------------------------------------------------------------------------------------------------------------------- 在原有位图的基础上缩放原位图,创建一个新的位图,代码如下: --------------------------------------------------------------------------------------------------------------------------------- createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) --------------------------------------------------------------------------------------------------------------------------------- 下面通过项目实战来学习,创建bitmapDemo项目,实现的功能是随着鼠标的点击drawable文件夹中的图片myimage.png跟着鼠标的点击移动。首先看看MainActivity代码如下,加载surfaceView,用于显示图像,代码如下: --------------------------------------------------------------------------------------------------------------------------------- public class MainActivity extends Activity { private surfaceView bitmapView = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bitmapView = new surfaceView(this); setContentView(bitmapView); } } --------------------------------------------------------------------------------------------------------------------------------- 创建surfaceView.java文件,用于处理资源文件的数据流。 --------------------------------------------------------------------------------------------------------------------------------- public class surfaceView extends SurfaceView{ // 控制surface的接口,提供了控制surface的大小、格式、像素 private SurfaceHolder surfaceHolder; private Canvas canvas = null; // x y用户才触摸屏幕的坐标 private float x=0,y=0; private Bitmap bitmap = null; public surfaceView(Context context) { super(context); surfaceHolder = this.getHolder(); this.setKeepScreenOn(true); // 获取资源文件res Resources res=getResources(); // 获取位图资源文件的输入流 InputStream inputStream=res.openRawResource(R.drawable. myimage); // 创建可绘制的位图对象 BitmapDrawable bitmapDrawable=new BitmapDrawable(inputStream); // 通过可绘制位图对象得到位图引用 bitmap=bitmapDrawable.getBitmap(); /* * // 获取资源文件的引用res Resources res = getResources(); // 获取图形资源文件 Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable. myimage); */ } //绘制位图 private void onDraw() { try { // 锁定Canvas画布 canvas = surfaceHolder.lockCanvas(); // 设置canvas画布背景为黑色 canvas.drawColor(Color.GREEN); // 在画布上绘制位图 //让位图的中心正好在触摸点位置上 canvas.drawBitmap(bitmap, x-bitmap.getWidth()/2, y-bitmap.getHeight()/2, null); } catch (Exception ex) { } finally { if (canvas != null) // 解锁画布,并显示绘制图片 surfaceHolder.unlockCanvasAndPost(canvas); } } //触摸事件 public boolean onTouchEvent(MotionEvent event){ x = event.getX(); y = event.getY(); onDraw(); return true; } } --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ●surfaceHolder = this.getHolder();获取SurfaceHolder接口 ●this.setKeepScreenOn(true);设置屏幕保持开启状态 ●InputStream inputStream=res.openRawResource(R.drawable. myimage);获取位图资源文件的输入流●BitmapDrawable bitmapDrawable=new BitmapDrawable(inputStream);创建可绘制的位图对象 ●bitmap=bitmapDrawable.getBitmap();通过可绘制位图对象得到位图引用 运行项目,如图10.6所示 图10.6 bitmapDemo项目运行图 10.4.Frame动画 Frame动画是一系列图片按照一定的顺序展示的过程,这些图片按照一定的时间间隔进行切换。这和电影的机制很相似,一般电影是每秒25帧播放连续的电影静态画面,由于人的视觉暂留在这种频率下播放感觉是连续的。下面我们使用AnimationDrawable和静态图片来制作Frame动画。 Android中的帧动画需要在一个动画文件中指定动画中的静态图片和每一张图片需要播放的时间(单位毫秒)。一般动画文件采用XML格式,下面我们使用实例进行讲解。 创建Anim Frame Demo工程,先创建res/anim目录,并在其中创建frame.xml文件,输入一下内容: ---------------------------------------------------------------------------------------------------------------------------------
android:oneshot="false"> --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ●元素是必须的,并且必须要作为根元素,可以包含一或多个 android:onshot如果定义为true的话,此动画只会执行一次,如果为false则一直循环。 ● 表此帧持续的时间,整数,单位为毫秒。 在工程中添加四张连续的图片,分别命名为anim1.png,anim2.png,anim3.png,anim4.png,并存放在drawable目录中。 编写完动画文件之后,就需要装载动画文件,并创建AnimationDrawable对象,AnimationDrawable是Drawable的子类,并在继承Drawable类后添加了控制动画的功能,创建AnimationDrawable对象的代码如下: --------------------------------------------------------------------------------------------------------------------------------- AnimationDrawableanim=(AnimationDrawable)getResources().getDrawable(R.anim.frame); --------------------------------------------------------------------------------------------------------------------------------- 在创建完AnimationDrawable对象之后,使用下面的代码将AnimationDrawable对象作为ImageView控件背景,代码如下: --------------------------------------------------------------------------------------------------------------------------------- ImageViewimage=(ImageView) findViewById(R.id.frame_image); image.setBackgroundResource(anim); --------------------------------------------------------------------------------------------------------------------------------- 当然,也可以使用image. setBackgroundResource()方法直接加载动画文件,并通过 image.getBackground()方法获得AnimationDrawable对象,代码如下: --------------------------------------------------------------------------------------------------------------------------------- ImageViewimage=(ImageView) findViewById(R.id.frame_image); image.setBackgroundResource(R.anim.frame); //将动画资源文件设置为ImageView的背景 AnimationDrawableanim= (AnimationDrawable) image.getBackground();//获取ImageView背景,此时已被编译成AnimationDrawable对象了。 anim.start();//开始动画 --------------------------------------------------------------------------------------------------------------------------------- 如果不在XML文件中保存AnimationDrawable对象,怎样使用代码直接加载呢?下面我们看看直接使用代码加载Drawable中的图像,代码如下: --------------------------------------------------------------------------------------------------------------------------------- AnimationDrawable anim = new AnimationDrawable(); for (int i = 1; i <= 4; i++) { //根据资源名称和目录获取R.java中对应的资源ID int id = getResources().getIdentifier("anim" + i, "drawable", getPackageName()); //根据资源ID获取到Drawable对象 Drawable drawable = getResources().getDrawable(id); //将此帧添加到AnimationDrawable中 anim.addFrame(drawable, 70); } anim.setOneShot(false); //设置为loop image.setBackgroundDrawable(anim); anim.start(); //开始动画 --------------------------------------------------------------------------------------------------------------------------------- 运行程序,如图10.7所示。 图10.7 AnimFrameDemo运行图 对象能做哪些事情 10.5.Tween动画 Tween动画是操作某个控件让其展现出旋转、渐变、移动、缩放的转换过程,称为补间动画。可以以XML形式定义动画,也可以编码实现。如果以XML形式定义一个动画,按照动画的定义语法完成XML,并放置于/res/anim目录下,文件名可以作为资源ID被引用;如果由编码实现,需要使用到Animation对象。 下面我们使用实例进行讲解,创建项目AnimTweenDemo,并创建res/anim目录,存放动画XML语法,实例中使用四个Button来控制动画效果,为了读者能够清晰的了解每个动画配置信息,将对旋转、 渐变、移动、缩放过程分别用四个XML来表示,首先创建alpha.xml(AlphaAnimation)的配置文件内容,代码如下: ---------------------------------------------------------------------------------------------------------------------------------、 --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ●XML文件中必须有一个根元素,可以是、 可以是 ● 属性:android:interpolator代表一个插值器资源,可以引用系统自带插值器资源,也可以用自定义插值器资源,默认值是匀速插值器;android:shareInterpolator代表 ●是渐变动画,可以实现fadeIn和fadeOut的效果,与之对应的Java对象是AlphaAnimation。 android:fromAlpha属性代表起始alpha值,浮点值,范围在0.0和1.0之间,分别代表透明和完全不透明,android:toAlpha属性代表结尾alpha值,浮点值,范围也在0.0和1.0之间。 上面我们使用了XML来描述Alpha动画,对应编码需AlphaAnimation类来操作,AlphaAnimation 是控制透明度变化动画类,常使用AlphaAnimation(float fromAlpha, float toAlpha)来构造;参数fromAlpha:动画开始时的透明度(取值范围为0.0到1.0);参数toAlpha:动画结束时的透明度; 接着创建scale.xml (ScaleAnimation)的配置文件内容,代码如下: ---------------------------------------------------------------------------------------------------------------------------------、 --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ● android:fromXScale属性代表起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;android:toXScale属性代表结尾的X方向上相对自身的缩放比例,浮点值;android:fromYScale属性代表起始的Y方向上相对自身的缩放比例,浮点值;android:toYScale属性代表结尾的Y方向上相对自身的缩放比例,浮点值;android:pivotX 属性代表缩放的中轴点X坐标,浮点值,android:pivotY属性代表缩放的中轴点Y坐标,浮点值,对于这两个属性,如果表示中轴点为图像的中心,可以把两个属性值定义成0.5或者50%。 上面使用了XML来描述Scale动画,对应编码需ScaleAnimation类来操作, ScaleAnimation控制尺度变化的动画类,常使用ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)来构造;参数fromX:动画开始X坐标上的伸缩尺度;参数toX:动画结束X坐标上的伸缩尺度;参数fromY:动画开始Y坐标上的伸缩尺度;参数toY:动画结 束Y坐标上的伸缩尺度;参数pivotXType:X坐标上的伸缩模式,取值有: Animation.ABSOLUTE,Animation.RELATIVE_TO_SELF, Animation.RELATIVE_TO_PARENT; 参数pivotXValue:X坐标上的伸缩值;参数pivotYType:Y坐标上的伸缩模式,取值有: Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, Animation.RELATIVE_TO_PARENT;参数pivotYValue: Y坐标上的伸缩值; 下面创建translate.xml (TranslateAnimation)的配置文件内容,代码如下: ---------------------------------------------------------------------------------------------------------------------------------、 --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ● android:fromXDelta属性代表起始X方向的位置,android:toXDelta代表结尾X方向上的位置, android:fromYScale属性代表起始Y方向上的位置,android:toYDelta属性代表结尾Y方向上的位置,以上四个属性都支持三种表示方式:浮点数、num%、num%p;如果以浮点数字表示,代表相对自身原始位置的像素值;如果以num%表示,代表相对于自己的百分比,比如toXDelta定义为 100%就表示在X方向上移动自己的1倍距离;如果以num%p表示,代表相对于父类组件的百分比。 上面我们使用了XML来描述Translate动画,对应编码需TranslateAnimation类来操作,TranslateAnimation控制位置变换的动画实现类,常使用TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)来构造;参数fromXDelta:动画开始的X坐标;参数toXDelta:动画结束的X坐标;参数fromYDelta:动画开始的Y坐标;参数toYDelta:动画结束的Y坐标; 最后创建rotate.xml (RotateAnimation)的配置文件内容,代码如下: ---------------------------------------------------------------------------------------------------------------------------------、 --------------------------------------------------------------------------------------------------------------------------------- 词条解释: ● 始角度,浮点值,单位:度;android:toDegrees属性代表结尾角度,浮点值,单位:度; android:pivotX属性代表旋转中心的X坐标值,android:pivotY属性代表旋转中心的Y坐标值,这两个属性也有三种表示方式,数字方式代表相对于自身左边缘的像素值,num%方式代表相对于自身左边缘或顶边缘的百分比,num%p方式代表相对于父容器的左边缘或顶边缘的百分比。 上面使用了XML来描述Rotate动画,对应编码需RotateAnimation类来操作,RotateAnimation控 制旋转的动画实现类,常使用RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)来构造;参数fromDegrees:旋转开始角度;参数toDegrees:旋转结束角度;参数pivotXType, pivotXValue, pivotYType, pivotYValue与尺度变化动画ScaleAnimation类似; 下面看看布局文件activity_main.xml,代码如下: ---------------------------------------------------------------------------------------------------------------------------------、 android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> android:id="@+id/TweenImage" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:src="@drawable/tween"/> ......//省略动画控制按钮 --------------------------------------------------------------------------------------------------------------------------------- 装载补间动画文件需要使用android.view.animation.AnimationUtils.loadAnimation方法,代码如下: --------------------------------------------------------------------------------------------------------------------------------- private ImageView tweenImage;//装载图片的控件 tweenImage = (ImageView) super.findViewById(R.id.TweenImage); Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate); --------------------------------------------------------------------------------------------------------------------------------- 加载之后,需要启动这个动画,代码如下: --------------------------------------------------------------------------------------------------------------------------------- tweenImage.startAnimation(animation); --------------------------------------------------------------------------------------------------------------------------------- 这样,补间动画就会被启动。下面看看补间动画的三个状态:动画开始、动画结束、动画循环。 要监听这三个状态需要实现android.view.animation.Animation.AnimationListener接口,该接口定义了三 个方法:onAnimationStart()、onAnimationRepeat()和onAnimationEnd(),这三个方法分别是在动画开始、动画循环和动画结束时调用。 那么下面看看MainActivity的完整代码,如下所示: --------------------------------------------------------------------------------------------------------------------------------- publicclass MainActivity extends Activity implements AnimationListener{ publicstaticfinal String TAG = "MainActivity"; // 动画图片 private ImageView tweenImage; publicvoid onCreate(Bundle cycle) { super.onCreate(cycle); super.setContentView(http://www.wendangku.net/doc/4de798144531b90d6c85ec3a87c24028905f8552.htmlyout.activity_main); // 取得动画图片 this.tweenImage = (ImageView) super.findViewById(R.id.TweenImage); } /** * 按钮:尺寸变化动画 */ publicvoid onBtnScaleAnimClick(View view) { // 动画开始 this.doStartAnimation(R.anim.scale); } /** * 按钮:渐变动画 */ publicvoid onBtnAlphaAnimClick(View view) { // 动画开始 this.doStartAnimation(R.anim.alpha); } /** * 按钮:位置变化动画 */ publicvoid onBtnTranslateAnimClick(View view) { // 动画开始 this.doStartAnimation(R.anim.translate); } /** * 按钮:旋转动画 */ publicvoid onBtnRotateAnimClick(View view) { // 动画开始 this.doStartAnimation(R.anim.rotate); } /** * 开始动画 */ privatevoid doStartAnimation(int animId) { // 加载动画 Animation animation = AnimationUtils.loadAnimation(this, animId); // 动画开始 this.tweenImage.startAnimation(animation); } @Override publicvoid onAnimationEnd(Animation arg0) { // TODO Auto-generated method stub } @Override publicvoid onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } @Override publicvoid onAnimationStart(Animation animation) { // TODO Auto-generated method stub } } --------------------------------------------------------------------------------------------------------------------------------- 运行程序,如图 图10.8 AnimFrameDemo运行图 小结 本章讲解了使用Android 2D绘图功能,学习了如何在屏幕上绘制各种图形或者图像,诸如PNG和JPG的图像、文本等等。以及如何使用各种颜色、图形的样式和色彩的渐变来绘制图形,同时使用标准的图像变换方法来对绘图进行修改。还学习了如何让这些可绘制的对象动起来,以制造动态的效果,相信在这个过程中你已经对Android基本的2D绘图功能有了深入的了解。