Gboard:在 EditText 上启用 GIF 插入
Posted
技术标签:
【中文标题】Gboard:在 EditText 上启用 GIF 插入【英文标题】:Gboard: Enable GIF insertion on EditText 【发布时间】:2018-06-14 23:42:22 【问题描述】:我在我的应用中使用来自 Google 的 Gboard,当我从键盘应用输入 GIF 到我的 EditText
时,它会显示祝酒词
“文本字段不支持从键盘插入 GIF”
我已经搜索了一千次,但找不到结果
任何帮助将不胜感激。
【问题讨论】:
【参考方案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); @ArwyShelke 检查此***.com/a/50058361/5996106【参考方案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_
android:layout_
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_
android:layout_
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());
);
【讨论】:
以上是关于Gboard:在 EditText 上启用 GIF 插入的主要内容,如果未能解决你的问题,请参考以下文章