这是我看着别人的博客写的 他的博客地址是 http://blog.csdn.net/venusic/article/details/52096710
他写的demo很不错 可是有好多地方可以改进 我在他的基础上改进了很多东西 包括添加虚线 照片底版颜色 设置
虚线设置很麻烦 起码在用这个工具类的时候关系虚线的设置很麻烦 弄了好久 代码时完整的 可以直接复制 拿来用
先看效果图
先是上传 封装好的工具
package com.example.administrator.dianziqianming; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.support.annotation.ColorInt; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class LinePathView extends View { private Context mContext; /** * 笔画X坐标起点 */ private float mX; /** * 笔画Y坐标起点 */ private float mY; /** * 手写画笔 */ private final Paint mGesturePaint = new Paint(); /** * 路径 */ private final Path mPath = new Path(); /** * 签名画笔 */ private Canvas cacheCanvas; /** * 签名画布 */ private Bitmap cachebBitmap; /** * 是否已经签名 */ private boolean isTouched = false; /** * 画笔宽度 px; */ private int mPaintWidth = 10; /** * 前景色 */ private int mPenColor = Color.BLACK; /** * 前景色 */ private int mBeiJingColor = Color.WHITE; /** /** * 背景色(指最终签名结果文件的背景颜色,默认为透明色) */ private int mBackColor=Color.TRANSPARENT; public LinePathView(Context context) { super(context); init(context); } public LinePathView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public LinePathView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public void init(Context context) { this.mContext = context; //设置抗锯齿 mGesturePaint.setAntiAlias(true); //设置签名笔画样式 mGesturePaint.setStyle(Paint.Style.STROKE); //设置笔画宽度 mGesturePaint.setStrokeWidth(mPaintWidth); //设置签名颜色 mGesturePaint.setColor(mPenColor); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //创建跟view一样大的bitmap,用来保存签名 cachebBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); cacheCanvas = new Canvas(cachebBitmap); cacheCanvas.drawColor(mBackColor); // cachebBitmap isTouched=false; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchDown(event); break; case MotionEvent.ACTION_MOVE: isTouched = true; touchMove(event); break; case MotionEvent.ACTION_UP: //将路径画到bitmap中,即一次笔画完成才去更新bitmap,而手势轨迹是实时显示在画板上的。 cacheCanvas.drawPath(mPath, mGesturePaint); mPath.reset(); break; } // 更新绘制 invalidate(); return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画此次笔画之前的签名 canvas.drawBitmap(cachebBitmap, 0, 0, mGesturePaint); // 通过画布绘制多点形成的图形 canvas.drawPath(mPath, mGesturePaint); } // 手指点下屏幕时调用 private void touchDown(MotionEvent event) { // 重置绘制路线 mPath.reset(); float x = event.getX(); float y = event.getY(); mX = x; mY = y; // mPath绘制的绘制起点 mPath.moveTo(x, y); } // 手指在屏幕上滑动时调用 private void touchMove(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); final float previousX = mX; final float previousY = mY; final float dx = Math.abs(x - previousX); final float dy = Math.abs(y - previousY); // 两点之间的距离大于等于3时,生成贝塞尔绘制曲线 if (dx >= 3 || dy >= 3) { // 设置贝塞尔曲线的操作点为起点和终点的一半 float cX = (x + previousX) / 2; float cY = (y + previousY) / 2; // 二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点 mPath.quadTo(previousX, previousY, cX, cY); // 第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值 mX = x; mY = y; } } /** * 清除画板 */ public void clear() { if (cacheCanvas != null) { isTouched = false; //更新画板信息 mGesturePaint.setColor(mPenColor); cacheCanvas.drawColor(mBackColor, PorterDuff.Mode.CLEAR); mGesturePaint.setColor(mPenColor); invalidate(); } } /** * 保存画板 * @param path 保存到路径 */ public void save(String path) throws IOException { save(path, false, 0); } /** * 保存画板 * @param path 保存到路径 * @param clearBlank 是否清除边缘空白区域 * @param blank 要保留的边缘空白距离 */ public void save(String path, boolean clearBlank, int blank) throws IOException { Bitmap bitmap=cachebBitmap; //BitmapUtil.createScaledBitmapByHeight(srcBitmap, 300);// 压缩图片 if (clearBlank) { bitmap = clearBlank(bitmap, blank); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); byte[] buffer = bos.toByteArray(); if (buffer != null) { File file = new File(path); if (file.exists()) { file.delete(); } OutputStream outputStream = new FileOutputStream(file); outputStream.write(buffer); outputStream.close(); } } /** * 获取画板的bitmap * @return */ public Bitmap getBitMap() { setDrawingCacheEnabled(true); buildDrawingCache(); Bitmap bitmap=getDrawingCache(); setDrawingCacheEnabled(false); return bitmap; } /** * 逐行扫描 清楚边界空白。 * * @param bp * @param blank 边距留多少个像素 * @return */ private Bitmap clearBlank(Bitmap bp, int blank) { int HEIGHT = bp.getHeight(); int WIDTH = bp.getWidth(); int top = 0, left = 0, right = 0, bottom = 0; int[] pixs = new int[WIDTH]; boolean isStop; //扫描上边距不等于背景颜色的第一个点 for (int y = 0; y < HEIGHT; y++) { bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1); isStop = false; for (int pix : pixs) { if (pix != mBackColor) { top = y; isStop = true; break; } } if (isStop) { break; } } //扫描下边距不等于背景颜色的第一个点 for (int y = HEIGHT - 1; y >= 0; y--) { bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1); isStop = false; for (int pix : pixs) { if (pix != mBackColor) { bottom = y; isStop = true; break; } } if (isStop) { break; } } pixs = new int[HEIGHT]; //扫描左边距不等于背景颜色的第一个点 for (int x = 0; x < WIDTH; x++) { bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT); isStop = false; for (int pix : pixs) { if (pix != mBackColor) { left = x; isStop = true; break; } } if (isStop) { break; } } //扫描右边距不等于背景颜色的第一个点 for (int x = WIDTH - 1; x > 0; x--) { bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT); isStop = false; for (int pix : pixs) { if (pix != mBackColor) { right = x; isStop = true; break; } } if (isStop) { break; } } if (blank < 0) { blank = 0; } //计算加上保留空白距离之后的图像大小 left = left - blank > 0 ? left - blank : 0; top = top - blank > 0 ? top - blank : 0; right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank; bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank; return Bitmap.createBitmap(bp, left, top, right - left, bottom - top); } /** * 设置画笔宽度 默认宽度为10px * * @param mPaintWidth */ public void setPaintWidth(int mPaintWidth) { mPaintWidth = mPaintWidth > 0 ? mPaintWidth : 10; this.mPaintWidth = mPaintWidth; mGesturePaint.setStrokeWidth(mPaintWidth); } public void setBackColor(@ColorInt int backColor) { mBackColor=backColor; } /** * 设置画笔颜色 * * @param mPenColor */ public void setPenColor(int mPenColor) { this.mPenColor = mPenColor; mGesturePaint.setColor(mPenColor); } /** * 是否有签名 * * @return */ public boolean getTouched() { return isTouched; } }
然后是签名页面
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" > <RelativeLayout android:id="@+id/rela_bottom" android:layout_width="match_parent" android:orientation="horizontal" android:layout_alignParentBottom="true" android:layout_height="wrap_content"> <LinearLayout android:layout_alignParentRight="true" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/clear1" android:background="#808080" android:text="清除" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/cancel" android:background="#ff7c4e" android:text="取消" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/save1" android:text="保存" android:background="#0398ff" /> </LinearLayout> </RelativeLayout> <TextView android:id="@+id/text_title" android:text="签名板" android:background="#FFFFFF" android:layout_width="match_parent" android:gravity="center" android:layout_height="wrap_content" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg_border_stroke" android:layout_above="@id/rela_bottom" android:layout_below="@id/text_title"> <com.example.administrator.dianziqianming.LinePathView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/view" android:layout_margin="15dp" android:layout_gravity="center_horizontal"/> </RelativeLayout> </RelativeLayout>
签名页面的activity
package com.example.administrator.dianziqianming; import android.app.Activity; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.IOException; import butterknife.BindView; import butterknife.ButterKnife; public class LandscapeActivity extends Activity { @BindView(R.id.clear1) Button mClear; @BindView(R.id.save1) Button mSave; @BindView(R.id.cancel) Button cAndel; @BindView(R.id.view) LinePathView pathView; // @Bind(R.id.view) // LinePathView pathView; // @Bind(R.id.clear1) // Button mClear; // @Bind(R.id.save1) // Button mSave; // @Bind(R.id.ll) // LinearLayout ll; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_hand_write); ButterKnife.bind(this); getNet(); Log.e("FFFFFFFFF","|KLDSFJKLDJFL"); setResult(50); mSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (pathView.getTouched()) { try { pathView.save(MainActivity.path1, false, 10); } catch (IOException e) { e.printStackTrace(); } setResult(101); finish(); } else { Toast.makeText(LandscapeActivity.this, "您没有签名~", Toast.LENGTH_SHORT).show(); } } }); mClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("EEEEEEEEEE","|KLDSFJKLDJFL"); pathView.clear(); } }); cAndel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private void getNet() { Log.e("MMMMMMMMMM","|KLDSFJKLDJFL"); pathView.clear(); } //这里是 在进入签名页面的时候将屏幕设置为横屏 @Override protected void onResume() { /** * 设置为横屏 */ if(getRequestedOrientation()!= ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } super.onResume(); } }
然后是 mainactivity 和 其xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#458632" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="横屏旋转" /> </LinearLayout> <TextView android:layout_width="wrap_content" android:textColor="@android:color/white" android:layout_height="wrap_content" android:text="横屏签名:"/> <ImageView android:id="@+id/img2" android:layout_width="320dp" android:background="#FFFFFF" android:scaleType="centerInside" android:layout_height="160dp" /> </LinearLayout>
package com.example.administrator.dianziqianming; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ImageView; import java.io.File; import butterknife.BindView; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity { public static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "qm.png"; public static String path1 = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "ls.png"; @BindView(R.id.btn2) Button btn2; @BindView(R.id.img2) ImageView img2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivityForResult(new Intent(MainActivity.this, LandscapeActivity.class), 1); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == 100) { // BitmapFactory.Options options = new BitmapFactory.Options(); // options.inSampleSize = 2; // Bitmap bm = BitmapFactory.decodeFile(path, options); // img1.setImageBitmap(bm); } else if (resultCode == 101) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; Bitmap bm = BitmapFactory.decodeFile(path1, options); img2.setImageBitmap(bm); } } //这里是在签名页面退出的时候 将页面切换为正常的屏幕 即竖屏 @Override protected void onResume() { if(getRequestedOrientation()!= ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } super.onResume(); } }
用到的资源文件
ba_border_stroke.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape> <solid android:color="#FFFFFF" /> <corners android:radius="5dp" /> </shape> </item> <item android:bottom="30dp" android:left="30dp" android:right="30dp" android:top="30dp"> <shape> <stroke android:dashGap="15dp" android:dashWidth="15dp" android:width="2.5dp" android:color="#E8A227" /> <solid android:color="#FFFFFF" /> <corners android:radius="1dp" /> </shape> </item> </layer-list>

本文介绍了基于他人博客改进的Android电子签名实现,包括添加虚线框和照片底版颜色设置。提供了完整的代码示例,方便直接使用。文章中展示了签名效果、签名工具类、签名页面Activity以及MainActivity的相关配置。
&spm=1001.2101.3001.5002&articleId=76127131&d=1&t=3&u=284a57c1a6134053bfb15e9946cced80)
1264

被折叠的 条评论
为什么被折叠?



