一,功能

拍照
添加画板
录音
书写转文字
添加图片

1,主页面

2,功能

二 ,实现

贴代码:

1,AndroidManifest.xml文件(添加权限)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.llw.notes"><uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="21" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-feature android:name="android.hardware.camera" /><uses-featureandroid:name="android.hardware.camera.autofocus"android:required="false" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:requestLegacyExternalStorage="true"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.AppCompat.Light"><activityandroid:name=".ShowRecord"android:exported="true" ></activity><activityandroid:name=".ShowPicture"android:exported="true"></activity><activityandroid:name=".HandWriteActivity"android:exported="true" /><activityandroid:name=".ActivityRecord"android:exported="true" /><activityandroid:name=".PaintActivity"android:exported="true" /><activityandroid:name=".AddActivity"android:exported="true" ></activity><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

2,Activity文件

ActivityRecord

package com.llw.notes;import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;public class ActivityRecord extends AppCompatActivity {private Button btn_record;private int isRecording = 0;private int isPlaying = 0;//语音保存路径private String FilePath = null;private Timer mTimer;private ImageView iv_microphone;private TextView tv_recordTime;private ImageView iv_record_wave_left,iv_record_wave_right;private AnimationDrawable ad_left,ad_right;//语音操作对象private MediaPlayer mPlayer = null;private MediaRecorder mRecorder = null;Button btn_save;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_record);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();btn_save = findViewById(R.id.bt_save);btn_save.setOnClickListener(new ClickEvent());Button btn_back = (Button)findViewById(R.id.bt_back);btn_back.setOnClickListener(new ClickEvent());btn_record = (Button)findViewById(R.id.btn_record);btn_record.setOnClickListener(new ClickEvent());iv_microphone = (ImageView)findViewById(R.id.iv_microphone);iv_microphone.setOnClickListener(new ClickEvent());iv_record_wave_left = (ImageView)findViewById(R.id.iv_record_wave_left);iv_record_wave_right = (ImageView)findViewById(R.id.iv_record_wave_right);
//        ad_left = (AnimationDrawable)iv_record_wave_left.getBackground();
//        ad_left = (AnimationDrawable)iv_record_wave_left.getBackground();// 通过逐帧动画的资源文件获得AnimationDrawable示例iv_record_wave_left.setImageResource(R.drawable.record_wave_left);iv_record_wave_right.setImageResource(R.drawable.record_wave_right);ad_left=((AnimationDrawable) iv_record_wave_left.getDrawable());ad_right=((AnimationDrawable) iv_record_wave_right.getDrawable());tv_recordTime = (TextView)findViewById(R.id.tv_recordTime);}final Handler handler = new Handler(){public void handleMessage(Message msg) {switch(msg.what){case 1 :String time[] = tv_recordTime.getText().toString().split(":");int hour = Integer.parseInt(time[0]);int minute = Integer.parseInt(time[1]);int second = Integer.parseInt(time[2]);if(second < 59){second++;}else if(second == 59 && minute < 59){minute++;second = 0;}if(second == 59 && minute == 59 && hour < 98){hour++;minute = 0;second = 0;}time[0] = hour + "";time[1] = minute + "";time[2] = second + "";//调整格式显示到屏幕上if(second < 10)time[2] = "0" + second;if(minute < 10)time[1] = "0" + minute;if(hour < 10)time[0] = "0" + hour;//显示在TextView中tv_recordTime.setText(time[0]+":"+time[1]+":"+time[2]);break;}}};class ClickEvent implements View.OnClickListener {@Overridepublic void onClick(View v) {switch(v.getId()){//点击的是开始录音按钮case  R.id.btn_record ://开始录音if(isRecording == 0){//每一次调用录音,可以录音多次,至多满意为至,最后只将最后一次的录音文件保存,其他的删除if(FilePath != null){File oldFile = new File(FilePath);oldFile.delete();}//获得系统当前时间,并以该时间作为文件名SimpleDateFormat formatter   =   new   SimpleDateFormat   ("yyyyMMddHHmmss");Date curDate   =   new   Date(System.currentTimeMillis());//获取当前时间String   str   =   formatter.format(curDate);str = str + "record.amr";File dir = new File("/sdcard/notes/");File file = new File("/sdcard/notes/",str);if (!dir.exists()) {dir.mkdir();}else{if(file.exists()){file.delete();}}FilePath = dir.getPath() +"/"+ str;//计时器mTimer = new Timer();//将麦克图标设置成不可点击,iv_microphone.setClickable(false);//将显示的时间设置为00:00:00tv_recordTime.setText("00:00:00");//将按钮换成停止录音isRecording = 1;btn_record.setBackgroundResource(R.drawable.tabbar_record_stop);mRecorder = new MediaRecorder();mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);mRecorder.setOutputFile(FilePath);mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);try {mRecorder.prepare();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}mRecorder.start();mTimer.schedule(new TimerTask() {@Overridepublic void run() {Message message = new Message();message.what = 1;handler.sendMessage(message);}},1000, 1000);//播放动画ad_left.start();ad_right.start();}//停止录音else{//将按钮换成开始录音isRecording = 0;btn_record.setBackgroundResource(R.drawable.tabbar_record_start);mRecorder.stop();mTimer.cancel();mTimer = null;mRecorder.release();mRecorder = null;//将麦克图标设置成可点击,iv_microphone.setClickable(true);//停止动画ad_left.stop();ad_right.stop();Toast.makeText(ActivityRecord.this, "单击麦克图标试听,再次点击结束试听", Toast.LENGTH_LONG).show();}break;//如果单击的是麦克图标,则可以是进入试听模式,再次点击,停止播放case R.id.iv_microphone :if(FilePath == null)Toast.makeText(ActivityRecord.this, "没有录音广播可以播放,请先录音", Toast.LENGTH_LONG).show();else{//试听if(isPlaying == 0){isPlaying = 1;mPlayer = new MediaPlayer();tv_recordTime.setText("00:00:00");mTimer = new Timer();mPlayer.setOnCompletionListener(new MediaCompletion());try {mPlayer.setDataSource(FilePath);mPlayer.prepare();mPlayer.start();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}mTimer.schedule(new TimerTask() {@Overridepublic void run() {Message message = new Message();message.what = 1;handler.sendMessage(message);}}, 1000,1000);//播放动画ad_left.start();ad_right.start();}//结束试听else{isPlaying = 0;mPlayer.stop();mPlayer.release();mPlayer = null;mTimer.cancel();mTimer = null;//停止动画ad_left.stop();ad_right.stop();}}break;//点击确定按钮case R.id.bt_save ://将最终的录音文件的路径返回Intent intent = getIntent();Bundle b = new Bundle();b.putString("audio", FilePath);intent.putExtras(b);setResult(RESULT_OK, intent);ActivityRecord.this.finish();break;case R.id.bt_back ://返回前将录音的文件删除if(FilePath != null){File oldFile = new File(FilePath);oldFile.delete();}ActivityRecord.this.finish();break;}}}class MediaCompletion implements MediaPlayer.OnCompletionListener {@Overridepublic void onCompletion(MediaPlayer mp) {mTimer.cancel();mTimer = null;isPlaying = 0;//停止动画ad_left.stop();ad_right.stop();Toast.makeText(ActivityRecord.this, "播放完毕", Toast.LENGTH_LONG).show();tv_recordTime.setText("00:00:00");}}
}

AddActivity

package com.llw.notes;import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ImageSpan;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class AddActivity extends AppCompatActivity {private GridView bottomMenu;private LineEditText et_Notes;private Button bt_back;private Button bt_save;private SQLiteDatabase db;private DatabaseOperation dop;Intent intent;String editModel = null;int item_Id;InputMethodManager imm;//底部按钮private int[] bottomItems = {R.drawable.tabbar_handwrite,R.drawable.tabbar_paint,R.drawable.tabbar_microphone,R.drawable.tabbar_photo,R.drawable.tabbar_camera,R.drawable.tabbar_appendix};//记录editText中的图片,用于单击时判断单击的是那一个图片private List<Map<String,String>> imgList = new ArrayList<Map<String,String>>();//配置底部菜单private void initBottomMenu(){ArrayList<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();for(int i = 0;i < bottomItems.length;i++){Map<String,Object> item = new HashMap<String,Object>();item.put("image",bottomItems[i]);menus.add(item);}bottomMenu.setNumColumns(bottomItems.length);bottomMenu.setSelector(R.drawable.bottom_item);SimpleAdapter mAdapter = new SimpleAdapter(AddActivity.this, menus,R.layout.item_button, new String[]{"image"}, new int[]{R.id.item_image});bottomMenu.setAdapter(mAdapter);}private TextView tv_title;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_add);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();et_Notes = (LineEditText)findViewById(R.id.et_note);et_Notes.setOnClickListener(new TextClickEvent());bottomMenu = (GridView)findViewById(R.id.bottomMenu);//配置菜单initBottomMenu();bottomMenu.setOnItemClickListener(new MenuClickEvent());bt_back = (Button)findViewById(R.id.bt_back);bt_back.setOnClickListener(new ClickEvent());bt_save = (Button)findViewById(R.id.bt_save);bt_save.setOnClickListener(new ClickEvent());//默认关闭软键盘,可以通过失去焦点设置//et_Notes.setFocusable(false);imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(et_Notes.getWindowToken(),0);dop = new DatabaseOperation(this,db);intent = getIntent();editModel = intent.getStringExtra("editModel");item_Id = intent.getIntExtra("noteId", 0);tv_title = (TextView)findViewById(R.id.tv_title);loadData();}//为EidtText设置监听器class TextClickEvent implements View.OnClickListener {@Overridepublic void onClick(View v) {Spanned s = et_Notes.getText();ImageSpan[] imageSpans;imageSpans = s.getSpans(0, s.length(), ImageSpan.class);int selectionStart = et_Notes.getSelectionStart();for(ImageSpan span : imageSpans){int start = s.getSpanStart(span);int end = s.getSpanEnd(span);//找到图片if(selectionStart >= start && selectionStart < end){//Bitmap bitmap = ((BitmapDrawable)span.getDrawable()).getBitmap();//查找当前单击的图片是哪一个图片//System.out.println(start+"-----------"+end);String path = null;for(int i = 0;i < imgList.size();i++){Map map = imgList.get(i);//找到了if(map.get("location").equals(start+"-"+end)){path = imgList.get(i).get("path");break;}}//接着判断当前图片是否是录音,如果为录音,则跳转到试听录音的Activity,如果不是,则跳转到查看图片的界面//录音,则跳转到试听录音的Activityif(path.substring(path.length()-3, path.length()).equals("amr")){Intent intent = new Intent(AddActivity.this,ShowRecord.class);intent.putExtra("audioPath", path);startActivity(intent);}//图片,则跳转到查看图片的界面else{//有两种方法,查看图片,第一种就是直接调用系统的图库查看图片,第二种是自定义Activity//调用系统图库查看图片/*Intent intent = new Intent(Intent.ACTION_VIEW);File file = new File(path);Uri uri = Uri.fromFile(file);intent.setDataAndType(uri, "image/*");*///使用自定义ActivityIntent intent = new Intent(AddActivity.this,ShowPicture.class);intent.putExtra("imgPath", path);startActivity(intent);}}else//如果单击的是空白出或文字,则获得焦点,即打开软键盘imm.showSoftInput(et_Notes, 0);}}}//加载数据private void loadData(){//如果是新增记事模式,则将editText清空if(editModel.equals("newAdd")){et_Notes.setText("");}//如果编辑的是已存在的记事,则将数据库的保存的数据取出,并显示在EditText中else if(editModel.equals("update")){tv_title.setText("编辑记事");dop.create_db();Cursor cursor = dop.query_db(item_Id);cursor.moveToFirst();//取出数据库中相应的字段内容@SuppressLint("Range") String context = cursor.getString(cursor.getColumnIndex("context"));//定义正则表达式,用于匹配路径Pattern p=Pattern.compile("/([^\\.]*)\\.\\w{3}");Matcher m=p.matcher(context);int startIndex = 0;while(m.find()){//取出路径前的文字if(m.start() > 0){et_Notes.append(context.substring(startIndex, m.start()));}SpannableString ss = new SpannableString(m.group().toString());//取出路径String path = m.group().toString();//取出路径的后缀String type = path.substring(path.length() - 3, path.length());Bitmap bm = null;Bitmap rbm = null;//判断附件的类型,如果是录音文件,则从资源文件中加载图片if(type.equals("amr")){bm = BitmapFactory.decodeResource(getResources(), R.drawable.record_icon);//缩放图片rbm = resize(bm,200);}else{//取出图片bm = BitmapFactory.decodeFile(m.group());//缩放图片rbm = resize(bm,480);}//为图片添加边框效果rbm = getBitmapHuaSeBianKuang(rbm);System.out.println(rbm.getWidth()+"-------"+rbm.getHeight());ImageSpan span = new ImageSpan(this, rbm);ss.setSpan(span,0, m.end() - m.start(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);et_Notes.append(ss);startIndex = m.end();//用List记录该录音的位置及所在路径,用于单击事件Map<String,String> map = new HashMap<String,String>();map.put("location", m.start()+"-"+m.end());map.put("path", path);imgList.add(map);}//将最后一个图片之后的文字添加在TextView中et_Notes.append(context.substring(startIndex,context.length()));dop.close_db();}}//等比例缩放图片private Bitmap resize(Bitmap bitmap,int S){int imgWidth = bitmap.getWidth();int imgHeight = bitmap.getHeight();double partion = imgWidth*1.0/imgHeight;double sqrtLength = Math.sqrt(partion*partion + 1);//新的缩略图大小double newImgW = S*(partion / sqrtLength);double newImgH = S*(1 / sqrtLength);float scaleW = (float) (newImgW/imgWidth);float scaleH = (float) (newImgH/imgHeight);Matrix mx = new Matrix();//坐标//对原图片进行缩放mx.postScale(scaleW, scaleH);bitmap = Bitmap.createBitmap(bitmap, 0, 0, imgWidth, imgHeight, mx, true);return bitmap;}//给图片加边框,并返回边框后的图片public Bitmap getBitmapHuaSeBianKuang(Bitmap bitmap) {float frameSize = 0.2f;Matrix matrix = new Matrix();// 用来做底图Bitmap bitmapbg = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);// 设置底图为画布Canvas canvas = new Canvas(bitmapbg);canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG));float scale_x = (bitmap.getWidth() - 2 * frameSize - 2) * 1f/ (bitmap.getWidth());float scale_y = (bitmap.getHeight() - 2 * frameSize - 2) * 1f/ (bitmap.getHeight());matrix.reset();matrix.postScale(scale_x, scale_y);// 对相片大小处理(减去边框的大小)bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, true);Paint paint = new Paint();paint.setColor(Color.WHITE);paint.setStrokeWidth(1);paint.setStyle(Paint.Style.FILL);// 绘制底图边框canvas.drawRect(new Rect(0, 0, bitmapbg.getWidth(), bitmapbg.getHeight()),paint);// 绘制灰色边框paint.setColor(Color.BLUE);canvas.drawRect(new Rect((int) (frameSize), (int) (frameSize), bitmapbg.getWidth() - (int) (frameSize), bitmapbg.getHeight()- (int) (frameSize)), paint);canvas.drawBitmap(bitmap, frameSize + 1, frameSize + 1, paint);return bitmapbg;}//设置按钮监听器class ClickEvent implements View.OnClickListener {@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.bt_back ://当前Activity结束,则返回上一个ActivityAddActivity.this.finish();break;//将记事添加到数据库中case R.id.bt_save ://取得EditText中的内容String context = et_Notes.getText().toString();if(context.isEmpty()){Toast.makeText(AddActivity.this, "记事为空!", Toast.LENGTH_LONG).show();}else{//取得当前时间SimpleDateFormat formatter   =   new   SimpleDateFormat   ("yyyy-MM-dd HH:mm");Date curDate   =   new   Date(System.currentTimeMillis());//获取当前时间String   time   =   formatter.format(curDate);//截取EditText中的前一部分作为标题,用于显示在主页列表中String title = (String) getTitle(context);//打开数据库dop.create_db();//判断是更新还是新增记事if(editModel.equals("newAdd")){//将记事插入到数据库中dop.insert_db(title,context,time);}//如果是编辑则更新记事即可else if(editModel.equals("update")){dop.update_db(title,context,time,item_Id);}dop.close_db();Intent intent=new Intent(AddActivity.this,MainActivity.class);startActivity(intent);//结束当前activityAddActivity.this.finish();}break;}}}//截取EditText中的前一部分作为标题,用于显示在主页列表中private String getTitle(String context){//定义正则表达式,用于匹配路径Pattern p=Pattern.compile("/([^\\.]*)\\.\\w{3}");Matcher m=p.matcher(context);StringBuffer strBuff = new StringBuffer();String title = "";int startIndex = 0;while(m.find()){//取出路径前的文字if(m.start() > 0){strBuff.append(context.substring(startIndex, m.start()));}//取出路径String path = m.group().toString();//取出路径的后缀String type = path.substring(path.length() - 3, path.length());//判断附件的类型if(type.equals("amr")){strBuff.append("[录音]");}else{strBuff.append("[图片]");}startIndex = m.end();//只取出前15个字作为标题if(strBuff.length() > 15){//统一将回车,等特殊字符换成空格title = strBuff.toString().replaceAll("\r|\n|\t", " ");return title;}}strBuff.append(context.substring(startIndex, context.length()));//统一将回车,等特殊字符换成空格title = strBuff.toString().replaceAll("\r|\n|\t", " ");return title;}//设置菜单项监听器class MenuClickEvent implements AdapterView.OnItemClickListener {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {Intent intent;switch(position){//手写case 0:intent = new Intent(AddActivity.this,HandWriteActivity.class);startActivityForResult(intent, 5);break;//绘图case 1:intent = new Intent(AddActivity.this,PaintActivity.class);startActivityForResult(intent, 3);break;//语音case 2:intent = new Intent(AddActivity.this,ActivityRecord.class);startActivityForResult(intent, 4);break;//照片case 3:intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");startActivityForResult(intent, 1);break;//拍照case 4 ://调用系统拍照界面intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//区分选择相片startActivityForResult(intent, 2);//附件case 5 :break;}}}//将图片等比例缩放到合适的大小并添加在EditText中void InsertBitmap(Bitmap bitmap,int S,String imgPath){bitmap = resize(bitmap,S);//添加边框效果bitmap = getBitmapHuaSeBianKuang(bitmap);//bitmap = addBigFrame(bitmap,R.drawable.line_age);final ImageSpan imageSpan = new ImageSpan(this,bitmap);SpannableString spannableString = new SpannableString(imgPath);spannableString.setSpan(imageSpan, 0, spannableString.length(), SpannableString.SPAN_MARK_MARK);//光标移到下一行//et_Notes.append("\n");Editable editable = et_Notes.getEditableText();int selectionIndex = et_Notes.getSelectionStart();spannableString.getSpans(0, spannableString.length(), ImageSpan.class);//将图片添加进EditText中editable.insert(selectionIndex, spannableString);//添加图片后自动空出两行et_Notes.append("\n");//用List记录该录音的位置及所在路径,用于单击事件Map<String,String> map = new HashMap<String,String>();map.put("location", selectionIndex+"-"+(selectionIndex+spannableString.length()));map.put("path", imgPath);imgList.add(map);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if(resultCode == RESULT_OK){//取得数据Uri uri = data.getData();ContentResolver cr = AddActivity.this.getContentResolver();Bitmap bitmap = null;Bundle extras = null;//如果是选择照片if(requestCode == 1){// 这里开始的第二部分,获取图片的路径:String[] proj = {MediaStore.Images.Media.DATA};Cursor cursor = managedQuery(uri, proj, null, null, null);//按我个人理解 这个是获得用户选择的图片的索引值int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);cursor.moveToFirst();
//最后根据索引值获取图片路径String path = cursor.getString(column_index);System.out.println("pppppp:"+path);try {//将对象存入Bitmap中bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}//插入图片InsertBitmap(bitmap,480,path);}//如果选择的是拍照else if(requestCode == 2){System.out.println("-----fjwefowefwef");;try {if(uri != null)//这个方法是根据Uri获取Bitmap图片的静态方法bitmap = MediaStore.Images.Media.getBitmap(cr, uri);//这里是有些拍照后的图片是直接存放到Bundle中的所以我们可以从这里面获取Bitmap图片else{extras = data.getExtras();bitmap = extras.getParcelable("data");}//将拍的照片存入指定的文件夹下//获得系统当前时间,并以该时间作为文件名SimpleDateFormat   formatter   =   new   SimpleDateFormat   ("yyyyMMddHHmmss");Date   curDate   =   new   Date(System.currentTimeMillis());//获取当前时间String   str   =   formatter.format(curDate);String paintPath = "";str = str + "paint.png";File dir = new File("/sdcard/notes/");File file = new File("/sdcard/notes/",str);if (!dir.exists()) {dir.mkdir();}else{if(file.exists()){file.delete();}}FileOutputStream fos = new FileOutputStream(file);// 将 bitmap 压缩成其他格式的图片数据bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);fos.flush();fos.close();String path = "/sdcard/notes/" + str;//插入图片System.out.println("tttttttttt:"+path);InsertBitmap(bitmap,480,path);} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//返回的是绘图后的结果else if(requestCode == 3){extras = data.getExtras();String path = extras.getString("paintPath");//通过路径取出图片,放入bitmap中bitmap = BitmapFactory.decodeFile(path);//插入绘图文件InsertBitmap(bitmap,480,path);}//返回的是录音文件else if(requestCode == 4){extras = data.getExtras();String audioPath = extras.getString("audio");bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.record_microphone_icon);//插入录音图标InsertBitmap(bitmap,80,audioPath);}//返回的是手写文件else if(requestCode == 5){extras = data.getExtras();String path = extras.getString("handwritePath");//通过路径取出图片,放入bitmap中bitmap = BitmapFactory.decodeFile(path);//插入绘图文件InsertBitmap(bitmap,680,path);}}}
}

DatabaseOperation

package com.llw.notes;import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.Toast;public class DatabaseOperation {private SQLiteDatabase db;private Context context;public DatabaseOperation(Context context,SQLiteDatabase db) {this.db = db;this.context = context;}//数据库的打开或创建public void create_db(){//创建或打开数据库db = SQLiteDatabase.openOrCreateDatabase(context.getFilesDir().toString()+"/mynotes.db3", null);db.execSQL("DROP TABLE IF EXISTS studentScore");if(db == null){Toast.makeText(context,"数据库创建不成功",Toast.LENGTH_LONG).show();}//Toast.makeText(context,"数据库创建成功",Toast.LENGTH_LONG).show();//创建表db.execSQL("create table if not exists notes(_id integer primary key autoincrement," +"title text," +"context text," +"time varchar(20))");}public void insert_db(String title,String text,String time){if(text.isEmpty()){Toast.makeText(context, "各字段不能为空", Toast.LENGTH_LONG).show();}else{db.execSQL("insert into notes(title,context,time) values('"+ title+"','"+ text+ "','"+time+"');");//Toast.makeText(context, "插入成功", Toast.LENGTH_LONG).show();}}public void update_db(String title,String text,String time,int item_ID){if( text.isEmpty()){Toast.makeText(context, "各字段不能为空", Toast.LENGTH_LONG).show();}else{//String sql = "update main set class1='" + class1 + "',class2='" + class2 + "',class3='" + class4 + "',class4='" + class4 + "'where days='" + days + "';";db.execSQL("update notes set context='"+text+ "',title='"+title+"',time='"+time+"'where _id='" + item_ID+"'");//Toast.makeText(context, "修改成功", Toast.LENGTH_LONG).show();}}public Cursor query_db(){Cursor cursor = db.rawQuery("select * from notes",null);return cursor;}public Cursor query_db(int item_ID){Cursor cursor = db.rawQuery("select * from notes where _id='"+item_ID+"';",null);return cursor;}public void delete_db(int item_ID){db.execSQL("delete from notes where _id='" + item_ID+"'");//Toast.makeText(context, "删除成功", Toast.LENGTH_LONG).show();}//关闭数据库public void close_db(){db.close();}
}

GetCutBitampLocation

package com.llw.notes;public class GetCutBitmapLocation {private float cutLeft = 0;private float cutTop = 0;private float cutRight = 0;private float cutBottom = 0;public void init(float x,float y){cutLeft = x;cutRight = x;cutTop = y;cutBottom = y;}//更新手写字的左右上下的位置public void setCutLeftAndRight(float x,float y){cutLeft = (x < cutLeft ? x : cutLeft);cutRight = (x > cutRight ? x : cutRight);cutTop = (y < cutTop ? y : cutTop);cutBottom = (y > cutBottom ? y : cutBottom);}//返回手写字的切割位置public float getCutLeft(){return cutLeft;}public float getCutTop(){return cutTop;}public float getCutRight(){return cutRight;}public float getCutBottom(){return cutBottom;}}

HandWriteActivity

package com.llw.notes;import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class HandWriteActivity extends AppCompatActivity {private LinearLayout paintLayout;private GridView paint_bottomMenu;private LineEditText et_handwrite;private TouchView touchView;private ArrayList<CharSequence> deleteChar = new ArrayList<CharSequence>();//菜单资源private int[]  paintItems = {R.drawable.paint_pencil,R.drawable.paint_icon_color,R.drawable.paint_icon_back,R.drawable.paint_icon_forward,R.drawable.paint_icon_delete};private Button btn_save;private Button btn_back;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_hand_write);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();paint_bottomMenu = (GridView)findViewById(R.id.paintBottomMenu);paint_bottomMenu.setOnItemClickListener(new MenuClickEvent());et_handwrite = (LineEditText)findViewById(R.id.et_handwrite);InitPaintMenu();touchView = (TouchView)findViewById(R.id.touch_view);touchView.setHandler(handler);btn_save = (Button)findViewById(R.id.bt_save);btn_back = (Button)findViewById(R.id.bt_back);btn_save.setOnClickListener(new ClickEvent());btn_back.setOnClickListener(new ClickEvent());}class ClickEvent implements View.OnClickListener {@Overridepublic void onClick(View v) {if(v == btn_save){//得到调用该Activity的Intent对象Intent intent = getIntent();Bundle b = new Bundle();String path = saveBitmap();b.putString("handwritePath", path);intent.putExtras(b);setResult(RESULT_OK, intent);HandWriteActivity.this.finish();}else if(v == btn_back){HandWriteActivity.this.finish();}}}//保存手写文件public String saveBitmap(){//获得系统当前时间,并以该时间作为文件名SimpleDateFormat formatter   =   new   SimpleDateFormat   ("yyyyMMddHHmmss");Date curDate   =   new   Date(System.currentTimeMillis());//获取当前时间String   str   =   formatter.format(curDate);String paintPath = "";str = str + "write.png";File dir = new File("/sdcard/notes/");File file = new File("/sdcard/notes/",str);if (!dir.exists()) {dir.mkdir();}else{if(file.exists()){file.delete();}}//将view转换成图片et_handwrite.setDrawingCacheEnabled(true);et_handwrite.setDrawingCacheBackgroundColor(Color.WHITE);Bitmap cutHandwriteBitmap = Bitmap.createBitmap(et_handwrite.getDrawingCache());et_handwrite.setDrawingCacheEnabled(false);try {//保存绘图文件路径paintPath = "/sdcard/notes/" + str;FileOutputStream out = new FileOutputStream(file);cutHandwriteBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);out.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return paintPath;}//配置绘图菜单public void InitPaintMenu(){ArrayList<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();for(int i = 0;i < paintItems.length;i++){Map<String,Object> item = new HashMap<String,Object>();item.put("image",paintItems[i]);menus.add(item);}paint_bottomMenu.setNumColumns(paintItems.length);paint_bottomMenu.setSelector(R.drawable.bottom_item);SimpleAdapter mAdapter = new SimpleAdapter(HandWriteActivity.this, menus,R.layout.item_button, new String[]{"image"}, new int[]{R.id.item_image});paint_bottomMenu.setAdapter(mAdapter);}//处理界面Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Bundle bundle = new Bundle();bundle = msg.getData();Bitmap myBitmap = bundle.getParcelable("bitmap");InsertToEditText(myBitmap);}};//将手写字插入到EditText中private void InsertToEditText(Bitmap mBitmap){int imgWidth = mBitmap.getWidth();int imgHeight = mBitmap.getHeight();//缩放比例float scaleW = (float) (160f/imgWidth);float scaleH = (float) (200f/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);}//设置菜单项监听器class MenuClickEvent implements AdapterView.OnItemClickListener {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {switch(position){//画笔大小case 0:showPaintSizeDialog(view);break;//颜色case 1:showPaintColorDialog(view);break;//删除case 2:Editable editable = et_handwrite.getText();//找到最后一个手写字,并删除最后一个手写字int selectionEnd = et_handwrite.getSelectionEnd();System.out.println("end = "+ selectionEnd);if(selectionEnd < 1){et_handwrite.setText("");}else if(selectionEnd == 1){et_handwrite.setText("");CharSequence deleteCharSeq = editable.subSequence(0,1);deleteChar.add(deleteCharSeq);}else{System.out.println("delete");CharSequence charSeq = editable.subSequence(0, selectionEnd - 1);CharSequence deleteCharSeq = editable.subSequence(selectionEnd - 1,selectionEnd);et_handwrite.setText(charSeq);et_handwrite.setSelection(selectionEnd - 1);//将删除的字存储到列表中,以便恢复使用deleteChar.add(deleteCharSeq);}break;//恢复case 3://取出删除列表中的元素int length = deleteChar.size();if(length > 0){et_handwrite.append(deleteChar.get(deleteChar.size()-1));deleteChar.remove(deleteChar.size()-1);}break;//清空屏幕case 4 :if(et_handwrite.getSelectionEnd() > 0){AlertDialog.Builder builder = new AlertDialog.Builder(HandWriteActivity.this);builder.setTitle("您确定要清空所有吗?");builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {et_handwrite.setText("");dialog.cancel();}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.cancel();}});Dialog dialog = builder.create();dialog.show();}break;default :break;}}}private int select_handwrite_color_index = 0;private int select_handwrite_size_index = 0;//弹出画笔大小选项对话框public void showPaintSizeDialog(View parent){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择画笔大小:");alertDialogBuilder.setSingleChoiceItems(R.array.paintsize, select_handwrite_size_index, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {select_handwrite_size_index = which;touchView.selectHandWritetSize(which);dialog.dismiss();}});alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});alertDialogBuilder.create().show();}//弹出画笔颜色选项对话框public void showPaintColorDialog(View parent){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择画笔颜色:");alertDialogBuilder.setSingleChoiceItems(R.array.paintcolor, select_handwrite_color_index, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {select_handwrite_color_index = which;touchView.selectHandWriteColor(which);dialog.dismiss();}});alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});alertDialogBuilder.create().show();}
}

LineEditActivity

package com.llw.notes;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;public class LineEditText extends androidx.appcompat.widget.AppCompatEditText {private Rect mRect;private Paint mPaint;public LineEditText(Context context, AttributeSet attrs) {// TODO Auto-generated constructor stubsuper(context,attrs);mRect = new Rect();mPaint = new Paint();mPaint.setColor(Color.GRAY);}@Overrideprotected 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);}}
}

MainActivity

package com.llw.notes;import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private Button bt_add;private SQLiteDatabase db;private DatabaseOperation dop;private ListView lv_notes;private TextView tv_note_id;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();bt_add = (Button)findViewById(R.id.bt_add);bt_add.setOnClickListener(new ClickEvent());dop = new DatabaseOperation(this, db);lv_notes = (ListView)findViewById(R.id.lv_notes);
//显示记事列表showNotesList();
//为记事列表添加监听器lv_notes.setOnItemClickListener(new ItemClickEvent());lv_notes.setOnItemLongClickListener(new ItemLongClickEvent());}//记事列表长按监听器class ItemLongClickEvent implements AdapterView.OnItemLongClickListener {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {tv_note_id = (TextView)view.findViewById(R.id.tv_note_id);int item_id = Integer.parseInt(tv_note_id.getText().toString());simpleList(item_id);return true;}}//简单列表对话框,用于选择操作public void simpleList(final int item_id){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择操作");alertDialogBuilder.setIcon(R.drawable.ic_launcher);alertDialogBuilder.setItems(R.array.itemOperation, new android.content.DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch(which){//编辑case 0 :Intent intent = new Intent(MainActivity.this,AddActivity.class);intent.putExtra("editModel", "update");intent.putExtra("noteId", item_id);startActivity(intent);break;//删除case 1 :dop.create_db();dop.delete_db(item_id);dop.close_db();//刷新列表显示lv_notes.invalidate();showNotesList();break;}}});alertDialogBuilder.create();alertDialogBuilder.show();}//显示记事列表private void showNotesList(){//创建或打开数据库dop.create_db();Cursor cursor = dop.query_db();SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.note_item,cursor,new String[]{"_id","title","time"}, new int[]{R.id.tv_note_id,R.id.tv_note_title,R.id.tv_note_time});lv_notes.setAdapter(adapter);dop.close_db();}//记事列表单击监听器class ItemClickEvent implements AdapterView.OnItemClickListener {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {tv_note_id = (TextView)view.findViewById(R.id.tv_note_id);int item_id = Integer.parseInt(tv_note_id.getText().toString());Intent intent = new Intent(MainActivity.this,AddActivity.class);intent.putExtra("editModel", "update");intent.putExtra("noteId", item_id);startActivity(intent);finish();}}class ClickEvent implements View.OnClickListener {@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.bt_add :Intent intent = new Intent(MainActivity.this,AddActivity.class);intent.putExtra("editModel", "newAdd");startActivity(intent);finish();}}}
}

PaintActivity

package com.llw.notes;import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.SimpleAdapter;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;public class PaintActivity extends Activity {private PaintView paintView;private GridView paint_bottomMenu;private ListView lv_popWindow;//菜单资源private int[]  paintItems = {R.drawable.paint_more,R.drawable.paint_pencil,R.drawable.paint_icon_color,R.drawable.paint_icon_back,R.drawable.paint_icon_forward,R.drawable.paint_icon_delete};//画笔大小资源private int[] penceilSizes = {};private Button btn_save;private Button btn_back;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_paint);paint_bottomMenu = (GridView)findViewById(R.id.paintBottomMenu);paint_bottomMenu.setOnItemClickListener(new MenuClickEvent());paintView = (PaintView)findViewById(R.id.paint_layout);InitPaintMenu();btn_save = (Button)findViewById(R.id.bt_save);btn_back = (Button)findViewById(R.id.bt_back);btn_save.setOnClickListener(new ClickEvent());btn_back.setOnClickListener(new ClickEvent());}//配置绘图菜单public void InitPaintMenu(){ArrayList<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();for(int i = 0;i < paintItems.length;i++){Map<String,Object> item = new HashMap<String,Object>();item.put("image",paintItems[i]);menus.add(item);}paint_bottomMenu.setNumColumns(paintItems.length);paint_bottomMenu.setSelector(R.drawable.bottom_item);SimpleAdapter mAdapter = new SimpleAdapter(PaintActivity.this, menus,R.layout.item_button, new String[]{"image"}, new int[]{R.id.item_image});paint_bottomMenu.setAdapter(mAdapter);}class ClickEvent implements OnClickListener{@Overridepublic void onClick(View v) {if(v == btn_save){//得到调用该Activity的Intent对象Intent intent = getIntent();Bundle b = new Bundle();String path = paintView.saveBitmap();b.putString("paintPath", path);intent.putExtras(b);setResult(RESULT_OK, intent);PaintActivity.this.finish();}else if(v == btn_back){PaintActivity.this.finish();}}}//设置菜单项监听器class MenuClickEvent implements OnItemClickListener{@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {Intent intent;switch(position){case 0:showMoreDialog(view);break;//画笔大小case 1:showPaintSizeDialog(view);break;//画笔颜色case 2:showPaintColorDialog(view);break;//撤销case 3:paintView.undo();break;//恢复case 4 :paintView.redo();break;//清空case 5 :AlertDialog.Builder builder = new AlertDialog.Builder(PaintActivity.this,R.style.custom_dialog);builder.setTitle("清空提示");builder.setMessage("您确定要清空所有吗?");builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {paintView.removeAllPaint();dialog.cancel();}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.cancel();}});Dialog dialog = builder.create();dialog.show();break;default :break;}}}//弹出画笔颜色选项对话框public void showPaintColorDialog(View parent){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择画笔颜色:");alertDialogBuilder.setSingleChoiceItems(R.array.paintcolor, select_paint_color_index, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {select_paint_color_index = which;paintView.selectPaintColor(which);dialog.dismiss();}});alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});alertDialogBuilder.create().show();}//弹出画笔大小选项对话框public void showPaintSizeDialog(View parent){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择画笔大小:");alertDialogBuilder.setSingleChoiceItems(R.array.paintsize, select_paint_size_index, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {select_paint_size_index = which;paintView.selectPaintSize(which);dialog.dismiss();}});alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});alertDialogBuilder.create().show();}private int select_paint_size_index = 0;private int select_paint_style_index = 0;private int select_paint_color_index = 0;//弹出选择画笔或橡皮擦的对话框public void showMoreDialog(View parent){AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this,R.style.custom_dialog);alertDialogBuilder.setTitle("选择画笔或橡皮擦:");alertDialogBuilder.setSingleChoiceItems(R.array.paintstyle, select_paint_style_index, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {select_paint_style_index = which;paintView.selectPaintStyle(which);dialog.dismiss();}});alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});alertDialogBuilder.create().show();}
}

PaintView

package com.llw.notes;import android.app.Activity;
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.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;public class PaintView extends View  {private Canvas  mCanvas;private Path    mPath;private Paint   mBitmapPaint;private Bitmap  mBitmap;private Paint mPaint;private ArrayList<DrawPath> savePath;private ArrayList<DrawPath> deletePath;private DrawPath dp;private float mX, mY;private static final float TOUCH_TOLERANCE = 4;private int bitmapWidth;private int bitmapHeight;private int currentColor = Color.RED;private int currentSize = 5;private int currentStyle = 1;//设置画笔样式public void setPaintStyle(){mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setDither(true);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeCap(Paint.Cap.ROUND);mPaint.setStrokeWidth(currentSize);if(currentStyle == 1)mPaint.setColor(currentColor);else{mPaint.setColor(Color.WHITE);}}//初始化画布public void initCanvas(){setPaintStyle();mBitmapPaint = new Paint(Paint.DITHER_FLAG);//画布大小mBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight,Bitmap.Config.RGB_565);mCanvas = new Canvas(mBitmap);  //所有mCanvas画的东西都被保存在了mBitmap中mCanvas.drawColor(Color.WHITE);mPath = new Path();mBitmapPaint = new Paint(Paint.DITHER_FLAG);}//画笔颜色private int[] paintColor = {Color.RED,Color.BLUE,Color.BLACK,Color.GREEN,Color.YELLOW,Color.CYAN,Color.LTGRAY};//设置画笔样式public void selectPaintStyle(int which){if(which == 0){currentStyle = 1;setPaintStyle();}//当选择的是橡皮擦时,设置颜色为白色if(which == 1){currentStyle = 2;setPaintStyle();mPaint.setStrokeWidth(20);}}//选择画笔大小public void selectPaintSize(int which){int size =Integer.parseInt(this.getResources().getStringArray(R.array.paintsize)[which]);currentSize = size;setPaintStyle();}//设置画笔颜色public void selectPaintColor(int which){currentColor = paintColor[which];setPaintStyle();}public PaintView(Context c) {super(c);//得到屏幕的分辨率DisplayMetrics dm = new DisplayMetrics();((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(dm);bitmapWidth = dm.widthPixels;bitmapHeight = dm.heightPixels - 2 * 45;initCanvas();savePath = new ArrayList<DrawPath>();deletePath = new ArrayList<DrawPath>();}public PaintView(Context c, AttributeSet attrs) {super(c,attrs);//得到屏幕的分辨率DisplayMetrics dm = new DisplayMetrics();((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(dm);bitmapWidth = dm.widthPixels;bitmapHeight = dm.heightPixels - 2 * 45;initCanvas();savePath = new ArrayList<DrawPath>();deletePath = new ArrayList<DrawPath>();}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);     //显示旧的画布if (mPath != null) {// 实时的显示canvas.drawPath(mPath, mPaint);}}//路径对象class DrawPath{Path path;Paint paint;}/*** 撤销的核心思想就是将画布清空,* 将保存下来的Path路径最后一个移除掉,* 重新将路径画在画布上面。*/public void undo(){System.out.println(savePath.size()+"--------------");if(savePath != null && savePath.size() > 0){//调用初始化画布函数以清空画布initCanvas();//将路径保存列表中的最后一个元素删除 ,并将其保存在路径删除列表中DrawPath drawPath = savePath.get(savePath.size() - 1);deletePath.add(drawPath);savePath.remove(savePath.size() - 1);//将路径保存列表中的路径重绘在画布上Iterator<DrawPath> iter = savePath.iterator();     //重复保存while (iter.hasNext()) {DrawPath dp = iter.next();mCanvas.drawPath(dp.path, dp.paint);}invalidate();// 刷新}}/*** 恢复的核心思想就是将撤销的路径保存到另外一个列表里面(栈),* 然后从redo的列表里面取出最顶端对象,* 画在画布上面即可*/public void redo(){if(deletePath.size() > 0){//将删除的路径列表中的最后一个,也就是最顶端路径取出(栈),并加入路径保存列表中DrawPath dp = deletePath.get(deletePath.size() - 1);savePath.add(dp);//将取出的路径重绘在画布上mCanvas.drawPath(dp.path, dp.paint);//将该路径从删除的路径列表中去除deletePath.remove(deletePath.size() - 1);invalidate();}}/** 清空的主要思想就是初始化画布* 将保存路径的两个List清空* */public void removeAllPaint(){//调用初始化画布函数以清空画布initCanvas();invalidate();//刷新savePath.clear();deletePath.clear();}/** 保存所绘图形* 返回绘图文件的存储路径* */public String saveBitmap(){//获得系统当前时间,并以该时间作为文件名SimpleDateFormat   formatter   =   new   SimpleDateFormat   ("yyyyMMddHHmmss");Date   curDate   =   new   Date(System.currentTimeMillis());//获取当前时间String   str   =   formatter.format(curDate);String paintPath = "";str = str + "paint.png";File dir = new File("/sdcard/notes/");File file = new File("/sdcard/notes/",str);if (!dir.exists()) {dir.mkdir();}else{if(file.exists()){file.delete();}}try {FileOutputStream out = new FileOutputStream(file);mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);//压缩out.flush();out.close();//保存绘图文件路径paintPath = "/sdcard/notes/" + str;} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return paintPath;}private void touch_start(float x, float y) {mPath.reset();//清空pathmPath.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, y);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, mPaint);savePath.add(dp);mPath = null;}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath = new Path();dp = new DrawPath();dp.path = mPath;dp.paint = mPaint;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;}}

ShowPicture

package com.llw.notes;import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;public class ShowPicture extends AppCompatActivity {private ImageView img;private Bitmap bm;private DisplayMetrics dm;private Matrix matrix = new Matrix();private Matrix savedMatrix = new Matrix();private PointF mid = new PointF();private PointF start = new PointF();private static int DRAG = 2;private static int ZOOM = 1;private static int NONE = 0;private int mode = 0;private float oldDist = 1f;private static float MINSCALER = 0.3f;private static float MAXSCALER = 3.0f;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_show_picture);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();Button bt_back = (Button)findViewById(R.id.bt_back);bt_back.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {ShowPicture.this.finish();}});Button bt_del = (Button)findViewById(R.id.bt_save);bt_del.setBackgroundResource(R.drawable.paint_icon_delete);dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm); //获取分辨率img = (ImageView)findViewById(R.id.iv_showPic);Intent intent = this.getIntent();String imgPath = intent.getStringExtra("imgPath");bm = BitmapFactory.decodeFile(imgPath);//设置居中显示savedMatrix.setTranslate((dm.widthPixels - bm.getWidth())/2 , (dm.heightPixels - bm.getHeight()) / 2);img.setImageMatrix(savedMatrix);//绑定图片img.setImageBitmap(bm);//触摸事件img.setOnTouchListener(new TouchEvent());}//添加触摸事件,实现图片的手势缩放class TouchEvent implements View.OnTouchListener {@Overridepublic boolean onTouch(View view, MotionEvent event) {switch(event.getActionMasked()){//单击触控,用于拖动case MotionEvent.ACTION_DOWN :matrix.set(img.getImageMatrix());savedMatrix.set(matrix);start.set(event.getX(), event.getY());mode = DRAG;break;//多点触控,按下时case MotionEvent.ACTION_POINTER_DOWN :oldDist = getSpacing(event);savedMatrix.set(matrix);getMidPoint(mid,event);mode = ZOOM;break;//多点触控,抬起时case MotionEvent.ACTION_POINTER_UP :mode = NONE;break;case MotionEvent.ACTION_MOVE :if(mode == DRAG){matrix.set(savedMatrix);matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);}//缩放else if(mode == ZOOM){//取得多指移动的直径,如果大于10,则认为是缩放手势float newDist = getSpacing(event);if(newDist > 10){matrix.set(savedMatrix);float scale = newDist / oldDist;matrix.postScale(scale, scale,mid.x,mid.y);}}break;}img.setImageMatrix(matrix);controlScale();//setCenter();center();return true;}}//求距离private float getSpacing(MotionEvent event){float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);}//求中点private void getMidPoint(PointF mid,MotionEvent event){float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);mid.set(x / 2, y / 2);}//控制缩放比例private void controlScale(){float values[] = new float[9];matrix.getValues(values);if(mode == ZOOM){if(values[0] < MINSCALER)matrix.setScale(MINSCALER, MINSCALER);else if(values[0] > MAXSCALER)matrix.setScale(MAXSCALER, MAXSCALER);}}//自动居中  左右及上下都居中protected void center(){center(true,true);}private void center(boolean horizontal, boolean vertical){Matrix m = new Matrix();m.set(matrix);RectF rect = new RectF(0, 0, bm.getWidth(), bm.getHeight());m.mapRect(rect);float height = rect.height();float width = rect.width();float deltaX = 0, deltaY = 0;if (vertical){int screenHeight = dm.heightPixels;  //手机屏幕分辨率的高度//int screenHeight = 400;if (height < screenHeight){deltaY = (screenHeight - height)/2 - rect.top;}else if (rect.top > 0){deltaY = -rect.top;}else if (rect.bottom < screenHeight){deltaY = screenHeight - rect.bottom;}}if (horizontal){int screenWidth = dm.widthPixels;  //手机屏幕分辨率的宽度//int screenWidth = 400;if (width < screenWidth){deltaX = (screenWidth - width)/2 - rect.left;}else if (rect.left > 0){deltaX = -rect.left;}else if (rect.right < screenWidth){deltaX = screenWidth - rect.right;}}matrix.postTranslate(deltaX, deltaY);}}

ShowRecord

package com.llw.notes;import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;public class ShowRecord extends AppCompatActivity {private String audioPath;private int isPlaying = 0;private AnimationDrawable ad_left,ad_right;private Timer mTimer;//语音操作对象private MediaPlayer mPlayer = null;private ImageView iv_record_wave_left,iv_record_wave_right,iv_microphone;private TextView tv_recordTime;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_show_record);//设置为全屏模式getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);ActionBar actionBar=getSupportActionBar();actionBar.hide();Button bt_back = (Button)findViewById(R.id.bt_back);bt_back.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {if(isPlaying == 1){mPlayer.stop();mPlayer.release();}ShowRecord.this.finish();}});Button bt_del = (Button)findViewById(R.id.bt_save);bt_del.setBackgroundResource(R.drawable.paint_icon_delete);iv_microphone = (ImageView)findViewById(R.id.iv_microphone);iv_microphone.setOnClickListener(new ClickEvent());Intent intent = this.getIntent();audioPath = intent.getStringExtra("audioPath");iv_record_wave_left = (ImageView)findViewById(R.id.iv_record_wave_left);iv_record_wave_right = (ImageView)findViewById(R.id.iv_record_wave_right);
//        ad_left = (AnimationDrawable)iv_record_wave_left.getBackground();
//        ad_left = (AnimationDrawable)iv_record_wave_left.getBackground();iv_record_wave_left.setImageResource(R.drawable.record_wave_left);iv_record_wave_right.setImageResource(R.drawable.record_wave_right);ad_left=((AnimationDrawable) iv_record_wave_left.getDrawable());ad_right=((AnimationDrawable) iv_record_wave_right.getDrawable());tv_recordTime = (TextView)findViewById(R.id.tv_recordTime);}final Handler handler = new Handler(){public void handleMessage(Message msg) {switch(msg.what){case 1 :String time[] = tv_recordTime.getText().toString().split(":");int hour = Integer.parseInt(time[0]);int minute = Integer.parseInt(time[1]);int second = Integer.parseInt(time[2]);if(second < 59){second++;}else if(second == 59 && minute < 59){minute++;second = 0;}if(second == 59 && minute == 59 && hour < 98){hour++;minute = 0;second = 0;}time[0] = hour + "";time[1] = minute + "";time[2] = second + "";//调整格式显示到屏幕上if(second < 10)time[2] = "0" + second;if(minute < 10)time[1] = "0" + minute;if(hour < 10)time[0] = "0" + hour;//显示在TextView中tv_recordTime.setText(time[0]+":"+time[1]+":"+time[2]);break;}}};class ClickEvent implements View.OnClickListener {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stub//试听if(isPlaying == 0){isPlaying = 1;mPlayer = new MediaPlayer();tv_recordTime.setText("00:00:00");mTimer = new Timer();mPlayer.setOnCompletionListener(new MediaCompletion());try {mPlayer.setDataSource(audioPath);mPlayer.prepare();mPlayer.start();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}mTimer.schedule(new TimerTask() {@Overridepublic void run() {Message message = new Message();message.what = 1;handler.sendMessage(message);}}, 1000,1000);//播放动画ad_left.start();ad_right.start();}//结束试听else{isPlaying = 0;mPlayer.stop();mPlayer.release();mPlayer = null;mTimer.cancel();mTimer = null;//停止动画ad_left.stop();ad_right.stop();}}}class MediaCompletion implements MediaPlayer.OnCompletionListener {@Overridepublic void onCompletion(MediaPlayer mp) {mTimer.cancel();mTimer = null;isPlaying = 0;//停止动画ad_left.stop();ad_right.stop();Toast.makeText(ShowRecord.this, "播放完毕", Toast.LENGTH_SHORT).show();tv_recordTime.setText("00:00:00");}}}

TouchView

package com.llw.notes;import android.app.Activity;
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.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;import java.util.Timer;
import java.util.TimerTask;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;private int currentColor = Color.RED;private int currentSize = 5;//画笔颜色private int[] paintColor = {Color.RED,Color.BLUE,Color.BLACK,Color.GREEN,Color.YELLOW,Color.CYAN,Color.LTGRAY};//设置画笔样式public void setPaintStyle(){mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setDither(true);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeCap(Paint.Cap.ROUND);mPaint.setStrokeWidth(currentSize);mPaint.setColor(currentColor);}//设置画笔的大小public void selectHandWritetSize(int which){int size =Integer.parseInt(this.getResources().getStringArray(R.array.paintsize)[which]);currentSize = size;setPaintStyle();}//设置画笔颜色public void selectHandWriteColor(int which){currentColor = paintColor[which];setPaintStyle();}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();}//设置handlerpublic void setHandler(Handler mBitmapHandler){bitmapHandler = mBitmapHandler;}//初始化画笔,画布private void initPaint(){//设置画笔样式setPaintStyle();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){//得到手写字的四周位置,并向外延伸10pxfloat 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();}@Overrideprotected 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();//清空pathmPath.moveTo(x, y);mX = x;mY = y;if(task != null)task.cancel();//取消之前的任务task = new TimerTask() {@Overridepublic 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() {@Overridepublic 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}}//处理界面事件@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {//down表示手势事件开始,up表示结束,move则代表着过程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;}}

3,最后res中drawable文件layout文件values文件粘贴上去就行了

功能可以看代码注释,不会可以在评论区提问我会解答。
本程序大家供学习使用。
我把源代码发到github上方便大家看代码学习:
网址:https://github.com/Rockffer/notes/tree/master

Android——多功能记事本(Android Studio)相关推荐

  1. android 最新功能介绍,Android Studio 常用功能介绍

    界面介绍 讲解1 这个界面,显示了我们使用 Android Studio时经常接触到的功能面板. Project 面板. 用于浏览项目文件. Project 面板会显示当前的所有的 module .  ...

  2. android增删功能代码,Android Studio开发实战 之 增删改查

    增删改查是一个应用最基础的操作,增删改查的流程走通了,下面的路程也就顺利多了.现在使用Android Studio开发一个简单的应用,该应用就实现了增删改查的操作,看似简单,到底简不简单呢,下面开始操 ...

  3. android实现简易记事本,Android使用GreenDao实现一个记事本App

    1.项目的创建 打开Android studio新建一个MyNotePad项目. 2.导入依赖以及相关配置 app 的build.gradle文件头部添加apply plugin: 'android- ...

  4. android碎片功能实现,Android 列表碎片

    Android 列表碎片 列表碎片的基本实现是用来在碎片中创建项目列表 实例 这个实例解释如何基于 ArrayAdapter 来创建列表碎片.让我们按照下面的步骤开始: 步骤 描述 1 使用 Andr ...

  5. android拍照功能编程,android实现手机App实现拍照功能示例

    实现手机App实现拍照功能结果如下 第一步: activity_takephoto.xml布局用SurfaceView xmlns:tools="http://schemas.android ...

  6. android手电筒功能吗,android通过led实现手电筒功能

    本文实例为大家分享了android通过led实现手电筒功能的具体代码,供大家参考,具体内容如下 第一步添加权限: 第二步实现手电筒工具类: import android.hardware.Camera ...

  7. android签到功能开发,Android简单实现app每月签到功能

    本文实例为大家分享了Android实现app每月签到功能的具体代码,供大家参考,具体内容如下 先上一张效果图: 其中这些签到的效果图是在网上找的,然后重要用到的控件就是 GridvVew 了, 代码很 ...

  8. android签到功能开发,Android应用开发之Android简单实现app每月签到功能

    本文将带你了解Android应用开发Android简单实现app每月签到功能,希望本文对大家学Android有所帮助. 本文实例为大家分享了Android实现app每月签到功能的具体代码,供大家参考, ...

  9. android悬浮功能实现,Android实现系统级悬浮按钮

    本文实例为大家分享了Android系统级悬浮按钮的具体代码,供大家参考,具体内容如下 具体的需求 1.就是做一个系统级的悬浮按钮,就像iPhone 桌面的那个悬浮按钮效果一样,能随意拖动,并且手一放开 ...

  10. android 聊天功能实现,Android聊天背景功能实现

    解决输入法弹出时背景被顶上去或者挤压变形的问题 先看效果图: Screenshot_1510219375.png Screenshot_1510219378.png 实现方案: package com ...

最新文章

  1. honey select 模型导出_道路建模-基本模型
  2. python画折线图代码-Python绘制折线图和散点图的详细方法介绍(代码示例)
  3. 全球及中国工业金刚石微米粉行业十四五规划研究与发展战略分析报告2021年版
  4. 201671010117 2016-2017-2 《Java程序设计》Java第二周学习心得
  5. java lambda表达式_凯哥带你从零学大数据系列之Java篇---第二十二章:Lambda表达式...
  6. cad和python哪个好学_对纯外行人来说,学习PS和Python哪个更容易?
  7. goroutine 修改全局变量无效问题
  8. DAC+DMA+TIM实现音频播放问题记录
  9. 一种身份证号码的编码压缩方法
  10. Stream,byte[],LZMA
  11. 笔记本输字母p出现仅计算机,电脑打不了字只有字母怎么办?最简单的解决方法...
  12. 汽车行业数字化工厂建设方案
  13. 在 Win7 下安装 KB4512506 补丁报告 0x80092004 错误的解决办法
  14. 小米最大的竞争对手不是苹果而是华为
  15. NVME Reset
  16. spring-retry
  17. 2018年什么编程语言最值得学习
  18. 实验 9 音频信号采集及处理
  19. 芯片内部长啥样?牛人用1500张照片,一层层放给你看
  20. java.lang.NoClassDefFoundError: com.google.gson.Gson

热门文章

  1. DSOFramer使用
  2. NBU查看备份集大小
  3. IntelliJ IDEA For Mac 的破解方法
  4. python程序设计——班级档案管理系统
  5. 各种常用的 Win32Api 汇总(持续更新中. . .)
  6. 1 统计学习方法基础
  7. CentOS7.5搭建ELK6.2.4集群与简单测试
  8. 用户故事与敏捷方法—估算用户故事
  9. 三种需求文档(BRD、MRD、PRD)
  10. 合肥工业大学机器人技术期末_机器人技术试题及答案.doc