Android——多功能记事本(Android Studio)

一,功能

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

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-sdk
        android: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-feature
        android:name="android.hardware.camera.autofocus"
        android:required="false" />

    <application
        android: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">
        <activity
            android:name=".ShowRecord"
            android:exported="true" >

        </activity>
        <activity
            android:name=".ShowPicture"
            android:exported="true">

        </activity>
        <activity
            android:name=".HandWriteActivity"
            android:exported="true" />
        <activity
            android:name=".ActivityRecord"
            android:exported="true" />
        <activity
            android:name=".PaintActivity"
            android:exported="true" />
        <activity
            android:name=".AddActivity"
            android:exported="true" >

        </activity>

        <activity
            android: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;
    @Override
    protected 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 {
    
    

        @Override
        public 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:00
                        tv_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 block
                            e.printStackTrace();
                        } catch (IOException e) {
    
    
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        mRecorder.start();
                        mTimer.schedule(new TimerTask() {
    
    

                            @Override
                            public 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 block
                                e.printStackTrace();
                            } catch (SecurityException e) {
    
    
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            } catch (IllegalStateException e) {
    
    
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            } catch (IOException e) {
    
    
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            mTimer.schedule(new TimerTask() {
    
    

                                @Override
                                public 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 {
    
    

        @Override
        public 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;
    @Override
    protected 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 {
    
    

        @Override
        public 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,如果不是,则跳转到查看图片的界面
                    //录音,则跳转到试听录音的Activity
                    if(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/*");*/
                        //使用自定义Activity
                        Intent 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 {
    
    

        @Override
        public void onClick(View v) {
    
    
            switch(v.getId()){
    
    
                case R.id.bt_back :
                    //当前Activity结束,则返回上一个Activity
                    AddActivity.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);
                        //结束当前activity
                        AddActivity.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 {
    
    

        @Override
        public 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);
    }

    @Override
    protected 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 block
                    e.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 block
                    e.printStackTrace();
                } catch (IOException e) {
    
    
                    // TODO Auto-generated catch block
                    e.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;
    @Override
    protected 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 {
    
    

        @Override
        public 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 block
            e.printStackTrace();
        } catch (IOException e) {
    
    
            // TODO Auto-generated catch block
            e.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(){
    
    
        @Override
        public 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 {
    
    

        @Override
        public 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() {
    
    

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
    
    
                                et_handwrite.setText("");
                                dialog.cancel();
                            }
                        });
                        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

                            @Override
                            public 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() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                select_handwrite_size_index = which;
                touchView.selectHandWritetSize(which);
                dialog.dismiss();
            }
        });

        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

            @Override
            public 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() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                select_handwrite_color_index = which;
                touchView.selectHandWriteColor(which);
                dialog.dismiss();
            }
        });

        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

            @Override
            public 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 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);
        }
    }
}

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;
    @Override
    protected 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 {
    
    

        @Override
        public 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() {
    
    

            @Override
            public 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 {
    
    

        @Override
        public 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 {
    
    

        @Override
        public 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;


    @Override
    protected 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{
    
    

        @Override
        public 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{
    
    

        @Override
        public 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() {
    
    

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
    
    
                            paintView.removeAllPaint();
                            dialog.cancel();
                        }
                    });
                    builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

                        @Override
                        public 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() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                select_paint_color_index = which;
                paintView.selectPaintColor(which);
                dialog.dismiss();
            }
        });

        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

            @Override
            public 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() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                select_paint_size_index = which;
                paintView.selectPaintSize(which);
                dialog.dismiss();
            }
        });

        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

            @Override
            public 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() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                select_paint_style_index = which;
                paintView.selectPaintStyle(which);
                dialog.dismiss();
            }
        });

        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    
    

            @Override
            public 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>();
    }



    @Override
    protected 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 block
            e.printStackTrace();
        } catch (IOException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return paintPath;
    }


    private void touch_start(float x, float y) {
    
    
        mPath.reset();//清空path
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }
    private void touch_move(float x, float y) {
    
    
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
    
    
            //mPath.quadTo(mX, mY, x, 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;

    }

    @Override
    public 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;



    @Override
    protected 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() {
    
    

            @Override
            public 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 {
    
    
        @Override
        public 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;


    @Override
    protected 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() {
    
    

            @Override
            public 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 {
    
    

        @Override
        public 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 block
                    e.printStackTrace();
                } catch (SecurityException e) {
    
    
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalStateException e) {
    
    
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
    
    
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                mTimer.schedule(new TimerTask() {
    
    

                    @Override
                    public 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 {
    
    

        @Override
        public 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();
    }
    //设置handler
    public 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){
    
    
        //得到手写字的四周位置,并向外延伸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()) {
    
    
            //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

猜你喜欢

转载自blog.csdn.net/qq_54537215/article/details/126989706
今日推荐