/* * 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.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Rect; import android.text.Editable; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.text.style.URLSpan; import android.util.AttributeSet; import android.util.Log; import android.view.ContextMenu; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.MotionEvent; import android.widget.EditText; import net.micode.notes.R; import java.util.HashMap; import java.util.Map; public class NoteEditText extends EditText { private static final String TAG = "NoteEditText"; private int mIndex; private int mSelectionStartBeforeDelete; public static final int MENU_ITEM_COLOR = Menu.FIRST + 1; // 使用 Menu.FIRST 避免冲突 private static final String SCHEME_TEL = "tel:" ; private static final String SCHEME_HTTP = "http:" ; private static final String SCHEME_EMAIL = "mailto:" ; private NoteEditActivity noteEditActivity; private static final Map sSchemaActionResMap = new HashMap(); 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); } /** * Call by the {@link NoteEditActivity} to delete or add edit text */ public interface OnTextViewChangeListener { /** * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens * and the text is null */ void onEditTextDelete(int index, String text); /** * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} * happen */ void onEditTextEnter(int index, String text); /** * Hide or show item option when text change */ void onTextChange(int index, boolean hasText); } private OnTextViewChangeListener mOnTextViewChangeListener; public NoteEditText(Context context) { super(context, null); mIndex = 0; if (context instanceof NoteEditActivity) { noteEditActivity = (NoteEditActivity) context; } /*原来它张这个样子 */ //徐家畅的修改 /*super(context, null, android.R.attr.editTextStyle); init();*/ }/* //新增的函数 private void init() { addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { checkSelectionAndShowMenu(); } }); setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_UP) { post(this::checkSelectionAndShowMenu); } return false; // 让 EditText 处理其他触摸事件 }); } //徐家畅添加 //徐家畅继续添加 private void checkSelectionAndShowMenu() { int selStart = getSelectionStart(); int selEnd = getSelectionEnd(); if (selStart != selEnd && Math.abs(selEnd - selStart) > 0) { showCustomColorPickerDialog(); // 自定义颜色选择器 } } private void showCustomColorPickerDialog() { final int[] colors = { android.graphics.Color.RED, android.graphics.Color.BLUE, android.graphics.Color.GREEN, android.graphics.Color.YELLOW, android.graphics.Color.BLACK }; final CharSequence[] colorNames = {"Red", "Blue", "Green", "Yellow", "Black"}; AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("Select A Color"); builder.setItems(colorNames, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int selectedColor = colors[which]; int start = getSelectionStart(); int end = getSelectionEnd(); Spannable spannable = (Spannable) getText(); // 移除旧的颜色样式 android.text.style.ForegroundColorSpan[] oldSpans = spannable.getSpans(start, end, android.text.style.ForegroundColorSpan.class); for (ForegroundColorSpan span : oldSpans) { spannable.removeSpan(span); } // 设置新颜色 spannable.setSpan(new android.text.style.ForegroundColorSpan(selectedColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } }); builder.show(); } //徐家畅添加*/ 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(); 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); 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) { 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); } } super.onFocusChanged(focused, direction, previouslyFocusedRect); } //重写事件菜单 @Override public boolean onTextContextMenuItem(int id) { if (id == MENU_ITEM_COLOR) { showColorPickerDialog(); return true; } return super.onTextContextMenuItem(id); } //徐家畅添加 @Override protected void onCreateContextMenu(ContextMenu menu) { if (getText() instanceof Spanned) { Log.d(TAG, "Creating context menu"); int selStart = getSelectionStart(); int selEnd = getSelectionEnd(); // 添加颜色选项 if(selStart!=selEnd){ menu.add(Menu.NONE, MENU_ITEM_COLOR, Menu.NONE, "Color") .setOnMenuItemClickListener(item -> { showColorPickerDialog(); return true; });} //这是徐家畅加的 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) { int defaultResId = 0; for(String schema: sSchemaActionResMap.keySet()) { if(urls[0].getURL().indexOf(schema) >= 0) { defaultResId = sSchemaActionResMap.get(schema); break; } } if (defaultResId == 0) { defaultResId = R.string.note_link_other; } menu.add(0, 0, 1, defaultResId).setOnMenuItemClickListener( new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { // goto a new intent urls[0].onClick(NoteEditText.this); return true; } }); } } super.onCreateContextMenu(menu); } private void showColorPickerDialog() { final int[] colors = { android.graphics.Color.RED, android.graphics.Color.BLUE, android.graphics.Color.GREEN, android.graphics.Color.YELLOW, android.graphics.Color.BLACK }; final CharSequence[] colorNames = {"Red", "Blue", "Green", "Yellow", "Black"}; AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("Select A Color"); builder.setItems(colorNames, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int selectedColor = colors[which]; int start = getSelectionStart(); int end = getSelectionEnd(); Spannable spannable = (Spannable) getText(); // 移除旧的前景色样式 android.text.style.ForegroundColorSpan[] oldSpans = spannable.getSpans(start, end, android.text.style.ForegroundColorSpan.class); for (ForegroundColorSpan span : oldSpans) { spannable.removeSpan(span); } // 设置新颜色 spannable.setSpan(new android.text.style.ForegroundColorSpan(selectedColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } }); builder.show(); } //根据文字选中情况来判断是否隐藏新按钮 @Override protected void onSelectionChanged(int selStart, int selEnd) { super.onSelectionChanged(selStart, selEnd); if(noteEditActivity!=null){ if (selStart != selEnd) { // 有文字被选中,显示按钮 noteEditActivity.showTextColorButton(); } else { // 没有文字被选中,隐藏按钮 noteEditActivity.hideTextColorButton(); } } } //这也是徐家畅加的 }