如何禁止在Android EditText中输入表情符号?

50

大多数EditText和TextView的text输入类型实现(除了URI、password等)允许使用Emoji,尽管在大多数Google键盘配置中这个按钮是隐藏的。是否有一种方法可以禁用在EditText中输入Emoji?是否有一个可以与textMultiLine配对的inputType参数可以禁用Emoji?


试试这个:https://dev59.com/-GAg5IYBdhLWcg3wdqwy#39491095 它适用于TextView和AutoCompleteTextView。 - user1506104
Kotlin解决方案在此处 - https://dev59.com/w1gR5IYBdhLWcg3ww_s0#52947835 - abitcode
14个回答

29

修改 build.gradle 文件,在你的项目中添加 XEditText

dependencies{
    compile 'com.xw.repo:xedittext:2.0.0@aar'
}

接着,在你的layout.xml文件中:

<com.xw.repo.XEditText
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:x_disableEmoji="true"/>

或者:

像这样自定义EditText:

public class CustomEditText extends EditText {
    public CustomEditText(Context context) {
        super(context);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setFilters(new InputFilter[]{new EmojiExcludeFilter()});
    }

    private class EmojiExcludeFilter implements InputFilter {

        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            for (int i = start; i < end; i++) {
                int type = Character.getType(source.charAt(i));
                if (type == Character.SURROGATE || type == Character.OTHER_SYMBOL) {
                    return "";
                }
            }
            return null;
        }
    }
}

两者都能正常使用!


“Character.SURROGATE”和“Character.OTHER_SYMBOL”对我来说是关键。 - annapetry
9
答案应该是后者。你不能建议开发者为这种问题使用第三方库。在Android中,这样一个小问题需要外部库来解决,这变得无法控制了。悲哀! - Neon Warge
1
两个问题仍存在漏洞,当我们输入文本,然后输入表情符号,按退格键时,会删除2个字符而不是1个。 - HendraWD
这不允许我想要接受的符号,比如度数符号。将类型==Character.SURROGATE(删除OTHER)更改为仅返回""会导致一些表情符号仍然被允许,这也是不可接受的。 - Mira_Cole
1
这样做会不会也阻止非表情符号的显示?比如日文/阿拉伯文字符?因为它们也使用代理。 - behelit
显示剩余2条评论

23

有一个巧妙的方法可以禁用键盘上的表情符号..

你只需要将

android:inputType="textEmailAddress"

设置给 EditText 即可。

  <EditText
    android:id="@+id/edt_note"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/note"
    android:inputType="textEmailAddress"
    android:padding="10dp"
    android:textColor="@color/white" />

我不确定它在所有情况下都有效,但在我的情况下,它对我起了作用...


3
这不会阻止用户复制粘贴表情符号。 - 林果皞

23

在xml文件中,digits属性可以为EditText控件提供值,你可以在该属性中设置所有接受的字符。

<EditText
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:digits="qwertyuiopasdfghjklzxcvbnm 1234567890 QWERTYUIOPASDFGHJKLZXCVBNM" />

我知道,这不是最好的解决办法,但起作用了 :)


6
如果您正在开发一个仅支持英语的应用程序,那么这是一个很好的解决方案。但我无法想象为每种我想要将我的应用本地化的语言都这样做。 - Slobodan Antonijević
1
有时这会导致编辑文本的行为变慢,基本上在输入时显示在编辑文本中的字母会有明显的延迟。 - Samrat

18

添加这个表情筛选器类:

public class EmojiFilter {
    public static InputFilter[] getFilter()
    {
         InputFilter EMOJI_FILTER = new InputFilter() {

            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                for (int index = start; index < end; index++) {

                    int type = Character.getType(source.charAt(index));

                    if (type == Character.SURROGATE || type==Character.NON_SPACING_MARK
                            || type==Character.OTHER_SYMBOL) {
                        return "";
                    }
                }
                return null;
            }
        };
         return new InputFilter[]{EMOJI_FILTER};
    }
}

如果想在编辑文本中禁用表情符号,请按照以下步骤进行:

editText.setFilters(EmojiFilter.getFilter());

有一些表情符号无法输入,因此我添加了它们:

type==Character.NON_SPACING_MARK || type==Character.OTHER_SYMBOL

在 if 条件中。


2
这是一个很棒的解决方案,到目前为止似乎运行得非常好,谢谢! :) - szaske
对我有用,也防止了复制粘贴表情符号。 - M A F
这个工作得很好,能够防止所有类型的表情符号。谢谢。 - Faldu Jaldeep

7

我已经为此编写了Kotlin扩展。它还可以防止复制粘贴表情符号。

扩展:

fun EditText.filterEmoji() {
    filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
        source.filter { Character.getType(it) != Character.SURROGATE.toInt() }
    })
}

在 Kotlin 类中:
editText.filterEmoji()

就这样。享受吧!


3
然而,它仍然允许一些符号。为了避免这些符号,请在过滤器内执行以下操作:Character.getType(it) != Character.SURROGATE.toInt() && Character.getType(it) != Character.OTHER_SYMBOL.toInt() - Shailendra Madda
但是使用这个过滤器打字时存在重复文本问题。 - Shailendra Madda

7

没有任何方法可以完全禁用表情符号。键盘可以根据它看到的任何模式以任何最佳方式来操作,因此没有设置可以防止表情符号。如果必须要防止它,请使用TextWatcher来列入白名单或黑名单字符。


7

@woxingxiao提供的代码非常好,但当您在xml中指定任何inputType时(例如android:inputType="textMultiLine"),该代码就会出现问题。

我对他的建议进行了一些修改,我认为它很好用。

public class EmojiExcludeEditText extends EditText {

    private EmojiExcludeFilter emojiExcludeFilter;

    public EmojiExcludeEditText(Context context) {
        super(context);
        init();
    }

    public EmojiExcludeEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EmojiExcludeEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        if (emojiExcludeFilter == null) {
            emojiExcludeFilter = new EmojiExcludeFilter();
        }
        setFilters(new InputFilter[]{emojiExcludeFilter});
    }

    @Override
    public void setFilters(InputFilter[] filters) {
        if (filters.length != 0) { //if length == 0 it will here return when init() is called
            boolean add = true;
            for (InputFilter inputFilter : filters) {
                if (inputFilter == emojiExcludeFilter) {
                    add = false;
                    break;
                }
            }
            if (add) {
                filters = Arrays.copyOf(filters, filters.length + 1);
                filters[filters.length - 1] = emojiExcludeFilter;
            }
        }
        super.setFilters(filters);
    }

    private class EmojiExcludeFilter implements InputFilter {

        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            for (int i = start; i < end; i++) {
                int type = Character.getType(source.charAt(i));
                if (type == Character.SURROGATE || type == Character.OTHER_SYMBOL) {
                    return "";
                }
            }
            return null;
        }
    }
}

1
很棒的解决方案,但如果editText在xml中有maxLength选项,则会崩溃,需要将new EmojiExcludeFilter()变量初始化移动到setFilters()部分以避免崩溃。 - Jonas
我把初始化操作移到了init()方法中,现在它对我有用了。 - lbenedetto

6
你可以编写输入过滤器来屏蔽/允许某些字符。
public static InputFilter getEditTextFilterEmoji()
{
    return new InputFilter()
    {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
        {
            CharSequence sourceOriginal = source;
            source = replaceEmoji(source);
            end = source.toString().length();

            if (end == 0) return ""; //Return empty string if the input character is already removed

            if (! sourceOriginal.toString().equals(source.toString()))
            {
                char[] v = new char[end - start];
                TextUtils.getChars(source, start, end, v, 0);

                String s = new String(v);

                if (source instanceof Spanned)
                {
                    SpannableString sp = new SpannableString(s);
                    TextUtils.copySpansFrom((Spanned) source, start, end, null, sp, 0);
                    return sp;
                }
                else
                {
                    return s;
                }
            }
            else
            {
                return null; // keep original
            }
        }

        private String replaceEmoji(CharSequence source)
        {

            String notAllowedCharactersRegex = "[^a-zA-Z0-9@#\\$%\\&\\-\\+\\(\\)\\*;:!\\?\\~`£\\{\\}\\[\\]=\\.,_/\\\\\\s'\\\"<>\\^\\|÷×]";
            return source.toString()
                    .replaceAll(notAllowedCharactersRegex, "");
        }

    };
}

然后将其设置为EditText过滤器;

InputFilter[] filterArray = new InputFilter[] {getEditTextFilterEmoji()}
editText.setFilters(filterArray);

1
这将覆盖许多有效的非英文文本(例如,日语)。 - benkc

1

您可以使用输入过滤器来删除不需要的字符,这里我使用ASCII值进行过滤。

public class CustomEditText extends AppCompatEditText {
private InputFilter unwantedCharacterFilter;

public CustomEditText(Context context) {
    super(context);
}

public CustomEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

private void init() {
    setFilters(new InputFilter[]{});
}
private InputFilter getUnwantedCharacterFilter() {
    if (null == unwantedCharacterFilter) {
        unwantedCharacterFilter = new InputFilter() {
            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                if (!TextUtils.isEmpty(source)) {
                    for (int index = start; index < end; index++) {
                        if (source.charAt(index) < 0 || source.charAt(index) > 177) {
                            return "";
                        }
                    }
                }
                return null;
            }
        };
    }
    return unwantedCharacterFilter;
}

@Override
public void setFilters(InputFilter[] filters) {
    List<InputFilter> filterList = new ArrayList<>(Arrays.asList(filters));
    filterList.add(getUnwantedCharacterFilter());
    InputFilter specifiedFilters[] = filterList.toArray(new InputFilter[]{});
    super.setFilters(specifiedFilters);
}

}


1

Emoji使用Unicode编码,其代码点范围为U+1F604至U+1F539。而Character.SURROGATE保留了超出Emoji范围的代码点范围。

val EMOJI_FILTER =InputFilter { source, start, end, dest, dstart, dend ->
                for (index in start until end) {
                    val type = Character.getType(source[index])
                    if (type == Character.SURROGATE.toInt()) {
                        return@InputFilter ""
                    }
                }
                null
            }


        etLintEdt.filters = arrayOf(EMOJI_FILTER)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接