欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android输入框添加emoje表情图标的实现代码

程序员文章站 2024-03-02 17:27:04
前言 再次写聊天的时候才发现,代码积累是一件非常重要的事情,就如这篇博客的意图其实就是代码积累的目的,其实没什么难度,但是一件很琐碎的事情真的也需要时间去完成和调试,所以...

前言

再次写聊天的时候才发现,代码积累是一件非常重要的事情,就如这篇博客的意图其实就是代码积累的目的,其实没什么难度,但是一件很琐碎的事情真的也需要时间去完成和调试,所以,获取你在写一个功能的时候会觉得并没有多难,但是如果可以最好把代码整理/积累下来。

demo描述

Android输入框添加emoje表情图标的实现代码

demo的功能其实就是仿照微信的 聊天 emoje 选择,采用了 viewpager+gridview 的方案,不过有空我会补上 recyclerview 的方案,目前还是先把功能实现了再说。另外在 textview 和 edittext 中添加 emoje ,可以看看这篇:android中使用textview及edittext来实现表情图标的显示及插入功能 ,这篇博客中介绍了两种方法:

方法一:使用html.fromhtml解析, 方法二:使用bitmap直接画出来,我采用了第二种方法,使用bitmap画出来。

read the fucking code

思路:既然是 viewpager + gridview 那么,先从大方向入手,完成 viewpager,再去完成 gridview。ps:代码里面使用了 rxjava、lambda、butterknife、eventbus、glide。

这里将整个底部布局写成了一个组合的viewgroup – chatbottombar,先从布局开始。

chatbottombar 的 xml – chat_bottom.xml:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:animatelayoutchanges="true"
  android:orientation="vertical">

  <include layout="@layout/chat_bottom_input"></include>
  <include layout="@layout/chat_bottom_function1"></include>

</linearlayout>

以下分别是 输入框的 xml 和 emoji 的 xml:

chat_bottom_input:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <relativelayout
    android:id="@+id/rl_input"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#f0f0f0">

    <imageview
      android:id="@+id/showmore"
      android:layout_width="42dp"
      android:layout_height="60dp"
      android:paddingbottom="5dp"
      android:paddingleft="9dp"
      android:paddingtop="9dp"
      android:src="@mipmap/ic_launcher" />


    <linearlayout
      android:layout_width="match_parent"
      android:layout_height="35dp"
      android:layout_centervertical="true"
      android:layout_marginright="15dp"
      android:layout_torightof="@+id/showmore"
      android:background="@drawable/shape_white_corner"
      android:gravity="center_vertical"
      android:orientation="horizontal">

      <imageview
        android:layout_width="45dp"
        android:layout_height="40dp"
        android:paddingbottom="10dp"
        android:paddingleft="10dp"
        android:paddingright="5dp"
        android:paddingtop="10dp"
        android:src="@mipmap/ic_launcher" />

      <edittext
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginright="10dp"
        android:background="@null"
        android:gravity="center_vertical"
        android:hint="说点什么"
        android:maxlines="3"
        android:textcolor="#999999"
        android:textcolorhint="#dddddd"
        android:textsize="13sp" />

    </linearlayout>


  </relativelayout>


</merge>

chat_bottom_function1:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:background="#ffffff"
  android:orientation="vertical">

  <android.support.v4.view.viewpager
    android:id="@+id/emojes"
    android:layout_width="match_parent"
    android:layout_height="110dp"></android.support.v4.view.viewpager>

</linearlayout>

首先是 viewpager 填充 gridview,从 pageadapter 看起,看看需要哪些数据:

package cjh.emojicondemo;

import android.content.context;
import android.support.v4.view.pageradapter;
import android.support.v4.view.viewpager;
import android.view.view;
import android.widget.gridview;

import java.util.arraylist;

/**
 * created by cjh on 16-11-8.
 */

public class emojipageadapter extends pageradapter {

  private arraylist<gridview> mlists;

  public emojipageadapter(context context, arraylist<gridview> array) {
    this.mlists = array;
  }

  @override
  public int getcount() {
    return mlists.size();
  }

  @override
  public boolean isviewfromobject(view arg0, object arg1) {

    return arg0 == arg1;
  }

  @override
  public object instantiateitem(view arg0, int arg1) {
    ((viewpager) arg0).addview(mlists.get(arg1));
    return mlists.get(arg1);
  }

  @override
  public void destroyitem(view arg0, int arg1, object arg2) {
    ((viewpager) arg0).removeview((view) arg2);
  }
}

其实基本就是pageradapter的模板代码,需要的仅仅只是 gridview,看下在chatbottombar中的代码:

@bindview(r.id.emojes)
android.support.v4.view.viewpager emojes;
....
//每一页有24个表情,然后使用math的ceil函数,计算出我们需要的最小页数
 private void initemoje() {
    int pagecount = (int) math.ceil(emojiutils.emojis.length / 24.0f);
    arraylist<gridview> pagedata = new arraylist<>();
    for (int i = 0; i < pagecount; i++) {
      gridview gv = getgridview(i);
      pagedata.add(gv);
    }
    emojes.setadapter(new emojipageadapter(context, pagedata));
  }  

大结构基本就是这样了,接着就是小细节了,比如gridview的创建和展示:

 @nonnull
  private gridview getgridview(int i) {
    gridview gv = new gridview(context);
    gv.setverticalscrollbarenabled(false);
    gv.setadapter(new emojigridadapter(context, i));
    gv.setgravity(gravity.center);
    gv.setclickable(true);
    gv.setfocusable(true);
    gv.setnumcolumns(8);
    return gv;
  }

adapter:

package cjh.emojicondemo;

import android.content.context;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseadapter;
import android.widget.imageview;

import org.greenrobot.eventbus.eventbus;

/**
 * created by cjh on 16-11-8.
 */

public class emojigridadapter extends baseadapter {

  private context context;
  private int page;

  public emojigridadapter(context context, int page) {
    this.context = context;
    this.page = page;
  }

  @override
  public int getcount() {
    return 24;
  }

  @override
  public object getitem(int i) {
    return null;
  }

  @override
  public long getitemid(int i) {
    return 0;
  }

  @override
  public view getview(int i, view view, viewgroup viewgroup) {

    viewholder holder = null;
    if (view == null) {
      view = layoutinflater.from(context).inflate(r.layout.chat_emoji, null);
      holder = new viewholder();
      holder.image = (imageview) view.findviewbyid(r.id.image);
      view.settag(holder);
    }

    holder = (viewholder) view.gettag();
    int position = page * 23 + i;
    if (position < emojiutils.emojis.length)
      imageloader.load(context, emojiutils.icons[position], holder.image);
    else
      holder.image.setvisibility(view.gone);
    holder.image.setonclicklistener(view1 -> eventbus.getdefault().post(new emojievent(emojiutils.emojis[page * 23 + i])));

    return view;
  }

  static class viewholder {
    public imageview image;
  }
}

在这里,点击时间的传递我使用的是eventbus。

大结构基本已经ok了,接着就要看比较核心的部分,emoji 的处理,在接收到event事件时,调用了chatbottombar.appandemoje(emojievent.s)

@subscribe
  public void onemojievent(emojievent emojievent) {
    chatbottombar.appandemoje(emojievent.s);
  }

那么来看看chatbottombar的代码:

public void appandemoje(string s) {
    rx.observable
        .just(s)
        .subscribeon(schedulers.io())
        .map(s1 -> {
          spannablestring emojetext = emojiutils.getemojitext(edittext.gettext().tostring() + s1);
          return emojetext;
        })
        .unsubscribeon(schedulers.io())
        .observeon(androidschedulers.mainthread())
        .subscribe(s2 -> {
          edittext.settext("");
          edittext.append(s2);
        });
  }

上面代码使用了rxjava,可以看到真正的核心是在
emojiutils.getemojitext(edittext.gettext().tostring() + s1);
return emojetext;这行代码里面。

那么就来看看 emojiutils 的代码吧:

package cjh.emojicondemo;

import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.drawable.drawable;
import android.net.uri;
import android.text.spannable;
import android.text.spannablestring;
import android.text.textutils;
import android.text.style.imagespan;
import android.text.style.relativesizespan;
import android.util.sparsearray;

import java.io.file;
import java.util.arraylist;
import java.util.hashmap;
import java.util.map;
import java.util.regex.matcher;
import java.util.regex.pattern;
import java.util.zip.inflater;

/**
 * created by cjh on 16-11-7.
 */

public class emojiutils {

  private static hashmap<pattern, integer> emomap = new hashmap<>();

  public static final string delete_key = "em_delete_delete_expression";

  public static string[] emojis = new string[]{
      "[微笑]",
      "[撇嘴]",
      "[色]",
      "[发呆]",
      "[得意]",
      "[流泪]",
      "[害羞]",
      "[闭嘴]",
      "[睡]",
      "[大哭]",
      "[尴尬]",
      "[发怒]",
      "[调皮]",
      "[呲牙]",
      "[惊讶]",
      "[难过]",
      "[酷]",
      "[冷汗]",
      "[抓狂]",
      "[吐]",
      "[偷笑]",
      "[愉快]",
      "[白眼]",
      "[傲慢]",
      "[饥饿]",
      "[困]",
      "[惊恐]",
      "[流汗]",
      "[憨笑]",
      "[悠闲]",
      "[奋斗]",
      "[咒骂]",
      "[疑问]",
      "[嘘]",
      "[晕]",
      "[疯了]",
      "[衰]",
      "[骷髅]",
      "[敲打]",
      "[再见]",
      "[擦汗]",
      "[抠鼻]",
      "[鼓掌]",
      "[糗大了]",
      "[坏笑]",
      "[左哼哼]",
      "[右哼哼]",
      "[哈欠]",
      "[鄙视]",
      "[委屈]",
      "[快哭了]",
      "[阴险]",
      "[亲亲]",
      "[吓]",
      "[可怜]",
      "[菜刀]",
      "[西瓜]",
      "[啤酒]",
      "[篮球]",
      "[乒乓]",
      "[咖啡]",
      "[饭]",
      "[猪头]",
      "[玫瑰]",
      "[凋谢]",
      "[嘴唇]",
      "[爱心]",
      "[心碎]",
      "[蛋糕]",
      "[闪电]",
      "[炸弹]",
      "[刀]",
      "[足球]",
      "[瓢虫]",
      "[便便]",
      "[月亮]",
      "[太阳]",
      "[礼物]",
      "[拥抱]",
      "[强]",
      "[弱]",
      "[握手]",
      "[胜利]",
      "[抱拳]",
      "[勾引]",
      "[拳头]",
      "[差劲]",
      "[爱你]",
      "[no]",
      "[ok]"
  };

  public static int[] icons = new int[]{
      r.drawable.ee_1,
      r.drawable.ee_2,
      r.drawable.ee_3,
      r.drawable.ee_4,
      r.drawable.ee_5,
      r.drawable.ee_6,
      r.drawable.ee_7,
      r.drawable.ee_8,
      r.drawable.ee_9,
      r.drawable.ee_10,
      r.drawable.ee_11,
      r.drawable.ee_12,
      r.drawable.ee_13,
      r.drawable.ee_14,
      r.drawable.ee_15,
      r.drawable.ee_16,
      r.drawable.ee_17,
      r.drawable.ee_18,
      r.drawable.ee_19,
      r.drawable.ee_20,
      r.drawable.ee_21,
      r.drawable.ee_22,
      r.drawable.ee_23,
      r.drawable.ee_24,
      r.drawable.ee_25,
      r.drawable.ee_26,
      r.drawable.ee_27,
      r.drawable.ee_28,
      r.drawable.ee_29,
      r.drawable.ee_30,
      r.drawable.ee_31,
      r.drawable.ee_32,
      r.drawable.ee_33,
      r.drawable.ee_34,
      r.drawable.ee_35,
      r.drawable.ee_36,
      r.drawable.ee_37,
      r.drawable.ee_38,
      r.drawable.ee_39,
      r.drawable.ee_40,
      r.drawable.ee_41,
      r.drawable.ee_42,
      r.drawable.ee_43,
      r.drawable.ee_44,
      r.drawable.ee_45,
      r.drawable.ee_46,
      r.drawable.ee_47,
      r.drawable.ee_48,
      r.drawable.ee_49,
      r.drawable.ee_50,
      r.drawable.ee_51,
      r.drawable.ee_52,
      r.drawable.ee_53,
      r.drawable.ee_54,
      r.drawable.ee_55,
      r.drawable.ee_56,
      r.drawable.ee_57,
      r.drawable.ee_58,
      r.drawable.ee_59,
      r.drawable.ee_60,
      r.drawable.ee_61,
      r.drawable.ee_62,
      r.drawable.ee_63,
      r.drawable.ee_64,
      r.drawable.ee_65,
      r.drawable.ee_66,
      r.drawable.ee_67,
      r.drawable.ee_68,
      r.drawable.ee_69,
      r.drawable.ee_70,
      r.drawable.ee_71,
      r.drawable.ee_72,
      r.drawable.ee_73,
      r.drawable.ee_74,
      r.drawable.ee_75,
      r.drawable.ee_76,
      r.drawable.ee_77,
      r.drawable.ee_78,
      r.drawable.ee_79,
      r.drawable.ee_80,
      r.drawable.ee_81,
      r.drawable.ee_82,
      r.drawable.ee_83,
      r.drawable.ee_84,
      r.drawable.ee_85,
      r.drawable.ee_86,
      r.drawable.ee_87,
      r.drawable.ee_88,
      r.drawable.ee_89,
      r.drawable.ee_90,
  };

  static {
    for (int i = 0; i < emojis.length; i++) {
      emomap.put(pattern.compile(pattern.quote(emojis[i])), icons[i]);
    }
  }

  public static spannablestring getemojitext(string s) {
    spannablestring spannable = new spannablestring(s);
    for (map.entry<pattern, integer> entry : emomap.entryset()) {
      matcher matcher = entry.getkey().matcher(spannable);
      while (matcher.find()) {
        for (imagespan span : spannable.getspans(matcher.start(),
            matcher.end(), imagespan.class))
          if (spannable.getspanstart(span) >= matcher.start()
              && spannable.getspanend(span) <= matcher.end())
            spannable.removespan(span);
          else
            break;
        drawable drawable = mainactivity.context.getresources().getdrawable(entry.getvalue());
        drawable.setbounds(0, 0, 60, 60);
        imagespan imagespan = new imagespan(drawable);
        spannable.setspan(imagespan,
            matcher.start(), matcher.end(),
            spannable.span_exclusive_exclusive);
      }
    }
    return spannable;
  }
}

这里为了方便知道插入表情的位置,我将emoji对应的中文转化成了pattern对象,在getemojitext里面做了遍历查询比对,这也就是为什么我会使用rx来异步操作。

基本就到这里了,回过来看写的内容,自己都懒得吐槽,不过,好在只要有具体的demo,能读代码,有没有讲解其实都还好,也不用怕自己之后看不懂了。

源码下载:https://github.com/cjhandroid/emojiinputdemo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。