在Android中添加自定义图像作为表情符号 [英] add custom image as Emoji in android

查看:656
本文介绍了在Android中添加自定义图像作为表情符号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何添加自定义图片作为表情符号的android的InputMethodService。 我已经尝试使用

  ImageGetter imageGetter =新ImageGetter(){
                公众可绘制getDrawable(字符串源){
                    StringTokenizer的ST =新的StringTokenizer(海峡。);
                    绘制对象D =新BitmapDrawable(getResources(),图释[的Integer.parseInt(st.nextToken()) -  1]);
                    d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
                    返回D组;
                }
            };

            跨区CS = Html.fromHtml(&所述; IMG SRC =+ STR +'/>中,imageGetter,空);


        。getCurrentInputConnection()commitText(CS,1);
 

但只得到一个物件文字图像。 有没有什么办法可以在Android的定制表情符号添加到消息(WhatsApp的/微博)

编辑:

在我,如果我键入Hello使用我的自定义键盘,我必须插入自定义你好画面编辑字段为安装在手机每一个应用程序的应用程序。

它可以实现?

编辑:2

我把它用法师转换为base64也,但没有发生与标签检查

  ImageGetter imageGetter =新ImageGetter(){
                @覆盖
                公众可绘制getDrawable(字符串源){
                    字节 [] en$c$cByte=Base64.de$c$c("iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",Base64.DEFAULT);
                    点阵位图= BitmapFactory.de codeByteArray(EN codeByte,0,EN codeByte.length);
                    绘制对象D =新BitmapDrawable(位);

                    Log.e(清洁香港,身高:+ d.getIntrinsicHeight());
                    Log.e(清洁香港,宽度:+ d.getIntrinsicWidth());

                    返回D组;
                }
            };

            跨区CS = Html.fromHtml(< IMG SRC =数据:图像/ PNG; BASE64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='/>", imageGetter,NULL);

            Log.e(清洁香港,12:+ 12);


        getCurrentInputConnection()setComposingText(CS,1);
 

编辑:3

我在我的自定义键盘应用程序使用此InputMethodService类。

 包com.example.android.softkeyboard;

进口的java.util.ArrayList;
进口的java.util.List;

进口android.graphics.Bitmap;
进口android.graphics.BitmapFactory;
进口android.graphics.drawable.BitmapDrawable;
进口android.graphics.drawable.Drawable;
进口android.inputmethodservice.InputMethodService;
进口android.inputmethodservice.Keyboard;
进口android.inputmethodservice.KeyboardView;
进口android.text.Html;
进口android.text.Html.ImageGetter;
进口android.text.Spanned;
进口android.text.method.MetaKeyKeyListener;
进口android.util.Base64;
进口android.view.KeyCharacterMap;
进口android.view.KeyEvent;
进口android.view.View;
进口android.view.inputmethod.CompletionInfo;
进口android.view.inputmethod.EditorInfo;
进口android.view.inputmethod.InputConnection;

公共类SoftKeyboard扩展InputMethodService工具
        KeyboardView.OnKeyboardActionListener {
    静态最终布尔DEBUG = FALSE;

    静态最终布尔PROCESS_HARD_KEYS = TRUE;

    私人KeyboardView mInputView;
    私人CandidateView mCandidateView;
    私人CompletionInfo [] mCompletions;

    私人StringBuilder的mComposing =新的StringBuilder();
    私人布尔米predictionOn;
    私人布尔mCompletionOn;
    私人诠释mLastDisplayWidth;
    私人布尔mCapsLock;
    专用长mLastShiftTime;
    专用长mMetaState;

    私人键盘mSymbolsKeyboard;
    私人键盘mSymbolsShiftedKeyboard;
    私人键盘mQwertyKeyboard;

    私人字符串mWordSeparators;

    StringBuilder的strBldrFrEmoji;

    私人无效makeKeyboards(){
        如果(mQwertyKeyboard!= NULL){
            //配置的变化可能发生的键盘得到后
            //重建,
            //所以我们需要能够如果可用重新打造的键盘
            //空间已经改变了。
            INT displayWidth = getMaxWidth();
            如果(displayWidth == mLastDisplayWidth)
                返回;
            mLastDisplayWidth = displayWidth;
        }
        mQwertyKeyboard =新LatinKeyboard(这一点,R.xml.qwerty);
        mSymbolsKeyboard =新LatinKeyboard(这一点,R.xml.symbols)​​;
        mSymbolsShiftedKeyboard =新LatinKeyboard(这一点,R.xml.symbols_shift);
    }

    @覆盖
    公共无效的onCreate(){
        super.onCreate();
        makeKeyboards();
        mWordSeparators = getResources()的getString(R.string.word_separators)。
    }

    @覆盖
    公共查看onCreateInputView(){
        //我们把makeKeyboards()在这里如果需要的话,由于再生他们
        //配置更改。
        makeKeyboards();
        mInputView =(KeyboardView)getLayoutInflater()。膨胀(R.layout.input,
                空值);
        mInputView.setOnKeyboardActionListener(本);
        mInputView.setKeyboard(mQwertyKeyboard);
        返回mInputView;
    }

    @覆盖
    公共查看onCreateCandidatesView(){
        mCandidateView =新CandidateView(本);
        mCandidateView.setService(本);
        返回mCandidateView;
    }

    @覆盖
    公共无效onStartInputView(EditorInfo属性,布尔重新启动){
        super.onStartInputView(属性,重新启动);

        //重置我们的国家。我们希望即使重新启动要做到这一点,因为
        //文本编辑器的基本状态可以在任何已更改
        // 方法。
        mComposing.setLength(0);
        updateCandidates();

        如果(!重新启动){
            //清除移位状态。
            mMetaState = 0;
        }

        米predictionOn = FALSE;
        mCompletionOn = FALSE;
        mCompletions = NULL;
        键盘键盘;

        //我们现在要根据类型来初始化我们的国家
        //文本进行编辑。
        开关(attribute.inputType&安培; EditorInfo.TYPE_MASK_CLASS){
        案例EditorInfo.TYPE_CLASS_NUMBER:
        案例EditorInfo.TYPE_CLASS_DATETIME:
            //数字和日期默认为符号键盘,带
            //没有额外的功能。
            键盘= mSymbolsKeyboard;
            打破;

        案例EditorInfo.TYPE_CLASS_PHONE:
            //电话也将默认为符号键盘,虽然
            //通常你会希望有一个专门的手机键盘。
            键盘= mSymbolsKeyboard;
            打破;

        案例EditorInfo.TYPE_CLASS_TEXT:

            //这是一般的文本编辑。我们将默认为
            //正常字母键盘,并且认为我们应该
            //做predictive文(显示候选人的
            //用户类型)。
            键盘= mQwertyKeyboard;
            米predictionOn = TRUE;

            //我们现在看文本的一些特殊的变异会
            //改变我们的行为。
            INT变化= attribute.inputType
                    &放大器; EditorInfo.TYPE_MASK_VARIATION;
            如果(变化== EditorInfo.TYPE_TEXT_VARIATION_PASSWORD){
                //不显示predictions /用户正在输入
                //当他们输入密码。
                米predictionOn = FALSE;
            }

            如果(变化== EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
                    ||变化== EditorInfo.TYPE_TEXT_VARIATION_URI){
                //我们的predictions不是为电子邮件地址有用
                //或URI的。
                米predictionOn = FALSE;
            }

            如果((attribute.inputType&安培;!EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE)= 0){
                //如果这是一个自动完成的文本视图,那么我们的predictions
                //将不会显示,而是我们将允许编辑器
                //提供自己。我们只显示了编辑器的
                //当考生在全屏模式下,否则依靠
                //拥有它显示其自己的用户界面。
                米predictionOn = FALSE;
                mCompletionOn = isFullscreenMode();
            }

            //我们也想看看编辑器的当前状态
            //来决定我们的字母键盘是否启动了
            //转移。
            updateShiftKeyState(属性);
            打破;

        默认:
            //对于所有未知的输入类型,默认为字母
            //键盘没有特殊的功能。
            键盘= mQwertyKeyboard;

        }

        //应用选择的键盘输入视图。
        如果(mInputView!= NULL){
            mInputView.setKeyboard(键盘);
            mInputView.closing();
        }
    }

    @覆盖
    公共无效onFinishInput(){
        super.onFinishInput();

        //清除当前合成的文本和候选人。
        mComposing.setLength(0);
        updateCandidates();

        //我们只当完成输入隐藏考生窗口
        //一个特定的编辑器,以避免突然出现的底层应用
        //向上和如果用户将文本输入的底部向下
        //它的窗口。
        setCandidatesViewShown(假);

        如果(mInputView!= NULL){
            mInputView.closing();
        }
    }

    @覆盖
    公共无效onUpdateSelection(INT oldSelStart,INT oldSelEnd,
            INT newSelStart,诠释newSelEnd,INT candidatesStart,
            INT candidatesEnd){

        //如果当前选择的文本视图的变化,我们应该
        //清晰的任何候选人的文字,我们有。
        如果(mComposing.length()大于0
                &功放;&安培; (newSelStart!= candidatesEnd || newSelEnd!= candidatesEnd)){
            mComposing.setLength(0);
            updateCandidates();
            InputConnection集成电路= getCurrentInputConnection();
            如果(IC!= NULL){
                ic.finishComposingText();

            }
        }
    }

    @覆盖
    公共无效onDisplayCompletions(CompletionInfo []完工){
        如果(mCompletionOn){
            mCompletions =落成;
            如果(完工== NULL){
                setSuggestions(空,假的,假的);
                返回;
            }

            名单<字符串> StringList的=新的ArrayList<字符串>();
            对(INT I = 0; I&≤(完井=空completions.length:!?0);我++){
                CompletionInfo CI =落成[I]
                如果(CI!= NULL)
                    stringList.add(ci.getText()的toString());
            }
            setSuggestions(StringList的,真实的,真正的);
        }
    }

    私人布尔translateKeyDown(INT键code,KeyEvent的事件){

        mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,关键code,
                事件);
        INT C = event.getUni codeCHAR(MetaKeyKeyListener
                .getMetaState(mMetaState));
        mMetaState = MetaKeyKeyListener.adjustMetaAfterKey preSS(mMetaState);
        InputConnection集成电路= getCurrentInputConnection();
        如果(C == 0 || IC == NULL){
            返回false;
        }

        布尔死亡= FALSE;

        如果((C&安培;!KeyCharacterMap.COMBINING_ACCENT)= 0){
            死亡= TRUE;
            C = C放大器; KeyCharacterMap.COMBINING_ACCENT_MASK;
        }

        如果(mComposing.length()大于0){
            焦炭口音= mComposing.charAt(mComposing.length() -  1);
            诠释组成= KeyEvent.getDeadChar(口音,C);

            如果(由!= 0){
                C =组成;
                mComposing.setLength(mComposing.length() -  1);
            }
        }

        onKey(C,NULL);

        返回true;
    }

    @覆盖
    公共布尔的onkeydown(INT键code,KeyEvent的事件){

        开关(钥匙code){

        案例KeyEvent.KEY code_BACK:
            //该InputMethodService已经取回来照顾
            //重点对我们来说,驳回输入法,如果它显示。
            //然而,我们的键盘可以被示出弹出窗口
            //这回应该解雇,所以我们首先允许它这样做。
            如果(event.getRepeatCount()== 0安培;&安培;!mInputView = NULL){
                如果(mInputView.handleBack()){
                    返回true;
                }
            }
            打破;

        案例KeyEvent.KEY code_DEL:
            //特别删除键的处理:如果我们现在是
            //合成的文本对于用户来说,我们要修改,而不是
            //让应用程序的删除自身。
            如果(mComposing.length()大于0){
                onKey(Keyboard.KEY code_DELETE,NULL);
                返回true;
            }
            打破;

        默认:
            //对于其他所有按键,如果我们想要做的转换上
            //正在输入用硬键盘的文字,我们需要处理
            //并做相应的动作。
            如果(PROCESS_HARD_KEYS){
                如果(键code == KeyEvent.KEY code_SPACE
                        &功放;&安培; (event.getMetaState()及KeyEvent.META_ALT_ON)!= 0){
                    //一个愚蠢的例子:在我们的输入法,Alt +空格
                    //为机器人用小写的快捷方式。
                    InputConnection集成电路= getCurrentInputConnection();
                    如果(IC!= NULL){
                        //首先,告诉编辑器,它不再是在
                        //移位状态,因为我们正在消耗这一点。
                        ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
                        keyDownUp(KeyEvent.KEY code_A);
                        keyDownUp(KeyEvent.KEY code_N);
                        keyDownUp(KeyEvent.KEY code_D);
                        keyDownUp(KeyEvent.KEY code_R);
                        keyDownUp(KeyEvent.KEY code_O);
                        keyDownUp(KeyEvent.KEY code_I);
                        keyDownUp(KeyEvent.KEY code_D);
                        //我们消耗此事件。
                        返回true;
                    }
                }
                如果(M predictionOn和放大器;&安培; translateKeyDown(键code,事件)){
                    返回true;
                }
            }
        }

        返回super.onKeyDown(键code,事件);
    }

    @覆盖
    公共布尔的onkeyup(INT键code,KeyEvent的事件){

        //如果我们想要做的文本转换正在进入一个硬
        //键盘,我们需要处理了事件更新meta键
        //状态,我们正在追踪。
        如果(PROCESS_HARD_KEYS){
            如果(M predictionOn){
                mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
                        关键code,事件);
            }
        }

        返回super.onKeyUp(键code,事件);
    }

    私人无效commitTyped(InputConnection inputConnection){

        如果(mComposing.length()大于0){
            inputConnection.commitText(mComposing,mComposing.length());
            mComposing.setLength(0);
            updateCandidates();
        }
    }

    私人无效updateShiftKeyState(EditorInfo ATTR){
        如果(ATTR = NULL和放大器;!&安培;!mInputView = NULL
                &功放;&安培; mQwertyKeyboard == mInputView.getKeyboard()){
            诠释帽= getCurrentInputConnection()。getCursorCapsMode(
                    attr.inputType);
            mInputView.setShifted(mCapsLock ||帽子!= 0);
        }
    }

    私人布尔isAlphabet(INT code){

        如果(Character.isLetter(code)){
            返回true;
        } 其他 {
            返回false;
        }
    }

    私人无效keyDownUp(INT的keyEvent code){

        getCurrentInputConnection()。sendKeyEvent(
                新的KeyEvent(KeyEvent.ACTION_DOWN,的keyEvent code));
        getCurrentInputConnection()。sendKeyEvent(
                新的KeyEvent(KeyEvent.ACTION_UP,的keyEvent code));
    }

    私人无效sendKey(INT键code){
        ;
        开关(钥匙code){
        案'\ n'的
            keyDownUp(KeyEvent.KEY code_ENTER);
            打破;
        默认:
            如果(键code> ='0'和;&放大器;关键$ C $℃下='9'){
                keyDownUp(键code  - '0'+ KeyEvent.KEY code_0);
            } 其他 {
                getCurrentInputConnection()。commitText(
                        将String.valueOf((char)的关键code),1);
            }
            打破;
        }
    }

    公共无效onKey(int主code,INT []键codeS){

        如果(主要code == 32 ||主要code == -5 ||主要code == 10){
            如果(strBldrFrEmoji!= NULL){
                strBldrFrEmoji = NULL;
            }
        }

        如果(isWordSeparator(主要code)){

            如果(mComposing.length()大于0){
                commitTyped(getCurrentInputConnection());
            }
            sendKey(主要code);
            updateShiftKeyState(getCurrentInputEditorInfo());
        }否则,如果(主要code == Keyboard.KEY code_DELETE){
            handleBackspace();
        }否则,如果(主要code == Keyboard.KEY code_SHIFT){
            handleShift();
        }否则,如果(主要code == Keyboard.KEY code_CANCEL){
            handleClose();
            返回;
        }否则,如果(主要code == LatinKeyboardView.KEY code_OPTIONS){
            //显示一个菜单或事端
        }否则,如果(主要code == Keyboard.KEY code_MODE_CHANGE
                &功放;&安培; mInputView!= NULL){
            键盘电流= mInputView.getKeyboard();
            如果(当前== mSymbolsKeyboard
                    ||目前== mSymbolsShiftedKeyboard){
                电流= mQwertyKeyboard;
            } 其他 {
                电流= mSymbolsKeyboard;
            }
            mInputView.setKeyboard(电流);
            如果(当前== mSymbolsKeyboard){
                current.setShifted(假);
            }
        } 其他 {
            handleCharacter(主要code,关键codeS);
        }
    }

    私人无效updateCandidates(){

        如果(!mCompletionOn){
            如果(mComposing.length()大于0){
                ArrayList的<字符串>名单=新的ArrayList<字符串>();
                list.add(mComposing.toString());
                setSuggestions(列表中,真正的,真实的);
            } 其他 {
                setSuggestions(空,假的,假的);
            }
        }
    }

    公共无效setSuggestions(名单<字符串>建议,布尔落成,
            布尔typedWordValid){

        如果(mCandidateView!= NULL){
            mCandidateView.setSuggestions(建议,完井,
                    typedWordValid);
            如果(建议=空&安培;!&安培; suggestions.size()大于0){
                setCandidatesViewShown(真正的);
            }否则如果(isFullscreenMode()){
                setCandidatesViewShown(真正的);
            }
        }
    }

    私人无效handleBackspace(){
        最终诠释长度= mComposing.length();
        如果(长度大于1){
            mComposing.delete(长度 -  1,长度);
            getCurrentInputConnection()。setComposingText(mComposing,
                    mComposing.length());
            updateCandidates();
        }否则如果(长度大于0){
            mComposing.setLength(0);
            getCurrentInputConnection()commitText(,0);
            updateCandidates();
        } 其他 {
            keyDownUp(KeyEvent.KEY code_DEL);
        }
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    私人无效handleShift(){
        如果(mInputView == NULL){
            返回;
        }

        键盘currentKeyboard = mInputView.getKeyboard();
        如果(mQwertyKeyboard == currentKeyboard){
            //字母键盘
            checkToggleCapsLock();
            mInputView.setShifted(mCapsLock || mInputView.isShifted()!);
        }否则,如果(currentKeyboard == mSymbolsKeyboard){
            mSymbolsKeyboard.setShifted(真正的);
            mInputView.setKeyboard(mSymbolsShiftedKeyboard);
            mSymbolsShiftedKeyboard.setShifted(真正的);
        }否则,如果(currentKeyboard == mSymbolsShiftedKeyboard){
            mSymbolsShiftedKeyboard.setShifted(假);
            mInputView.setKeyboard(mSymbolsKeyboard);
            mSymbolsKeyboard.setShifted(假);
        }
    }

    私人无效handleCharacter(int主code,INT []键codeS){

        如果(strBldrFrEmoji == NULL){
            strBldrFrEmoji =新的StringBuilder();

        }
        strBldrFrEmoji.append(将String.valueOf((char)的主要code));

        checkEnteredText(strBldrFrEmoji.toString());

        如果(isInputViewShown()){
            如果(mInputView.isShifted()){
                主要code = Character.toUpperCase(主要code);
            }
        }
        如果(isAlphabet(主要code)及和放大器,M predictionOn){
            mComposing.append((char)的主要code);
            getCurrentInputConnection()。setComposingText(mComposing,
                    mComposing.length());
            updateShiftKeyState(getCurrentInputEditorInfo());
            updateCandidates();
        } 其他 {
            getCurrentInputConnection()。commitText(
                    将String.valueOf((char)的主要code),1);
        }
    }

    无效checkEnteredText(字符串STR1){

        如果(str1.length()大于0){
            如果(str1.equalsIgnoreCase(你好)){


                / **
                ImageGetter imageGetter =新ImageGetter(){
            公众可绘制getDrawable(字符串源){
                绘制对象D =新BitmapDrawable(getResources(),BitmapFactory.de codeResource(getResources()
                        R.drawable.ic_smiley));
                d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
                返回D组;
            }
        };

        跨区CS = Html.fromHtml(&所述; A HREF ='的http://www.google.com'>&所述; IMG SRC =+ STR1 +'/>&其中;一个>中,imageGetter,空);
                * /
                ImageGetter imageGetter =新ImageGetter(){
                    @覆盖
                    公众可绘制getDrawable(字符串源){
                        byte []的EN codeByte =的Base64
                                .de$c$c("iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
                                        Base64.DEFAULT);
                        点阵位图= BitmapFactory.de codeByteArray(
                                EN codeByte,0,EN codeByte.length);
                        绘制对象D =新BitmapDrawable(位);

                        返回D组;
                    }
                };

                跨区CS =的Html
                        .fromHtml(
                                < IMG SRC =数据:图像/ PNG; BASE64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='/>",
                                imageGetter,NULL);

                getCurrentInputConnection()setComposingText(CS,1);

            }
        }

    }

    私人无效handleClose(){

        commitTyped(getCurrentInputConnection());
        // dismissSoftInput(0);
        mInputView.closing();
    }

    私人无效checkToggleCapsLock(){
        长今= System.currentTimeMillis的();
        如果(mLastShiftTime + 800>接着){
            mCapsLock = mCapsLock!;
            mLastShiftTime = 0;
        } 其他 {
            mLastShiftTime =现在;
        }
    }

    私人字符串getWordSeparators(){
        返回mWordSeparators;
    }

    公共布尔isWordSeparator(INT code){

        串隔板= getWordSeparators();
        返回separators.contains(将String.valueOf((char)的code));
    }

    公共无效pickDefaultCandidate(){
        pickSuggestionManually(0);
    }

    公共无效pickSuggestionManually(INT指数){
        如果(mCompletionOn&安培;&安培; mCompletions = NULL和放大器;!&安培;索引> = 0
                &功放;&安培;指数< mCompletions.length){
            CompletionInfo CI = mCompletions [指数]
            。getCurrentInputConnection()commitCompletion(CI);
            如果(mCandidateView!= NULL){
                mCandidateView.clear();
            }
            updateShiftKeyState(getCurrentInputEditorInfo());
        }否则如果(mComposing.length()大于0){
            //如果我们对当前生成候选建议
            //文字,我们会犯下其中之一在这里。但对于此示例,
            //我们只提交当前文本。
            commitTyped(getCurrentInputConnection());
        }
    }

    公共无效swipeRight(){
        如果(mCompletionOn){
            pickDefaultCandidate();
        }
    }

    公共无效swipeLeft(){
        handleBackspace();
    }

    公共无效swipeDown(){
        handleClose();
    }

    公共无效swipeUp(){
    }

    在preSS(int主code){公共无效
    }

    公共无效onRelease(int主code){
    }

    @覆盖
    公共无效onText(CharSequence的文字){

    }
}
 

解决方案

您正试图发送一个图片叽叽喳喳/ WhatsApp的,不是一个表情符号。是有区别的。

绘文字的字面意思是图片文字,并依赖于手机的字符集接收机使用。即使你更换自己的手机emojis相关的图片,你的人发送的表情符号,以将只能看到自己的emojis的按键组。这是不是你想要的。

图像无关,与手机按键组,他们被送到该手机将不管出现大致相同。您需要管你的形象与用户当前专注于应用程序相关的意图。

  1. 在看Android的应用程序栈。
  2. 找到顶部的应用程序。
  3. 管道通过intent.putExtra(Intent.EXTRA_STREAM,BitmapUriLocation)位图到应用程序中;

这是应用程序如何在这里引用: https://开头play.google.com/store/apps/details?id=com.plantpurple.emojidom 最有可能做的事情。

how to add custom image as emoji in android InputMethodService. i have tried using

ImageGetter imageGetter = new ImageGetter() {
                public Drawable getDrawable(String source) {    
                    StringTokenizer st = new StringTokenizer(str, ".");
                    Drawable d = new BitmapDrawable(getResources(),emoticons[Integer.parseInt(st.nextToken()) - 1]);
                    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
                    return d;
                }
            };

            Spanned cs = Html.fromHtml("<img src ='"+ str +"'/>", imageGetter, null);


        getCurrentInputConnection().commitText(cs,1);

but only getting a obj text image. is there any way to add custom emoji to message(whatsapp /twitter) in android

Edit :

in my application if i type hello using my custom keyboard i have to insert a custom hello picture in edit field for every app installed in phone.

can it achieved ?

Edit : 2

i have checked it using convert mage to base64 also but nothing happen with Tag

ImageGetter imageGetter = new ImageGetter() {
                @Override
                public Drawable getDrawable(String source) {    
                    byte [] encodeByte=Base64.decode("iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",Base64.DEFAULT);
                    Bitmap bitmap=BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);      
                    Drawable d = new BitmapDrawable(bitmap);

                    Log.e("Chk", "Height : "+d.getIntrinsicHeight());
                    Log.e("Chk", "Width : " + d.getIntrinsicWidth());                       

                    return d;
                }
            };

            Spanned cs = Html.fromHtml("<img src='data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='/>", imageGetter,null);

            Log.e("Chk", "12 : " + 12);


        getCurrentInputConnection().setComposingText(cs,1);

Edit : 3

I am using this InputMethodService class in my custom keyboard application.

package com.example.android.softkeyboard;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Html;
import android.text.Html.ImageGetter;
import android.text.Spanned;
import android.text.method.MetaKeyKeyListener;
import android.util.Base64;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;

public class SoftKeyboard extends InputMethodService implements
        KeyboardView.OnKeyboardActionListener {
    static final boolean DEBUG = false;

    static final boolean PROCESS_HARD_KEYS = true;

    private KeyboardView mInputView;
    private CandidateView mCandidateView;
    private CompletionInfo[] mCompletions;

    private StringBuilder mComposing = new StringBuilder();
    private boolean mPredictionOn;
    private boolean mCompletionOn;
    private int mLastDisplayWidth;
    private boolean mCapsLock;
    private long mLastShiftTime;
    private long mMetaState;

    private Keyboard mSymbolsKeyboard;
    private Keyboard mSymbolsShiftedKeyboard;
    private Keyboard mQwertyKeyboard;

    private String mWordSeparators;

    StringBuilder strBldrFrEmoji;

    private void makeKeyboards() {
        if (mQwertyKeyboard != null) {
            // Configuration changes can happen after the keyboard gets
            // recreated,
            // so we need to be able to re-build the keyboards if the available
            // space has changed.
            int displayWidth = getMaxWidth();
            if (displayWidth == mLastDisplayWidth)
                return;
            mLastDisplayWidth = displayWidth;
        }
        mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
        mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
        mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        makeKeyboards();
        mWordSeparators = getResources().getString(R.string.word_separators);
    }

    @Override
    public View onCreateInputView() {
        // We call makeKeyboards() here to regenerate them if needed due to
        // a configuration change.
        makeKeyboards();
        mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input,
                null);
        mInputView.setOnKeyboardActionListener(this);
        mInputView.setKeyboard(mQwertyKeyboard);
        return mInputView;
    }

    @Override
    public View onCreateCandidatesView() {
        mCandidateView = new CandidateView(this);
        mCandidateView.setService(this);
        return mCandidateView;
    }

    @Override
    public void onStartInputView(EditorInfo attribute, boolean restarting) {
        super.onStartInputView(attribute, restarting);

        // Reset our state. We want to do this even if restarting, because
        // the underlying state of the text editor could have changed in any
        // way.
        mComposing.setLength(0);
        updateCandidates();

        if (!restarting) {
            // Clear shift states.
            mMetaState = 0;
        }

        mPredictionOn = false;
        mCompletionOn = false;
        mCompletions = null;
        Keyboard keyboard;

        // We are now going to initialize our state based on the type of
        // text being edited.
        switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
        case EditorInfo.TYPE_CLASS_NUMBER:
        case EditorInfo.TYPE_CLASS_DATETIME:
            // Numbers and dates default to the symbols keyboard, with
            // no extra features.
            keyboard = mSymbolsKeyboard;
            break;

        case EditorInfo.TYPE_CLASS_PHONE:
            // Phones will also default to the symbols keyboard, though
            // often you will want to have a dedicated phone keyboard.
            keyboard = mSymbolsKeyboard;
            break;

        case EditorInfo.TYPE_CLASS_TEXT:

            // This is general text editing. We will default to the
            // normal alphabetic keyboard, and assume that we should
            // be doing predictive text (showing candidates as the
            // user types).
            keyboard = mQwertyKeyboard;
            mPredictionOn = true;

            // We now look for a few special variations of text that will
            // modify our behavior.
            int variation = attribute.inputType
                    & EditorInfo.TYPE_MASK_VARIATION;
            if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD) {
                // Do not display predictions / what the user is typing
                // when they are entering a password.
                mPredictionOn = false;
            }

            if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
                    || variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
                // Our predictions are not useful for e-mail addresses
                // or URIs.
                mPredictionOn = false;
            }

            if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                // If this is an auto-complete text view, then our predictions
                // will not be shown and instead we will allow the editor
                // to supply their own. We only show the editor's
                // candidates when in fullscreen mode, otherwise relying
                // own it displaying its own UI.
                mPredictionOn = false;
                mCompletionOn = isFullscreenMode();
            }

            // We also want to look at the current state of the editor
            // to decide whether our alphabetic keyboard should start out
            // shifted.
            updateShiftKeyState(attribute);
            break;

        default:
            // For all unknown input types, default to the alphabetic
            // keyboard with no special features.
            keyboard = mQwertyKeyboard;

        }

        // Apply the selected keyboard to the input view.
        if (mInputView != null) {
            mInputView.setKeyboard(keyboard);
            mInputView.closing();
        }
    }

    @Override
    public void onFinishInput() {
        super.onFinishInput();

        // Clear current composing text and candidates.
        mComposing.setLength(0);
        updateCandidates();

        // We only hide the candidates window when finishing input on
        // a particular editor, to avoid popping the underlying application
        // up and down if the user is entering text into the bottom of
        // its window.
        setCandidatesViewShown(false);

        if (mInputView != null) {
            mInputView.closing();
        }
    }

    @Override
    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
            int newSelStart, int newSelEnd, int candidatesStart,
            int candidatesEnd) {

        // If the current selection in the text view changes, we should
        // clear whatever candidate text we have.
        if (mComposing.length() > 0
                && (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) {
            mComposing.setLength(0);
            updateCandidates();
            InputConnection ic = getCurrentInputConnection();
            if (ic != null) {
                ic.finishComposingText();

            }
        }
    }

    @Override
    public void onDisplayCompletions(CompletionInfo[] completions) {
        if (mCompletionOn) {
            mCompletions = completions;
            if (completions == null) {
                setSuggestions(null, false, false);
                return;
            }

            List<String> stringList = new ArrayList<String>();
            for (int i = 0; i < (completions != null ? completions.length : 0); i++) {
                CompletionInfo ci = completions[i];
                if (ci != null)
                    stringList.add(ci.getText().toString());
            }
            setSuggestions(stringList, true, true);
        }
    }

    private boolean translateKeyDown(int keyCode, KeyEvent event) {

        mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState, keyCode,
                event);
        int c = event.getUnicodeChar(MetaKeyKeyListener
                .getMetaState(mMetaState));
        mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
        InputConnection ic = getCurrentInputConnection();
        if (c == 0 || ic == null) {
            return false;
        }

        boolean dead = false;

        if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
            dead = true;
            c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
        }

        if (mComposing.length() > 0) {
            char accent = mComposing.charAt(mComposing.length() - 1);
            int composed = KeyEvent.getDeadChar(accent, c);

            if (composed != 0) {
                c = composed;
                mComposing.setLength(mComposing.length() - 1);
            }
        }

        onKey(c, null);

        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        switch (keyCode) {

        case KeyEvent.KEYCODE_BACK:
            // The InputMethodService already takes care of the back
            // key for us, to dismiss the input method if it is shown.
            // However, our keyboard could be showing a pop-up window
            // that back should dismiss, so we first allow it to do that.
            if (event.getRepeatCount() == 0 && mInputView != null) {
                if (mInputView.handleBack()) {
                    return true;
                }
            }
            break;

        case KeyEvent.KEYCODE_DEL:
            // Special handling of the delete key: if we currently are
            // composing text for the user, we want to modify that instead
            // of let the application to the delete itself.
            if (mComposing.length() > 0) {
                onKey(Keyboard.KEYCODE_DELETE, null);
                return true;
            }
            break;

        default:
            // For all other keys, if we want to do transformations on
            // text being entered with a hard keyboard, we need to process
            // it and do the appropriate action.
            if (PROCESS_HARD_KEYS) {
                if (keyCode == KeyEvent.KEYCODE_SPACE
                        && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
                    // A silly example: in our input method, Alt+Space
                    // is a shortcut for 'android' in lower case.
                    InputConnection ic = getCurrentInputConnection();
                    if (ic != null) {
                        // First, tell the editor that it is no longer in the
                        // shift state, since we are consuming this.
                        ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
                        keyDownUp(KeyEvent.KEYCODE_A);
                        keyDownUp(KeyEvent.KEYCODE_N);
                        keyDownUp(KeyEvent.KEYCODE_D);
                        keyDownUp(KeyEvent.KEYCODE_R);
                        keyDownUp(KeyEvent.KEYCODE_O);
                        keyDownUp(KeyEvent.KEYCODE_I);
                        keyDownUp(KeyEvent.KEYCODE_D);
                        // And we consume this event.
                        return true;
                    }
                }
                if (mPredictionOn && translateKeyDown(keyCode, event)) {
                    return true;
                }
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {

        // If we want to do transformations on text being entered with a hard
        // keyboard, we need to process the up events to update the meta key
        // state we are tracking.
        if (PROCESS_HARD_KEYS) {
            if (mPredictionOn) {
                mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
                        keyCode, event);
            }
        }

        return super.onKeyUp(keyCode, event);
    }

    private void commitTyped(InputConnection inputConnection) {

        if (mComposing.length() > 0) {
            inputConnection.commitText(mComposing, mComposing.length());
            mComposing.setLength(0);
            updateCandidates();
        }
    }

    private void updateShiftKeyState(EditorInfo attr) {
        if (attr != null && mInputView != null
                && mQwertyKeyboard == mInputView.getKeyboard()) {
            int caps = getCurrentInputConnection().getCursorCapsMode(
                    attr.inputType);
            mInputView.setShifted(mCapsLock || caps != 0);
        }
    }

    private boolean isAlphabet(int code) {

        if (Character.isLetter(code)) {
            return true;
        } else {
            return false;
        }
    }

    private void keyDownUp(int keyEventCode) {

        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
    }

    private void sendKey(int keyCode) {
        ;
        switch (keyCode) {
        case '\n':
            keyDownUp(KeyEvent.KEYCODE_ENTER);
            break;
        default:
            if (keyCode >= '0' && keyCode <= '9') {
                keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
            } else {
                getCurrentInputConnection().commitText(
                        String.valueOf((char) keyCode), 1);
            }
            break;
        }
    }

    public void onKey(int primaryCode, int[] keyCodes) {

        if (primaryCode == 32 || primaryCode == -5 || primaryCode == 10) {
            if (strBldrFrEmoji != null) {
                strBldrFrEmoji = null;
            }
        }

        if (isWordSeparator(primaryCode)) {

            if (mComposing.length() > 0) {
                commitTyped(getCurrentInputConnection());
            }
            sendKey(primaryCode);
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
            handleBackspace();
        } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
            handleShift();
        } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
            handleClose();
            return;
        } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
            // Show a menu or somethin'
        } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE
                && mInputView != null) {
            Keyboard current = mInputView.getKeyboard();
            if (current == mSymbolsKeyboard
                    || current == mSymbolsShiftedKeyboard) {
                current = mQwertyKeyboard;
            } else {
                current = mSymbolsKeyboard;
            }
            mInputView.setKeyboard(current);
            if (current == mSymbolsKeyboard) {
                current.setShifted(false);
            }
        } else {
            handleCharacter(primaryCode, keyCodes);
        }
    }

    private void updateCandidates() {

        if (!mCompletionOn) {
            if (mComposing.length() > 0) {
                ArrayList<String> list = new ArrayList<String>();
                list.add(mComposing.toString());
                setSuggestions(list, true, true);
            } else {
                setSuggestions(null, false, false);
            }
        }
    }

    public void setSuggestions(List<String> suggestions, boolean completions,
            boolean typedWordValid) {

        if (mCandidateView != null) {
            mCandidateView.setSuggestions(suggestions, completions,
                    typedWordValid);
            if (suggestions != null && suggestions.size() > 0) {
                setCandidatesViewShown(true);
            } else if (isFullscreenMode()) {
                setCandidatesViewShown(true);
            }
        }
    }

    private void handleBackspace() {
        final int length = mComposing.length();
        if (length > 1) {
            mComposing.delete(length - 1, length);
            getCurrentInputConnection().setComposingText(mComposing,
                    mComposing.length());
            updateCandidates();
        } else if (length > 0) {
            mComposing.setLength(0);
            getCurrentInputConnection().commitText("", 0);
            updateCandidates();
        } else {
            keyDownUp(KeyEvent.KEYCODE_DEL);
        }
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    private void handleShift() {
        if (mInputView == null) {
            return;
        }

        Keyboard currentKeyboard = mInputView.getKeyboard();
        if (mQwertyKeyboard == currentKeyboard) {
            // Alphabet keyboard
            checkToggleCapsLock();
            mInputView.setShifted(mCapsLock || !mInputView.isShifted());
        } else if (currentKeyboard == mSymbolsKeyboard) {
            mSymbolsKeyboard.setShifted(true);
            mInputView.setKeyboard(mSymbolsShiftedKeyboard);
            mSymbolsShiftedKeyboard.setShifted(true);
        } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
            mSymbolsShiftedKeyboard.setShifted(false);
            mInputView.setKeyboard(mSymbolsKeyboard);
            mSymbolsKeyboard.setShifted(false);
        }
    }

    private void handleCharacter(int primaryCode, int[] keyCodes) {

        if (strBldrFrEmoji == null) {
            strBldrFrEmoji = new StringBuilder();

        }
        strBldrFrEmoji.append(String.valueOf((char) primaryCode));

        checkEnteredText(strBldrFrEmoji.toString());

        if (isInputViewShown()) {
            if (mInputView.isShifted()) {
                primaryCode = Character.toUpperCase(primaryCode);
            }
        }
        if (isAlphabet(primaryCode) && mPredictionOn) {
            mComposing.append((char) primaryCode);
            getCurrentInputConnection().setComposingText(mComposing,
                    mComposing.length());
            updateShiftKeyState(getCurrentInputEditorInfo());
            updateCandidates();
        } else {
            getCurrentInputConnection().commitText(
                    String.valueOf((char) primaryCode), 1);
        }
    }

    void checkEnteredText(String str1) {

        if (str1.length() > 0) {
            if (str1.equalsIgnoreCase("hello")) {


                /**
                ImageGetter imageGetter = new ImageGetter() {
            public Drawable getDrawable(String source) {    
                Drawable d = new BitmapDrawable(getResources(),BitmapFactory.decodeResource(getResources(),
                        R.drawable.ic_smiley));
                d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
                return d;
            }
        };

        Spanned cs = Html.fromHtml("<a href='http://www.google.com'><img src ='"+ str1 +"'/><a>", imageGetter, null);
                */
                ImageGetter imageGetter = new ImageGetter() {
                    @Override
                    public Drawable getDrawable(String source) {
                        byte[] encodeByte = Base64
                                .decode("iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
                                        Base64.DEFAULT);
                        Bitmap bitmap = BitmapFactory.decodeByteArray(
                                encodeByte, 0, encodeByte.length);
                        Drawable d = new BitmapDrawable(bitmap);

                        return d;
                    }
                };

                Spanned cs = Html
                        .fromHtml(
                                "<img src='data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='/>",
                                imageGetter, null);

                getCurrentInputConnection().setComposingText(cs, 1);

            }
        }

    }

    private void handleClose() {

        commitTyped(getCurrentInputConnection());
        // dismissSoftInput(0);
        mInputView.closing();
    }

    private void checkToggleCapsLock() {
        long now = System.currentTimeMillis();
        if (mLastShiftTime + 800 > now) {
            mCapsLock = !mCapsLock;
            mLastShiftTime = 0;
        } else {
            mLastShiftTime = now;
        }
    }

    private String getWordSeparators() {
        return mWordSeparators;
    }

    public boolean isWordSeparator(int code) {

        String separators = getWordSeparators();
        return separators.contains(String.valueOf((char) code));
    }

    public void pickDefaultCandidate() {
        pickSuggestionManually(0);
    }

    public void pickSuggestionManually(int index) {
        if (mCompletionOn && mCompletions != null && index >= 0
                && index < mCompletions.length) {
            CompletionInfo ci = mCompletions[index];
            getCurrentInputConnection().commitCompletion(ci);
            if (mCandidateView != null) {
                mCandidateView.clear();
            }
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (mComposing.length() > 0) {
            // If we were generating candidate suggestions for the current
            // text, we would commit one of them here. But for this sample,
            // we will just commit the current text.
            commitTyped(getCurrentInputConnection());
        }
    }

    public void swipeRight() {
        if (mCompletionOn) {
            pickDefaultCandidate();
        }
    }

    public void swipeLeft() {
        handleBackspace();
    }

    public void swipeDown() {
        handleClose();
    }

    public void swipeUp() {
    }

    public void onPress(int primaryCode) {
    }

    public void onRelease(int primaryCode) {
    }

    @Override
    public void onText(CharSequence text) {

    }
}

解决方案

You're trying to send an image to twitter/whatsapp, not an emoji. There is a difference.

Emoji literally means "picture to character" and are dependent on the phone's character set that the receiver is using. Even if you replaced the images associated with your own phone's emojis, the person you are sending the emoji to would only be able to see their own keysets of emojis. This is not what you want.

Images have nothing to do with phone keysets and will appear roughly the same no matter which phones they are sent to. You need to pipe your image to an intent associated with the application the user is currently focused on.

  1. Look at Android's application stack.
  2. Find the Application on top.
  3. Pipe the bitmap via intent.putExtra(Intent.EXTRA_STREAM, BitmapUriLocation) into the application;

This is how the app referenced here : https://play.google.com/store/apps/details?id=com.plantpurple.emojidom most likely did things.

这篇关于在Android中添加自定义图像作为表情符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆