`
yunlonglove
  • 浏览: 231044 次
社区版块
存档分类
最新评论

Android开发之对上下两个图层的操作

 
阅读更多

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 myMetricsnew DisplayMetrics();

myMetrics =this.getResources().getDisplayMetrics();

//getWindowManager().getDefaultDisplay().getMetrics(myMetrics);

两种方式来给myMetrics值。

注:构造函数DisplayMetrics不需要传递任何参数;调用getWindowManager()之后,会取得现有ActivityHandle,此时,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这是一个非常强大的转换模式,使用它,可以使用图像合成的16Porter-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)来解决, setDitherTextureNode的方法.

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面试知识点详解 #### 一、Android DVM与Linux进程关系 - **定义与区别**:DVM(Dalvik ...以上是对给定文件中提到的知识点的详细解释与扩展,旨在帮助读者深入理解Android开发的关键概念和技术细节。

    百度地图定位开发包

    在这个上下文中,可能包含地图相关的图像资源,如图标、自定义图层数据或者用于展示的地图样式文件。 3. **libs**:这个目录通常包含开发所需的库文件,可能是JAR或AAR格式,这些库文件提供了与百度地图服务进行...

    Android仿开心消消乐大树星星无限循环效果

    在Android开发中,实现"Android仿开心消消乐大树星星无限循环效果"涉及到多个关键知识点,包括自定义View、Bitmap操作、触摸事件处理以及动画效果的实现。以下是对这些技术点的详细解释: 1. **自定义View**: 在...

    安卓连连看

    匹配规则通常是两个相邻且相同的图案可以消除,相邻通常指的是上下左右或对角线方向。消除过程需要考虑不能跨越其他图案,且消除后棋盘上不能有孤岛(无法匹配的图案)。计分系统根据消除的图案数量和连击次数给予...

    2048源码(Cocos2dx)

    - **得分计算**:每当两个方块合并,得分增加,达到2048即为胜利,若无位置可合并则游戏结束。 3. **Cocos2dx实现**: - **节点系统**:Cocos2dx使用Node类作为基本元素,可以创建、组合和管理游戏对象。在2048中...

    点9PNG制作

    点9PNG制作是Android开发中一个重要的图像处理技术,它主要解决了UI元素在不同尺寸屏幕上的自适应问题。在Android应用开发中,由于设备屏幕尺寸和分辨率的多样性,普通的PNG图片在拉伸时可能会出现像素失真,影响...

    cocos2d-x3.2版本2048和FlappyBird游戏源码

    本篇文章将深入探讨基于cocos2d-x3.2版本的2048和FlappyBird游戏源码,帮助开发者理解这两个经典游戏的实现原理,并学习如何利用cocos2d-x进行游戏开发。 首先,我们来看2048游戏。2048是一款数字合成的益智游戏,...

    xamarin.form实现了访问Mysql

    这两个库提供了与 MySQL 服务器交互的接口。安装这些库可以通过 NuGet 包管理器进行,只需在 Visual Studio 或 Xamarin Studio 中搜索相应的包并添加到项目中。 接下来,我们需要创建数据库连接。在 C# 中,我们...

    IndiaBuzzNews:Android应用程式

    Java是这款应用程式开发的基础,它是Android平台上最广泛使用的编程语言之一。Java以其"一次编写,到处运行"的特性,确保了应用在不同设备上的兼容性和稳定性。开发者利用Java的面向对象编程特性,创建出模块化的...

    地图控件

    地图控件是软件开发中一个重要的组成部分,尤其在地理信息系统(GIS)和移动应用中扮演着不可或缺的角色。它允许用户在应用程序中查看、交互和分析地理位置数据。在本篇文章中,我们将深入探讨地图控件的核心功能、...

    workflow,用于生成可组合状态机的库,以及由这些状态机驱动的ui。.zip

    【描述】提到这个库是为Kotlin和Swift两种编程语言设计的,这意味着它可以跨平台使用,覆盖Android和iOS开发。"单向数据流"(Unidirectional Data Flow)是一种软件架构模式,它确保数据在系统中的流动方向是明确的...

Global site tag (gtag.js) - Google Analytics