添加圆角

添加圆角的功能,要用到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;@Overrideprotected 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);}@Overridepublic 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() {@Overridepublic void run() {rl_text.setDrawingCacheEnabled(false);rl_text.setDrawingCacheEnabled(true);}};@Overridepublic boolean onCanSave(String absolutePath, String fileName) {return true;}@Overridepublic 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();}@Overridepublic 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);}@Overridepublic 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)@Overridepublic 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;@Overrideprotected 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);}@Overridepublic 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() {@Overridepublic void run() {rl_image.setDrawingCacheEnabled(false);rl_image.setDrawingCacheEnabled(true);}};@Overridepublic boolean onCanSave(String absolutePath, String fileName) {return true;}@Overridepublic 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();}@Overridepublic 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);}}@Overridepublic 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)@Overridepublic 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;@Overrideprotected 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);}@Overridepublic 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() {@Overridepublic void run() {  //ViewGroup下面的子视图也要清空缓存view_signature.setDrawingCacheEnabled(false);fl_signature.setDrawingCacheEnabled(false);view_signature.setDrawingCacheEnabled(true);fl_signature.setDrawingCacheEnabled(true);;}};@Overridepublic boolean onCanSave(String absolutePath, String fileName) {return true;}@Overridepublic 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();}@Overridepublic 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);}@Overridepublic 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);}@Overrideprotected 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")@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(cachebBitmap, 0, 0, null);canvas.drawPath(path, paint); //这个是需要的,最近一次的路径保存在这里}private float cur_x, cur_y;@SuppressLint("ClickableViewAccessibility")@Overridepublic 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开发笔记的完整目录

Android开发笔记(九十八)往图片添加部件相关推荐

  1. Android开发笔记(八十九)单例模式

    基本概念 单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,从而方便对实例个数的控制并节约系统资源. 单例模式有三个特点: 1.某个类只能有一个实例: 2.它要自行创建这个实例: 3.它只有 ...

  2. Android开发笔记(八十八)同步与加锁

    同步synchronized 同步方法 synchronized可用来给方法或者代码块加锁,当它修饰一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.这就意味着,当两个并发线程同时访 ...

  3. Android开发笔记(八十七)几个修饰关键字

    原生native native是方法修饰符,表示该方法是由其他一种语言(如C/C++)实现的原生方法.其实native只在JNI接口中使用,java代码中只有原生方法的定义,具体的实现代码在其他语言( ...

  4. Android开发笔记(八十六)几个特殊的类

    接口interface interface是一些功能的集合,但它只定义了对象必须实现的成员,而不包含成员的实现代码,成员的具体代码由实现接口的类提供.Android对接口的使用场景主要有三类:事件监听 ...

  5. Android开发笔记(八十三)多语言支持

    汉字转拼音 app中有许多场景要对汉字排序,例如通讯录姓名.商品名称.城市名称等等,这些汉字词汇通常是按照拼音排序,所以产生了把汉字转换为拼音的需求. Android自带库 Android自带的联系人 ...

  6. Android开发笔记(八十一)屏幕规格适配

    Configuration 适配各种屏幕规格,首先要取到系统对于屏幕的配置信息,这些配置可从工具类Configuration获得.Configuration对象在Activity中通过调用getRes ...

  7. Android开发笔记(八十)运行状态检查

    大家都知道刻舟求剑的寓言故事,说的是事物是发展变化着的,如果拘泥于原来的情况,那随着情况的改变,就不会得到预期的结果.同样,影响app运行的因素,并不只是外部环境(如硬件.系统.权限等等),还包括ap ...

  8. Android开发笔记(八十五)手机数据库Realm

    Realm应用背景 Android自带的SQLite数据库,在多数场合能够满足我们的需求,但随着app广泛使用,SQLite也暴露了几个不足之处: 1.开发者编码比较麻烦,而且还要求开发者具备SQL语 ...

  9. Android开发笔记(八十二)SDK版本兼容

    统一主题与风格 Android控件很多属性都有默认值,比如文字默认黑色.编辑框默认透明背景等等,但因为android是开源的,各厂商都会自行修修补补,所以很多时候默认值并不靠谱.举例如下: 1.在某些 ...

  10. Android开发笔记(八十四)使用Properties读写属性值

    Properties概述 Java中的配置文件常为.properties文件,而Properties类便是读写此类文件的工具.属性文件有两种格式,一种是文本格式,其内容是"键=值" ...

最新文章

  1. 【2017下集美大学软工1412班_助教博客】结对编程1——模块化
  2. uni-app小程序 点击页面滚动到指定位置
  3. 不同型号服务器如何做双击热备,服务器做双机热备教程
  4. 如何使用dll ip转换_如何使用多功能转换插座更安全
  5. 【NOIP2005】【Luogu1052】过河
  6. AD画图器件变灰如何恢复SHIFT+C清除过滤器
  7. oracle的成本核算,Oracle11gR2全表扫描成本计算(工作量模式-workload)
  8. 一张图,详解大数据技术架构
  9. PMP第十章:项目沟通管理
  10. 计算机网络管理员下午试题答案,(完整版)计算机网络管理员考试试题库和答案(13页)-原创力文档...
  11. java11降到java8
  12. Android性能优化学习记录(二)稳定性与内存优化
  13. 【小程序源码】游戏助手王者荣耀战力查询,游戏扫码登录器等
  14. 使用shp裁剪县区遥感影像
  15. 邮件开发:邮件作用、邮件服务器、电子邮箱与邮件客户端软件
  16. 推荐学习!通过五轮面试斩获offer阿里实习生亲述,深度解析,值得收藏
  17. 2014计算机考研分数线,2014年全国统计算机考研各个大学录取分数线汇总.doc
  18. python怎么群发邮件_python群发邮件怎么做
  19. 为什么建议大家使用 Linux 开发?爽(外加七个感叹号)
  20. 系统上电复位后GPIO默认输出电平对系统的影响

热门文章

  1. 理解各种聚类算法的差异
  2. 半数以上国产手游曾使用他开源的引擎:Cocos和王哲的故事 | 二叉树视频
  3. Python学习手册之内部方法、操作符重载和对象生命周期
  4. python中result的用法_Python中qutip用法示例详解
  5. Navicat安装(图文教程)
  6. date工具类 DateUtils.java
  7. 11.8 Ext.util.Event.fire(): Attempting to fire “click“ event on destroyed 问题分析与解决
  8. 年夜饭之 --- 蒜蓉粉丝蒸扇贝
  9. FTP 编写 4:命令解析
  10. 雅可比迭代c++实现_线性方程组(3)-静态迭代法