Android开发之对上下两个图层的操作
/*
* Android开发之对上下两个图层的操作
* 北京Android俱乐部群:167839253
*Created on: 2012-7-17
*Author: blueeagle
* Email:liujiaxiang@gmail.com
*/
我们在玩“美女脱衣服”游戏中,看到的可以把美女身上的衣服脱掉,其实是运用了图层的技术。其根本还是两张图片,将上层图片来依据手的触摸使上层图层消失。可以理解为,上层图层是一个View,下层可以是View的一个背景。新建一个View类,myView
这样去写他的构造函数:
public myView(Context context) {
super(context);
setFocusable(true);
setScreenWH();
setBackgroundResource(R.drawable.back);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.background);
setUpBmp(bmp);
}
注释:
public void setFocusable (booleanfocusable)
Set whether this view can receivethe focus. Setting this to false will also ensure that this view is notfocusable in touch mode.
public void setBackgroundResource (intresid)
Set the background to a givenresource. The resource should refer to a Drawable object or 0 to remove thebackground.
setScreenWH();函数用来获得屏幕长宽像素。
publicDisplayMetrics getDisplayMetrics ()
Return the current display metricsthat are in effect for this resource object. The returned object should betreated as read-only.
注意: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);函数中,进行以下操作:
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);
}
注释:
public XfermodesetXfermode (Xfermodexfermode)
Set or clear the xfermode object.
Pass null to clear any previousxfermode. As a convenience, the parameter passed is also returned.
public PorterDuffXfermode (PorterDuff.Modemode)
Create an xfermode that uses thespecified porter-duff mode.
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的实现:
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;
}
整个代码:
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;
}
}
}
分享到:
相关推荐
### Android面试知识点详解 #### 一、Android DVM与Linux进程关系 - **定义与区别**:DVM(Dalvik ...以上是对给定文件中提到的知识点的详细解释与扩展,旨在帮助读者深入理解Android开发的关键概念和技术细节。
在这个上下文中,可能包含地图相关的图像资源,如图标、自定义图层数据或者用于展示的地图样式文件。 3. **libs**:这个目录通常包含开发所需的库文件,可能是JAR或AAR格式,这些库文件提供了与百度地图服务进行...
在Android开发中,实现"Android仿开心消消乐大树星星无限循环效果"涉及到多个关键知识点,包括自定义View、Bitmap操作、触摸事件处理以及动画效果的实现。以下是对这些技术点的详细解释: 1. **自定义View**: 在...
匹配规则通常是两个相邻且相同的图案可以消除,相邻通常指的是上下左右或对角线方向。消除过程需要考虑不能跨越其他图案,且消除后棋盘上不能有孤岛(无法匹配的图案)。计分系统根据消除的图案数量和连击次数给予...
- **得分计算**:每当两个方块合并,得分增加,达到2048即为胜利,若无位置可合并则游戏结束。 3. **Cocos2dx实现**: - **节点系统**:Cocos2dx使用Node类作为基本元素,可以创建、组合和管理游戏对象。在2048中...
点9PNG制作是Android开发中一个重要的图像处理技术,它主要解决了UI元素在不同尺寸屏幕上的自适应问题。在Android应用开发中,由于设备屏幕尺寸和分辨率的多样性,普通的PNG图片在拉伸时可能会出现像素失真,影响...
本篇文章将深入探讨基于cocos2d-x3.2版本的2048和FlappyBird游戏源码,帮助开发者理解这两个经典游戏的实现原理,并学习如何利用cocos2d-x进行游戏开发。 首先,我们来看2048游戏。2048是一款数字合成的益智游戏,...
这两个库提供了与 MySQL 服务器交互的接口。安装这些库可以通过 NuGet 包管理器进行,只需在 Visual Studio 或 Xamarin Studio 中搜索相应的包并添加到项目中。 接下来,我们需要创建数据库连接。在 C# 中,我们...
Java是这款应用程式开发的基础,它是Android平台上最广泛使用的编程语言之一。Java以其"一次编写,到处运行"的特性,确保了应用在不同设备上的兼容性和稳定性。开发者利用Java的面向对象编程特性,创建出模块化的...
地图控件是软件开发中一个重要的组成部分,尤其在地理信息系统(GIS)和移动应用中扮演着不可或缺的角色。它允许用户在应用程序中查看、交互和分析地理位置数据。在本篇文章中,我们将深入探讨地图控件的核心功能、...
【描述】提到这个库是为Kotlin和Swift两种编程语言设计的,这意味着它可以跨平台使用,覆盖Android和iOS开发。"单向数据流"(Unidirectional Data Flow)是一种软件架构模式,它确保数据在系统中的流动方向是明确的...
### Unity3D初识知识点详解...综上所述,Unity3D不仅是一款强大的游戏开发工具,也是一个集成了多种功能的综合性平台,适用于各种规模的游戏项目开发。无论是初学者还是资深开发者,都能从中找到适合自己的工具和资源。