添加圆角
添加圆角的功能,要用到Canvas类的drawRoundRect方法,即把画布裁剪成指定的圆角矩形。
下面是给图片添加圆角的效果截图:
下面是给图片添加圆角的代码片段:
public static Bitmap getRoundImage(Bitmap bitmap, int roundPixels) {
//创建一个和原始图片一样大小位图
Bitmap roundConcerImage = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
//创建带有位图roundConcerImage的画布
Canvas canvas = new Canvas(roundConcerImage);
//创建画笔
Paint paint = new Paint();
//创建一个和原始图片一样大小的矩形
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF rectF = new RectF(rect);
// 去锯齿
paint.setAntiAlias(true);
//画一个和原始图片一样大小的圆角矩形
canvas.drawRoundRect(rectF, roundPixels, roundPixels, paint);
//设置相交模式
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
//把图片画到矩形去
canvas.drawBitmap(bitmap, null, rect, paint);
return roundConcerImage;
}
添加边框
添加边框有两种形式,一种是在图片四周添加图案,另一种是给图片添加边框图片。本文实现的添加边框指的是后一种形式,该形式又有两种实现方式:
1、简单地把边框图片画在原图片上面,该方式的图像效果不够平滑,有明显的边缘;
2、对每个点,都把边框图与原图的颜色进行叠加,这样相当于是两张图片融合在一起,看起来更平滑更自然,当然处理速度也会比较慢。
下面是给图片添加边框的效果截图:
下面是给图片添加边框的代码片段:
方式一
public static Bitmap getFrameImageLight(Context context, Bitmap bmp, Bitmap frame) { //bmp原图(前景) bm资源图片(背景)
// int padding = 50;
// int width = bmp.getWidth()+padding*2;
// int height = bmp.getHeight()+padding*2;
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap drawBitmap = Bitmap.createBitmap(width, height, bmp.getConfig());
Canvas canvas = new Canvas(drawBitmap);
Paint paint = new Paint();
//canvas.drawBitmap(bmp, padding, padding, paint);
canvas.drawBitmap(bmp, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(android.
graphics.PorterDuff.Mode.LIGHTEN));
//对边框进行缩放
int w = frame.getWidth();
int h = frame.getHeight();
//缩放比 如果图片尺寸超过边框尺寸 会自动匹配
float scaleX = width*1F / w;
float scaleY = height*1F / h;
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY); //缩放图片
Bitmap frameBitmap = Bitmap.createBitmap(frame, 0, 0, w, h, matrix, true);
canvas.drawBitmap(frameBitmap, 0, 0, paint);
return drawBitmap;
}
方式二
public static Bitmap getFrameImageDark(Bitmap bmp, Bitmap frame) { //bmp原图 frameBitmap资源图片(边框)
//bmp原图 创建新位图
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap frameBitmap =Bitmap.createBitmap(width, height, Config.RGB_565);
//对边框进行缩放
int w = frame.getWidth();
int h = frame.getHeight();
float scaleX = width*1F / w; //缩放比 如果图片尺寸超过边框尺寸 会自动匹配
float scaleY = height*1F / h;
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY); //缩放图片
Bitmap copyBitmap = Bitmap.createBitmap(frame, 0, 0, w, h, matrix, true);
int pixColor = 0;
int layColor = 0;
int newColor = 0;
int pixR = 0;
int pixG = 0;
int pixB = 0;
int pixA = 0;
int newR = 0;
int newG = 0;
int newB = 0;
int newA = 0;
int layR = 0;
int layG = 0;
int layB = 0;
int layA = 0;
float alpha = 0.8F;
float alphaR = 0F;
float alphaG = 0F;
float alphaB = 0F;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
pixColor = bmp.getPixel(i, j);
layColor = copyBitmap.getPixel(i, j);
// 获取原图片的RGBA值
pixR = Color.red(pixColor);
pixG = Color.green(pixColor);
pixB = Color.blue(pixColor);
pixA = Color.alpha(pixColor);
// 获取边框图片的RGBA值
layR = Color.red(layColor);
layG = Color.green(layColor);
layB = Color.blue(layColor);
layA = Color.alpha(layColor);
// 颜色与纯黑色相近的点
if (layR < 20 && layG < 20 && layB < 20) {
alpha = 1F;
} else {
alpha = 0.3F;
}
alphaR = alpha;
alphaG = alpha;
alphaB = alpha;
// 两种颜色叠加
newR = (int) (pixR * alphaR + layR * (1 - alphaR));
newG = (int) (pixG * alphaG + layG * (1 - alphaG));
newB = (int) (pixB * alphaB + layB * (1 - alphaB));
layA = (int) (pixA * alpha + layA * (1 - alpha));
// 值在0~255之间
newR = Math.min(255, Math.max(0, newR));
newG = Math.min(255, Math.max(0, newG));
newB = Math.min(255, Math.max(0, newB));
newA = Math.min(255, Math.max(0, layA));
//绘制
newColor = Color.argb(newA, newR, newG, newB);
frameBitmap.setPixel(i, j, newColor);
}
}
return frameBitmap;
}
添加文本
添加文本的主要思路先加入一个布局容器,里面放上展示图片的ImageView,同时启用布局容器的绘图缓存。然后给该布局容器添加触摸监听器,在按下时创建并加入一个编辑框EditText,并输入文本。最后结束添加,从布局容器的绘图缓存中获取位图,并保存为图片文件。获取位图后要注意两点:
1、先禁用布局容器的绘图缓存,这是为了清空绘图缓存,不然下次截图还是上次的位图;再启用布局容器的绘图缓存。
2、禁用绘图缓存的操作要延时执行,因为禁用绘图缓存会回收位图资源,如果这时在页面上展示该位图,就会报错位图已回收。
下面是给图片添加文本的效果截图:
下面是给图片添加文本的代码例子:
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.ImageView;
import android.widget.Toast;
import com.aqi00.lib.dialog.FileSaveFragment;
import com.aqi00.lib.dialog.FileSelectFragment;
import com.aqi00.lib.dialog.FileSaveFragment.FileSaveCallbacks;
import com.aqi00.lib.dialog.FileSelectFragment.FileSelectCallbacks;
import com.aqi00.lib.util.BitmapUtil;
public class TextActivity extends Activity implements OnClickListener,OnTouchListener,
FileSelectCallbacks, FileSaveCallbacks {
private final static String TAG = "TextActivity";
private RelativeLayout rl_text;
private ImageView iv_text_old, iv_text_new;
private Bitmap mOldBitmap = null, mNewBitmap = null;
private String mExtesion;
private int mQuality = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_text);
rl_text = (RelativeLayout) findViewById(R.id.rl_text);
Button btn_open_text = (Button) findViewById(R.id.btn_open_text);
Button btn_save_text = (Button) findViewById(R.id.btn_save_text);
Button btn_add_text = (Button) findViewById(R.id.btn_add_text);
Button btn_end_text = (Button) findViewById(R.id.btn_end_text);
Button btn_reset_text = (Button) findViewById(R.id.btn_reset_text);
Button btn_revoke_text = (Button) findViewById(R.id.btn_revoke_text);
btn_open_text.setOnClickListener(this);
btn_save_text.setOnClickListener(this);
btn_add_text.setOnClickListener(this);
btn_end_text.setOnClickListener(this);
btn_reset_text.setOnClickListener(this);
btn_revoke_text.setOnClickListener(this);
iv_text_old = (ImageView) findViewById(R.id.iv_text_old);
iv_text_new = (ImageView) findViewById(R.id.iv_text_new);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_open_text) {
FileSelectFragment.show(this, new String[] { "jpg", "png" }, null);
} else if (v.getId() == R.id.btn_save_text) {
if (mNewBitmap == null) {
Toast.makeText(this, "请先打开图片并添加部件", Toast.LENGTH_LONG).show();
return;
}
FileSaveFragment.show(this, mExtesion);
} else if (v.getId() == R.id.btn_add_text) {
rl_text.setOnTouchListener(this);
rl_text.setDrawingCacheEnabled(true);
} else if (v.getId() == R.id.btn_end_text) {
if (et_text != null) {
et_text.setFocusable(false);
}
mNewBitmap = rl_text.getDrawingCache();
iv_text_new.setImageBitmap(mNewBitmap);
rl_text.setOnTouchListener(null);
mHandler.postDelayed(mResetCache, 200);
} else if (v.getId() == R.id.btn_reset_text) {
for (EditText et_temp : etList) {
rl_text.removeView(et_temp);
}
etList.clear();
} else if (v.getId() == R.id.btn_revoke_text) {
if (etList.size() >= 1) {
EditText et_temp = etList.pollLast();
rl_text.removeView(et_temp);
}
}
}
private Handler mHandler = new Handler();
private Runnable mResetCache = new Runnable() {
@Override
public void run() {
rl_text.setDrawingCacheEnabled(false);
rl_text.setDrawingCacheEnabled(true);
}
};
@Override
public boolean onCanSave(String absolutePath, String fileName) {
return true;
}
@Override
public void onConfirmSave(String absolutePath, String fileName) {
String path = String.format("%s/%s", absolutePath, fileName);
BitmapUtil.saveBitmap(path, mNewBitmap, mExtesion, mQuality);
Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_LONG).show();
}
@Override
public void onConfirmSelect(String absolutePath, String fileName,
Map<String, Object> map_param) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
if (extension.toUpperCase(Locale.getDefault()).equals("PNG") == true) {
mExtesion = "png";
} else {
mExtesion = "jpg";
}
String path = String.format("%s/%s", absolutePath, fileName);
mOldBitmap = BitmapUtil.openBitmap(path);
iv_text_old.setImageBitmap(mOldBitmap);
}
@Override
public boolean isFileValid(String absolutePath, String fileName,
Map<String, Object> map_param) {
return true;
}
private EditText et_text;
private LinkedList<EditText> etList = new LinkedList<EditText>();
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "getX()="+event.getX()+", getY()="+event.getY());
et_text = new EditText(this);
rl_text.addView(et_text);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins((int)event.getX(), (int)event.getY(), 0, 0);
//LayoutParams要在addView之后设置才有效
et_text.setLayoutParams(params);
et_text.setBackground(null);
et_text.requestFocus(); //让编辑框默认获得焦点
etList.add(et_text);
}
return true;
}
}
添加图像
添加图像的实现思路类似添加文本,也是在触摸按下时给布局容器添加部件,即添加部件图像的ImageView。
下面是给图片添加图像的效果截图:
下面是给图片添加图像的代码例子:
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.aqi00.lib.dialog.FileSaveFragment;
import com.aqi00.lib.dialog.FileSelectFragment;
import com.aqi00.lib.dialog.FileSaveFragment.FileSaveCallbacks;
import com.aqi00.lib.dialog.FileSelectFragment.FileSelectCallbacks;
import com.aqi00.lib.util.BitmapUtil;
public class ImageActivity extends Activity implements OnClickListener,
OnTouchListener, FileSelectCallbacks, FileSaveCallbacks {
private final static String TAG = "TextActivity";
private RelativeLayout rl_image;
private ImageView iv_image_old, iv_image_new;
private Bitmap mOldBitmap = null, mNewBitmap = null;
private String mExtesion;
private int mQuality = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_image);
rl_image = (RelativeLayout) findViewById(R.id.rl_image);
Button btn_open_image = (Button) findViewById(R.id.btn_open_image);
Button btn_save_image = (Button) findViewById(R.id.btn_save_image);
Button btn_add_image = (Button) findViewById(R.id.btn_add_image);
Button btn_end_image = (Button) findViewById(R.id.btn_end_image);
Button btn_reset_image = (Button) findViewById(R.id.btn_reset_image);
Button btn_revoke_image = (Button) findViewById(R.id.btn_revoke_image);
btn_open_image.setOnClickListener(this);
btn_save_image.setOnClickListener(this);
btn_add_image.setOnClickListener(this);
btn_end_image.setOnClickListener(this);
btn_reset_image.setOnClickListener(this);
btn_revoke_image.setOnClickListener(this);
iv_image_old = (ImageView) findViewById(R.id.iv_image_old);
iv_image_new = (ImageView) findViewById(R.id.iv_image_new);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_open_image) {
FileSelectFragment.show(this, new String[] { "jpg", "png" }, null);
} else if (v.getId() == R.id.btn_save_image) {
if (mNewBitmap == null) {
Toast.makeText(this, "请先打开图片并添加部件", Toast.LENGTH_LONG).show();
return;
}
FileSaveFragment.show(this, mExtesion);
} else if (v.getId() == R.id.btn_add_image) {
rl_image.setOnTouchListener(this);
rl_image.setDrawingCacheEnabled(true);
} else if (v.getId() == R.id.btn_end_image) {
if (iv_image != null) {
iv_image.setFocusable(false);
}
mNewBitmap = rl_image.getDrawingCache();
iv_image_new.setImageBitmap(mNewBitmap);
rl_image.setOnTouchListener(null);
mHandler.postDelayed(mResetCache, 200);
} else if (v.getId() == R.id.btn_reset_image) {
for (ImageView iv_temp : ivList) {
rl_image.removeView(iv_temp);
}
ivList.clear();
} else if (v.getId() == R.id.btn_revoke_image) {
if (ivList.size() >= 1) {
ImageView iv_temp = ivList.pollLast();
rl_image.removeView(iv_temp);
}
}
}
private Handler mHandler = new Handler();
private Runnable mResetCache = new Runnable() {
@Override
public void run() {
rl_image.setDrawingCacheEnabled(false);
rl_image.setDrawingCacheEnabled(true);
}
};
@Override
public boolean onCanSave(String absolutePath, String fileName) {
return true;
}
@Override
public void onConfirmSave(String absolutePath, String fileName) {
String path = String.format("%s/%s", absolutePath, fileName);
BitmapUtil.saveBitmap(path, mNewBitmap, mExtesion, mQuality);
Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_LONG).show();
}
@Override
public void onConfirmSelect(String absolutePath, String fileName,
Map<String, Object> map_param) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
if (extension.toUpperCase(Locale.getDefault()).equals("PNG") == true) {
mExtesion = "png";
} else {
mExtesion = "jpg";
}
String path = String.format("%s/%s", absolutePath, fileName);
if (map_param == null) {
mOldBitmap = BitmapUtil.openBitmap(path);
iv_image_old.setImageBitmap(mOldBitmap);
} else {
Integer x = (Integer) map_param.get("x");
Integer y = (Integer) map_param.get("y");
iv_image = new ImageView(this);
rl_image.addView(iv_image);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, 0, 0);
// LayoutParams要在addView之后设置才有效
iv_image.setLayoutParams(params);
iv_image.setImageBitmap(BitmapUtil.openBitmap(path));
iv_image.setScaleType(ScaleType.CENTER_INSIDE);
ivList.add(iv_image);
}
}
@Override
public boolean isFileValid(String absolutePath, String fileName,
Map<String, Object> map_param) {
return true;
}
private ImageView iv_image;
private LinkedList<ImageView> ivList = new LinkedList<ImageView>();
@SuppressLint("UseValueOf")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "getX()=" + event.getX() + ", getY()=" + event.getY());
HashMap<String, Object> param = new HashMap<String, Object>();
param.put("x", new Integer((int) event.getX()));
param.put("y", new Integer((int) event.getY()));
FileSelectFragment.show(this, new String[] { "jpg", "png" }, param);
}
return true;
}
}
添加手写签名
手写签名需要自己写个自定义控件,然后加入到布局容器中,其难点主要是自定义签名控件的实现上。这个主要用到了Path类的moveTo和quadTo方法,以及Canvas的drawPath方法。在高级使用场合,还得考虑能够回退写坏了的笔画,这需要建个路径数组,把签名每个步骤的路径都保存下来,在回退时就能按顺序依次回退。
另外一个值得注意的地方,是如何把画布清空。如果仅仅画上透明背景,等于没画;要想真正清空,还得设置绘图模式为Mode.CLEAR。下面是清空画布的示例代码:
cacheCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
下面是给图片添加手写签名的效果截图:
下面是给图片添加手写签名的代码例子:
import java.util.Locale;
import java.util.Map;
import com.aqi00.lib.dialog.FileSaveFragment;
import com.aqi00.lib.dialog.FileSaveFragment.FileSaveCallbacks;
import com.aqi00.lib.dialog.FileSelectFragment;
import com.aqi00.lib.dialog.FileSelectFragment.FileSelectCallbacks;
import com.aqi00.lib.util.BitmapUtil;
import com.example.exmimageadd.widget.SignatureView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;
public class SignatureActivity extends Activity implements OnClickListener,
FileSelectCallbacks, FileSaveCallbacks {
private FrameLayout fl_signature;
private ImageView iv_signature_old, iv_signature_new;
private Bitmap mOldBitmap = null, mNewBitmap = null;
private String mExtesion;
private int mQuality = 100;
private SignatureView view_signature;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_signature);
fl_signature = (FrameLayout) findViewById(R.id.fl_signature);
view_signature = (SignatureView) findViewById(R.id.view_signature);
Button btn_open_signature = (Button) findViewById(R.id.btn_open_signature);
Button btn_save_signature = (Button) findViewById(R.id.btn_save_signature);
Button btn_add_signature = (Button) findViewById(R.id.btn_add_signature);
Button btn_end_signature = (Button) findViewById(R.id.btn_end_signature);
Button btn_reset_signature = (Button) findViewById(R.id.btn_reset_signature);
Button btn_revoke_signature = (Button) findViewById(R.id.btn_revoke_signature);
btn_open_signature.setOnClickListener(this);
btn_save_signature.setOnClickListener(this);
btn_add_signature.setOnClickListener(this);
btn_end_signature.setOnClickListener(this);
btn_reset_signature.setOnClickListener(this);
btn_revoke_signature.setOnClickListener(this);
iv_signature_old = (ImageView) findViewById(R.id.iv_signature_old);
iv_signature_new = (ImageView) findViewById(R.id.iv_signature_new);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_open_signature) {
FileSelectFragment.show(this, new String[] { "jpg", "png" }, null);
} else if (v.getId() == R.id.btn_save_signature) {
if (mNewBitmap == null) {
Toast.makeText(this, "请先打开图片并添加部件", Toast.LENGTH_LONG).show();
return;
}
FileSaveFragment.show(this, mExtesion);
} else if (v.getId() == R.id.btn_add_signature) {
fl_signature.setDrawingCacheEnabled(true);
view_signature.setDrawingCacheEnabled(true);
} else if (v.getId() == R.id.btn_reset_signature) {
view_signature.clear();
} else if (v.getId() == R.id.btn_revoke_signature) {
view_signature.revoke();
} else if (v.getId() == R.id.btn_end_signature) {
if (fl_signature.isDrawingCacheEnabled() != true) {
Toast.makeText(this, "请先开始签名", Toast.LENGTH_LONG).show();
} else {
mNewBitmap = fl_signature.getDrawingCache();
iv_signature_new.setImageBitmap(mNewBitmap);
mHandler.postDelayed(mResetCache, 200);
}
}
}
private Handler mHandler = new Handler();
private Runnable mResetCache = new Runnable() {
@Override
public void run() { //ViewGroup下面的子视图也要清空缓存
view_signature.setDrawingCacheEnabled(false);
fl_signature.setDrawingCacheEnabled(false);
view_signature.setDrawingCacheEnabled(true);
fl_signature.setDrawingCacheEnabled(true);;
}
};
@Override
public boolean onCanSave(String absolutePath, String fileName) {
return true;
}
@Override
public void onConfirmSave(String absolutePath, String fileName) {
String path = String.format("%s/%s", absolutePath, fileName);
BitmapUtil.saveBitmap(path, mNewBitmap, mExtesion, mQuality);
Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_LONG).show();
}
@Override
public void onConfirmSelect(String absolutePath, String fileName,
Map<String, Object> map_param) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
if (extension.toUpperCase(Locale.getDefault()).equals("PNG") == true) {
mExtesion = "png";
} else {
mExtesion = "jpg";
}
String path = String.format("%s/%s", absolutePath, fileName);
mOldBitmap = BitmapUtil.openBitmap(path);
iv_signature_old.setImageBitmap(mOldBitmap);
}
@Override
public boolean isFileValid(String absolutePath, String fileName,
Map<String, Object> map_param) {
return true;
}
}
下面是自定义手写签名的代码:
import java.util.ArrayList;
import com.example.exmimageadd.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class SignatureView extends View {
private static final String TAG = "SignatureView";
private Paint paint;
private Canvas cacheCanvas;
private Bitmap cachebBitmap;
private Path path;
private int paint_color = Color.BLACK;
private int stroke_width = 3;
private PathPosition pos = new PathPosition();
private ArrayList<PathPosition> pathArray = new ArrayList<PathPosition>();
private int mWidth=0, mHeight=0;
public SignatureView(Context context,AttributeSet attrs) {
super(context, attrs);
if (attrs != null) {
TypedArray attrArray=getContext().obtainStyledAttributes( attrs, R.styleable.SignatureView);
paint_color = attrArray.getColor(R.styleable.SignatureView_paint_color, Color.BLACK);
stroke_width = attrArray.getInt(R.styleable.SignatureView_stroke_width, 3);
attrArray.recycle();
}
}
public SignatureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray attrArray=getContext().obtainStyledAttributes( attrs, R.styleable.SignatureView);
paint_color = attrArray.getColor(R.styleable.SignatureView_paint_color, Color.BLACK);
stroke_width = attrArray.getColor(R.styleable.SignatureView_stroke_width, 3);
attrArray.recycle();
}
}
public SignatureView(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = this.getMeasuredWidth();
mHeight = this.getMeasuredHeight();
Log.d(TAG, "onMeasure width="+mWidth+",height="+mHeight);
init(mWidth, mHeight);
}
public SignatureView(Context context, int width, int height) {
super(context);
init(width, height);
}
public int getPaintColor() {
return paint_color;
}
public void setPaintColor(int paint_color) {
this.paint_color = paint_color;
}
public int getStrokeWidth() {
return stroke_width;
}
public void setStrokeWidth(int stroke_width) {
this.stroke_width = stroke_width;
}
public Bitmap getCachebBitmap() {
return getDrawingCache();
}
private void init(int width, int height) {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(stroke_width);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(paint_color);
path = new Path();
setDrawingCacheEnabled(true);
cachebBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
cacheCanvas = new Canvas(cachebBitmap);
clear();
}
public void clear() {
if (cacheCanvas != null) {
pathArray.clear();
cacheCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //透明背景
invalidate();
}
}
public void revoke() {
if (pathArray.size() > 0) {
pathArray.remove(pathArray.size()-1);
cacheCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i=0; i<pathArray.size(); i++) {
Path posPath = new Path();
posPath.moveTo(pathArray.get(i).firstX, pathArray.get(i).firstY);
posPath.quadTo(pathArray.get(i).firstX, pathArray.get(i).firstY,
pathArray.get(i).nextX, pathArray.get(i).nextY);
cacheCanvas.drawPath(posPath, paint);
}
invalidate();
}
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(cachebBitmap, 0, 0, null);
canvas.drawPath(path, paint); //这个是需要的,最近一次的路径保存在这里
}
private float cur_x, cur_y;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
cur_x = x;
cur_y = y;
path.moveTo(cur_x, cur_y);
pos.firstX = cur_x;
pos.firstY = cur_y;
break;
case MotionEvent.ACTION_MOVE:
path.quadTo(cur_x, cur_y, x, y);
cur_x = x;
cur_y = y;
pos.nextX = cur_x;
pos.nextY = cur_y;
pathArray.add(pos);
pos = new PathPosition();
pos.firstX = cur_x;
pos.firstY = cur_y;
break;
case MotionEvent.ACTION_UP:
cacheCanvas.drawPath(path, paint);
path.reset();
break;
}
invalidate();
return true;
}
private class PathPosition {
public float firstX;
public float firstY;
public float nextX;
public float nextY;
public PathPosition() {
firstX = 0;
firstY = 0;
nextX = 0;
nextY = 0;
}
}
}
点此查看Android开发笔记的完整目录