【问题标题】:Gboard: Enable GIF insertion on EditTextGboard:在 EditText 上启用 GIF 插入
【发布时间】:2018-06-14 23:42:22
【问题描述】:

我在我的应用中使用来自 Google 的 Gboard,当我从键盘应用输入 GIF 到我的 EditText 时,它会显示祝酒词

“文本字段不支持从键盘插入 GIF”

我已经搜索了一千次,但找不到结果

任何帮助将不胜感激。

【问题讨论】:

    标签: android android-edittext gboard


    【解决方案1】:

    图像键盘支持

    用户经常希望与表情符号、贴纸和其他丰富的
    内容进行交流。在以前的 Android 版本中,软键盘(也称为输入法编辑器或 IME)只能向应用发送 unicode 表情符号。对于丰富的
    内容,应用必须构建无法在
    其他应用中使用的特定于应用的 API,或者使用解决方法,例如通过 Easy Share Action 或
    剪贴板发送图像。

    工作原理

    键盘图像插入需要 IME 和 应用程序。以下序列描述了图像中的每个步骤 插入过程:

    当用户点击 EditText 时,编辑器会发送一个 MIME 列表 它在 EditorInfo.contentMimeTypes 中接受的内容类型。

    IME 读取支持的类型列表并在 编辑器可以接受的软键盘。

    当用户选择图像时,IME 调用 commitContent() 并 向编辑器发送 InputContentInfo。 commitContent() 调用是 类似于 commitText() 调用,但内容丰富。 InputContentInfo 包含一个标识内容的 URI 内容提供商。然后,您的应用可以请求权限并读取 来自 URI 的内容。

    要接受来自 IME 的丰富内容,应用程序必须告诉 IME 它
    接受哪些内容类型,并指定在接收到内容时执行的回调方法。
    。以下示例演示了如何创建一个
    接受 PNG 图像的 EditText:
    EditText editText = new EditText(this) {
        @Override
        public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
            final InputConnection ic = super.onCreateInputConnection(editorInfo);
            EditorInfoCompat.setContentMimeTypes(editorInfo,
                    new String [] {"image/png"});
    
            final InputConnectionCompat.OnCommitContentListener callback =
                new InputConnectionCompat.OnCommitContentListener() {
                    @Override
                    public boolean onCommitContent(InputContentInfoCompat inputContentInfo,
                            int flags, Bundle opts) {
                        // read and display inputContentInfo asynchronously
                        if (BuildCompat.isAtLeastNMR1() && (flags &
                            InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
                            try {
                                inputContentInfo.requestPermission();
                            }
                            catch (Exception e) {
                                return false; // return false if failed
                            }
                        }
    
                        // read and display inputContentInfo asynchronously.
                        // call inputContentInfo.releasePermission() as needed.
    
                        return true;  // return true if succeeded
                    }
                };
            return InputConnectionCompat.createWrapper(ic, editorInfo, callback);
        }
    };
    

    这里是完整的文档参考

    https://developer.android.com/guide/topics/text/image-keyboard.html#how_it_works

    为 IME 添加图像支持

    想要向应用发送丰富内容的 IME 必须实现 提交 Content API 如下所示:

    覆盖 onStartInput()onStartInputView() 并读取列表 目标编辑器支持的内容类型。以下代码 sn -p 显示如何检查目标编辑器是否接受 GIF 图片。

    @Override
    public void onStartInputView(EditorInfo info, boolean restarting) {
        String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);
    
        boolean gifSupported = false;
        for (String mimeType : mimeTypes) {
            if (ClipDescription.compareMimeTypes(mimeType, "image/gif")) {
                gifSupported = true;
            }
        }
    
        if (gifSupported) {
            // the target editor supports GIFs. enable corresponding content
        } else {
            // the target editor does not support GIFs. disable corresponding content
        }
    }
    

    当用户选择图像时,将内容提交到应用程序。避免 当有任何组成文本时调用commitContent(),因为它 可能会导致编辑器失去焦点。以下代码 sn -p 显示 如何提交 GIF 图片。

    /**
     * Commits a GIF image
     *
     * @param contentUri Content URI of the GIF image to be sent
     * @param imageDescription Description of the GIF image to be sent
     */
    public static void commitGifImage(Uri contentUri, String imageDescription) {
        InputContentInfoCompat inputContentInfo = new InputContentInfoCompat(
                contentUri,
                new ClipDescription(imageDescription, new String[]{"image/gif"}));
        InputConnection inputConnection = getCurrentInputConnection();
        EditorInfo editorInfo = getCurrentInputEditorInfo();
        Int flags = 0;
        if (android.os.Build.VERSION.SDK_INT >= 25) {
            flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
        }
        InputConnectionCompat.commitContent(
                inputConnection, editorInfo, inputContentInfo, flags, opts);
    }
    

    这里是完整的文档

    https://developer.android.com/guide/topics/text/image-keyboard.html#adding_image_support_to_imes

    【讨论】:

    • 您能告诉我为什么BuildCompat.isAtLeastNMR1(),以及API级别低于该级别如何处理吗?
    • @STG 对图像键盘的支持仅在 NMr1 (Android 7.1) 中添加
    【解决方案2】:

    我从某个地方找到了以下解决方案。希望对大家有一定的帮助。

    import android.content.Context;
    import android.os.Bundle;
    import android.support.v13.view.inputmethod.EditorInfoCompat;
    import android.support.v13.view.inputmethod.InputConnectionCompat;
    import android.support.v13.view.inputmethod.InputContentInfoCompat;
    import android.support.v4.os.BuildCompat;
    import android.util.AttributeSet;
    import android.view.inputmethod.EditorInfo;
    import android.view.inputmethod.InputConnection;
    
    
    public class MyEditText extends android.support.v7.widget.AppCompatEditText {
    
        private String[] imgTypeString;
        private KeyBoardInputCallbackListener keyBoardInputCallbackListener;
    
        public MyEditText(Context context) {
            super(context);
            initView();
        }
    
        public MyEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }
    
        private void initView() {
            imgTypeString = new String[]{"image/png",
                    "image/gif",
                    "image/jpeg",
                    "image/webp"};
        }
    
        @Override
        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
            final InputConnection ic = super.onCreateInputConnection(outAttrs);
            EditorInfoCompat.setContentMimeTypes(outAttrs,
                    imgTypeString);
            return InputConnectionCompat.createWrapper(ic, outAttrs, callback);
        }
    
    
        final InputConnectionCompat.OnCommitContentListener callback =
                new InputConnectionCompat.OnCommitContentListener() {
                    @Override
                    public boolean onCommitContent(InputContentInfoCompat inputContentInfo,
                                                   int flags, Bundle opts) {
    
                        // read and display inputContentInfo asynchronously
                        if (BuildCompat.isAtLeastNMR1() && (flags &
                                InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
                            try {
                                inputContentInfo.requestPermission();
                            } catch (Exception e) {
                                return false; // return false if failed
                            }
                        }
                        boolean supported = false;
                        for (final String mimeType : imgTypeString) {
                            if (inputContentInfo.getDescription().hasMimeType(mimeType)) {
                                supported = true;
                                break;
                            }
                        }
                        if (!supported) {
                            return false;
                        }
    
                        if (keyBoardInputCallbackListener != null) {
                            keyBoardInputCallbackListener.onCommitContent(inputContentInfo, flags, opts);
                        }
                        return true;  // return true if succeeded
                    }
                };
    
        public interface KeyBoardInputCallbackListener {
            void onCommitContent(InputContentInfoCompat inputContentInfo,
                                 int flags, Bundle opts);
        }
    
        public void setKeyBoardInputCallbackListener(KeyBoardInputCallbackListener keyBoardInputCallbackListener) {
            this.keyBoardInputCallbackListener = keyBoardInputCallbackListener;
        }
    
        public String[] getImgTypeString() {
            return imgTypeString;
        }
    
        public void setImgTypeString(String[] imgTypeString) {
            this.imgTypeString = imgTypeString;
        }
    }
    

    【讨论】:

    • 怎么用?不适合我,editTextComment = findViewById(R.id.editTextComment); editTextComment = new MyEditText(context);
    【解决方案3】:

    如果您想要一个内置此功能的 EditText,请查看我的库 RichContentEditText:https://github.com/GregoryConrad/RichContentEditText

    它可以轻松地将丰富的内容(图像和其他文件)从 IME 传输到应用程序。下面是一些示例代码:

    XML

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Root layout can be anything. Just make sure to include xmlns:app line. -->
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <!-- The RichContentEditText -->
        <!-- Notice app:allowedMimeTypes="images"; it is what accepts certain mime types
                 (you can do this programmatically too) -->
        <com.gsconrad.richcontentedittext.RichContentEditText
            android:id="@+id/rich_content_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/rich_content_edit_text_hint"
            android:inputType="text"
            app:allowedMimeTypes="images" />
    </android.support.constraint.ConstraintLayout>
    

    Java

    // MainActivity.java
    private void setupRichContentEditText() {
        RichContentEditText editText = findViewById(R.id.rich_content_edit_text);
        // The following line sets the listener that is called when rich content is received
        editText.setOnRichContentListener(new RichContentEditText.OnRichContentListener() {
            // Called when a keyboard sends rich content
            @Override
            public void onRichContent(Uri contentUri, ClipDescription description) {
                if (description.getMimeTypeCount() > 0) {
                    final String fileExtension = MimeTypeMap.getSingleton()
                            .getExtensionFromMimeType(description.getMimeType(0));
                    final String filename = "filenameGoesHere." + fileExtension;
                    File richContentFile = new File(getFilesDir(), filename);
                    // See the library example app for an implementation of writeToFileFromContentUri
                    if (!writeToFileFromContentUri(richContentFile, contentUri)) {
                        // We are in the background right now, make sure to run this in the foreground
                        Toast.makeText(MainActivity.this,
                                R.string.rich_content_copy_failure, Toast.LENGTH_LONG).show();
                    } else {
                        // We are in the background right now, make sure to run this in the foreground
                        WebView displayView = findViewById(R.id.display_view);
                        displayView.loadUrl("file://" + richContentFile.getAbsolutePath());
                    }
                }
            }
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      • 2019-04-28
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      • 2021-02-03
      相关资源
      最近更新 更多