добавить пользовательское изображение как Emoji в Android

как добавить пользовательское изображение в качестве смайликов в Android InputMethodService. я пытался использовать

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);

но только получая введите описание изображения здесьтекстовое изображение obj. есть ли способ добавить пользовательский смайлик в сообщение (whatsapp / twitter) в android

Изменить:

в моем приложении, если я набираю приветствие с помощью своей пользовательской клавиатуры, мне нужно вставить собственное изображение приветствия в поле редактирования для каждого приложения, установленного в телефоне.

может это достигнуто?

Изменить : 2

Я также проверил это с помощью конвертации мага в base64, но ничего не происходит с тегом

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);

Изменить : 3

Я использую этот класс InputMethodService в своем пользовательском приложении клавиатуры.

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) {

    }
}

person Community    schedule 11.08.2014    source источник
comment
я также проверил stackoverflow.com/q/24100615/3472378, но ответа нет.   -  person    schedule 11.08.2014
comment
Справочный пример: github.com/chiragjain/Emoticons-Keyboard   -  person VVB    schedule 11.08.2014
comment
@RIT эй, спасибо за повтор, но не могли бы вы увидеть отредактированный вопрос. и я уже проверил ссылку выше.   -  person    schedule 11.08.2014
comment
что бы вы хотели получить вместо изображения OBJ?   -  person pskink    schedule 11.08.2014
comment
@pskink я хочу показать изображение из папки с возможностью рисования.   -  person    schedule 12.08.2014
comment
где вы вызываете getCurrentInputConnection().setComposingText(cs,1); от?   -  person pskink    schedule 12.08.2014
comment
@pskink Я добавил свой класс InputMethodService, о котором идет речь.   -  person    schedule 12.08.2014
comment
Хорошо, создайте папку с ресурсами, добавьте файл obj1.png в папку с ресурсами и попробуйте запустить pastebin.com/9WPJHpHJ. , это даст вам представление о том, как получить составное изображение   -  person pskink    schedule 12.08.2014
comment
@pskink это приложение для клавиатуры (мягкая клавиатура Smaple). он включается только тогда, когда пользователь выбирает его из языка и меню ввода в настройках устройства. у меня нет edittext/ui в моем приложении.   -  person    schedule 12.08.2014
comment
@pskink на самом деле мы собираемся создать клавиатуру, когда пользователь набирает с этой клавиатуры некоторые определенные слова, вместо этого он добавит изображение. например, если пользователь вводит приветствие, он удалит приветствие и добавит значок изображения в поле редактирования. Я пытаюсь около 3 дней, но до сих пор не нашел решения, чем помочь?   -  person    schedule 12.08.2014
comment
EditText здесь не важен, он просто показывает текст Spanned, чтобы убедиться, что ImageSpan работает нормально, вам нужно передать ssb в ваш метод commitText   -  person pskink    schedule 12.08.2014
comment
так что важные вещи находятся внутри предложения try, кроме setText, конечно   -  person pskink    schedule 12.08.2014
comment
@pskink я пробовал как SpannableStringBuilder ssb = new SpannableStringBuilder(x); Объект what = new ImageSpan(BitmapFactory.decodeStream(getAssets().open(1.png))); ssb.setSpan(что, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Составной cs = ssb; getCurrentInputConnection().setComposingText(cs, 1); но это не рендеринг изображения, просто показывая x :(   -  person    schedule 12.08.2014
comment
вот почему я разместил код с EditText, чтобы убедиться, что вы все настроили, вы пытались поместить его в Activity.onCreate и запустить? если да, то вы видите изображение obj1.png?   -  person pskink    schedule 12.08.2014
comment
@pskink, когда я добавляю активность в свое приложение и выбираю этот метод ввода в качестве клавиатуры, он работает нормально, но когда я использую эту клавиатуру для ввода текста в другом приложении, таком как WhatsApp, Twitter, он не работает. также, если я копирую текст из своего приложения в другое, он также не копирует, просто вставляет пустое место.   -  person    schedule 12.08.2014
comment
попробуйте TextUtils.dumpSpans вставленного буфера, он будет регистрировать промежутки в объекте Spanned   -  person pskink    schedule 12.08.2014
comment
@pskink я использовал TextUtils.dumpSpans, который он печатает. 08-12 14:09:14.006: D/CHECK(14297): span x: 41079428 android.text.style.ImageSpan (0-1) fl=#33   -  person    schedule 12.08.2014
comment
поэтому ImageSpan находится внутри вставленного буфера, попробуйте получить его через Spanned.getSpans и попытайтесь увидеть его Drawable (метод ImageSpan.getDrawable)   -  person pskink    schedule 12.08.2014
comment
@pskink я получаю объект рисования с помощью ImageSpan.getDrawable, а также получаю его высоту и ширину. Могу ли я спросить, как это помогает показать изображение.   -  person    schedule 12.08.2014
comment
если бы Drawable был нулевым или размеры были нулевыми, ответ был бы очевиден, теперь, когда он действителен Drawable, ответ таков: я не знаю, почему он пуст, вы бы опубликовали для меня весь код, чтобы проверить его, но я думаю, что вы не можете этого сделать   -  person pskink    schedule 12.08.2014
comment
@pskink Вот ссылка на проект, который я хочу изменить. android.googlesource.com/platform/development/+/master/samples/ я изменяю только класс SoftKeyboard, который опубликован в вопросе, и добавляю изображение значка в папку активов с именем 1.png. и заранее спасибо, было бы очень полезно для меня, если вы поможете.   -  person    schedule 12.08.2014
comment
@pskink, а это ссылка для скачивания проекта android. googlesource.com/platform/development/+archive/master/   -  person    schedule 12.08.2014
comment
вместо ImageSpan попробуйте использовать любой ParcelableSpan (например, Background/ForegroundColorSpan) и посмотрите, работают ли они, если да, то я боюсь, что вы можете использовать только ParcelableSpans в разных процессах, хотя вы можете создать собственный ImageSpan, реализующий Parcelable iface, я не проверить это   -  person pskink    schedule 12.08.2014
comment
Вы пробовали Background/ForegroundColorSpan? они работали?   -  person pskink    schedule 12.08.2014
comment
@pskink я проверил, что цвет работает. я опубликую код через 15 часов, потому что моя IDE теперь закрыта моим работодателем. Благодарю.   -  person    schedule 12.08.2014
comment
поэтому я думаю, что в таких случаях можно использовать только Spans, реализующие ParcelableSpan... но вы можете попробовать, как я уже сказал, создать собственный ImageSpan, который реализует Parcelable, но я не думаю, что это поможет...   -  person pskink    schedule 12.08.2014
comment
@pskink я использовал 1. wordtoSpan.setSpan(новый ForegroundColorSpan(Color.BLUE), 15, 30, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); (не работает) 2. Строка ss = text.replace(Android, ‹font color=\#ff0000\›Android‹/font›); //А затем edtresult.setText(Html.fromHtml(ss); (работает только при наборе текста)   -  person    schedule 13.08.2014
comment
wordtoSpan.setSpan тоже будет работать, вам нужны правильные начальные и конечные параметры, и, пожалуйста, не используйте дрянной материал Html.fromHtml   -  person pskink    schedule 13.08.2014
comment
INVISIBLe Вам удалось решить проблему? Я немного в такой же ситуации.   -  person Tazz    schedule 18.09.2014
comment
@Tazz, я не нашел решения ..   -  person    schedule 18.09.2014
comment
любое решение для вышеупомянутого обсуждения   -  person jagadesh    schedule 27.07.2016


Ответы (1)


Вы пытаетесь отправить изображение в Twitter/WhatsApp, не смайлик. Есть разница.

Эмодзи буквально означает «картинка в символ» и зависит от набора символов телефона, который использует получатель. Даже если вы заменили изображения, связанные с смайликами вашего телефона, человек, которому вы отправляете смайлики, сможет видеть только свои собственные наборы смайликов. Это не то, что вы хотите.

Изображения не имеют ничего общего с наборами телефонов и будут выглядеть примерно одинаково независимо от того, на какие телефоны они отправлены. Вам нужно направить изображение в намерение, связанное с приложением, на котором в данный момент сосредоточен пользователь.

  1. Посмотрите на стек приложений Android.
  2. Найдите Приложение вверху.
  3. Передайте растровое изображение через намерение.putExtra(Intent.EXTRA_STREAM, BitmapUriLocation) в приложение;

Вот как приложение упоминается здесь: https://play.google.com/store/apps/details?id=com.plantpurple.emojidom, скорее всего, что-то делал.

person HarshMarshmallow    schedule 30.01.2015