android项目 之 记事本(6)----- 添加手写

android项目 之 记事本(11) ----- 添加数据库 为记事本添加数据库支持,这样,就可以记事进行保存,修改,查看,删除等操作,这里面涉及到将图片以及录音文件存储到数据库中,这里并不是才用将图片及录音本身存储到数据库,而是将其所在的路径存储到数据库,在查看,修改时,从数据库中读取出路径,主要是用到了正则表达式来识别数据库中的路径,从而根据路径取出源文件。 阅读详情

       想必大家都用过QQ的白板功能,里面主要有两项,一个是涂鸦功能,其实类似于上节的画板功能,而另一个就是手写,那记事本怎么能没有这个功能呢,今天就来为我们的记事本添加手写功能。

       先上图,看看效果:

       看了效果图,是不是心动了呢?那就赶紧着手做吧,其实,手写功能并不难实现,大体就是全屏书写,定时发送handle消息,更新activity。

       实现手写功能的主要步骤:

             1. 自定义两个View,一个是TouchView,用于在上面画图,另一个是EditText,用于将手写的字显示在其中,并且,要将两个自定义View通过FrameLayout帧式布局重叠在起,以实现全屏手写的功能。

             2  在TouchView中实现写字,并截取画布中的字以Bitmap保存。

             3. 设置定时器,利用handle更新界面。

       

        下面是实现的细节:

            1. 手写的界面设计:

                      如上图所示,和上节的画板界面一致,底部分选项菜单栏,有5个选项,分别是调整画笔大小,画笔颜色,撤销,恢复,以及清空,对于这些功能,之后几节再实现。

                    布局文件activity_handwrite.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
     >

  	<FrameLayout
 	android:layout_width="fill_parent"
  	android:layout_height="wrap_content"
  	android:id="@+id/finger_layout"  
  	>
        
        <com.example.notes.LineEditText
        android:id="@+id/et_handwrite"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:fadingEdge="vertical"
        android:inputType="textMultiLine"
        android:gravity="top"
        android:textSize="20sp"
        android:layout_margin="5dp"
        android:focusable="true"
        android:lineSpacingExtra="10dp"
        android:textColor="#00000000"
        android:background="#00000000"
        
        />
        
 	  <com.example.notes.TouchView
        	android:id="@+id/touch_view"
        	android:layout_width="fill_parent"
        	android:layout_height="wrap_content"
        	android:background="@android:color/transparent" >
     </com.example.notes.TouchView>
  	
    
    </FrameLayout>
    <ImageView 
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:src="@drawable/line"
      android:layout_above="@+id/paintBottomMenu"
      />
   
    <GridView 
       android:id="@+id/paintBottomMenu" 
       android:layout_width="match_parent"
       android:layout_height="45dp"
       android:numColumns="auto_fit"
       android:background="@drawable/navigationbar_bg"
       android:horizontalSpacing="10dp"
       android:layout_alignParentBottom="true"
       ></GridView>

</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中,具体如下:

	private LineEditText et_handwrite;      
	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);
	   }
	    

            这样,就实现了手写的功能,下节就实现手写字的撤销,恢复,以及清空的功能。

                 

            

              

 

 

 

      

手写控件HandWrite 飞米手写控件,完全免费,没有任何限制,封装为OCX。支持Delphi,VC,VB,C#等 立即下载

相关推荐

大疆OcuSync系统背后的黑科技:跳频扩频技术如何让你的无人机飞得更稳

本文深入解析了大疆OcuSync系统如何运用跳频扩频技术等先进无线通信方案,显著提升无人机在复杂环境下的飞行稳定性。系统通过跳频扩频与直接序列扩频技术协同工作,结合双频智能切换与多天线MIMO,有效对抗信号干扰与多径效应,确保控制指令与高清图传的可靠、低延迟传输,为用户带来更安心、更流畅的飞行体验。

ol7890123的博客 630

AndroidStudio实现在图片上涂鸦并记录涂鸦轨迹

AndroidStudio实现在图片上涂鸦并记录涂鸦轨迹

weixin_51143190的博客 2401

告别密码本!用Windows NPS给华为/华三交换机做Radius认证,SSH登录更安全

本文详细介绍了如何利用Windows NPS实现华为/华三交换机的Radius认证,提升SSH登录安全性。通过集中化管理、精细化控制和完整审计追踪,企业可告别传统密码本,大幅提升网络设备管理效率。文章包含NPS服务部署指南、交换机配置详解及调试技巧,助力企业构建安全高效的统一认证体系。

weixin_42549723的博客 419

Android——记事本功能业务(完整代码)

一、搭建记事本页面布局activity_notepad.xml 二、搭建记事本界面Item布局notepad_item_layout.xml 三、封装记录信息实体类NotepadBean类 四、编写记事本界面列表适配器NotepadAdapter类 五、创建数据库 六、实现记事本界面的显示功能 七、搭建添加记录界面和修改记录界面的布局 八、实现添加记录界面的功能 九、实现修改记录界面的功能 十、删除记事本中的记录

weixin_72634509的博客 2万+

普源精电DHO系列示波器选购指南:从学生党到工程师的完整对比

本文深入评测普源精电DHO系列示波器,从DHO800到DHO4000各型号的核心参数、功能特点及适用场景进行全面对比,帮助学生党和工程师根据实际需求选择最佳型号。重点分析带宽、采样率、存储深度等关键指标,并提供实用的选购建议和进阶使用技巧,帮助用户充分发挥示波器性能。

weixin_30485379的博客 167

Open3D 体素下采样【2026最新版】

体素滤波,博客长期更新,本文最近更新时间为:2026年4月11日。

点云侠的博客 37万+

Android记事本

记事本

QZHliangzai的博客 2775

OpenTK简介

OpenTK 因其强大的功能、跨平台特性和灵活性,适用于多种需要图形和计算能力的应用场景,为开发者提供了丰富的可能性和创作空间。

仰望星空的博客 1980

基于Android Studio 开发的简易记事本APP

基于Android Studio 开发的简易记事本APP Android初学者开发第一个完整的基础实例项目应该就属《记事本》了,该项目基于Android Studio开发使用Java语言,该项目包含SQLlit数据库的使用、listview、等。

编程乐学的博客 9976

【科研数据获取】根据Excel表个中的企业/公司信息批量获取经纬度坐标,并进行地图可视化

批量获取企业/公司的经纬度坐标,并进行地图可视化1 需求2 实现途径3 需求逐步实现 1 需求 在做项目的时候,老板或者项目答辩时候甲方最喜欢看到的就是可视化结果,尤其是涉及到地图可视化。很多时候会遇到企业/公司的数据,想要做地图可视化,必不可少的就是要获取它们具体地址:第一种就是像查户口一样精准一下具体的城镇街道,还有一种就是经纬度信息,前一种属于文字内容往往用于管理方面,第二种数字信息多用于数据处理与分析。 2 实现途径 获取地理信息数据,自然需要使用到地图的功能,这里直接采用百度地图的拾取坐标系统,

lys_828的博客 2337

EndNote X9 快速上手教程(毕业论文参考文献管理器)

EndNote X9 快速上手教程一、EndNote X9安装1.安装2 安装之后重要步骤二、第一次打开 EndNote三、参考文献引用1. 导入知网文献2. 参考文献引用四、常见问题1. 引用文献中出现%J的问题2 参考文献中出现et.al1 在文章中引用的编号的地方出现2 在参看文献列表里出现 一、EndNote X9安装 1.安装 打开文件夹 安装前,一定要读 #Readme.txt 文件 一定要把License.dat和ENX9Inst.msi放在同一文件夹,安装的时候会自动激活。 我的安装路

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 2万+

实现一个简单的记事本APP

Android中简单记事本的实现

alhbr的博客 4793

泛微OA集成阿里云短信(E9保姆教程)

泛微OA集成阿里云短信(E9保姆教程)

技术分享 517

android项目 之 记事本(15) ----- 保存手写及绘图

将手写和绘图以图片的形式保存到指定目录下,并以时间作为文件名。

jesson20121020的专栏 5908

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

android 记事本软件,安卓日历记事本软件

哪款手机记事本或者日历软件比较好这些都可以使用系统自带的,自己的记事本都差不多,严格来讲,这类功能单一的东西差别还是比较小的,苹果的有手写功能,锤子便签可以写markdown,还有魅族的便签,各有特色吧,其实差异不大,主要是自己多用用习惯就好。至于日历,个人一直都是outlook,这个是第三方的,各个平台都有。自带日历主要是看日期的话,其实都一样。万年历可以自己下载一个,现在一般都自带农历了。哪款...

weixin_33162074的博客 956

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

android 记事本demo_android开发中如何实现手写输入的记事本

展开全部实现手写功能的主要步骤:1. 自定义两个View,一个是TouchView,用于在上面画图,另一个是EditText,用于将手写的字显32313133353236313431303231363533e4b893e5b19e31333337613236示在其中,并且,要将两个自定义View通过FrameLayout帧式布局重叠在起,以实现全屏手写的功能。2 在TouchView中实现写字,并...

weixin_39612220的博客 765

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

android项目 之 记事本(7)----- 手写功能之删除、恢复和清空

为手写功能添加删除,恢复,清空的功能

jesson20121020的专栏 3956

【安卓开发】开源Notepad记事本APP项目(完整代码+说明文档)

记事本app

我们都有光明的未来 5448

android记事本 图文存储,android项目 之 记事本(15) ----- 保存手写及绘图

之前,忘了写如何将手写和绘图保存,现在补上。首先看如何保存绘图,先看效果图:因为记事本的绘图功能主要用到了画布,而在构建画布时,指定了Bitmap,也就是说在画布上的所画的东西都被保存在了Bitmap中,因此,我们只要保存该Bitmap,就可以将我们的所绘制的图形以图片的形式保存,主要代码如下:/** 保存所绘图形* 返回绘图文件的存储路径* */public String saveBitmap(...

weixin_39608132的博客 641

android记事本全选删除,android项目 之 记事本(7)----- 手写功能之删除、恢复和清空...

上一节,为记事本添加了手写的功能,但是没有实现底部按钮的各种功能,这节就先实现撤销,恢复和清空的功用。因为不会录制屏幕成gif图片,所以就以图片形式给出吧,不是很形象,凑合着看:显然,需要为底部GridView的添加item单击事件:private GridView paint_bottomMenu;paint_bottomMenu = (GridView)findViewById(R.id.pa...

weixin_42509708的博客 620

android记事本全选删除,android项目 之 记事本(7)----- 手写功能之删除、恢复和清空...

上一节,为记事本添加了手写的功能,但是没有实现底部按钮的各种功能,这节就先实现撤销,恢复和清空的功用。因为不会录制屏幕成gif图片,所以就以图片形式给出吧,不是很形象,凑合着看: 显然,需要为底部GridView的添加item单击事件:private GridView paint_bottomMenu;paint_bottomMenu = (GridView)findViewById(R.id...

weixin_39670849的博客 325

android手写缓存图片工具,android项目 之 记事本(15) ----- 保存手写及绘图

本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog..net/jesson20121020之前,忘了写如何将手写和绘图保存,现在补上。首先看如何保存绘图,先看效果图:因为记事本的绘图功能主要用到了画布,而在构建画布时,指定了Bitmap,也就是说在画布上的所画的东西都被保存在了Bitmap中,因此,我们只要保存该Bitmap,就可以将我们的所绘制的图形以图片的形式保存,主要代码...

weixin_36033417的博客 330

android项目 之 记事本(6)----- 加入手写

想必大家都用过QQ的白板功能,里面主要有两项,一个是涂鸦功能,事实上类似于上节的画板功能,而还有一个就是手写,那记事本怎么能没有这个功能呢,今天就来为我们的记事本加入手写功能。 先上图,看看效果: 看了效果图,是不是心动了呢?那就赶紧着手做吧,事实上,手写功能并不难实现,大体就是全屏书写,定时发送handle消息,更新activi...

weixin_30563319的博客 130

android记事本改变字体颜色,android项目 之 记事本(10) ----- 手写功能之设置画笔大小和画笔颜色...

上一节,实现了画板的所有功能,包括设置画笔大小,设置画笔颜色,橡皮擦等功能,而手写,也可以添加设置笔迹大小和颜色的功能,这节就顺势实现手写的调整笔迹大小和调整笔迹的颜色。先看图:其实,手写和画板的这些功能都类似,直接复用之前的代码就行,原理如下:1. 设置画笔大小的功能:1)初始化画笔。2)设置画笔的大小为所选择的大小。3)用一个变量记住当前画笔的大小,用于在进行其他操作后还保持之前设置的画笔大小...

weixin_31699893的博客 668

android项目 之 记事本(10) ----- 手写功能之设置画笔大小和画笔颜色

android实现手写功能中的设置画笔的大小和颜色的功能,这样,就可以用不同颜色,不同大小的画笔书写字。

jesson20121020的专栏 3549
上一篇: 数据结构(C实现)------- 单链表
下一篇: android项目 之 记事本(7)----- 手写功能之删除、恢复和清空
jesson20121020
博客等级 码龄15年 361粉丝 99原创
评论 25
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值