【问题标题】:EditText TextWatcher replace text works with desktop keyboard (emulator), but not keyboardEditText TextWatcher 替换文本适用于桌面键盘(模拟器),但不适用于键盘
【发布时间】:2018-05-27 15:48:05
【问题描述】:

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

预期 Input -> Output:

hi :) -> hi ????

hi :( -> hi ????

hi:) -> hi:)

hi :) -> hi ???? -> 删除 -> hi<space>

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

代码

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));
    }
}

【问题讨论】:

  • 你想输入什么字符然后返回?您能给我们一些示例输入和预期结果吗?
  • 你找到解决办法了吗?
  • @kmalmur 不,我还没有,我最近没有解决这个问题。

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


【解决方案1】:

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

我刚刚使用setText 并替换。

【讨论】:

    猜你喜欢
    • 2017-09-04
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    • 2011-12-14
    • 2019-04-21
    • 1970-01-01
    • 2021-09-30
    相关资源
    最近更新 更多