You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
java/ui/NoteEditText.java

199 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
// 导入所需的 Android SDK 类和包
public class NoteEditText extends EditText {
// 类成员变量
private static final String TAG = "NoteEditText";
private int mIndex; // 当前笔记的索引
private int mSelectionStartBeforeDelete; // 删除前的文本选择开始位置
// 定义几种常见的 URL Scheme
private static final String SCHEME_TEL = "tel:" ;
private static final String SCHEME_HTTP = "http:" ;
private static final String SCHEME_EMAIL = "mailto:" ;
// 定义一个映射表,用于将 URL Scheme 映射到对应的操作资源 ID
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
static {
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
}
// 定义一个接口,用于处理文本视图的变化事件
public interface OnTextViewChangeListener {
void onEditTextDelete(int index, String text);
void onEditTextEnter(int index, String text);
void onTextChange(int index, boolean hasText);
}
// 成员变量,用于回调文本变化事件
private OnTextViewChangeListener mOnTextViewChangeListener;
// 构造函数,用于创建 NoteEditText 实例
public NoteEditText(Context context) {
super(context, null);
mIndex = 0;
}
// 设置当前笔记的索引
public void setIndex(int index) {
mIndex = index;
}
// 设置文本变化事件的监听器
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
// 其他构造函数,用于从 XML 布局文件中创建 NoteEditText 实例
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
}
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 空的构造函数体,可能用于后续扩展
}
// 重写 onTouchEvent 方法,用于处理触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
// 当用户触摸屏幕时,获取触摸位置,并更新文本的选择位置
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 计算触摸位置,并设置文本选择
// ...
break;
}
// 调用父类的 onTouchEvent 方法
return super.onTouchEvent(event);
}
// 重写 onKeyDown 方法,用于处理按键事件
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 处理回车键和删除键的事件
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
// 如果设置了文本变化监听器,调用其 onEditTextEnter 方法
// ...
return false;
case KeyEvent.KEYCODE_DEL:
// 记录删除前的文本选择开始位置
mSelectionStartBeforeDelete = getSelectionStart();
break;
default:
// 默认行为
break;
}
// 调用父类的 onKeyDown 方法
return super.onKeyDown(keyCode, event);
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch(keyCode) {
case KeyEvent.KEYCODE_DEL:
if (mOnTextViewChangeListener != null) {
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
return true;
}
} else {
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
case KeyEvent.KEYCODE_ENTER:
if (mOnTextViewChangeListener != null) {
int selectionStart = getSelectionStart();
String text = getText().subSequence(selectionStart, length()).toString();
setText(getText().subSequence(0, selectionStart));
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
} else {
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
default:
break;
}
return super.onKeyUp(keyCode, event);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
// 当控件获得或失去焦点时调用
if (mOnTextViewChangeListener != null) {
// 如果设置了文本变化监听器
if (!focused && TextUtils.isEmpty(getText())) {
// 如果控件失去焦点并且文本为空,则通知监听器没有文本
mOnTextViewChangeListener.onTextChange(mIndex, false);
} else {
// 否则,通知监听器文本已更改
mOnTextViewChangeListener.onTextChange(mIndex, true);
}
}
// 调用父类的 onFocusChanged 方法
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
protected void onCreateContextMenu(ContextMenu menu) {
// 当需要创建上下文菜单时调用
if (getText() instanceof Spanned) {
// 如果文本是 Spanned 类型(可以包含样式,如 URLSpan
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
// 获取当前选中文本中的 URLSpan 对象
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
if (urls.length == 1) {
// 如果选中的文本只包含一个 URLSpan
int defaultResId = 0;
for(String schema: sSchemaActionResMap.keySet()) {
// 检查 URL 是否匹配预定义的 Scheme
if(urls[0].getURL().indexOf(schema) >= 0) {
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
// 如果没有匹配的 Scheme使用默认的资源 ID
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
// 添加一个菜单项,并设置点击事件
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
// 当点击菜单项时,执行 URLSpan 的 onClick 方法(可能会打开一个网页或打电话等)
urls[0].onClick(NoteEditText.this);
return true;
}
});
}
}
// 调用父类的 onCreateContextMenu 方法
super.onCreateContextMenu(menu);
}