自定义控件之手势签名

Android中,我们常用的控件,例如按钮(Button)、文本框(TextView,可编辑文本框(EditText,列表框(ListView,复选框(CheckBox,单选框(RadioButton,滚动条(Gallery,微调器(Spinner, 等等,还有一些比较先进的有着特殊用途的View组件,例如AutoCompleteTextView, ImageSwitcher TextSwitcher。除此之外,种类繁多的像 线性布局(LinearLayout, 框架布局(FrameLayout, 这样的布局组件(Layout)也被认为是View组件,他们是从View类派生过来的。本文呢,我们就先创建一个网络签名的控件SignatureView,具体的理论,本文就先不介绍这么多了,有点饿了,赶紧写完去吃饭,下次再详细研究下里面的理论知识。好,开始我们的实验。

 

第一步:创建自定义控件SignatureView.java

 

 

 

package com.figo.helloworld;

 

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.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

 

/**

 * 自定义签名控件

 *

 * @author zhuzhifei

 * 版权所有 20120912

 */

public class SignatureView extends View {

         private Bitmap mBitmap;// 绘成的图片

         private Canvas mCanvas;// 画布

         private Path mPath;// 绘图路径

         private Paint mBitmapPaint;// 绘制图片的画笔

         private Paint mPathPaint;// 绘制路径的画笔

         private float mX, mY;// 坐标

         private static final float TOUCH_TOLERANCE = 4;// 公差4dp

 

         // 构造函数

         public SignatureView(Context context) {

                   super(context);

                   init();

         }

 

         // 构造函数

         public SignatureView(Context context, AttributeSet attrs) {

                   super(context, attrs);

                   init();

         }

 

         // 构造函数

         public SignatureView(Context context, AttributeSet attrs, int defStyle) {

                   super(context, attrs, defStyle);

                   init();

         }

 

         // 新建绘图路径,画笔,和画布

         private void init() {

                   mPath = new Path();// 绘图路径

                   mBitmapPaint = new Paint(Paint.DITHER_FLAG);// 绘制图片的画笔

                   mPathPaint = new Paint();// 绘制路径的画笔

                   mPathPaint.setAntiAlias(true);

                   mPathPaint.setDither(true);

                   mPathPaint.setColor(0xFF000000);// 颜色

                   mPathPaint.setStyle(Paint.Style.STROKE);// 样式 线条

                   mPathPaint.setStrokeJoin(Paint.Join.ROUND);

                   mPathPaint.setStrokeCap(Paint.Cap.ROUND);

                   mPathPaint.setStrokeWidth(7);// 笔画宽度

         }

 

         // 测量手机屏幕宽度和高度

         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

                   super.onMeasure(widthMeasureSpec, heightMeasureSpec);

                   this.createBitmap();

         }

 

         // 生成签名图片

         protected void createBitmap() {

                   if (mBitmap != null) {

                            return;

                   }

                   mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),

                                     Bitmap.Config.ARGB_8888);

                   mBitmap.eraseColor(Color.TRANSPARENT);

                   mCanvas = new Canvas(mBitmap);

         }

 

         @Override

         protected void onSizeChanged(int w, int h, int oldw, int oldh) {

                   super.onSizeChanged(w, h, oldw, oldh);

         }

 

         // 绘制视图

         @Override

         protected void onDraw(Canvas canvas) {

                   canvas.drawColor(Color.TRANSPARENT);

 

                   canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

 

                   canvas.drawPath(mPath, mPathPaint);

         }

 

         // 开始绘制

         private void touch_start(float x, float y) {

                   mPath.reset();

                   mPath.moveTo(x, y);

                   mX = x;

                   mY = y;

         }

 

         // 绘制过程

         private void touch_move(float x, float y) {

                   float dx = Math.abs(x - mX);// 横坐标移动量

                   float dy = Math.abs(y - mY);// 纵坐标移动量

                   if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {

                            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);// 移动画笔

                            mX = x;

                            mY = y;

                   }

         }

 

         // 停止绘制

         private void touch_up() {

                   mPath.lineTo(mX, mY);// 路径到达终点坐标

                   mCanvas.drawPath(mPath, mPathPaint);// 通过路径,在画布上画图

                   mPath.reset();// 重新设置绘图路径到原始状态

         }

 

         // 触屏事件

         @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);

                            invalidate();// 绘制结束更新视图,触发ondraw事件

                            break;

                   case MotionEvent.ACTION_MOVE:// 手指移动

                            touch_move(x, y);

                            invalidate();

                            break;

                   case MotionEvent.ACTION_UP:// 手指释放

                            touch_up();

                            invalidate();

                            break;

                   }

                   return true;

         }

 

         // 清除之前画的图像

         public void clearSignature() {

                   mBitmap.eraseColor(Color.TRANSPARENT);

                   invalidate();

         }

 

         // 获取画好的图像

         public Bitmap getSignatureBitmap() {

                   return mBitmap;

         }

}

第二步:设计Activity对应的布局页面signature.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent" >

 

    <com.figo.helloworld.SignatureView

        android:id="@+id/signatureView1"

        android:layout_width="fill_parent"

        android:layout_height="180dp"

        android:layout_alignParentLeft="true"

        android:background="@drawable/sign_tip" />

 

    <Button

        android:id="@+id/btnSave"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentRight="true"

        android:layout_below="@+id/signatureView1"

        android:layout_marginRight="104dp"

        android:layout_marginTop="55dp"

         android:onClick="onSaveClick"

        android:text="     " />

 

    <Button

        android:id="@+id/btnReset"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignBaseline="@+id/btnSave"

        android:layout_alignBottom="@+id/btnSave"

        android:layout_marginRight="34dp"

        android:layout_toLeftOf="@+id/btnSave"

        android:onClick="onResetClick"

        android:text="     " />

 

    <ImageView

        android:id="@+id/imgShow"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/btnReset"

        android:layout_marginTop="18dp"

        android:background="@drawable/sign_tip"/>

 

</RelativeLayout>

 

第三步:创建Acitivity  SignatureActivity.java 这个activity里面我们将引用上面创建的控件

 

package com.figo.helloworld;

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

 

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.Matrix;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.view.View;

import android.widget.ImageView;

 

/**

 * 使用自定义绘图控件 签名、保存签名图片、显示签名

 *

 * @author zhuzhifei 版权所有 20120912

 */

public class SignatureActivity extends Activity {

         SignatureView sigView = null;

         private Bitmap newSigBmp = null;

         private ImageView image;

 

         public void onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.signature);

                   initView();

 

         }

 

         private void initView() {

                   sigView = (SignatureView) findViewById(R.id.signatureView1);

                   image = (ImageView) findViewById(R.id.imgShow);

 

         }

 

         public void onResetClick(View view) {

                   sigView.clearSignature();

         }

 

         public void onSaveClick(View view) throws IOException {

                   // 判断是否有签名后再操作...

                   Bitmap bitMap = sigView.getSignatureBitmap();

                   // 方法一:直接显示

                   // image.setImageBitmap(bitMap);

                   // 方法二:保存后再显示

                   newSigBmp = scaleToNewBitmap(bitMap, 0.3f);

                   SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");

                   String fn = df.format(new Date());

                   String path = saveBitmapToPngFile(newSigBmp, fn);

                   image.setImageURI(Uri.parse(path));

 

         }

 

         // 更换图片尺寸

         private Bitmap scaleToNewBitmap(Bitmap origin, float scaleRate) {

                   Matrix matrix = new Matrix();

                   matrix.postScale(scaleRate, scaleRate);

                   Bitmap newBitmap = Bitmap.createBitmap(origin, 0, 0, origin.getWidth(),

                                     origin.getHeight(), matrix, true);

                   return newBitmap;

         }

 

         // bmp格式图片转换成png格式,同时保存到sdcard/Sign这个文件夹里面

         private String saveBitmapToPngFile(Bitmap b, String name) {

                   String currentPath = Environment.getExternalStorageDirectory()

                                     .getAbsolutePath() + "/Sign";

                   FileOutputStream fos = null;

                   try {

                            File sddir = new File(currentPath);

                            if (!sddir.exists()) {

                                     sddir.mkdirs();

                            }

                            File file = new File(currentPath + "/" + name + ".png");

                            if (file.exists()) {

                                     file.delete();

                            }

                            file.createNewFile();

                            fos = new FileOutputStream(file);

                            if (fos != null) {

                                     b.compress(Bitmap.CompressFormat.PNG, 50, fos);

                                     fos.close();

                            }

                            return currentPath + "/" + name + ".png";

                   } catch (Exception e) {

                            e.printStackTrace();

                   }

                   return currentPath;

 

         }

}

 

第四步:AndroidManifest.xml 注册Acitivity和设置写sdcard的权限

 

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name" >

        <activity

            android:name=".SignatureActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

</application>

 

第五步:运行效果

点击保存后,签名图片写入sdcard,同时将图片显示在下面的一个imageView里面

原文地址:https://www.cnblogs.com/javawebsoa/p/3060112.html