Android NotePad的简单实现

MyNotePad

1.0 Version

运行环境

AndroidStudio 3.3.1
JDK 1.8
minSdkVersion 21 TargetSdkVersion 28
模拟机API 23

时间戳

代码分析

(1)在布局文件中增加一个TextView来显示时间戳

<TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="12dp"
        android:gravity="center_vertical"
        android:paddingLeft="10dip"
        android:singleLine="true"
        android:layout_weight="1"
        android:layout_margin="0dp"
        />

(2)数据库中已有文本创建时间和修改时间连个字段,在NodeEditor.java中,找到updateNode()这个函数,选取修改时间这一字段,并将其格式化存入数据库

Date nowTime = new Date(System.currentTimeMillis());
SimpleDateFormat sdFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String retStrFormatNowDate = sdFormatter.format(nowTime);
values.put(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, retStrFormatNowDate);

(3)在NoteList.java的PROJECTION数组中增加该字段的描述,并在SimpleCursorAdapter中的参数viewsIDs和dataColumns增加子段描述,以达到将其读出和显示的目的

//The columns needed by the cursor adapter
private static final String[] PROJECTION = new String[] {
            NotePad.Notes._ID, // 0
            NotePad.Notes.COLUMN_NAME_TITLE, // 1
            NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE,
    };
// The names of the cursor columns to display in the view, initialized to the title column
private String[] dataColumns = { NotePad.Notes.COLUMN_NAME_TITLE ,NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE} ;
// The view IDs that will display the cursor columns, initialized to the TextView in
private int[] viewIDs = { R.id.text1,R.id.text2 };

效果

在这里插入图片描述

搜索笔记以title为关键字段

代码分析

(1)在NodeList.java的布局文件中新增SearchView控件(备注:引用的是support.v7的包,如未找到,需在build.gradle(Module.app)中添加依赖

<android.support.v7.widget.SearchView
            android:id="@+id/sv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />

(2)在NodeList.java中创建一个函数专门来配置SeachView,实现查询的基本思想是新创建一个Cursor来通过SeacrhView搜索的字段在数据库中进行模糊搜索从而装配数据,并在ListView中即时显示,无需点击搜索按键,最后在onCreate()中调用

private void SearchView(){
        searchView=findViewById(R.id.sv);
        // a display model
        searchView.onActionViewExpanded();
        //default display
        searchView.setQueryHint("搜索笔记");
        //display submit button
        searchView.setSubmitButtonEnabled(true);
        //implement SearchView TextListener
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            // when text has been submitted
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }
            // when text is changing
            @Override
            public boolean onQueryTextChange(String s) {
                if(!s.equals("")){
                    String selection=NotePad.Notes.COLUMN_NAME_TITLE+" GLOB '*"+s+"*'";//query selection condition
                    updatecursor = getContentResolver().query(
                            getIntent().getData(),            // Use the default content URI for the provider.
                            PROJECTION,                       // Return the note ID and title for each note.
                            selection,                             // No where clause, return all records.
                            null,                             // No where clause, therefore no where column values.
                            NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                    );
                }
               else {
                    updatecursor = getContentResolver().query(
                            getIntent().getData(),            // Use the default content URI for the provider.
                            PROJECTION,                       // Return the note ID and title for each note.
                            null,                             // No where clause, return all records.
                            null,                             // No where clause, therefore no where column values.
                            NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                    );
                }
                // change adapter from SimpleCursorAdapter cursor
                adapter.swapCursor(updatecursor);
               // adapter.notifyDataSetChanged();
                return false;
            }
        });
    }

效果

在这里插入图片描述
在这里插入图片描述

修改背景色及字体颜色

代码分析

(1)在OptionMenu中添加修改颜色这一选项,并划分为两类,修改背景颜色和修改字体颜色

<item
        android:title="改变颜色">
        <menu>
            <item
                android:title="改变背景颜色"
                android:id="@+id/background-color">
            </item>
            <item android:id="@+id/text-color"
                android:title="改变字体颜色">
            </item>
        </menu>
</item>

(2)采用AlertDialog来实现界面交互效果,并采用自定义布局定义UI界面,因为两种修改颜色调用的是同一个函数showColor(),因此定义一个boolean变量flag来判断

private void showColor(){
        AlertDialog alertDialog=new AlertDialog.Builder(this).setTitle("请选择颜色").
                setIcon(R.mipmap.ic_launcher).setView(R.layout.color_layout)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).create();
        alertDialog.show();
    }

AlertDialog布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <Button
        android:id="@+id/orange"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/orange"
        android:layout_weight="1"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/chocolate"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/chocolate"
        android:layout_weight="1"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/aqua"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/aqua"
        android:layout_weight="1"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/gray"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/gray"
        android:layout_weight="1"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/pink"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        android:layout_weight="1"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/green"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/green"
        android:layout_weight="1"
        android:onClick="onClick"/>
</LinearLayout>

布局文件按钮的点击事件

public void onClick(View v) {
        switch (v.getId()){
            case R.id.orange:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#FF8C00"));
                    colorBack="#FF8C00";
                }else{
                    mText.setTextColor(Color.parseColor("#FF8C00"));
                    colorText="#FF8C00";
                }
                break;
            case R.id.chocolate:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#D2691E"));
                    colorBack="#D2691E";
                }else{
                    mText.setTextColor(Color.parseColor("#D2691E"));
                    colorText="#D2691E";
                }
                break;
            case R.id.aqua:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#00FFFF"));
                    colorBack="#00FFFF";
                }else{
                    mText.setTextColor(Color.parseColor("#00FFFF"));
                    colorText="#00FFFF";
                }
                break;
            case R.id.gray:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#696969"));
                    colorBack="#696969";
                }else{
                    mText.setTextColor(Color.parseColor("#696969"));
                    colorText="#696969";
                }
                break;
            case R.id.pink:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#D81B60"));
                    colorBack="#D81B60";
                }else{
                    mText.setTextColor(Color.parseColor("#D81B60"));
                    colorText="#D81B60";
                }
                break;
            case R.id.green:
                if(isFlag){
                    mText.setBackgroundColor(Color.parseColor("#00FF7F"));
                    colorBack="#00FF7F";
                }else{
                    mText.setTextColor(Color.parseColor("#00FF7F"));
                    colorText="#00FF7F";
                }
                break;
        }
    }

(3)在onOptionItemSelected()中添加点击事件

case R.id.background_color:
    isFlag=true;
    showColor();
    break;
case R.id.text_color:
    isFlag=false;
    showColor();
    break;

(4)点击保存之后将颜色的16进制保存到数据库,也是通过updateNote()函数,具体实现与时间戳功能类似,这里说明一下数据库新增字段的实现

1.在NotePad.java中的内部类Notes添加契约

/*
* NoteEditor.java EditText setBackGroundColor
* */
public static final String COLUMN_BACKGROUND_COLOR="bColor";
/*
 * NoteEditor.java EditText setTextColor
 * */
public static final String COLUMN_TEXT_COLOR="tColor";

2.在NotePadProvider.java的静态构造块往sNotesProjectionMap添加相应的键值对

//Maps "bColor" to "bColor"
sNotesProjectionMap.put(
        NotePad.Notes.COLUMN_BACKGROUND_COLOR,
        NotePad.Notes.COLUMN_BACKGROUND_COLOR
);
//Maps "tColor" to "tColor"
sNotesProjectionMap.put(
        NotePad.Notes.COLUMN_TEXT_COLOR,
        NotePad.Notes.COLUMN_TEXT_COLOR
);

备注:如果已经在手机中安装app之后要新增或删减字段,需要在onUpgrade()中更换版本号,或者卸载重装。

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

添加标签以将文本分类

代码分析

(1)在数据库中添加标签字段,与修改颜色功能类似,不作相应代码显示
(2)在NodeEditor.java布局文件中添加Button控件,点击弹出AlertDialog显示类别选项,设置按钮文本

//tag selection defined
private final String items[]={"Default","Travel","Work","Study","Life"};
public void tagSelect(View v){
        AlertDialog.Builder tagbuilder;
        AlertDialog alertDialog;
        tagbuilder=new AlertDialog.Builder(this);
        tagbuilder.setTitle("Tag Selection:");
        tagbuilder.setIcon(R.mipmap.ic_launcher);

        tagbuilder.setSingleChoiceItems(items, checkItem, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                checkItem=which;
                button.setText(items[checkItem]);

            }
        });
        tagbuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        alertDialog=tagbuilder.create();
        alertDialog.show();
    }

(3)点击保存之后会将按钮文本保存到数据库,与时间戳功能类似,不再作具体演示
(4)在NoteList.java添加抽屉布局,以显示侧滑菜单栏的效果

1.在AndroidManifest.xml中更改主题,禁用ActionBar,查看引用,在styles.xml中进行修改

android:theme="@style/AppTheme"
style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"

2.在布局文件中使用DrawerLayout布局和toolbar,还有NavigationView,与之前同理,导入的分别是v4和v7的包,如果没有,需要添加依赖(注:CoordinatorLayout是之前想做一个浮动布局加的,但后来放弃了,所以这个布局是可以删除的,只要修改号里面控件的width和height就可以)

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/dl"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:focusableInTouchMode="true"
        android:focusable="true"

       >
        <android.support.v7.widget.Toolbar
            android:id="@+id/tb"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            app:titleTextColor="@color/white"
            app:title="MyNotePad"
            app:navigationIcon="@android:drawable/ic_menu_sort_by_size"
            >

        </android.support.v7.widget.Toolbar>
        <android.support.v7.widget.SearchView
            android:id="@+id/sv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
        <android.support.design.widget.CoordinatorLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            >
            <ListView
                android:id="@+id/tv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

        </android.support.design.widget.CoordinatorLayout>
    </LinearLayout>
    <android.support.design.widget.NavigationView
        android:id="@+id/nv"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:layout_gravity="left"
        app:headerLayout="@layout/nv_header"
        app:menu="@menu/nv_menu"
        >

    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>

3.NavigationView的菜单编写

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group>
        <item android:title="NotePad">
            <menu>
                <item
                    android:id="@+id/notepad"
                    android:title="MyNotePad">
                </item>
            </menu>
        </item>
    </group>
    <group>
        <item android:title="tag">
            <menu>
                <item
                    android:id="@+id/travel"
                    android:title="Travel">
                </item>
                <item
                    android:id="@+id/work"
                    android:title="Work">
                </item>
                <item
                    android:id="@+id/study"
                    android:title="Study">
                </item>
                <item
                    android:id="@+id/life"
                    android:title="Life">
                </item>
                <item
                    android:id="@+id/def"
                    android:title="Default">
                </item>
            </menu>
        </item>
    </group>
</menu>

(3)编写toolbar的监听事件和NavigationView的监听事件
1.toolbar

setSupportActionBar(toolbar); //set support toolbar in this Activity
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        drawerLayout.openDrawer(Gravity.START);// set from left open NavigationView Menu
    }
});

2.NavigationView

navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                switch (menuItem.getItemId()){
                    case R.id.notepad:
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                null,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("MyNotePad");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                    case R.id.travel:
                        tagSelection=NotePad.Notes.COLUMN_TAG_SELECTION_INDEX+" = 'Travel'";
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                tagSelection,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("Travel");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                    case R.id.work:
                        tagSelection=NotePad.Notes.COLUMN_TAG_SELECTION_INDEX+" = 'Work'";
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                tagSelection,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("Work");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                    case R.id.study:
                        tagSelection=NotePad.Notes.COLUMN_TAG_SELECTION_INDEX+" = 'Study'";
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                tagSelection,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("Study");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                    case R.id.life:
                        tagSelection=NotePad.Notes.COLUMN_TAG_SELECTION_INDEX+" = 'Life'";
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                tagSelection,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("Life");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                    case R.id.def:
                        tagSelection=NotePad.Notes.COLUMN_TAG_SELECTION_INDEX+" = 'Default'";
                        tagCursor = getContentResolver().query(
                                getIntent().getData(),            // Use the default content URI for the provider.
                                PROJECTION,                       // Return the note ID and title for each note.
                                tagSelection,                             // No where clause, return all records.
                                null,                             // No where clause, therefore no where column values.
                                NotePad.Notes.DEFAULT_SORT_ORDER  // Use the default sort order.
                        );
                        adapter.swapCursor(tagCursor);//swap cursor from SimpleCursorAdapter
                        toolbar.setTitle("Default");
                        drawerLayout.closeDrawer(navigationView);//close NavigationView menu
                        break;
                }
                return true;
            }
        });

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在文本中插入图片

代码分析

(1)在NodeEditor.java的optionmenu中添加选项

<item android:title="插入图片"
        android:icon="@android:drawable/ic_menu_gallery"
        app:showAsAction="always|withText">
        <menu>
            <item
                android:title="相册"
                android:icon="@android:drawable/ic_menu_gallery"
                android:id="@+id/insert_album">
            </item>
            <item
                android:id="@+id/insert_camera"
                android:icon="@android:drawable/ic_menu_camera"
                android:title="拍照">
            </item>
        </menu>
    </item>

(2)拍照要在AndroidManifest.xml中设置权限,API23以上还要在代码中设置动态权限,API28以上权限设置更为严格,本功能并不适用。而从图库中选取照片权限要求较低.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
//从相册取图片
public void getPhoto() {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
        startActivityForResult(intent, PHOTO_FROM_GALLERY);
}
//拍照取照片
public void takeCamera() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions( this, new String[] { Manifest.permission.CAMERA }, PHOTO_FROM_CAMERA);
        }
        else {
            File file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
            try {
                if(file.exists()){
                    file.delete();
                }
                file.createNewFile();
            }catch (IOException e){
                e.printStackTrace();
            }
            imageUri=Uri.fromFile(file);
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
            startActivityForResult(intent, PHOTO_FROM_CAMERA);
        }
}

(3)编写onActivityResult定义返回动作

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        ContentResolver resolver = getContentResolver();
        super.onActivityResult(requestCode, resultCode, data);
        //第一层switch
        switch (requestCode) {
            case PHOTO_FROM_GALLERY:
                //第二层switch
                switch (resultCode) {
                    case RESULT_OK:
                        if (data != null) {
                            Uri uri = data.getData();//获取Intent uri
                            Bitmap bitmap = null;
                            //判断该路径是否存在
                            try {
                                Bitmap originalBitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri));
                                bitmap = resizeImage(originalBitmap, 200, 200);//图片缩放
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            }
                            if(bitmap != null){//如果图片存在
                                //将选择的图片追加到EditText中光标所在位置
                                int index = mText.getSelectionStart(); //获取光标所在位置
                                Editable edit_text = mText.getEditableText();//编辑文本框
                                if(index <0 || index >= edit_text.length()){
                                    edit_text.append(uri.toString());
                                    updateNoteText(mText.getText().toString());//更新到数据库
                                }else{
                                    edit_text.insert(index,uri.toString());
                                    updateNoteText(mText.getText().toString());//更新到数据库
                                }
                            }else{
                                Toast.makeText(NoteEditor.this, "获取图片失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                        break;
                    case RESULT_CANCELED:
                        break;
                }
                break;
            case PHOTO_FROM_CAMERA:
                if (resultCode == RESULT_OK) {
                    Bitmap originalBitmap1=null;
                    //判断图片是否存在
                    try{
                        originalBitmap1=BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                    }catch (FileNotFoundException e){
                        e.printStackTrace();
                    }
                    if(originalBitmap1 != null){//如果图片存在保存URI
                        //将选择的图片追加到EditText中光标所在位置
                        int index = mText.getSelectionStart(); //获取光标所在位置
                        Editable edit_text = mText.getEditableText();//编辑文本框
                        if(index <0 || index >= edit_text.length()){
                            edit_text.append(imageUri.toString());
                            updateNoteText(mText.getText().toString());//更新到数据库
                        }else{
                            edit_text.insert(index, imageUri.toString());
                            updateNoteText(mText.getText().toString());//更新到数据库
                        }
                    }else{
                        Toast.makeText(NoteEditor.this, "获取图片失败", Toast.LENGTH_SHORT).show();
                    }

                } else {
                    Log.e("result", "is not ok" + resultCode);
                }
                break;
            default:
                break;
        }
    }

(4)定义两个正则表达式,提取文本的图片路径,用SpannableString进行图片文字替换,从而实现图片的插入

private static final String regex="content://com.android.providers.media.documents/"
    +"document/image%\\w{4}";
private static final String reg="file:///storage/emulated/0/\\d+.jpg";

onResumn()和cancelNote()中编写

    int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);//提取数据库中的文本

    String note = mCursor.getString(colNoteIndex);
    ArrayList<String> contentList=new ArrayList<>();//存放图片路径
    ArrayList<Integer> startList=new ArrayList<>();//存放图片路径起点位置
    ArrayList<Integer> endList=new ArrayList<>();//存放图片路径终点位置
    Pattern p=Pattern.compile(regex);
    Matcher m=p.matcher(note);
    //当匹配到图库相应资源地址,将对应信息存入List
    while(m.find()){
        contentList.add(m.group());
        startList.add(m.start());
        endList.add(m.end());
        flag=true;
    }
    p=Pattern.compile(reg);
    m=p.matcher(note);
    //当匹配到拍照的图片相应资源地址,将对应信息存入List
    while(m.find()){
        contentList.add(m.group());
        startList.add(m.start());
        endList.add(m.end());
        flag=true;
    }
    //判断文本中是否有图片资源地址
    if(!flag){
        mText.setText(note);
    }else{
        pushPicture(note,contentList,startList,endList);
    }

图片处理

private void pushPicture(String note,ArrayList<String> contentList,ArrayList<Integer> startList,ArrayList<Integer> endList) {
        //创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
        SpannableString spannableString = new SpannableString(note);
        for(int i=0;i<contentList.size();i++) {
            Uri uri = Uri.parse(contentList.get(i));
            Bitmap bitmap = null;
            try {
                Bitmap originalBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
                bitmap = resizeImage(originalBitmap, 200, 200);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            if (bitmap != null) {
                //根据Bitmap对象创建ImageSpan对象
                ImageSpan imageSpan = new ImageSpan(NoteEditor.this, bitmap);

                //  用ImageSpan对象替换face
                spannableString.setSpan(imageSpan, startList.get(i), endList.get(i), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        mText.setText("");
        Editable edit_text = mText.getEditableText();
        edit_text.append(spannableString);
    }

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设置各文本的提醒时间

代码分析

(1)在NoteEditor.java中添加控件,我是选用Button,比较方便通过监听来处理事件,比较简单,就不作代码演示
(2)在NoteEditor.java中的OptionMenu中添加相应的选项,和选择事件的触发,也比较简单和上述功能类似,也不做代码演示
(3)创建DatePickerDialog和TimePickerDialog来进行时间与日期的选择
1.DatePickerDialog

private void createDateDialog(){
        final Calendar calendar=Calendar.getInstance();
        DatePickerDialog dialog = new DatePickerDialog(this, AlertDialog.THEME_HOLO_DARK,
                new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                        date=year+"-"+(month+1)+"-"+dayOfMonth;
                        if(time!=null){
                            dateButton.setText(date+time);
                        }else{
                            String text=calendar.get(Calendar.HOUR_OF_DAY)+":"+(calendar.get(Calendar.MINUTE)+5);
                            time=" "+text;//如果时间未指定,则默认为当前时间的5分钟后提醒
                            dateButton.setText(date+" "+text);
                        }

                        dateButton.setVisibility(View.VISIBLE);
                    }
                },
                calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH));
        dialog.getDatePicker().setMinDate(System.currentTimeMillis()-1000);//选择以当前时间开始,避免无效时间的选择
        dialog.setTitle("选择日期:");
        dialog.show();
    }

2.TimePickerDialog

private void createTimeDialog(){
        final Calendar calendar=Calendar.getInstance();
        TimePickerDialog dialog=new TimePickerDialog(this, AlertDialog.THEME_HOLO_DARK,new TimePickerDialog.OnTimeSetListener() {
            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                String text=calendar.get(Calendar.YEAR)+"-"+(calendar.get(Calendar.MONTH)+1)+"-"+calendar.get(Calendar.DAY_OF_MONTH);
                /*
                * 判断时间的选择是否为无效时间,在当前的时间之前
                * */
                if(text.equals(date)||date==null){
                    if(hourOfDay<=calendar.get(Calendar.HOUR_OF_DAY))
                        if(minute-5<=calendar.get(Calendar.MINUTE)){
                            //为无效时间的话就将时间设为五分钟之后
                            time=" "+calendar.get(Calendar.HOUR_OF_DAY)+":"+(calendar.get(Calendar.MINUTE)+5);
                        }
                        else{
                            time=" "+calendar.get(Calendar.HOUR_OF_DAY)+":"+minute;
                        }
                    else{
                        time=" "+hourOfDay+":"+minute;
                    }
                }else{
                    time=" "+hourOfDay+":"+minute;
                }
                if(date!=null){
                    dateButton.setText(date+time);
                }else{
                    date=text;
                    dateButton.setText(text+time);
                }
                dateButton.setVisibility(View.VISIBLE);
            }
        },
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE), true);
        dialog.setTitle("选择时间:");

        dialog.show();
    }

(4)当保存笔记之后,将需要提醒的信息封装进PendingIntent,以广播的形式发送出去

private void notifyMessage(){
        if(time!=null&&date!=null){
            SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm");
            long t=System.currentTimeMillis()+5000;
            try {
                t=simpleDateFormat.parse(date+time).getTime();
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            //是Intent跳转到指定的广播处理
            Intent intent=new Intent(NoteEditor.this, RemindActionBroadcast.class);
            /*
            * 把文本的内容和标题存入Intent
            * */
            intent.putExtra("title",mCursor.getString(mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE)));
            intent.putExtra("context",mCursor.getString(mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE)));
            //将requestCode设为每个文本的ID以实现能够发送不同的信息,不会被覆盖
            PendingIntent pendingIntent=PendingIntent.getBroadcast(NoteEditor.this,mCursor.getInt(mCursor.getColumnIndex(NotePad.Notes._ID)),intent,PendingIntent.FLAG_UPDATE_CURRENT);

            Calendar calendar=Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.add(Calendar.SECOND,(int)((t-System.currentTimeMillis())/1000));

            //使用AlarmManager实现定时功能
            AlarmManager alarmManager=(AlarmManager)getSystemService(ALARM_SERVICE);
            alarmManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent);
        }
    }

(5)在广播接受类中进行处理和通知

public class RemindActionBroadcast extends BroadcastReceiver {
    public static int id=0;
    @Override
    public void onReceive(Context context, Intent intent) {

        PendingIntent pendingIntent=PendingIntent.getActivity(context,0,intent,0);
        NotificationManager notificationManager=(NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
        Notification.Builder mbuilder=new Notification.Builder(context);
        mbuilder.setContentTitle(intent.getStringExtra("title"));//设置通知栏标题
        mbuilder.setContentText(intent.getStringExtra("context"));//设置通知栏内容
        mbuilder.setSmallIcon(R.mipmap.ic_launcher);//设置小图标
        mbuilder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher));//设置大图标
        mbuilder.setContentIntent(pendingIntent);//设置点击跳转的Intent,因为没有设置uri,所以跳转为空
        mbuilder.setAutoCancel(true);//点击之后消失
        Notification notification=mbuilder.build();
        notificationManager.notify(id++,notification);//能够传送多条消息
    }
}

(6)点击设置时间按钮取消设置通知时间

public void dateClick(View view){
        AlertDialog.Builder builder=new AlertDialog.Builder(this);
        builder.setMessage("请确认是否删除提醒时间:").setPositiveButton("确认", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                date=null;
                time=null;
                dateButton.setVisibility(View.GONE);
                dialog.dismiss();
            }
        }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
    }

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后

附上源码地址:https://github.com/smartflowers/MyNotePad
记得点个Star哟

在这里插入图片描述

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Android记事本上设置使用中文,您可以按照以下步骤进行操作: 1. 打开您的Android设备上的记事本应用程序。大多数设备默认已经安装有记事本应用程序。 2. 进入记事本的设置选项。您可以在记事本的主界面上找到一个齿轮形状的图标,点击它即可进入设置页面。 3. 在设置页面中,寻找语言设置选项。这个选项通常位于“常规”或“外观”等相关设置中。 4. 点击语言设置选项,进入语言选择页面。您会看到一个列表,其中列出了各种可用的语言。 5. 在语言列表中,找到并选择中文。您可以滚动浏览或使用搜索框快速定位。 6. 选择中文后,返回到记事本的主界面。您会发现应用程序已经切换为中文显示了。 现在,您已经成功将Android记事本设置为中文。您可以根据需要使用中文输入或阅读中文内容。希望这个回答对您有所帮助! ### 回答2: 要在Android Notepad(便签)应用中设置中文,可以按照以下步骤进行操作: 1. 打开Android设备上的应用程序列表,并找到Notepad(便签)应用。 2. 单击应用图标以打开该应用。 3. 在Notepad(便签)应用中,找到设置选项。通常可以在右上角的菜单按钮中找到。 4. 单击设置选项以进入设置界面。 5. 在设置界面中,浏览不同的选项,寻找关于语言或输入的设置选项。 6. 找到语言或输入设置选项后,单击进入该选项的子菜单。 7. 在语言或输入子菜单中,查找和选择中文作为首选语言。可以通过单击中文选项或切换开关将中文设置为默认语言。 8. 退出设置界面并返回Notepad(便签)应用。 9. 现在,Notepad(便签)应用将以中文显示,您可以使用中文输入法输入和编辑文本。 请注意,不同的Android设备和Notepad(便签)应用版本可能具有不同的设置界面和选项名称。如果上述步骤与您的设备不符,可以尝试在Notepad(便签)应用的帮助文档或在设备的设置菜单中寻找更具体的设置选项。 希望这些步骤能帮助您在Android Notepad(便签)应用程序中成功设置中文显示。 ### 回答3: 要在Android的记事本应用中设置中文,只需按照以下步骤操作: 1. 打开你的Android手机或平板上的记事本应用。记事本应用通常是预装在设备上的,你可以在应用列表中找到它。 2. 进入应用后,打开设置选项。在许多记事本应用中,设置选项通常是通过在屏幕上滑动来显示隐藏菜单栏。 3. 在设置菜单中,找到“语言”或“语言和地区”选项。这个选项可能在不同的应用中有所区别,但通常会提供选择与语言相关的设置。 4. 点击“语言”选项后,你会看到一个包含可用语言的列表。在这个列表中,找到“中文”或“Chinese”选项,然后点击选择。 5. 一旦选择了中文,记事本应用会立即应用该设置,并将应用界面的语言切换为中文。你可以在记事本应用的界面上看到这一变化。 请注意,有些记事本应用的设置选项可能与上述步骤略有不同,但大体上应该是相似的。如果你无法找到设置中文语言选项,你可以尝试进入设备的整体设置,然后找到语言或区域设置,将系统的语言设置为中文。这样一来,记事本应用的界面语言通常也会随之更改为中文。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值