NotePad记事本——Android 笔记应用开发

NotePad记事本——Android 笔记应用开发

Android 笔记应用开发背景
在移动办公与学习场景日益普及的当下,便捷的笔记工具成为刚需。传统记事本功能单一,难以满足用户分类管理、快速查询、数据备份等多元化需求。基于此,本次以 NotePad 开源项目为基础,开展 Android 笔记应用扩展开发,通过新增时间戳、查询功能及个性化拓展,打造更贴合用户使用习惯、功能全面且体验优良的笔记工具,夯实移动开发技术实践。

一、核心功能实现:满足基础使用需求
根据实验要求,我首先完成了三项核心功能的开发,确保应用的基础实用性。

(一)笔记查询功能开发
为了让用户能快速找到所需笔记,我实现了基于标题和内容的模糊查询功能:

在 NoteList 界面顶部添加搜索框组件,设置搜索按钮和输入监听;
优化数据访问层,增加查询方法,支持根据输入关键词对笔记标题和内容进行模糊匹配;
处理搜索结果的展示逻辑,当用户输入关键词并点击搜索后,列表会实时刷新显示匹配的笔记;
支持搜索框为空时自动显示所有笔记,提升用户体验。
(二)UI 美化优化
原应用的 UI 风格较为简洁,缺乏个性化设计,我从以下几个方面进行了美化:

主题定制:为应用设计了不同颜色主题,用户可根据使用场景切换;
背景优化:允许用户为记事本选择自定义背景,提供多种纯色背景和简约图案背景供选择,也支持设置透明度,避免背景影响文字阅读;
编辑器优化:调整笔记编辑界面的字体大小、行间距,增加字体颜色选择功能,支持粗体、斜体等基础格式设置,提升编辑体验;
列表项优化:为笔记列表项添加圆角效果和轻微阴影,hover 时显示高亮状态,让界面更具层次感。
二、主要功能模块
在完成核心功能后,我额外实现了四项实用的扩展功能,让应用更具竞争力。

  1. 笔记管理
  • 创建笔记
  • 编辑笔记
  • 删除笔记
  • 复制笔记
  • 搜索笔记
  • 分类管理
  1. 用户界面
  • 列表视图
  • 编辑视图
  • 背景颜色切换
  1. 数据持久化
  • SQLite 数据库存储
  • ContentProvider 数据访问
  • 自动保存机制
  1. 高级功能
  • Live Folder 支持
  • 剪贴板集成
  • Intent 过滤器
  • 替代操作(Alternative Actions)

三、项目结构分析

  1. NotesList.java
    功能: 笔记列表主界面Activity

主要职责:

  • 显示所有笔记的列表
  • 支持搜索功能
  • 提供创建、编辑、删除笔记的入口
  • 支持背景颜色切换

/**
* 自定义CursorAdapter,用于在列表项中显示笔记信息并设置操作按钮。
*
*

该类扩展了SimpleCursorAdapter,添加了以下功能:
*


  • *
  • 自定义视图绑定:显示标题、内容预览、时间戳和缩略图

  • *
  • 编辑按钮:快速编辑笔记

  • *
  • 删除按钮:快速删除笔记(带确认对话框)

  • *
  • 搜索模式适配:在搜索模式下隐藏操作按钮

  • *

*
*

视图元素:
*


  • *
  • 标题(text1):笔记标题

  • *
  • 内容预览(text_content_preview):笔记内容的前80个字符

  • *
  • 时间戳(text_timestamp):修改日期(可选显示)

  • *
  • 缩略图(thumbnail):根据内容类型显示的图标

  • *
  • 编辑按钮(btn_edit):打开编辑界面

  • *
  • 删除按钮(btn_delete):删除笔记

  • *

*
* @see android.widget.SimpleCursorAdapter
*/
private class NotesCursorAdapter extends SimpleCursorAdapter {
public NotesCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);
        
        // Convert cursor to Note entity
        Cursor cursor = (Cursor) getItem(position);
        Note note = Note.fromCursor(cursor);
        
        if (note != null) {
            // Set title using entity getter
            TextView textTitle = (TextView) view.findViewById(android.R.id.text1);
            if (textTitle != null && note.getTitle() != null) {
                textTitle.setText(note.getTitle());
            }
            
            // Set content preview using entity getter
            TextView textContentPreview = (TextView) view.findViewById(R.id.text_content_preview);
            if (textContentPreview != null) {
                String noteContent = note.getNote();
                if (noteContent != null && noteContent.length() > 0) {
                    // Remove line breaks and limit length for preview
                    String preview = noteContent.replaceAll("\\n", " ").trim();
                    if (preview.length() > 100) {
                        preview = preview.substring(0, 100) + "...";
                    }
                    textContentPreview.setText(preview);
                    textContentPreview.setVisibility(View.VISIBLE);
                } else {
                    textContentPreview.setVisibility(View.GONE);
                }
            }
            
            // Set timestamp using entity getter
            TextView textTimestamp = (TextView) view.findViewById(R.id.text_timestamp);
            if (textTimestamp != null) {
                boolean isSearchMode = mCurrentFilter != null && mCurrentFilter.length() > 0;
                if (isSearchMode || !mShowTimestamp) {
                    textTimestamp.setVisibility(View.GONE);
                } else {
                    textTimestamp.setVisibility(View.VISIBLE);
                    // Only show modified date
                    long modified = note.getModified();
                    if (modified > 0) {
                        DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日", java.util.Locale.CHINESE);
                        String dateStr = dateFormat.format(new Date(modified));
                        textTimestamp.setText(dateStr);
                    }
                }
            }
            
            // Setup edit and delete buttons
            long noteId = cursor.getLong(0);
            if (noteId >= 0) {
                Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), noteId);
                boolean isSearchMode = mCurrentFilter != null && mCurrentFilter.length() > 0;
                
                ImageButton btnEdit = (ImageButton) view.findViewById(R.id.btn_edit);
                ImageButton btnDelete = (ImageButton) view.findViewById(R.id.btn_delete);
                
                if (isSearchMode) {
                    if (btnEdit != null) btnEdit.setVisibility(View.GONE);
                    if (btnDelete != null) btnDelete.setVisibility(View.GONE);
                } else {
                    if (btnEdit != null) {
                        btnEdit.setVisibility(View.VISIBLE);
                        btnEdit.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                startActivity(new Intent(Intent.ACTION_EDIT, noteUri));
                            }
                        });
                    }
                    if (btnDelete != null) {
                        btnDelete.setVisibility(View.VISIBLE);
                        btnDelete.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                new AlertDialog.Builder(NotesList.this)
                                        .setTitle(R.string.menu_delete)
                                        .setMessage(getString(R.string.confirm_delete_message))
                                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                getContentResolver().delete(noteUri, null, null);
                                                Cursor newCursor = queryNotes(mCurrentFilter);
                                                mAdapter.swapCursor(newCursor);
                                                mCursor = newCursor;
                                                updateListTitle();
                                            }
                                        })
                                        .setNegativeButton(android.R.string.no, null)
                                        .show();
                            }
                        });
                    }
                }
            }
        }
        
        return view;
    }
}
  1. NoteEditor.java
    功能: 笔记编辑Activity

主要职责:

  • 创建新笔记
  • 编辑现有笔记
  • 从剪贴板粘贴创建笔记
  • 支持背景颜色自定义
  • 自动保存功能

/**
* 自定义EditText视图,在每行文本之间绘制行线。
*
*

该类扩展了标准的EditText,添加了类似笔记本的行线效果,
* 使文本编辑体验更接近真实的纸质笔记本。
*
*

特性:
*


  • *
  • 自动绘制行线

  • *
  • 支持主题感知的行线颜色

  • *
  • 行线位置与文本基线对齐

  • *

*
*

使用方式:在布局XML中直接使用此类作为EditText的替代。
*
* @see android.widget.EditText
*/
public static class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;

    // This constructor is used by LayoutInflater
    public LinedEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Creates a Rect and a Paint object, and sets the style and color of the Paint object.
        mRect = new Rect();
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(1.0f);
        
        // Use theme-aware color for lines
        // Default to a subtle gray that works in both light and dark themes
        int lineColor = 0x40000000; // Semi-transparent black (works in light theme)
        try {
            // Try to get theme color
            android.content.res.TypedArray a = context.obtainStyledAttributes(
                new int[]{android.R.attr.textColorSecondary});
            int textColorSecondary = a.getColor(0, 0x40000000);
            a.recycle();
            // Use a lighter version for lines
            lineColor = (textColorSecondary & 0x00FFFFFF) | 0x40000000;
        } catch (Exception e) {
            // Fallback to default
        }
        mPaint.setColor(lineColor);
    }
  1. NotePad.java
    功能: 数据库契约类(Contract Class)

主要职责:

  • 定义数据库表结构常量
  1. NotePadProvider.java
    功能: 数据访问层

主要职责:

  • 管理 SQLite 数据库
  • 提供增删改查操作
  1. NotePadSettings.java
    功能: 应用设置Activity

主要职责:

  • 背景颜色设置
  • 时间戳显示开关
  • 默认排序方式设置

/**

  • NotePad设置Activity,提供应用配置选项。
  • 允许用户配置以下选项:

    • 主题选择:浅色主题或深色主题
    • 时间戳显示:控制是否在列表中显示笔记的修改时间
    • 默认排序:按时间或按标题排序
    • 使用PreferenceActivity和SharedPreferences来管理用户设置。

    • 主题变更会立即应用到整个应用。
      */
    • import android.content.SharedPreferences;
      import android.os.Bundle;
      import android.preference.PreferenceActivity;
      import android.preference.PreferenceManager;

      public class NotePadSettings extends PreferenceActivity
      implements SharedPreferences.OnSharedPreferenceChangeListener {

      public static final String PREF_THEME = "pref_theme";
      public static final String PREF_THEME_LIGHT = "light";
      public static final String PREF_THEME_DARK = "dark";
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          // Apply theme before super.onCreate
          applyTheme();
          super.onCreate(savedInstanceState);
          addPreferencesFromResource(R.xml.preferences);
          
          // Register preference change listener
          PreferenceManager.getDefaultSharedPreferences(this)
                  .registerOnSharedPreferenceChangeListener(this);
      }
      
      @Override
      protected void onDestroy() {
          super.onDestroy();
          PreferenceManager.getDefaultSharedPreferences(this)
                  .unregisterOnSharedPreferenceChangeListener(this);
      }
      
      @Override
      public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
          if (PREF_THEME.equals(key)) {
              // Theme changed, recreate activity to apply new theme
              recreate();
          }
      }
      
      /**
       * Apply theme based on user preference.
       */
      private void applyTheme() {
          SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
          String theme = prefs.getString(PREF_THEME, PREF_THEME_LIGHT);
          
          if (PREF_THEME_DARK.equals(theme)) {
              setTheme(android.R.style.Theme_Holo);
          } else {
              setTheme(android.R.style.Theme_Holo_Light);
          }
      }
      

      }

      1. TitleEditor.java
        功能: 标题编辑Activity

      主要职责:

      • 提供独立的标题编辑界面
      1. NotesLiveFolder.java
        功能: Live Folder 创建Activity

      主要职责:

      • 创建 Android Live Folder
      1. Note.java
        功能: 笔记实体类

      主要职责:

      • 封装笔记数据
      • 提供从 Cursor 创建 Note 对象的工厂方法

      关键属性:

      • id: 笔记ID
      • title: 标题
      • note: 内容
      • created: 创建时间
      • modified: 修改时间
      • category: 分类

      public class Note {
      private long id;
      private String title;
      private String note;
      private long created;
      private long modified;
      private String category;

      public Note() {
      }
      
      public Note(long id, String title, String note, long created, long modified, String category) {
          this.id = id;
          this.title = title;
          this.note = note;
          this.created = created;
          this.modified = modified;
          this.category = category;
      }
      

      数据库结构:notes 表

      | 列名 | 类型 | 说明 |
      | ID | INTEGER PRIMARY KEY | 主键,自增 |
      | title | TEXT | 笔记标题 |
      | note | TEXT | 笔记内容 |
      | created | INTEGER | 创建时间戳 |
      | modified | INTEGER | 修改时间戳 |
      | category | TEXT | 分类 |

      四、技术栈

      • 开发语言: Java
      • 最低 SDK: Android API Level
      • 数据库: SQLite
      • 数据访问: ContentProvider
      • UI 框架: Android SDK
      • 构建工具: Gradle

      五、开发总结与未来规划
      通过这次 NotePad 应用的扩展开发,我不仅巩固了 Android 基础开发知识,还学会了如何从用户需求出发设计功能,提升应用的实用性和用户体验。在开发过程中,我也遇到了不少问题,比如数据库升级时的数据兼容、云备份的同步逻辑等,通过查阅官方文档、请教同学和调试代码,最终都顺利解决了这些问题。

      未来,我计划继续完善这款应用,添加更多实用功能,比如:

      支持多类型笔记,如图片、语音、视频等多媒体内容的存储;
      实现 OCR 扫描功能,支持将纸质文档扫描为电子笔记;
      增加语音搜索功能,用户可通过语音指令快速查找笔记;
      优化云同步功能,支持多设备实时同步笔记数据。

      作者:黄哲轩
      原文链接:NotePad记事本——Android 笔记应用开发

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值