EditText TextWatcher替换文本可用于桌面键盘(仿真器),但不适用于键盘

问题描述 投票:0回答:1

我将TextWatcher添加到EditText字段,以将表情符号转换为表情符号。当我键入一个空格,然后输入表情符号:)时,它将立即转换为微笑表情符号,并且将光标放置在表情符号之后。然后我删除表情符号。使用模拟器上的桌面键盘,一切都可以正常工作。但是,当我在模拟器或设备上使用Android键盘时,删除操作会导致出现一个未知字符来代替表情符号,该表情符号也必须删除。我知道表情符号会占用额外的字符,但是我不明白为什么一个键盘与另一个键盘会发生这种情况?我该如何解决?

期望 Input-> Output

hi :)-> hi 😊

hi :(-> hi 😞

hi:)-> hi:)

hi :)-> hi 😊->删除-> 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));
    }
}
android android-edittext keyboard android-softkeyboard textwatcher
1个回答
0
投票

messageText.setText(oldText.replace(startOfWordIndex, endOfWordIndex, possibleEmoji));messageText.setSelection(messageText.getText().length());

我刚用过setText并替换。

© www.soinside.com 2019 - 2024. All rights reserved.