Android Spannable - 表情符号删除UTF 16

时间:2016-01-31 22:50:36

标签: android unicode android-softkeyboard emoji utf-16

我的软键盘连接和ankushsachdeva的emojicon键盘的自定义实现与emojione图像有问题。

https://github.com/ankushsachdeva/emojicon

当我以UTF 16格式插入一些较新的Emojis时,就像这个家庭表情一样:http://www.unicode.org/Public/emoji/2.0//emoji-zwj-sequences.txt

或具有不同肤色的笑脸。我的ImageSpans正确地替换了unicode。

当我按下表情符号键盘中的特殊后退按钮时,它会通过调用键事件来删除完整的表情符号。

    mEmojiView.setOnEmojiconBackspaceClickedListener(new EmojiView.OnEmojiconBackspaceClickedListener() {
        @Override
        public void onEmojiconBackspaceClicked(View v) {
            KeyEvent event = new KeyEvent(
                    0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
            send_text.dispatchKeyEvent(event);
        }
    });

但问题出在这里:

当我尝试按下默认键盘上的键盘退格键时,它会删除char中的char而不是整个表情符号。

因为较新的笑脸由多个chars / unicode代理组成,我必须多次按退格按钮并面对一些奇怪的其他笑脸组合。

当我尝试通过长按EditText来选择表情符号时,甚至有一些奇怪的行为,它只选择那个较长表情符号的第一个字符,但标记整个ImageSpan。

有任何建议如何解决?

2 个答案:

答案 0 :(得分:1)

感谢Gabe Sechan的帮助。

这是一些对我有用的代码。随意添加改进。

修复Custom EditText中的选择:

LinkedList<EmojiData.EmojiTupel> mEmojis = new LinkedList<>();
boolean fromReselecting = false;
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
    //Log.d("Selection changed", selStart + " " + selEnd + " length: "  + getText().length());
    if(!fromReselecting && selStart != selEnd){
        EmojiData.EmojiTupel toFix = inBetweenEmoji(selStart, selEnd);
        if(toFix != null){
                    fromReselecting = true;
                    setSelection(toFix.start, toFix.end);
        }
    }
    else{
        fromReselecting = false;
    }
}

private EmojiData.EmojiTupel inBetweenEmoji(int selStart, int selEnd){
    if(mEmojis == null){
        return null;
    }
    for (EmojiData.EmojiTupel tupel: mEmojis) {
        if((tupel.start < selStart && selEnd <= tupel.end) ||
                (tupel.start <= selStart && selEnd < tupel.end)
                ){
            //Log.d("InBetween ", "Selection: " + selStart + " " + selEnd + " Emoji: " + tupel.start + " "+ tupel.end );
            return tupel;
        }
    }
    return null;
}


@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
            mEmojis = EmojiUtils.insertEmojis(getContext(), getText(), mEmojiconSize);
}

还有在应删除Text时使用KeyEvents的Custom InputConnection。适用于多个Emojis,因为选择是固定的。

@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    return new EmojiInputConnection(super.onCreateInputConnection(outAttrs),
            true);
}

private class EmojiInputConnection extends InputConnectionWrapper {

    public EmojiInputConnection(InputConnection target, boolean mutable) {
        super(target, mutable);
    }


    @Override
    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
        if (beforeLength == 1 && afterLength == 0) {
            return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
                    && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
        } else{
            int cursorPos = getSelectionStart();
            int cursorEnd = getSelectionEnd();
            if(cursorEnd == cursorPos && beforeLength == 2 && afterLength == 0){
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
                        && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
            }
        }

        return super.deleteSurroundingText(beforeLength, afterLength);
    }

}

其中EmojiTupel是来自另一个类的String中索引的包装器。

public static class EmojiTupel{
                public int start, end;
                public EmojiTupel(int start, int end){
                        this.start = start;
                        this.end = end;
                }
}

答案 1 :(得分:0)

这是因为软键盘的工作原理。他们中很少使用关键事件。他们更有可能使用deleteSurroundingText进行删除操作。您需要做的是覆盖视图的inputConnection,并覆盖deleteSurrounding文本,这样如果删除区域中有表情符号,它将删除整个表情符号,而不仅仅是单个字符。