今天项目需要完成一个支持手写和键盘都可以输入的功能,点击键盘切换到软键盘输入,此时按钮会变成手写,在点击就回到手写。按钮是checkbox。功能很简单。

   支持手写和键盘输入,其实并不难,就是布局麻烦点,还有就是画布麻烦点(我是网上找现成的),其他的都很简单。我注释写的很清楚就直接贴代码了。1.画布代码。
package example.caobin.com.myhandwrite;import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
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;/*** 绘制Path的View 用于手写签名*/
@SuppressLint("ClickableViewAccessibility")
public class LinePathView extends View {private  static final String TAG=LinePathView.class.getSimpleName();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;/*** 背景Bitmap缓存*/private Bitmap cachebBitmap;/*** 是否已经签名*/private boolean isTouched = false;/*** 画笔宽度 px;*/private int mPaintWidth = 10;/*** 前景色*/private int mPenColor = Color.BLACK;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(Style.STROKE);mGesturePaint.setStrokeWidth(mPaintWidth);mGesturePaint.setColor(mPenColor);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);cachebBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);cacheCanvas = new Canvas(cachebBitmap);cacheCanvas.drawColor(mBackColor);isTouched=false;}@Overridepublic 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:cacheCanvas.drawPath(mPath, mGesturePaint);mPath.reset();break;}// 更新绘制invalidate();return true;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(cachebBitmap, 0, 0, mGesturePaint);// 通过画布绘制多点形成的图形canvas.drawPath(mPath, mGesturePaint);}// 手指点下屏幕时调用private void touchDown(MotionEvent event) {// mPath.rewind();// 重置绘制路线,即隐藏之前绘制的轨迹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;}
}
 2.布局代码
<?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:orientation="vertical"><!--顶部布局--><RelativeLayout
        android:layout_width="wrap_content"android:layout_height="35dp"android:background="@drawable/register_list_top_bg"><Button
            android:id="@+id/btn_dialog_close"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_marginBottom="3dp"android:layout_marginLeft="8dp"android:layout_marginTop="3dp"android:background="@drawable/btn_close_selector" /><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="请签名"android:textColor="@color/black"android:textSize="17sp" /><Button
            android:id="@+id/btn_save"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="3dp"android:layout_marginRight="8dp"android:layout_marginTop="3dp"android:layout_toLeftOf="@+id/tv_empty"android:background="@drawable/save_note_selector" /><TextView
            android:id="@+id/tv_empty"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:text="" /></RelativeLayout><!--下部布局--><LinearLayout
        android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="@drawable/register_bias_bg"><LinearLayout
            android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="8dp"android:background="#FCFBF9"android:orientation="vertical"><FrameLayout
                android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="0.84"><ImageView
                    android:id="@+id/img_view_hand_write_hint"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:src="@drawable/hand_write_name_hint_bg" /><example.caobin.com.myhandwrite.LinePathView
                    android:id="@+id/path_view"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="visible" /><EditText
                    android:id="@+id/edit_keyboard_register"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@null"android:gravity="left|top"android:imeOptions="flagNoExtractUi"android:visibility="invisible" /></FrameLayout><ImageView
                android:layout_width="match_parent"android:layout_height="1dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:src="@drawable/bottom_dotted_line" /><LinearLayout
                android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="0.1"android:gravity="center_vertical"><CheckBox
                    android:id="@+id/check_input_type"android:layout_width="60dp"android:layout_height="30dp"android:layout_marginLeft="30dp"android:checked="true"android:button="@null"android:background="@drawable/btn_keyboard_selector" /><Button
                    android:id="@+id/btn_clear_screen"android:layout_width="60dp"android:layout_height="30dp"android:layout_marginLeft="10dp"android:background="@drawable/btn_clear_screen_gray_bg" /><View
                    android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="0.65" /><TextView
                    android:id="@+id/tv_date"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_marginRight="20dp"android:gravity="center"android:text="2016年15月15"android:textColor="@color/black"android:textSize="18sp" /></LinearLayout></LinearLayout></LinearLayout>
</LinearLayout>

3.mainActivity代码

package example.caobin.com.myhandwrite;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private LinePathView mLinePathView;//手写输入private Button clearBtn;//清屏按钮private EditText keyboardInputEdit;//键盘输入private CheckBox inputTypeCheckBox;//切换输入方式(手写/键盘)private int inputType = 1;//1手写(默认) 0键盘private ImageView inputHintView;//输入框提示背景图片@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initListener();}private void initView() {mLinePathView = (LinePathView) findViewById(R.id.path_view);clearBtn = (Button) findViewById(R.id.btn_clear_screen);keyboardInputEdit = (EditText) findViewById(R.id.edit_keyboard_register);inputTypeCheckBox = (CheckBox) findViewById(R.id.check_input_type);inputHintView = (ImageView) findViewById(R.id.img_view_hand_write_hint);findViewById(R.id.btn_dialog_close).setOnClickListener(this);findViewById(R.id.btn_save).setOnClickListener(this);keyboardInputEdit.setOnClickListener(this);clearBtn.setOnClickListener(this);//显示当前日期Calendar c = Calendar.getInstance();SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault());((TextView) findViewById(R.id.tv_date)).setText(sdf.format(c.getTime()));}/*** 监听事件*/private void initListener() {//判断签名框是否有签名,改变清除按钮背景和隐藏签名提示背景mLinePathView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {inputHintView.setVisibility(View.INVISIBLE);clearBtn.setBackgroundResource(R.drawable.btn_clear_screen_selector);return false;}});//切换输入方式inputTypeCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {cleanScreen();//true手写  false键盘if (isChecked) {keyboardInputEdit.setVisibility(View.INVISIBLE);mLinePathView.setVisibility(View.VISIBLE);inputType = 1;} else {keyboardInputEdit.setVisibility(View.VISIBLE);mLinePathView.setVisibility(View.INVISIBLE);inputType = 0;}}});}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_dialog_close: {//关闭finish();}break;case R.id.edit_keyboard_register: {//edittext点击inputHintView.setVisibility(View.INVISIBLE);clearBtn.setBackgroundResource(R.drawable.btn_clear_screen_selector);}break;case R.id.btn_save: {//保存save();}break;case R.id.btn_clear_screen: {//清屏cleanScreen();}break;default:break;}}/*** 清屏*/private void cleanScreen() {mLinePathView.clear();keyboardInputEdit.setText(null);}private String name = "";//键盘输入姓名,当然你可以自定义保存的方式/*** 保存信息*/private void save() {if (inputType == 1) {//手写if (!mLinePathView.getTouched()) {//没有输入就点击保存,给用户提示toast("请签写你的姓名!");} else {//如果已经签写内容,进行保存saveImage("image");}} else {//键盘if (TextUtils.isEmpty(keyboardInputEdit.getText())) {//没有输入就点击保存,给用户提示toast("请输入你的姓名!");} else {//如果已经签写内容,进行保存,保存的方式可以自定义,这里就只保存在类变量里。name = keyboardInputEdit.getText().toString();toast("保存的姓名为:" + name);}}}/*** 保存签字图片** @param imageName 保存的名称*/private void saveImage(String imageName) {//图片保存的路径. 我的手机是小米//图片在data/saveImagePath目录下String imagePath = Constants.FilePath + File.separator + imageName + ".png";try {mLinePathView.save(imagePath, false, 0);toast("保存成功!");//保存成功后清屏cleanScreen();} catch (IOException e) {toast("保存失败!");}}/*** Toast任何类型的数据** @param object*/private void toast(Object object) {Toast.makeText(this, object.toString(), Toast.LENGTH_SHORT).show();}
}

4.当然还有一些资源文件,太零碎了。想要的直接从github上clone吧。
我的git

手写输入和软键盘输入相关推荐

  1. 软键盘输入设计(C语言)

    前言 之前写过一篇关于软键盘输入设计的文章点击这里查看,用的是掌机自支持的zzdbase语言,文章结尾说了其实最初想用C来实现的,但是中途遇到了困难,便改为zzdbase语言了.最近项目中想到一个比较 ...

  2. Android获取软键盘输入内容

    该功能的实现是通过Android辅助功能来进行实现的, 先上效果图:                                                      下面说一下如何使用Acc ...

  3. Unity3d C# 实现UGUI 输入框调用软键盘输入的完整功能(含工程源码,适用触屏一体机等)

    前言 如题的需求经常会在甲方的需求中出现,比如一体机上,大多客户会不选择键盘和鼠标,因为觉得比较low的可能.自己弄一个内置UI键盘的话也是可行的,只不过可能就英文输入好实现,实现带中文的输入可能就比 ...

  4. qt调用android键盘,QT 软键盘输入

    1.从QInputContext派生自己的InputContext类 ,例如: class MyInputPanelContext : public QInputContext { Q_OBJECT ...

  5. Android软键盘输入详解

    IM(Input Method): 输入法.是指通过键盘等输入设备输入 输入设备上没有 的字符的 方法/程序/处理器 .最开始是特指在拉丁字母键盘上输入CJK (Chinese, Japanese a ...

  6. QT LineEdit实现软键盘输入

    描述:当光标选中LineEdit时弹出软键盘并且点击键盘能将内容输入到LineEdit中 首先我们先实现选中LineEdit时键盘能弹出 给LineEdit安装事件过滤器,重写mousePressEv ...

  7. Android软键盘调用及隐藏,以及获得点击软键盘输入的字母信息

    在Android提供的EditText中单击的时候,会自动的弹出软键盘,其实对于软键盘的控制我们可以通过InputMethodManager这个类来实现.我们需要控制软键盘的方式就是两种一个是像Edi ...

  8. android字符软键盘,android – 如何在视图中捕获软键盘输入?

    我有一个子类视图,当它在onTouchEvent中收到"修饰"时弹出键盘.它通过请求焦点,检索InputMethodManager,然后调用showSoftInput来显示此信息. ...

  9. XNA游戏:软键盘弹窗输入

    在XNA中如果我们需要输入文字,那么我们就需要使用到软键盘了,在XNA中使用软键盘要用到Guide.BeginShowKeyboardInput方法,由于游戏的Update是会不断地执行的,所以要由G ...

最新文章

  1. xp/2003开关3389指令
  2. Linux下运行.cpp文件
  3. 2014第12周二学习记
  4. c语言二fseek从文件头移动_编程C语言文件的随机读写
  5. 以太坊再爆高危漏洞!黑客增发ATN 1100万枚token事件始末
  6. 华工网络教育C语言校考答案,计算机应用基础(统考)随堂练习2017秋华工答案.docx...
  7. mysql keepalived双主双活_mysql高可用架构方案之中的一个(keepalived+主主双活)
  8. 容器编排技术 -- Kubernetes 应用连接到 Service
  9. STM32 - 定时器的设定 - 基础-04 - 输出波形控制 - PWM 模式
  10. 【JAVA SE】第十一章 正则表达式、包装类和BigDecimal
  11. python开源项目2019_2019年6月Github上最热门的Python开源项目
  12. c++简单的加法函数
  13. [大数据、Hadoop、数据采集、MySQL、计算机基础、Windows、练习题库、面试]
  14. JAVA高效批量插入数据到数据库demo
  15. 树莓派安装Ubuntu server无屏幕开机自动连接WIFI
  16. 【Unity开发小技巧】Unity日志输出存储
  17. hadoop之MapReduce统计选修课程人数,不及格门数,选课人数
  18. 【论文翻译】EIDETIC 3D LSTM: A MODEL FOR VIDEO PREDICTION AND BEYOND
  19. VS2019打包程序安装后无法运行
  20. revit 2021 r2(3D建筑信息模型构建软件)pjb 附安装教程

热门文章

  1. Berkeley DB 的内容
  2. Vehicle Color Recognition on an Urban Road by Feature Context - 车辆颜色识别数据集
  3. linux 系统调用详解
  4. win10系统日志事件ID 7023
  5. labels.size(0) 是什么意思
  6. java sendmessage函数_Unity3D中的SendMessage使用(消息传递的三种方法)
  7. Linux总结(一)常识 -vi和vim
  8. 关于两个椭圆的面积并的问题
  9. 基于javaee的酒店预订管理系统设计与实现、ssh框架+mysql数据库
  10. 悬挂运动控制系统(E题) 07年