android开发中如何实现手写输入的记事本
只要写一个简单的记事本即可以,手写输入是android本身的功能,不需要另外写
你是不是安装了瑞星杀毒?
2008的瑞星带主动防御,是这个阻止了你的手写板程序向QQ写字,,解决办法有两个:
1,在聊QQ时关闭瑞星实时监控,
2,在右键单击屏幕右下的瑞星图标,选择主动防御设置---应用程序控制---在右边的窗口中选择QQ程序,点下方的编辑,取消里面的“防模拟键盘”。点确定保存退出就可以了。。
实现手写功能的主要步骤:
1. 自定义两个View,一个是TouchView,用于在上面画图,另一个是EditText,用于将手写的字显示在其中,并且,要将两个自定义View通过FrameLayout帧式布局重叠在起,以实现全屏手写的功能。
2 在TouchView中实现写字,并截取画布中的字以Bitmap保存。
3. 设置定时器,利用handle更新界面。
下面是实现的细节:
1. 手写的界面设计:
如上图所示,和上节的画板界面一致,底部分选项菜单栏,有5个选项,分别是调整画笔大小,画笔颜色,撤销,恢复,以及清空,对于这些功能,之后几节再实现。
布局文件activity_handwrite.xml
<!--?xml version=1.0 encoding=utf-8?-->
<relativelayout android:background="@android:color/white" android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"><imageview android:layout_above="@+id/paintBottomMenu" android:layout_height="wrap_content" android:layout_width="match_parent" android:src="@drawable/line">
</imageview></relativelayout>
可以看出,里面有两个自定义view,并且通过FrameLayout重叠在一起。
先来看com.example.notes.LineEditText,这个其实和添加记事中的界面一样,就是自定义EditText,并且在字的下面画一条线。
LineEditText.java
public class LineEditText extends EditText {
private Rect mRect;
private Paint mPaint;
public LineEditText(Context context, AttributeSet attrs) {
// TODO Auto-generated constructor stub
super(context,attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setColor(Color.GRAY);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//得到EditText的总行数
int lineCount = getLineCount();
Rect r = mRect;
Paint p = mPaint;
//为每一行设置格式
for(int i = 0; i < lineCount;i++){
//取得每一行的基准Y坐标,并将每一行的界限值写到r中
int baseline = getLineBounds(i, r);
//设置每一行的文字带下划线
canvas.drawLine(r.left, baseline+20, r.right, baseline+20, p);
}
}
}
另一个就是com.example.notes.TouchView,实现了绘制,及定时更新界面的功能,具体看代码
TouchView.java
public class TouchView extends View {
private Bitmap mBitmap,myBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
private Handler bitmapHandler;
GetCutBitmapLocation getCutBitmapLocation;
private Timer timer;
DisplayMetrics dm;
private int w,h;
public TouchView(Context context) {
super(context);
dm = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
w = dm.widthPixels;
h = dm.heightPixels;
initPaint();
}
public TouchView(Context context, AttributeSet attrs) {
super(context,attrs);
dm = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
w = dm.widthPixels;
h = dm.heightPixels;
initPaint();
}
//设置handler
public void setHandler(Handler mBitmapHandler){
bitmapHandler = mBitmapHandler;
}
//初始化画笔,画布
private void initPaint(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF00FF00);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(15);
getCutBitmapLocation = new GetCutBitmapLocation();
//画布大小
mBitmap = Bitmap.createBitmap(w, h,
Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); //所有mCanvas画的东西都被保存在了mBitmap中
mCanvas.drawColor(Color.TRANSPARENT);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
timer = new Timer(true);
}
/**
* 处理屏幕显示
*/
Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
myBitmap = getCutBitmap(mBitmap);
Message message = new Message();
message.what=1;
Bundle bundle = new Bundle();;
bundle.putParcelable(bitmap,myBitmap);
message.setData(bundle);
bitmapHandler.sendMessage(message);
RefershBitmap();
break;
}
super.handleMessage(msg);
}
};
/**
* 发送消息给handler更新ACTIVITY
*/
TimerTask task = new TimerTask() {
public void run() {
Message message = new Message();
message.what=1;
Log.i(线程, 来了);
handler.sendMessage(message);
}
};
//切割画布中的字并返回
public Bitmap getCutBitmap(Bitmap mBitmap){
//得到手写字的四周位置,并向外延伸10px
float cutLeft = getCutBitmapLocation.getCutLeft() - 10;
float cutTop = getCutBitmapLocation.getCutTop() - 10;
float cutRight = getCutBitmapLocation.getCutRight() + 10;
float cutBottom = getCutBitmapLocation.getCutBottom() + 10;
cutLeft = (0 > cutLeft ? 0 : cutLeft);
cutTop = (0 > cutTop ? 0 : cutTop);
cutRight = (mBitmap.getWidth() < cutRight ? mBitmap.getWidth() : cutRight);
cutBottom = (mBitmap.getHeight() < cutBottom ? mBitmap.getHeight() : cutBottom);
//取得手写的的高度和宽度
float cutWidth = cutRight - cutLeft;
float cutHeight = cutBottom - cutTop;
Bitmap cutBitmap = Bitmap.createBitmap(mBitmap, (int)cutLeft, (int)cutTop, (int)cutWidth, (int)cutHeight);
if (myBitmap!=null ) {
myBitmap.recycle();
myBitmap= null;
}
return cutBitmap;
}
//刷新画布
private void RefershBitmap(){
initPaint();
invalidate();
if(task != null)
task.cancel();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); //显示旧的画布
canvas.drawPath(mPath, mPaint); //画最后的path
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
//手按下时
private void touch_start(float x, float y) {
mPath.reset();//清空path
mPath.moveTo(x, y);
mX = x;
mY = y;
if(task != null)
task.cancel();//取消之前的任务
task = new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what=1;
Log.i(线程, 来了);
handler.sendMessage(message);
}
};
getCutBitmapLocation.setCutLeftAndRight(mX,mY);
}
//手移动时
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, y);
// mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);//源代码是这样写的,可是我没有弄明白,为什么要这样?
mX = x;
mY = y;
if(task != null)
task.cancel();//取消之前的任务
task = new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what=1;
Log.i(线程, 来了);
handler.sendMessage(message);
}
};
getCutBitmapLocation.setCutLeftAndRight(mX,mY);
}
}
//手抬起时
private void touch_up() {
//mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
if (timer!=null) {
if (task!=null) {
task.cancel();
task = new TimerTask() {
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
timer.schedule(task, 1000, 1000); //2200秒后发送消息给handler更新Activity
}
}else {
timer = new Timer(true);
timer.schedule(task, 1000, 1000); //2200秒后发送消息给handler更新Activity
}
}
//处理界面事件
@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(); //刷新
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
这里面的难点就是利用TimerTask和Handle来更新界面显示,需要在onTouchEvent的三个事件中都要通过handle发送消息来更新显示界面。
接下来就是在activity里通过handle来得到绘制的字,并添加在editText中。
关于配置底部菜单,以及顶部标题栏,这里不再赘述,直接如何将绘制的字得到,并添加在edittext中:
得到绘制字体的Bitmap
//处理界面
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = new Bundle();
bundle = msg.getData();
Bitmap myBitmap = bundle.getParcelable(bitmap);
InsertToEditText(myBitmap);
}
};
其中myBitmap就是取得的手写字,保存在Bitmap中, InsertToEditText(myBitmap);是将该图片添加在edittext中,具体如下:
?
1
private LineEditText et_handwrite;
?
1
et_handwrite = (LineEditText)findViewById(R.id.et_handwrite);
//将手写字插入到EditText中
private void InsertToEditText(Bitmap mBitmap){
int imgWidth = mBitmap.getWidth();
int imgHeight = mBitmap.getHeight();
//缩放比例
float scaleW = (float) (80f/imgWidth);
float scaleH = (float) (100f/imgHeight);
Matrix mx = new Matrix();
//对原图片进行缩放
mx.postScale(scaleW, scaleH);
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, imgWidth, imgHeight, mx, true);
//将手写的字插入到edittext中
SpannableString ss = new SpannableString(1);
ImageSpan span = new ImageSpan(mBitmap, ImageSpan.ALIGN_BOTTOM);
ss.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
et_handwrite.append(ss);
}
我也想问。Android的APIDemo里有这个例子,但是我找不到 ,你能告诉我在哪吗
Android的APIDemo里有这个例子,可以去看下
如何定位Android NDK开发中遇到的错误
利用Android NDK开发本地应用的时候,几乎所有的程序员都遇到过程序崩溃的问题,但它的崩溃会在logcat中打印一堆看起来类似天书的堆栈信息,让人举足无措。单靠添加一行行的打印信息来定位错误代码做在的行数,无疑是一件令人崩溃的事情。在网上搜索“Android NDK崩溃”,可以搜索到很多文章来介绍如何通过Android提供的工...
Android系统中的Activity和Service有什么区别
Android系统中的Activity和Service有什么区别?在Android应用开发中,Activity和Service是两个非常重要的概念。Activity是Android系统中的一个核心组件,可以理解为应用程序的一个窗口。而Service是后台服务组件,可以在后台执行某些任务。虽然这两个组件都是Android中的核心组件,但是它们之间的功能和用途却是完全...
android 开发中怎么设置闹铃和获取当前时间
设置闹钟与获得当前时间,下面代码中都用 import java.util.Calendar;import android.app.Activity;import android.app.AlarmManager;import android.app.PendingIntent;import android.app.TimePickerDialog;import android.app.TimePickerDialog.OnTimeSetListener;import android.content.Intent;import android.os....
在android应用开发中,用户登录后怎么实现用户密码的修改??
如果是保存在本地数据库,在设置里面修改用户密码通常会有一个设置,那就更新本地数据库里的密码。如果你的帐号信息是保存在服务端的,把新密码提交到服务端就好了 在该Activity中用map或者namevalue装载修改的密码和其他必须的参数android开发中,更新数据库,用户的密码肯定是放在服务器端的数据库中的,...
Android 开发中 如何做到XML多屏幕适配?
高密度: hdpi (High dots per inch)中等密度: mdpi (Medium dots per inch)低密度: ldpi (Low dots per inch)并且布局中推荐使用密度无关单位dip或dp,来作为长度或者宽度的单位.这样,从理论上来讲,开发者只需要做:1. 为不同的密度屏幕准备图片资源 (图片是没办法的,因为图片...
安卓开发需要掌握哪些技术安卓开发需要
Android开发都需要使用什么语言?首先先说明一下app开发的类型:1、有原生开发的app,接近系统底层,可以调用系统组件,稳定,缺点是开发周期长,使用java语言开发 2、基于web开发的app,主要是把手机端网页封装到app中,缺点就是他本质只是网页,安卓苹果端都能用,需要掌握前端知识,例如html,css,javascript...
如何定位Android NDK开发中遇到的错误
Android NDK定义 Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C \/ C++之类的原生代码语言执行部分程序。NDK作用 代码保护,由于APK的Java层代码很容易被反编译,而C\/C++库反汇难度较大。ND...
Android WebView 在开发过程中有哪些坑?
所以,当你的程序中需要用到多线程时候,也请使用 runOnUiThread()方法来保证你关于WebView的操作是在UI线程中进行的:runOnUiThread(newRunnable(){ Override publicvoid run(){ \/\/ Code for WebView goes here } });2.线程阻塞 永远不要阻塞UI线程,这是开发Android程序的一个真理。虽然是真理,...
android开发什么叫内存泄露
下面小编搜罗了5个android开发中比较常见的内存泄漏问题及解决办法,分享给大家,一起来看看吧。 一、单例造成的内存泄漏 Android的单例模式非常受开发者的喜爱,不过使用的不恰当的话也会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例...
iOS、Android等开发中px、ppi、pt、pd、dpi的个人理解
但是Android也有很好的解决方案就是使用pd作为逻辑分辨率,从pd定义可知(幕像素点密度为160ppi时1px长度),pd是个固定的物理大小单位。因此如果以pd计算dpi的话,那dpi在不同设备上应该是一样的160dpi,和iOS以dpi≈164基本差不多,所以在Android、iOS设计开发的时候才会把他们两等同。android图 ...
沈沫熊胆: 只要写一个简单的记事本即可以,手写输入是android本身的功能,不需要另外写
新平彝族傣族自治县19219003455: Android开发之如何手写代码进行页面布局?
沈沫熊胆: 首先,创建线性布局对象 LinearLayout layout = new LinearLayout(this);//为本Activity创建一个线性布局对象 //并且设置它的属性 android:layout_width 与 android:layout_height 都为 FILL_PARENTLinearLayout.LayoutParams layoutParams = new ...
新平彝族傣族自治县19219003455: android开发 自定义键盘 - ?
沈沫熊胆: 最简单粗暴的方法,屏蔽系统键盘,然后使用popupwindow作为你的键盘载体,然后当点击其上的按钮时,输入相应文本.当然需要记得移动光标到最后哦.当然要专业点,你就使用android.inputmethodservice.Keyboard
新平彝族傣族自治县19219003455: android 5.0 版本 没有手写输入法 - ?
沈沫熊胆: 自带的Android键盘(AOSP)键盘是不支持手写输入的. 可以选择下载第三方输入法实现手写输入.如百度输入法,搜狗输入法,讯飞,QQ拼音,触宝等.以百度输入法为例: 1. 到百度首页搜索百度输入法安卓版,下载并安装到手机. 2. 打开安卓版百度输入法,这时会出现向导,第一步启用百度输入法. 3. 去勾选百度输入法. 至此设置完成,打开短信页面,点击百度输入法最上层的“拼音”,如图所示,选择为“手写”即可.
新平彝族傣族自治县19219003455: 安卓系统怎么实现输入法手写整句输入 - ?
沈沫熊胆: 设置输入法 在输入法设置里面有 查看更多答案>>
新平彝族傣族自治县19219003455: 安卓android开发短期内有没有可能自己做出一个能够手写识别一整个英文单词的app,包括连笔 - ?
沈沫熊胆: 如果你有现成的大数据的网络接口,做个简单的有可能.但是这种识别类型的大数据都是要收费的.个人不大可能要到. 如果是完全自己写,包括所有的数据分析,这完全不可能.
新平彝族傣族自治县19219003455: 安卓开发 点击imagebutton按钮之后进行输入记录功能然后把输入的内容进行储存 - ?
沈沫熊胆: 输入文本的控件是EditText 确认输入按键Button 给Button添加一个点击监听OnClickListener(),在监听里面实现EditText.getText()获取输入框里面的内容,获取到的内容随便你拿去干嘛...
新平彝族傣族自治县19219003455: 安卓系统怎样实现输入法手写整句输入谢谢了,大神帮忙啊 - ?
沈沫熊胆: 下个搜狗或shi百度输入法可以了 查看原帖>>
新平彝族傣族自治县19219003455: 开发Android时,如何实现TextView文字逐个打出的效果? - ?
沈沫熊胆: 其实这个最笨的实现方法就是弄一个for循环,你要输出的内容是str for(int i=1;i{ textview.setText(str.subString(0,i)); } 当然这回很快!这只是一个思路,你可以启一个线程,每隔多少毫秒执行一次这个循环的内容
新平彝族傣族自治县19219003455: 一个android开发的问题:如何实现输入内容后自动保存,即按返回后再打开或程序关闭后再打开输入的内容还在 - ?
沈沫熊胆: 恩,最普通的输入框EditText就行. 不过要实现还得自己控制. 就是说在此Activity的onstop()方法中,实现保存此字符串(保存数据库或本地都行); 在Activity的onresume方法中取出你保存的字符串,然后editText.setText(str),就可以看到了. 如果说程序关闭后还在,你要在onDestroy()方法中保存,onCreate方法里取出显示.