在Android系统里,原生的EditText里输入了字符串后,再长按“选择文字”,“剪切”,“粘贴”,这个字符串的前后会加上空格,这个本来是为了用户体验,告诉用户字符串是粘贴的,但是在某些地方,会因为空格而导致错误,比如Calculator。今天就以Calculator为例,介绍下我的解决思路和想法。因为空格是为了提示用户,所以保留空格,只处理计算结果,后面也会告诉大家该怎么解决空格的。
1.当长按文字后出现ContextMenu
2.然后长按出现"剪切",然后"粘贴",
3.输入"减号"后得到结果,现在是修改好的,没有问题了。
因为要处理最终的输出结果,所以就追踪"="的相关代码。
在App下的Calculator下就是计算器的相关代码。从main.xml布局中这段代码找到"="的ID.
<com.android.calculator2.ColorButton
android:id="@+id/equal"
android:text="@string/equal"
style="@style/button_style"
/>
然后根据ID来搜索项目,得到4个类里含有这个字符串,在根据这些类里的方法,判断EventListener.java才是我们要找的。
case R.id.equal:
mHandler.onEnter();
break;
然后点击onEnter()方法,跳转到Logic.java的onEnter()方法了,这里就是最终的计算结果,我们在这里过滤掉空格即可。
void onEnter() {
//start add
String text = getText();
StringBuilder sb=new StringBuilder();
for(int i=0;i<text.length();i++){
if(text.charAt(i)!=' '){
sb.append(text.charAt(i));
}
}
text=sb.toString();
//end add
if (text.equals(mResult)) {
clearWithHistory(false); //clear after an Enter on result
} else {
mHistory.enter(text);
try {
mResult = evaluate(text);
} catch (SyntaxException e) {
mIsError = true;
mResult = mErrorString;
}
if (text.equals(mResult)) {
//no need to show result, it is exactly what the user entered
clearWithHistory(true);
} else {
setText(mResult);
//mEqualButton.setText(mEnterString);
}
}
}
现在计算器这里的结果输出就正常了,大家可以试试自己的手机,HTC G10就是错误的,虚拟机也是错误的。
要想让所有的EditText的空格都没有,因为是"粘贴"之后出现的,所以从"粘贴"跟系统的这个ContextMenu入手。到Framework的base/core/res/res/values/strings.xml里搜索"编辑文字",因为这个字符串比较偏,可以减少大量重复结果。
<string name="editTextMenuTitle" msgid="1672989176958581452">"编辑文字"</string>
然后用SourceInsight这个软件来搜索name,根据结果显示在TextView.java这个类的onCreateContextMenu(ContextMenu menu)方法里引用了这个name。
if (added) {
hideControllers();
menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
}
这里就是创建这个ContextMenu的地方了。
onTextContextMenuItem(int id)这个方法是用来判断用户选择了那个事件,比如“剪切”,“粘贴”等。
case ID_PASTE:
CharSequence paste = clip.getText();
android.util.Log.e("kingfly","kingfly selectText ID_PASTE paste :"+paste.toString()+":>>>>>>");
if (paste != null && paste.length() > 0) {
long minMax = prepareSpacesAroundPaste(min, max, paste);
android.util.Log.e("kingfly","kingfly selectText ID_PASTE minMax :"+minMax);
min = extractRangeStartFromLong(minMax);
max = extractRangeEndFromLong(minMax);
android.util.Log.e("kingfly","kingfly selectText ID_PASTE min :"+min+" max :"+max);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
stopTextSelectionMode();
}
return true;
然后看里面的prepareSpacesAroundPaste(int min, int max, CharSequence paste)这个方法,这个就是用来控制空格的。
/**
* Prepare text so that there are not zero or two spaces at beginning and end of region defined
* by [min, max] when replacing this region by paste.
*/
private long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
// Paste adds/removes spaces before or after insertion as needed.
android.util.Log.e("kingfly","kingfly prepareSpacesAroundPaste :"+paste);
if (Character.isSpaceChar(paste.charAt(0))) {
if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
// Two spaces at beginning of paste: remove one
final int originalLength = mText.length();
//空格
((Editable) mText).replace(min - 1, min, "");
// Due to filters, there is no garantee that exactly one character was
// removed. Count instead.
final int delta = mText.length() - originalLength;
min += delta;
max += delta;
}
} else {
if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) {
// No space at beginning of paste: add one
final int originalLength = mText.length();
//空格
((Editable) mText).replace(min, min, "");
// Taking possible filters into account as above.
final int delta = mText.length() - originalLength;
min += delta;
max += delta;
}
}
if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
// Two spaces at end of paste: remove one
//空格
((Editable) mText).replace(max, max + 1, "");
}
} else {
if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
// No space at end of paste: add one
//空格
((Editable) mText).replace(max, max, "");
}
}
return packRangeInLong(min, max);
}
这就是我们一般定位问题的方式,根据字符串或者图片来找到相关的代码,进行修改,一些自己新增的功能则需自己调研了。
相关代码可以自行下载google源码进行分析,我们用的是基于高通平台的2.3.5的代码。