Android开发之对上下两个图层的操作
Android开发之对上下两个图层的操作
/*
* Android开发之对上下两个图层的操作
* 北京Android俱乐部群:167839253
* Created on: 2012-7-17
* Author: blueeagle
* Email:liujiaxiang@gmail.com
*/
我们在玩“美女脱衣服”游戏中,看到的可以把美女身上的衣服脱掉,其实是运用了图层的技术。其根本还是两张图片,将上层图片来依据手的触摸使上层图层消失。可以理解为,上层图层是一个View,下层可以是View的一个背景。新建一个View类,myView
这样去写他的构造函数:
注意:Android可设置为随着窗口大小调整缩放比例,但即便如此,手机程序设计人员还是必须知道手机屏幕的边界,以避免缩放造成的布局变形问题。手机的分辨率信息是手机的一项重要信息,很好的是,Android已经提供DisplayMetircs类可以很方便的获取分辨率。
Andorid.util包下的DisplayMetrics类提供了一种关于显示的通用信息,如显示大小,分辨率和字体。
为了获取DisplayMetrics成员,首先初始化一个对象如下:
DisplayMetrics myMetrics=new DisplayMetrics();
myMetrics =this.getResources().getDisplayMetrics();
//getWindowManager().getDefaultDisplay().getMetrics(myMetrics);
两种方式来给myMetrics值。
注:构造函数DisplayMetrics不需要传递任何参数;调用getWindowManager()之后,会取得现有Activity的Handle,此时,getDefaultDisplay()方法将取得的宽高维度存放于DisplayMetrics对象中,而取得的宽高维度是以像素为单位(Pixel),“像素”所指的是“绝对像素”而非“相对像素”。
setUpBmp(bmp);函数就是设置已经获取到的bmp为上层图像。
在setUpBmp(bmp);函数中,进行以下操作:
Xfermode有三个子类,分别如下:AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。
PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
要应用转换模式,可以使用setXferMode方法
对应的模式:
PorterDuff.Mode
ADD
Saturate(S + D)
PorterDuff.Mode
CLEAR
[0, 0]
PorterDuff.Mode
DARKEN
[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]
PorterDuff.Mode
DST
[Da, Dc]
PorterDuff.Mode
DST_ATOP
[Sa, Sa * Dc + Sc * (1 - Da)]
PorterDuff.Mode
DST_IN
[Sa * Da, Sa * Dc]
PorterDuff.Mode
DST_OUT
[Da * (1 - Sa), Dc * (1 - Sa)]
PorterDuff.Mode
DST_OVER
[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]
PorterDuff.Mode
LIGHTEN
[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]
PorterDuff.Mode
MULTIPLY
[Sa * Da, Sc * Dc]
PorterDuff.Mode
OVERLAY
PorterDuff.Mode
SCREEN
[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]
PorterDuff.Mode
SRC
[Sa, Sc]
PorterDuff.Mode
SRC_ATOP
[Da, Sc * Da + (1 - Sa) * Dc]
PorterDuff.Mode
SRC_IN
[Sa * Da, Sc * Da]
PorterDuff.Mode
SRC_OUT
[Sa * (1 - Da), Sc * (1 - Da)]
PorterDuff.Mode
SRC_OVER
[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]
PorterDuff.Mode
XOR
[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC显示上层绘制图片
3.PorterDuff.Mode.DST显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
13.PorterDuff.Mode.DARKEN
14.PorterDuff.Mode.LIGHTEN
15.PorterDuff.Mode.MULTIPLY
16.PorterDuff.Mode.SCREEN效果图:
myPaint.setDither(true);
有时候你可能发现设置了背景图片之后,在屏幕上的效果不太理想,主要表现为颜色过渡不平滑,色块现象比较严重.主要原因是因为WiEngine底层设置OpenGL的缓冲区格式缺省是RGB565,这个设置可以提高速度,但是很显然颜色精度会受到影响.这个时候可以用setDither(true)来解决, setDither是TextureNode的方法.
Sprite bg= ...;
bg.setDither(true);
Dither的意思是抖动,是一种用有限颜色模拟其它颜色的方式,比如将白色和红色均匀的混合,你会看到粉红色.通过这种方式, 可以消除背景上的色块,使颜色过渡平滑.这种方式当然会损失一点性能,但是基本也就是背景用一下,问题不大.
WYGLSurfaceView支持透明背景,这种模式下OpenGL使用RGBA8888格式的缓冲区,所以不需要抖动背景图片也将显示的很好.使用透明背景的WYGLSurfaceView很简单:
WYGLSurfaceViewv=new WYGLSurfaceView(this,true);//第二个参数传true表示背景透明
setContentView(v);
游戏需要用透明背景的不多,一般透明背景WYGLSurfaceView可以用在增强现实的应用中
myPaint.setStrokeCap(Paint.Cap.ROUND);
设置笔帽的样子。
myPaint.setStrokeJoin(Paint.Join.ROUND);
Paint.setStrokeJoin(Joinjoin)这里的Join参数为设置结合处的样子,Miter:结合处为锐角, Round:结合处为圆弧:BEVEL:结合处为直线。
OnDraw的实现:
package com.blueeagle.www;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Bitmap.Config;import android.os.Bundle;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.View; public class DuotucengActivity extends Activity { private int SCREENW; private int SCREENH; /** Calledwhen the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new myView(this)); } public class myView extends View { private Bitmap myBitmap; private Canvas myCanvas; private Paint myPaint; private Path myPath; private float myX,myY; private static final float TOUCH_TOLERANCE = 4; public myView(Context context) { super(context); setFocusable(true); setScreenWH(); setBackgroundResource(R.drawable.back); Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.background); setUpBmp(bmp); } private void setUpBmp(Bitmap bmp) { // TODO Auto-generatedmethod stub myPaint = new Paint(); myPaint.setAlpha(0); myPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); myPaint.setAntiAlias(true); myPaint.setDither(true); myPaint.setStyle(Paint.Style.STROKE); //myPaint.setStrokeCap(Paint.Cap.ROUND); myPaint.setStrokeJoin(Paint.Join.ROUND); myPaint.setStrokeWidth(20); // 设置路径 myPath = new Path(); myBitmap = Bitmap.createBitmap(SCREENW, SCREENH,Config.ARGB_8888); myCanvas = new Canvas(); myCanvas.setBitmap(myBitmap); myCanvas.drawBitmap(bmp, 0, 0,null); } private void setScreenWH() { // TODO Auto-generatedmethod stub DisplayMetrics dm = new DisplayMetrics(); //dm =this.getResources().getDisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int screenWidth = dm.widthPixels; int screenHeight = dm.heightPixels; SCREENW = screenWidth; SCREENH = screenHeight; } protected void onDraw(Canvas canvas){ canvas.drawBitmap(myBitmap, 0, 0,null); myCanvas.drawPath(myPath, myPaint); super.onDraw(canvas); } private void touch_start(float x, float y){ myPath.reset(); myPath.moveTo(x, y); myX=x; myY=y; } private void touch_move(float x,float y){ float dx = Math.abs(x-myX); float dy = Math.abs(y-myY); if(dx>=TOUCH_TOLERANCE || dy>=TOUCH_TOLERANCE ){ myPath.quadTo(myX, myY, (x+myX)/2, (y+myY)/2); myX=x; myY=y; } } private void touch_up(){ myPath.lineTo(myX, myY); myCanvas.drawPath(myPath,myPaint); myPath.reset(); } public boolean onTouchEvent(MotionEvent event){ float x = event.getX(); float y = event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: touch_start(x,y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x,y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); invalidate(); break; } return true; } }}
