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

添加圆角

添加圆角的功能,要用到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开发笔记的完整目录
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值