diff --git a/java/net/micode/notes/ui/NoteEditText.java b/java/net/micode/notes/ui/NoteEditText.java index 2afe2a8..b53aa46 100644 --- a/java/net/micode/notes/ui/NoteEditText.java +++ b/java/net/micode/notes/ui/NoteEditText.java @@ -36,16 +36,19 @@ import net.micode.notes.R; import java.util.HashMap; import java.util.Map; - +/** + * 自定义EditText,用于笔记编辑界面 + * 扩展功能包括:支持链接识别、回车换行处理、删除空行处理等 + */ public class NoteEditText extends EditText { private static final String TAG = "NoteEditText"; - private int mIndex; - private int mSelectionStartBeforeDelete; - + private int mIndex;// 当前EditText在列表中的索引位置 + private int mSelectionStartBeforeDelete;// 删除操作前的光标起始位置 + // 链接协议常量 private static final String SCHEME_TEL = "tel:" ; private static final String SCHEME_HTTP = "http:" ; private static final String SCHEME_EMAIL = "mailto:" ; - + // 链接协议与对应菜单资源ID的映射 private static final Map sSchemaActionResMap = new HashMap(); static { sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); @@ -76,16 +79,16 @@ public class NoteEditText extends EditText { } private OnTextViewChangeListener mOnTextViewChangeListener; - + //构造方法 public NoteEditText(Context context) { super(context, null); mIndex = 0; } - + // 设置当前EditText索引 public void setIndex(int index) { mIndex = index; } - + // 设置文本变化监听器 public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { mOnTextViewChangeListener = listener; } @@ -101,20 +104,22 @@ public class NoteEditText extends EditText { @Override public boolean onTouchEvent(MotionEvent event) { + // 处理触摸事件,精确定位光标位置 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - + // 计算触摸点坐标(考虑padding和滚动偏移) int x = (int) event.getX(); int y = (int) event.getY(); x -= getTotalPaddingLeft(); y -= getTotalPaddingTop(); x += getScrollX(); y += getScrollY(); - + + // 获取触摸点对应的文本位置 Layout layout = getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); - Selection.setSelection(getText(), off); + Selection.setSelection(getText(), off);// 设置光标位置 break; } @@ -123,14 +128,15 @@ public class NoteEditText extends EditText { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + // 按键按下事件处理 switch (keyCode) { - case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_ENTER://回车键 if (mOnTextViewChangeListener != null) { - return false; + return false;// 交给onKeyUp处理 } break; - case KeyEvent.KEYCODE_DEL: - mSelectionStartBeforeDelete = getSelectionStart(); + case KeyEvent.KEYCODE_DEL://删除键 + mSelectionStartBeforeDelete = getSelectionStart();// 记录删除前光标位置 break; default: break; @@ -140,23 +146,26 @@ public class NoteEditText extends EditText { @Override public boolean onKeyUp(int keyCode, KeyEvent event) { + // 按键释放事件处理 switch(keyCode) { - case KeyEvent.KEYCODE_DEL: + case KeyEvent.KEYCODE_DEL://删除键 if (mOnTextViewChangeListener != null) { + // 如果光标在开头且不是第一个EditText,则删除当前EditText if (0 == mSelectionStartBeforeDelete && mIndex != 0) { mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); - return true; + return true;// 已处理,不继续传递 } } else { Log.d(TAG, "OnTextViewChangeListener was not seted"); } break; - case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_ENTER:// 回车键 if (mOnTextViewChangeListener != null) { + // 从光标处分割文本,后半部分放入新EditText int selectionStart = getSelectionStart(); String text = getText().subSequence(selectionStart, length()).toString(); - setText(getText().subSequence(0, selectionStart)); - mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); + setText(getText().subSequence(0, selectionStart));// 保留前半部分 + mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);// 创建新EditText } else { Log.d(TAG, "OnTextViewChangeListener was not seted"); } @@ -169,11 +178,12 @@ public class NoteEditText extends EditText { @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + // 焦点变化时通知监听器 if (mOnTextViewChangeListener != null) { if (!focused && TextUtils.isEmpty(getText())) { - mOnTextViewChangeListener.onTextChange(mIndex, false); + mOnTextViewChangeListener.onTextChange(mIndex, false); // 无文本 } else { - mOnTextViewChangeListener.onTextChange(mIndex, true); + mOnTextViewChangeListener.onTextChange(mIndex, true); // 有文本 } } super.onFocusChanged(focused, direction, previouslyFocusedRect); @@ -181,15 +191,17 @@ public class NoteEditText extends EditText { @Override protected void onCreateContextMenu(ContextMenu menu) { + // 创建上下文菜单(长按弹出) if (getText() instanceof Spanned) { int selStart = getSelectionStart(); int selEnd = getSelectionEnd(); - + // 获取选中范围的URL链接 int min = Math.min(selStart, selEnd); int max = Math.max(selStart, selEnd); final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); if (urls.length == 1) { + // 根据URL类型添加对应的菜单项 int defaultResId = 0; for(String schema: sSchemaActionResMap.keySet()) { if(urls[0].getURL().indexOf(schema) >= 0) { @@ -199,9 +211,9 @@ public class NoteEditText extends EditText { } if (defaultResId == 0) { - defaultResId = R.string.note_link_other; + defaultResId = R.string.note_link_other; // 默认菜单项 } - + // 添加菜单项并设置点击事件 menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) {