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.
read/src/net/micode/notes/ui/NoteEditText.java

214 lines
10 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; // 定义包名
import android.content.Context; // 导入Context类
import android.graphics.Rect; // 导入Rect类
import android.text.Layout; // 导入Layout类
import android.text.Selection; // 导入Selection类
import android.text.Spanned; // 导入Spanned接口
import android.text.TextUtils; // 导入TextUtils类
import android.text.style.URLSpan; // 导入URLSpan类
import android.util.AttributeSet; // 导入AttributeSet类
import android.util.Log; // 导入Log类
import android.view.ContextMenu; // 导入ContextMenu类
import android.view.KeyEvent; // 导入KeyEvent类
import android.view.MenuItem; // 导入MenuItem类
import android.view.MenuItem.OnMenuItemClickListener; // 导入菜单项点击监听器接口
import android.view.MotionEvent; // 导入MotionEvent类
import android.widget.EditText; // 导入EditText类
import net.micode.notes.R; // 导入资源类
import java.util.HashMap; // 导入HashMap类
import java.util.Map; // 导入Map接口
public class NoteEditText extends EditText { // 定义NoteEditText类继承自EditText
private static final String TAG = "NoteEditText"; // 日志TAG
private int mIndex; // 当前索引
private int mSelectionStartBeforeDelete; // 删除前的选择起始位置
private static final String SCHEME_TEL = "tel:"; // 电话链接前缀
private static final String SCHEME_HTTP = "http:"; // HTTP链接前缀
private static final String SCHEME_EMAIL = "mailto:"; // 邮件链接前缀
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); // HTTP链接
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); // 邮件链接
}
/**
* 被{@link NoteEditActivity}调用以删除或添加编辑文本
*/
public interface OnTextViewChangeListener { // 文本视图变化监听器接口
/**
* 当{@link KeyEvent#KEYCODE_DEL}发生且文本为空时删除当前编辑文本
*/
void onEditTextDelete(int index, String text); // 删除事件
/**
* 当{@link KeyEvent#KEYCODE_ENTER}发生时,在当前编辑文本后添加编辑文本
*/
void onEditTextEnter(int index, String text); // 添加事件
/**
* 文本变化时隐藏或显示项选项
*/
void onTextChange(int index, boolean hasText); // 文本变化事件
}
private OnTextViewChangeListener mOnTextViewChangeListener; // 文本视图变化监听器
public NoteEditText(Context context) { // 构造函数
super(context, null); // 调用父类构造函数
mIndex = 0; // 初始化索引为0
}
public void setIndex(int index) { // 设置索引
mIndex = index; // 更新索引
}
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { // 设置文本视图变化监听器
mOnTextViewChangeListener = listener; // 更新监听器
}
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); // 调用父类构造函数
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) { // 触摸事件处理
switch (event.getAction()) { // 处理触摸事件的不同动作
case MotionEvent.ACTION_DOWN: // 按下动作
int x = (int) event.getX(); // 获取触摸点的x坐标
int y = (int) event.getY(); // 获取触摸点的y坐标
x -= getTotalPaddingLeft(); // 减去左侧填充
y -= getTotalPaddingTop(); // 减去顶部填充
x += getScrollX(); // 添加水平滚动值
y += getScrollY(); // 添加垂直滚动值
Layout layout = getLayout(); // 获取布局
int line = layout.getLineForVertical(y); // 获取y坐标对应的行号
int off = layout.getOffsetForHorizontal(line, x); // 获取x坐标对应的偏移
Selection.setSelection(getText(), off); // 设置文本选择
break;
}
return super.onTouchEvent(event); // 调用父类的触摸事件处理
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { // 按键按下处理
switch (keyCode) { // 根据按键代码进行处理
case KeyEvent.KEYCODE_ENTER: // 回车键
if (mOnTextViewChangeListener != null) { // 如果设置了监听器
return false; // 不处理
}
break;
case KeyEvent.KEYCODE_DEL: // 删除键
mSelectionStartBeforeDelete = getSelectionStart(); // 保存删除前的选择起始位置
break;
default:
break;
}
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) { // 如果删除前选择位置为0且当前索引不为0
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); // 通知删除
return true; // 返回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); // 通知文本变化为有文本
}
}
super.onFocusChanged(focused, direction, previouslyFocusedRect); // 调用父类的焦点变化处理
}
@Override
protected void onCreateContextMenu(ContextMenu menu) { // 创建上下文菜单
if (getText() instanceof Spanned) { // 如果文本是Spanned类型
int selStart = getSelectionStart(); // 获取选择起始位置
int selEnd = getSelectionEnd(); // 获取选择结束位置
int min = Math.min(selStart, selEnd); // 选择的最小位置
int max = Math.max(selStart, selEnd); // 选择的最大位置
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); // 获取选中的URLSpan
if (urls.length == 1) { // 如果选中的URLSpan只有一个
int defaultResId = 0; // 初始化默认资源ID
for (String schema : sSchemaActionResMap.keySet()) { // 遍历链接方案映射
if (urls[0].getURL().indexOf(schema) >= 0) { // 检查URL是否包含方案
defaultResId = sSchemaActionResMap.get(schema); // 获取对应的资源ID
break; // 跳出循环
}
}
if (defaultResId == 0) { // 如果没有匹配的方案
defaultResId = R.string.note_link_other; // 设置为其他链接
}
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( // 添加菜单项
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) { // 菜单项点击事件
// 触发网址点击的意图
urls[0].onClick(NoteEditText.this); // 当点击URL时调用其onClick方法
return true; // 返回true表示事件已处理
}
});
}
}
super.onCreateContextMenu(menu); // 调用父类的上下文菜单创建处理
}
}