各位大神,我最近在做一个Android的作品,想要实现在一个画布上面写字。 里面有一个功能:想要根据用户触屏时间,修改笔画粗细。
我现在已经实现了能够根据触屏时间,修改整个笔画的粗细,但是,我想更进一步,能不能修改用户点击的点附近的笔画粗细。
代码如下(有写注释,如果熟悉的话,应该 很容易看懂):
package com.ink;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;public class ChirographyView extends ImageView{
private Bitmap mBitmap;//用于保存所画图像的图画
private Canvas mCanvas;//用于保存所画图像的画布
private Path mPath, rPath;
private Paint mBitmapPaint;// 画布的画笔
private Paint mPaint;// 真实的画笔
private String nameOfPhoto; //图片名字
private float mX, mY, tx, ty, tX=0, tY=0;
private static final float TOUCH_TOLERANCE = 4;
private Calendar starttime; //笔画开始时间
private Calendar endtime; //笔画结束时间
// 保存Path路径的集合,用List集合来模拟栈
private static List<DrawPath> savePath;
// 记录Path路径的对象
private DrawPath dp;
private class DrawPath {
public Path path;// 路径
public Paint paint;// 画笔
}
// Matrix 实例
private Matrix matrix = new Matrix();
// 位图宽和高
private int w, h;
// 判断平移
public boolean isTranslate = false;
/*******
在XML中使用自定义View必须要使用含AttributeSet变量参数的构造函数
******/
public ChirographyView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
/*********设置画笔********/
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
mPaint.setStrokeWidth(1);// 画笔宽度
savePath = new ArrayList<DrawPath>();
nameOfPhoto = "text";
} public void setBitmap(Bitmap b){
mBitmap=b;
mCanvas = new Canvas(mBitmap);
// 获得位图宽
w = mBitmap.getWidth();
// 获得位图高
h = mBitmap.getHeight();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, matrix, null);//把之前画出来保存后的图再画出来
if(!isTranslate){
if (rPath != null) {
// 实时的显示
canvas.drawPath(rPath, mPaint);
}
}
else{
matrix.reset();
matrix.setTranslate(tx+tX, ty+tY);
// 根据原始位图和Matrix创建新视图
Bitmap bm = Bitmap.createBitmap(mBitmap, 0, 0, w, h, matrix, true);
// 绘制新视图
canvas.drawBitmap(bm, matrix, null);
}
}
private void touch_start(float x, float y) {
starttime = Calendar.getInstance();
mX = x;
mY = y;
if(!isTranslate){
// 每次down下去重新new一个Path
mPath = new Path();
rPath = new Path();
//每一次记录的路径对象是不一样的
dp = new DrawPath();
dp.path = mPath;
dp.paint = mPaint;
mPath.moveTo(x-tX, y-tY);
rPath.moveTo(x, y);
invalidate();
}
}
private void touch_move(float x, float y) {
if(!isTranslate){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX-tX, mY-tY, (x + mX)/2-tX, (y + mY)/2-tY);
rPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
endtime = Calendar.getInstance();
int second = endtime.get(Calendar.SECOND) - starttime.get(Calendar.SECOND);
int mimute = endtime.get(Calendar.MINUTE) - starttime.get(Calendar.MINUTE);
mPaint.setStrokeWidth(5+second);
}
}
else{
endtime = Calendar.getInstance();
int second = endtime.get(Calendar.SECOND) - starttime.get(Calendar.SECOND);
int mimute = endtime.get(Calendar.MINUTE) - starttime.get(Calendar.MINUTE);
mPaint.setStrokeWidth(5+second);
tx = x-mX;
ty = y-mY;
}
invalidate();
}
private void touch_up() {
if(!isTranslate){
mPath.lineTo(mX-tX, mY-tY);
rPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
savePath.add(dp);
mPath = null;// 重新置空
rPath = null;
invalidate();
}
else{
tX+= tx;
tY+= ty;
}
}
/**
* 撤销的核心思想就是将画布清空,
* 将保存下来的Path路径最后一个移除掉,
* 重新将路径画在画布上面。
*/
public void backout(boolean back) {
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1).copy(Bitmap.Config.ARGB_8888, true);
mCanvas.setBitmap(mBitmap);// 重新设置画布,相当于清空画布
// 清空画布,但是如果图片有背景的话,则使用上面的重新初始化的方法,用该方法会将背景清空掉...
if (savePath != null && savePath.size() > 0 && back == true) {
// 移除最后一个path,相当于出栈操作
savePath.remove(savePath.size() - 1); Iterator<DrawPath> iter = savePath.iterator();
while (iter.hasNext()) {
DrawPath drawPath = iter.next();
mCanvas.drawPath(drawPath.path, drawPath.paint);
}
}
else
savePath.clear();
invalidate();// 刷新
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
touch_up();
break;
}
return true;
}
public String getName(){
return nameOfPhoto;
}
public void setName(String name){
nameOfPhoto = name;
}
}
我现在已经实现了能够根据触屏时间,修改整个笔画的粗细,但是,我想更进一步,能不能修改用户点击的点附近的笔画粗细。
代码如下(有写注释,如果熟悉的话,应该 很容易看懂):
package com.ink;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;public class ChirographyView extends ImageView{
private Bitmap mBitmap;//用于保存所画图像的图画
private Canvas mCanvas;//用于保存所画图像的画布
private Path mPath, rPath;
private Paint mBitmapPaint;// 画布的画笔
private Paint mPaint;// 真实的画笔
private String nameOfPhoto; //图片名字
private float mX, mY, tx, ty, tX=0, tY=0;
private static final float TOUCH_TOLERANCE = 4;
private Calendar starttime; //笔画开始时间
private Calendar endtime; //笔画结束时间
// 保存Path路径的集合,用List集合来模拟栈
private static List<DrawPath> savePath;
// 记录Path路径的对象
private DrawPath dp;
private class DrawPath {
public Path path;// 路径
public Paint paint;// 画笔
}
// Matrix 实例
private Matrix matrix = new Matrix();
// 位图宽和高
private int w, h;
// 判断平移
public boolean isTranslate = false;
/*******
在XML中使用自定义View必须要使用含AttributeSet变量参数的构造函数
******/
public ChirographyView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
/*********设置画笔********/
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
mPaint.setStrokeWidth(1);// 画笔宽度
savePath = new ArrayList<DrawPath>();
nameOfPhoto = "text";
} public void setBitmap(Bitmap b){
mBitmap=b;
mCanvas = new Canvas(mBitmap);
// 获得位图宽
w = mBitmap.getWidth();
// 获得位图高
h = mBitmap.getHeight();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, matrix, null);//把之前画出来保存后的图再画出来
if(!isTranslate){
if (rPath != null) {
// 实时的显示
canvas.drawPath(rPath, mPaint);
}
}
else{
matrix.reset();
matrix.setTranslate(tx+tX, ty+tY);
// 根据原始位图和Matrix创建新视图
Bitmap bm = Bitmap.createBitmap(mBitmap, 0, 0, w, h, matrix, true);
// 绘制新视图
canvas.drawBitmap(bm, matrix, null);
}
}
private void touch_start(float x, float y) {
starttime = Calendar.getInstance();
mX = x;
mY = y;
if(!isTranslate){
// 每次down下去重新new一个Path
mPath = new Path();
rPath = new Path();
//每一次记录的路径对象是不一样的
dp = new DrawPath();
dp.path = mPath;
dp.paint = mPaint;
mPath.moveTo(x-tX, y-tY);
rPath.moveTo(x, y);
invalidate();
}
}
private void touch_move(float x, float y) {
if(!isTranslate){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX-tX, mY-tY, (x + mX)/2-tX, (y + mY)/2-tY);
rPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
endtime = Calendar.getInstance();
int second = endtime.get(Calendar.SECOND) - starttime.get(Calendar.SECOND);
int mimute = endtime.get(Calendar.MINUTE) - starttime.get(Calendar.MINUTE);
mPaint.setStrokeWidth(5+second);
}
}
else{
endtime = Calendar.getInstance();
int second = endtime.get(Calendar.SECOND) - starttime.get(Calendar.SECOND);
int mimute = endtime.get(Calendar.MINUTE) - starttime.get(Calendar.MINUTE);
mPaint.setStrokeWidth(5+second);
tx = x-mX;
ty = y-mY;
}
invalidate();
}
private void touch_up() {
if(!isTranslate){
mPath.lineTo(mX-tX, mY-tY);
rPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
savePath.add(dp);
mPath = null;// 重新置空
rPath = null;
invalidate();
}
else{
tX+= tx;
tY+= ty;
}
}
/**
* 撤销的核心思想就是将画布清空,
* 将保存下来的Path路径最后一个移除掉,
* 重新将路径画在画布上面。
*/
public void backout(boolean back) {
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1).copy(Bitmap.Config.ARGB_8888, true);
mCanvas.setBitmap(mBitmap);// 重新设置画布,相当于清空画布
// 清空画布,但是如果图片有背景的话,则使用上面的重新初始化的方法,用该方法会将背景清空掉...
if (savePath != null && savePath.size() > 0 && back == true) {
// 移除最后一个path,相当于出栈操作
savePath.remove(savePath.size() - 1); Iterator<DrawPath> iter = savePath.iterator();
while (iter.hasNext()) {
DrawPath drawPath = iter.next();
mCanvas.drawPath(drawPath.path, drawPath.paint);
}
}
else
savePath.clear();
invalidate();// 刷新
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
touch_up();
break;
}
return true;
}
public String getName(){
return nameOfPhoto;
}
public void setName(String name){
nameOfPhoto = name;
}
}
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货