您的位置:首页 > Web前端

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

2015-11-09 17:05 429 查看


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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: