自定义控件(6)---PorterDuffXfermode图形过滤器之橡皮擦应用

自定义控件(6)---PorterDuffXfermode图形过滤器之橡皮擦应用_第1张图片

activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        xmlns:tools="http://schemas.android.com/tools"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" >  
      
        <com.imooc.guaguaka.view.GuaGuaKa  
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent" />  
      
    </RelativeLayout>  

MainActivity
package com.imooc.guaguaka;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

}

GuaGuaKa
package com.imooc.guaguaka.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class GuaGuaKa extends View {

	/** 内存中创建的Canvas */
	private Canvas mCanvas;
	/** 绘制线条的Paint,即用户手指绘制Path */
	private Paint mOutterPaint = new Paint();
	/** 记录用户绘制的Path */
	private Path mPath = new Path();
	/** mCanvas绘制内容在其上 */
	private Bitmap mBitmap;

	private int mLastX;
	private int mLastY;

	/** 绘制字体 */
	private Paint mBackPint = new Paint();
	private Rect mTextBound = new Rect();
	private String mText = "500,0000,000";

	public GuaGuaKa(Context context) {
		this(context, null);
	}

	public GuaGuaKa(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public GuaGuaKa(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		int width = getMeasuredWidth();
		int height = getMeasuredHeight();
		mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		// 在canvas初始化的时候就传入了一个空的bitmap
		// 最后canvas中绘画的内容都被绘制到了bitmap中,从而得到了我们需要的bitmap
		mCanvas = new Canvas(mBitmap);
		setUpBackPaint();
		setOutPaint();

		// 表面绘制一层灰色
		mCanvas.drawColor(Color.parseColor("#c0c0c0"));
	}

	private void setOutPaint() {
		// 设置画笔
		mOutterPaint.setColor(Color.RED);
		mOutterPaint.setAntiAlias(true);
		mOutterPaint.setDither(true);
		mOutterPaint.setStyle(Paint.Style.STROKE);
		mOutterPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
		mOutterPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
		mOutterPaint.setStrokeWidth(20);
	}

	private void setUpBackPaint() {
		mBackPint.setStyle(Style.FILL);
		mBackPint.setTextScaleX(2f);
		mBackPint.setColor(Color.DKGRAY);
		mBackPint.setTextSize(22);
		// getTextBounds(String text, int start, int end, Rect bounds)
		mBackPint.getTextBounds(mText, 0, mText.length(), mTextBound);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2,
				getHeight() / 2 + mTextBound.height() / 2, mBackPint);

		mOutterPaint
				.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
		mCanvas.drawPath(mPath, mOutterPaint);
		canvas.drawBitmap(mBitmap, 0, 0, null);

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		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:

		        mPath.lineTo(x, y);

			mLastX = x;
			mLastY = y;
			break;
		}

		invalidate();
		return true;
	}

}

*************************************************二*******************************************


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    android:orientation="vertical" >

    <com.aigestudio.customviewdemo.views.EraserView
        android:id="@+id/main_cv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity
package com.aigestudio.customviewdemo.activities;

import android.app.Activity;
import android.os.Bundle;

import com.aigestudio.customviewdemo.R;

/**
 * 主界面
 */
public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
}

MeasureUtil
package com.aigestudio.customviewdemo.utils;

import android.app.Activity;
import android.util.DisplayMetrics;

/**
 * 测绘工具类
 */
public final class MeasureUtil {
	/**
	 * 获取屏幕尺寸
	 * 
	 * @param activity
	 *            Activity
	 * @return 屏幕尺寸像素值,下标为0的值为宽,下标为1的值为高
	 */
	public static int[] getScreenSize(Activity activity) {
		DisplayMetrics metrics = new DisplayMetrics();
		activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
		return new int[] { metrics.widthPixels, metrics.heightPixels };
	}
}

EraserView
package com.aigestudio.customviewdemo.views;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
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.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.aigestudio.customviewdemo.R;
import com.aigestudio.customviewdemo.utils.MeasureUtil;

/**
 * 橡皮檫View
 */
public class EraserView extends View {
	private static final int MIN_MOVE_DIS = 5;// 最小的移动距离:如果我们手指在屏幕上的移动距离小于此值则不会绘制

	private Bitmap fgBitmap, bgBitmap;// 前景橡皮擦的Bitmap和背景我们底图的Bitmap
	private Canvas mCanvas;// 绘制橡皮擦路径的画布
	private Paint mPaint;// 橡皮檫路径画笔
	private Path mPath;// 橡皮擦绘制路径

	private int screenW, screenH;// 屏幕宽高
	private float preX, preY;// 记录上一个触摸事件的位置坐标

	public EraserView(Context context, AttributeSet set) {
		super(context, set);

		// 计算参数
		cal(context);

		// 初始化对象
		init(context);
	}

	/**
	 * 计算参数
	 * 
	 * @param context
	 *            上下文环境引用
	 */
	private void cal(Context context) {
		// 获取屏幕尺寸数组
		int[] screenSize = MeasureUtil.getScreenSize((Activity) context);

		// 获取屏幕宽高
		screenW = screenSize[0];
		screenH = screenSize[1];
	}

	/**
	 * 初始化对象
	 */
	private void init(Context context) {
		// 实例化路径对象
		mPath = new Path();

		// 实例化画笔并开启其抗锯齿和抗抖动
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

		// 设置画笔透明度为0是关键!我们要让绘制的路径是透明的,然后让该路径与前景的底色混合“抠”出绘制路径
		mPaint.setARGB(128, 255, 0, 0);

		// 设置混合模式为DST_IN
		mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

		// 设置画笔风格为描边
		mPaint.setStyle(Paint.Style.STROKE);

		// 设置路径结合处样式
		mPaint.setStrokeJoin(Paint.Join.ROUND);

		// 设置笔触类型
		mPaint.setStrokeCap(Paint.Cap.ROUND);

		// 设置描边宽度
		mPaint.setStrokeWidth(50);

		// 生成前景图Bitmap
		fgBitmap = Bitmap.createBitmap(screenW, screenH, Config.ARGB_8888);

		// 将其注入画布
		mCanvas = new Canvas(fgBitmap);

		// 绘制画布背景为中性灰
		mCanvas.drawColor(0xFF808080);

		// 获取背景底图Bitmap
		bgBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.a4);

		// 缩放背景底图Bitmap至屏幕大小
		bgBitmap = Bitmap.createScaledBitmap(bgBitmap, screenW, screenH, true);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// 绘制背景
		canvas.drawBitmap(bgBitmap, 0, 0, null);

		// 绘制前景
		canvas.drawBitmap(fgBitmap, 0, 0, null);

		/*
		 * 这里要注意canvas和mCanvas是两个不同的画布对象
		 * 当我们在屏幕上移动手指绘制路径时会把路径通过mCanvas绘制到fgBitmap上
		 * 每当我们手指移动一次均会将路径mPath作为目标图像绘制到mCanvas上,而在上面我们先在mCanvas上绘制了中性灰色
		 * 两者会因为DST_IN模式的计算只显示中性灰,但是因为mPath的透明,计算生成的混合图像也会是透明的
		 * 所以我们会得到“橡皮擦”的效果
		 */
		mCanvas.drawPath(mPath, mPaint);
	}

	/**
	 * View的事件将会在7/12详解
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		/*
		 * 获取当前事件位置坐标
		 */
		float x = event.getX();
		float y = event.getY();

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:// 手指接触屏幕重置路径
			mPath.reset();
			mPath.moveTo(x, y);
			preX = x;
			preY = y;
			break;
		case MotionEvent.ACTION_MOVE:// 手指移动时连接路径
			float dx = Math.abs(x - preX);
			float dy = Math.abs(y - preY);
			if (dx >= MIN_MOVE_DIS || dy >= MIN_MOVE_DIS) {
				mPath.quadTo(preX, preY, (x + preX) / 2, (y + preY) / 2);
				preX = x;
				preY = y;
			}
			break;
		}

		// 重绘视图
		invalidate();
		return true;
	}
}



你可能感兴趣的:(自定义控件(6)---PorterDuffXfermode图形过滤器之橡皮擦应用)