一、简介:

今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!!

上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文《Android实现自定义圆形、圆角和椭圆ImageView(使用Xfermode图形渲染方法)》,

今天我们来看看如何实现电商app里常用到的刮刮卡效果的view组件,其实原理和实现圆角图片的差不多,都是使用Xfermode渲染模式来实现的。

(老规矩,源码在博文最后给出哈)

基本原理步骤是这样的:

1.首先绘制下层(即Dst层),即:刮刮卡背景图层

2.设置Xfermode模式为DST_OUT

3.绘制刮扫的路径,绘制上层

这样通过这三步,就可以达到实现刮刮卡的效果啦,因为 使用了DST_OUT模式,这样就是取上下层交集的下层部分,下面我们看看具体效果吧

二、效果图:

三、Xfermode渲染模式简介:

xfermode影响在Canvas已经有的图像上绘制新的颜色的方式
* 正常的情况下,在图像上绘制新的形状,如果新的Paint不是透明的,那么会遮挡下面的颜色.
* 如果新的Paint是透明的,那么会被染成下面的颜色

下面的Xfermode子类可以改变这种行为:

AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。

PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。

PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

这里不得不提到那个经典的图:

上面的16种模式的说明如下:

从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:

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

取两图层全部区域,交集部分变为透明色

四、自定义刮刮卡效果View组件的实现:

1.绘制下层的背景图层

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // TODO Auto-generated method stub        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = getMeasuredWidth();        int height = getMeasuredHeight();        //初始化bitmap        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);        //初始化canvas        mCanvas = new Canvas(mBitmap);                //设置画笔的一些属性        setOutterPaint();        setOutBmpPaint();        setTextPaint();        //绘制一层刮刮卡圆角背景图层        mCanvas.drawRoundRect(new RectF(0,0,width,height), 30, 30, mOutBmpPaint);        mCanvas.drawBitmap(mOutterBitmap, null, new RectF(0,0,width,height),null);    }

2.设置Xfermode模式并绘制上层路径层

/**     * 设置Xfermode模式为DST_OUT,并绘制扫的路径     */    private void drawPath() {        // TODO Auto-generated method stub                mOutterPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));                mCanvas.drawPath(mPath, mOutterPaint);    }

3.最后在ondraw里面绘制出来:

@Override    protected void onDraw(Canvas canvas) {        // TODO Auto-generated method stub        //绘制文字        canvas.drawText(mText, getWidth()/2-mTextBound.width()/2, getHeight()/2+mTextBound.height()/2, mTextPaint);        //刮扫完成回调        if(mCompleted){            if(null != mOnCompleteListener){                mOnCompleteListener.complete();            }        }        //判断是否完成,如果完成了就不绘制遮盖层        if(!mCompleted){            drawPath();            canvas.drawBitmap(mBitmap,0,0,null);        }    }

4.手势触摸记录路径的实现:

@Override    public boolean onTouchEvent(MotionEvent event) {        // TODO Auto-generated method stub        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action) {            case MotionEvent.ACTION_DOWN:                mLastX = x;                mLastY = y;                mPath.moveTo(mLastX, mLastY);                                break;            case MotionEvent.ACTION_MOVE:                int dx = Math.abs(x - mLastX);                int dy = Math.abs(y - mLastY);                if(dx >3 || dy > 3){                    mPath.lineTo(x, y);                }                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_UP:                new Thread(mRunnable).start();                break;            default:                break;        }        invalidate();        return true;    }

5. 刮扫区域面积的计算以及刮扫完成的实现,为了不影响绘制,单独在子线程里实现该部分

/**     * 起一个线程来计算已经扫的面积及占总区域的比例     * 根据区域来判断是否完成     */    private Runnable mRunnable = new Runnable(){        @Override        public void run() {            int w = getWidth();            int h = getHeight();                        float wipeArea = 0;            float totalArea = w * h ;                        Bitmap bitmap = mBitmap;                         int[] mPixels = new int[w * h];            //获取bitmap的所有像素信息            bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);            for(int i= 0; i< w;i++)                for(int j= 0; j< h;j++){                    int index = i + j * w;                    if(mPixels[index] == 0){                        wipeArea ++;                    }                }            //计算已扫区域所占的比例            if(wipeArea >0 && totalArea > 0){                int percent = (int) (wipeArea * 100 / totalArea);                Log.v("czm", "percent="+percent);                                if(percent > 70){                    //清除图层区域                    mCompleted = true;                    postInvalidate();                                    }            }        };    };

到此,自定义刮刮卡效果View的核心模块代码都介绍完毕了。下面就看看使用该view的布局的实现,其实很简单。

五、视图布局的实现

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent">        <com.czm.xcguaguaka.XCGuaguakaView        android:id="@+id/ggk"        android:layout_width="300dp"    android:layout_height="100dp"    android:layout_centerInParent="true" />    </RelativeLayout>

六、使用并测试自定义刮刮卡效果View

上面直接绘制的自定义View写完了,下面就是使用这个自定义的View了,使用方法和普通的View一样,当作普通控件使用即可。

package com.czm.xcguaguaka;import com.czm.xcguaguaka.XCGuaguakaView.OnCompleteListener;import android.app.Activity;import android.app.ActionBar;import android.app.Fragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.Toast;import android.os.Build;/** * 使用并测试自定义刮刮卡效果View * @author caizhiming * */public class MainActivity extends Activity {    private XCGuaguakaView xcGuaguakaView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        xcGuaguakaView = (XCGuaguakaView)findViewById(R.id.ggk);        xcGuaguakaView.setOnCompleteListener(new OnCompleteListener() {                        @Override            public void complete() {                // TODO Auto-generated method stub                Toast.makeText(getApplicationContext(), "您已经刮的差不多啦", Toast.LENGTH_SHORT).show();            }        });    }}

七、照例,最后提供完整源码下载

真题园网http://www.zhentiyuan.com

源码下载http://download.csdn.net/detail/jczmdeveloper/8317629

更多相关文章

  1. Android中ImageView 中xml属性值android:scaleType 缩放类型含义
  2. 曲线实时AChartEngine实现Android实时曲线绘制
  3. Android字符串绘制示例
  4. android 自定义手势
  5. Android(安卓)自定义View(二)仿滴滴大头针跳动效果
  6. Android(安卓)自定义View实现动画效果切换主题颜色
  7. Android(安卓)4.0的图形硬件加速及绘制技巧(1)
  8. 卡拉OK歌词原理和实现高仿Android网易云音乐
  9. Android(安卓)UI开发专题(五) Bitmap和Canvas实例

随机推荐

  1. android识别鼠标左键,右键操作
  2. Android(安卓)界面设计工具 droiddraw
  3. Android基于TitleBar页面导航实现
  4. Business mobile application developmen
  5. android 实现图片加载效果
  6. Android(安卓)自定义正方形布局
  7. Android(安卓)中歌曲录制。。。
  8. android
  9. Android(安卓)吸入动画效果详解(仿mac退出
  10. [ 转载]Android(安卓)by example : MVVM