EditText TextWatcher替换文本适用于桌面键盘(模拟器),但不适用于键盘

时间:2017-12-13 16:51:38

标签: android android-edittext keyboard android-softkeyboard textwatcher

我在EditText字段中添加了TextWatcher,将表情符号转换为表情符号。当我键入一个空格然后输入表情符号:)它会立即转换为笑脸表情符号,并且光标会紧跟表情符号后面。然后我删除了表情符号。在模拟器上使用我的桌面键盘,一切都很好用。但是,当我在模拟器或设备上使用Android键盘时,删除会导致出现一个未知字符代替表情符号,表情符号也必须删除。我知道emojis会占用额外的角色,但是我不明白为什么一个键盘与另一个键盘会发生这种情况?我该如何解决这个问题?

预期 Input - > Output

hi :) - > hi

hi :( - > hi

hi:) - > hi:)

hi :) - &gt; hi - &gt;删除 - &gt; hi<space>

屏幕截图删除表情符号后无法识别的字符

Unrecognized character after deleting emoji

代码

EmojiTextWatcher.class

/**
 * Follows the following principles:
 * 1. When an emoticon is added and a space is typed following it, that emoticon can be converted to
 *      emoji if it has a space preceding it, or it is at the beginning.
 * 2. When an emoji is deleted AND it was the last converted emoticon, emoticons will not be
 *      converted until another space is typed.
 */
public class EmojiTextWatcher implements TextWatcher {
    public static final String TAG = EmojiTextWatcher.class.getName();

    private EditText mEditText;
    private boolean allowNextEmoji = true;
    @Nullable
    private Integer lastEmojiIndex = null;
    private int selectorIndex;


    public EmojiTextWatcher(EditText editText) {
        mEditText = editText;
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        selectorIndex = mEditText.getSelectionEnd();
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {}

    @Override
    public void afterTextChanged(Editable s) {
        int newSelectorIndex = mEditText.getSelectionEnd();
        if (newSelectorIndex - selectorIndex == 1) { // one character added
            if (allowNextEmoji) {
                int startOfWordIndex = getPreviousSpaceInTextFromIndex(s, selectorIndex) + 1;
                int endOfWordIndex = newSelectorIndex;
                String possibleEmoji = getEmojiFromSubstring(s, startOfWordIndex, endOfWordIndex);
                if (possibleEmoji != null) { // word was an emoticon
                    // remove then re-add listener so this method isn't called again when updating text
                    mEditText.removeTextChangedListener(this);
                    Editable oldText = mEditText.getText();
                    oldText.replace(startOfWordIndex, endOfWordIndex, possibleEmoji);
                    lastEmojiIndex = startOfWordIndex;
                    mEditText.addTextChangedListener(this);
                }
            } else if (s.charAt(selectorIndex) == ' ') { // character was a space
                allowNextEmoji = true;
            }
        } else if (newSelectorIndex - selectorIndex < 0) { // deletion of text
            if (lastEmojiIndex != null &&
                    lastEmojiIndex >= newSelectorIndex) { // deleted the last converted emoji
                allowNextEmoji = false;
                lastEmojiIndex = null;
            }
        }
    }

    private String getEmojiFromSubstring(CharSequence sequence, int startIndex, int endIndex) {
        return getEmojiFromSubstring(sequence.toString(), startIndex, endIndex);
    }

    private String getEmojiFromSubstring(String text, int startIndex, int endIndex) {
        String word = text.substring(startIndex, endIndex);
        return Emoji.getEmojiFromEmoticon(word);
    }

    /**
     * Gets the previous space index in the text, or -1 if there are no previous spaces.
     *
     * @param s the charsequence to look through
     * @param lookBeforeIndex index to look for previous space before
     * @return the index of the previous space
     */
    private int getPreviousSpaceInTextFromIndex(CharSequence s, int lookBeforeIndex) {
        return s.subSequence(0, lookBeforeIndex).toString().lastIndexOf(' ');
    }
}

Emoji.class

public class Emoji {

    private static class ReplacementsMap extends HashMap<String,Integer> {

        private static ReplacementsMap mInstance;

        private ReplacementsMap() {
            super();
            put(":)", 0x1F60A);
            put(":(", 0x1F61E);
            put("<3", 0x2764);
        }

        public static ReplacementsMap getInstance() {
            if (mInstance == null) {
                mInstance = new ReplacementsMap();
            }
            return mInstance;
        }

    }


    public static String getEmojiFromEmoticon(String possibleEmoticon) {
        Integer possibleEmoji = ReplacementsMap.getInstance().get(possibleEmoticon);
        if (possibleEmoji != null) {
            return getUnicodeChar(possibleEmoji);
        }
        return null;
    }

    private static String getUnicodeChar(int codepoint) {
        return new String(Character.toChars(codepoint));
    }
}

1 个答案:

答案 0 :(得分:0)

Info.plist messageText.setText(oldText.replace(startOfWordIndex, endOfWordIndex, possibleEmoji));

我刚刚使用messageText.setSelection(messageText.getText().length());并替换了。