Implementação de Suporte a Emojis no Teclado Sogou para Aplicativos Android

Importância do Suporte a Emojis no Android

Na comunicação digital atual, os emojis tornaram-se uma linguagem universal para expressão emocional. Em aplicativos Android, o suporte adequado a emojis não apenas melhora a experiência do usuário, mas também aumenta a interatividade e a expressividade do aplicativo. Desenvolvedores devem enfrentar desafios de compatibilidade em diferentes dispositivos e versões do Android para garantir uma renderização correta.

Embora o Android tenha melhorado seu suporte nativo a emojis ao longo das versões, os desenvolvedores ainda precisam implementar técnicas otimizadas para renderização e entrada de emojis. Este guia explora métodos eficazes para implementar e otimizar o suporte a emojis em suas aplicações.

Implementação de Componentes para Emojis

Componente EmojiEditText

O componente EmojiEditText estende as funcionalidades do EditText tradicional, otimizando a entrada e processamento de emojis. Essa implementação é especialmente útil em aplicativos de redes sociais, mensagens instantâneas e editores de conteúdo.

Código de Implementação:


public class CampoEntradaEmoji extends AppCompatEditText {
    private TextWatcher observadorTexto;
    private Paint paintPersonalizado;
    
    public CampoEntradaEmoji(Contexto contexto, AttributeSet atributos) {
        super(contexto, atributos);
        inicializadorEmoji();
    }
    
    private void inicializadorEmoji() {
        paintPersonalizado = new Paint();
        paintPersonalizado.setColor(getCurrentTextColor());
        paintPersonalizado.setTextSize(getTextSize());
        paintPersonalizado.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
        
        observadorTexto = new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // Lógica pré-processamento
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                processarEntradaEmoji(s, start, before, count);
            }

            @Override
            public void afterTextChanged(Editable s) {
                // Pós-processamento
            }
        };
        
        addTextChangedListener(observadorTexto);
    }
    
    private void processarEntradaEmoji(CharSequence texto, int inicio, int anterior, int novo) {
        // Implementação específica para tratamento de emojis
        String textoCompleto = texto.toString();
        if (textoCompleto.contains(EmojiUtils.INDICADOR_EMOJI)) {
            // Adicionar lógica de processamento
        }
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Lógica de renderização personalizada
    }
}

Componente EmojiTextView

O componente EmojiTextView otimiza a exibição de texto contendo emojis, garantindo uma renderização correta e eficiente em diferentes cenários.

Código de Implementação:


public class TextoEmoji extends AppCompatTextView {
    private Map<character drawable=""> cacheEmoji;
    private Handler manipuladorLayout;
    
    public TextoEmoji(Contexto contexto, AttributeSet atributos) {
        super(contexto, atributos);
        cacheEmoji = new HashMap<>();
        manipuladorLayout = new Handler();
        inicializador();
    }
    
    private void inicializador() {
        addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, 
                                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
                manipuladorLayout.post(new Runnable() {
                    @Override
                    public void run() {
                        atualizarTamanhoEmoji();
                    }
                });
            }
        });
    }
    
    private void atualizarTamanhoEmoji() {
        // Implementação para ajuste dinâmico
        int alturaTexto = getHeight();
        int larguraTexto = getWidth();
        
        for (Map.Entry<character drawable=""> entrada : cacheEmoji.entrySet()) {
            Drawable emoji = entrada.getValue();
            if (emoji != null) {
                emoji.setBounds(0, 0, larguraTexto / 2, alturaTexto / 2);
            }
        }
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        // Lógica de renderização personalizada
        super.onDraw(canvas);
        renderizarEmojisPersonalizados(canvas);
    }
    
    private void renderizarEmojisPersonalizados(Canvas canvas) {
        String texto = getText().toString();
        int posicaoAtual = 0;
        
        for (int i = 0; i < texto.length(); i++) {
            char caractere = texto.charAt(i);
            if (EmojiUtils.ehEmoji(caractere)) {
                Drawable emoji = cacheEmoji.get(caractere);
                if (emoji != null) {
                    canvas.save();
                    canvas.translate(getPaddingLeft() + posicaoAtual, getPaddingTop());
                    emoji.draw(canvas);
                    canvas.restore();
                    
                    int larguraEmoji = emoji.getBounds().width();
                    posicaoAtual += larguraEmoji;
                }
            } else {
                posicaoAtual += getPaint().measureText(String.valueOf(caractere));
            }
        }
    }
}
</character></character>

Personalização de InputConnectionWrapper

Para processar eficientemente a entrada de emojis, podemos personalizar a classe InputConnectionWrapper para interceptar e modificar o comportamento padrão do método de entrada.

Código de Implementação:


public class ConexaoEntradaPersonalizada extends InputConnectionWrapper {
    private Contexto contexto;
    private ManipuladorEmoji manipuladorEmoji;
    
    public ConexaoEntradaPersonalizada(InputConnection original, Handler handler, Contexto contexto) {
        super(original, true);
        this.contexto = contexto;
        this.manipuladorEmoji = new ManipuladorEmoji(contexto);
    }
    
    @Override
    public boolean commitText(CharSequence texto, int novoCursor) {
        // Verificar se o texto contém emojis
        if (manipuladorEmoji.contemEmoji(texto)) {
            // Processar e substituir emojis por equivalentes compatíveis
            CharSequence textoProcessado = manipuladorEmoji.processarEmojis(texto);
            return super.commitText(textoProcessado, novoCursor);
        }
        return super.commitText(texto, novoCursor);
    }
    
    @Override
    public boolean sendKeyEvent(KeyEvent evento) {
        // Implementar lógica para atalhos de emoji, se necessário
        return super.sendKeyEvent(evento);
    }
}

Renderização de Emojis com drawText() ou Bibliotecas de Terceiros

A renderização correta de emojis pode ser implementada através da sobrescrita do método drawText() ou utilizando bibliotecas especializadas.

Sobrescrita do drawText()


public class RenderizadorTextoPersonalizado extends TextView {
    private Paint paintEmoji;
    private Map<character bitmap=""> cacheEmojiBitmap;
    
    public RenderizadorTextoPersonalizado(Contexto contexto, AttributeSet atributos) {
        super(contexto, atributos);
        paintEmoji = new Paint();
        cacheEmojiBitmap = new HashMap<>();
        inicializar();
    }
    
    private void inicializar() {
        paintEmoji.setColor(getCurrentTextColor());
        paintEmoji.setTextSize(getTextSize());
        paintEmoji.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        String texto = getText().toString();
        float posicaoX = getPaddingLeft();
        float posicaoY = getPaddingTop() + getPaint().getTextSize();
        
        for (int i = 0; i < texto.length(); i++) {
            char caractere = texto.charAt(i);
            
            if (EmojiUtils.ehEmoji(caractere)) {
                Bitmap emojiBitmap = cacheEmojiBitmap.get(caractere);
                if (emojiBitmap == null) {
                    emojiBitmap = EmojiUtils.obterBitmapParaEmoji(caractere, (int)getTextSize());
                    cacheEmojiBitmap.put(caractere, emojiBitmap);
                }
                
                if (emojiBitmap != null) {
                    canvas.drawBitmap(emojiBitmap, posicaoX, posicaoY - getTextSize(), paintEmoji);
                    posicaoX += emojiBitmap.getWidth();
                }
            } else {
                canvas.drawText(String.valueOf(caractere), posicaoX, posicaoY, getPaint());
                posicaoX += getPaint().measureText(String.valueOf(caractere));
            }
        }
    }
}
</character>

Integração com Bibliotecas de Terceiros

Bibliotecas como EmojiCompat do Google podem simplificar o processo de renderização de emojis:


// Configuração do EmojiCompat
EmojiConfig configuracao = new EmojiConfig.Builder(contexto)
    .setReplaceAll(true)
    .setEmojiLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL)
    .build();

EmojiCompat.init(configuracao);

// Verificação de disponibilidade
EmojiCompat.get().registerInitCallback(new EmojiCompat.InitCallback() {
    @Override
    public void onInitialized() {
        // EmojiCompat inicializado com sucesso
        atualizarViewsComEmojis();
    }
    
    @Override
    public void onFailed(@Nullable Throwable throwable) {
        // Lidar com falha na inicialização
    }
});

// Atualização de TextViews
private void atualizarViewsComEmojis() {
    for (TextView view : listaTextViews) {
        EmojiCompat.get().loadEmojiSpan(view.getText(), view);
    }
}

Integração do SDK do Teclado Sogou

O SDK do teclado Sogou oferece funcionalidades avançadas para processamento de texto, incluindo suporte a emojis.

Passos de Integração:

  1. Adicionar dependência ao projeto:

dependencies {
    implementation files('libs/SogouIME-release.aar')
}

  1. Configurar manifest:

<uses-permission android:name="android.permission.INTERNET" />

<application>
    <activity android:name="com.sogou.ime.ui.InputMethodUI" />
</application>

  1. Inicializar o SDK:

public class MinhaAplicacao extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SogouIMESDKManager.getInstance().inicializar(this);
        SogouIMESDKManager.getInstance().carregarBibliotecaEmojis();
    }
}

  1. Implementar gerenciamento de emojis:

public class GerenciadorEmojisSogou {
    private Contexto contexto;
    private Map<string drawable=""> cacheEmojis;
    
    public GerenciadorEmojisSogou(Contexto contexto) {
        this.contexto = contexto;
        this.cacheEmojis = new HashMap<>();
        carregarEmojis();
    }
    
    private void carregarEmojis() {
        String[] categoriasEmojis = {"padrao", "animais", "comida", "atividades"};
        
        for (String categoria : categoriasEmojis) {
            List<string> emojis = SogouIMESDKManager.getInstance().obterEmojisPorCategoria(categoria);
            for (String emoji : emojis) {
                Drawable drawable = SogouIMESDKManager.getInstance().obterDrawableParaEmoji(emoji);
                cacheEmojis.put(emoji, drawable);
            }
        }
    }
    
    public Drawable obterEmoji(String unicode) {
        return cacheEmojis.get(unicode);
    }
    
    public void adicionarEmojiAoTexto(TextView textView, String emoji) {
        Drawable emojiDrawable = obterEmoji(emoji);
        if (emojiDrawable != null) {
            ImageSpan imageSpan = new ImageSpan(emojiDrawable);
            SpannableString spannable = new SpannableString(emoji);
            spannable.setSpan(imageSpan, 0, emoji.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            textView.append(spannable);
        }
    }
}
</string></string>

Otimização com SpannableString e SpannableStringBuilder

Para melhorar o desempenho ao lidar com texto contendo emojis, podemos utilizar classes de texto com formatação.

Exemplo de Otimização:


public class GerenciadorTextoOtimizado {
    private Contexto contexto;
    private LruCache<string drawable=""> cacheEmojis;
    
    public GerenciadorTextoOtimizado(Contexto contexto) {
        this.contexto = contexto;
        int memoriaMaxima = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheTamanho = memoriaMaxima / 8;
        
        cacheEmojis = new LruCache<string drawable="">(cacheTamanho) {
            @Override
            protected int sizeOf(String key, Drawable drawable) {
                return drawable.getIntrinsicWidth() * drawable.getIntrinsicHeight() * 4;
            }
        };
    }
    
    public SpannableString criarTextoComEmojis(String texto) {
        SpannableString spannable = new SpannableString(texto);
        
        for (int i = 0; i < texto.length(); i++) {
            if (EmojiUtils.ehEmoji(texto.charAt(i))) {
                String emojiStr = String.valueOf(texto.charAt(i));
                Drawable emojiDrawable = cacheEmojis.get(emojiStr);
                
                if (emojiDrawable == null) {
                    emojiDrawable = EmojiUtils.obterDrawableParaEmoji(emojiStr, contexto);
                    cacheEmojis.put(emojiStr, emojiDrawable);
                }
                
                if (emojiDrawable != null) {
                    emojiDrawable.setBounds(0, 0, emojiDrawable.getIntrinsicWidth(), 
                                           emojiDrawable.getIntrinsicHeight());
                    ImageSpan imageSpan = new ImageSpan(emojiDrawable);
                    spannable.setSpan(imageSpan, i, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
        }
        
        return spannable;
    }
    
    public void atualizarTextoComEmojis(TextView textView, String texto) {
        SpannableString spannable = criarTextoComEmojis(texto);
        textView.setText(spannable);
    }
}
</string></string>

Esta implementação utiliza um cache LRU para armazenar em memória os desenháveis dos emojis, evitando recarregamentos constantes e melhorando o desempenho. A classe SpannableString permite aplicar formatação específica para cada caractere, incluindo emojis.

Tags: android SDK Sogou Emojis Desenvolvimento Mobile Otimização de UI

Publicado em 6-29 05:13