Android自带的emoji表情的使用

什么是emoji表情

emoji表情是一种表情符号,在代码中它现在其实是一组遵循Unicode的编码,即每一个表情符号都对应了一个Unicode编码。更进一步说,emoji表情实际上是一组Unicode编码与一组表情描述之间的对应。注意,这里所说的不是表情图片,而是表情描述。那么图片的实现是由谁来负责的呢?图片是由各个系统或者软件针对统一的表情描述来各自实现的,他们都遵循统一的Unicode编码规范。也就是说Unicode编码其所对应的表情描述是统一的,是所有人都要共同遵守的一套标准或者规范,而具体的表情图片则可能因平台的不同而产生差异。


首先你得先从网上收集一套emoji的Unicode编码,例如这个网站Emoji Unicode Tables
该网站上面给出了每个emoji表情的图片,描述,Unicode编码的对照表,点击表中每一项emoji可看到如下所示:
这里写图片描述
红色框框就是我们要的值.在java中的Unicode表示就是:”\ud83d\ude01”,该编码字符可以直接被Android的TextView和EditText控件识别成对应的emoji表情.
本次demo中展示了从 “\ud83d\ude00” - “\ud83c\udf7c”这216个emoji表情.
效果图如下:
这里写图片描述

关于emoji编码的存放和获取

由于有216个emoji编码字符串,因此我把它整理到一个json数组中,然后保存到assets目录下.
然后获取的话,通过如下代码方式获取:

/**
* 从assets目录下获取所有表情
*
* @return
*/
public String[] getEmojis() {
   BufferedReader br = null;
   String emojis[] = null;
   try {
       InputStream is = mContext.getAssets().open("emoji.json");
       StringBuffer sb = new StringBuffer();
       br = new BufferedReader(new InputStreamReader(is));
       String line = null;
       while (null != (line = br.readLine())) {
           sb.append(line).append("\r\n");
       }
       JSONArray emojiArray = new JSONArray(sb.toString());
       if (null != emojiArray && emojiArray.length() > 0) {
           emojis = new String[emojiArray.length()];
           for (int i = 0; i < emojiArray.length(); i++) {
               emojis[i] = emojiArray.optString(i);
           }
       }
   } catch (Exception e) {
       e.printStackTrace();
   } finally {
       if (null != br) {
           try {
               br.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
   return emojis;
}

表情组设计

通过上面的效果图也可以看得出,216个emoji表情被分成了8组,每组27个emoji+1个删除按钮.
实现这个效果也很简单,就是通过ViewPager来展示每一组emoji,而每一组emoji里面又是一个GridView控件,里面的item就是一个个的TextView.
每一组emoji页面的创建代码如下:

/**
* 获取所有表情GridView页面的集合
*
* @return
*/
public List<View> getPagerList() {
   List<View> pagers = null;
   String[] eachPageEmojis = null;
   if (null != mEmojis && mEmojis.length > 0) {
       pagers = new ArrayList<>();
       int pageCount = mEmojis.length / 27;//共8页表情
       for (int i = 0; i < pageCount; i++) {
           GridView gridView = new GridView(mContext);
           gridView.setNumColumns(7);
           gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));
           gridView.setCacheColorHint(Color.TRANSPARENT);
           gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
           gridView.setGravity(Gravity.CENTER);
           eachPageEmojis = new String[28];
           //总共216个表情字符,索引变化为:0-26,27-53,54-80,81-107,108-134,135-161,162-188,189-215
           System.arraycopy(mEmojis, i * 27, eachPageEmojis, 0, 27);
           eachPageEmojis[27] = "del";//第28是删除按钮,用特殊字符串表示
           gridView.setAdapter(new EmojiGvAdapter(mContext, eachPageEmojis));
           //点击表情监听
           gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
               @Override
               public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                   //获取选中的表情字符
                   String emoji = (String) parent.getAdapter().getItem(position);
                   if (null != mEmojiClickListener) {
                       mEmojiClickListener.onClick(emoji);
                   }
               }
           });
           pagers.add(gridView);
       }
   }
   return pagers;
}

MainActivity的布局和代码

主布局是一个垂直的线性布局,大体分2部分,表情面板和上面的视图界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   >
    <!--显示表情的TextView-->
    <TextView
        android:id="@+id/tv_info"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="15dp"
        />
    <!--表情,输入框,发送-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/btn_emoji"
            android:layout_width="55dp"
            android:layout_height="wrap_content"
            android:text="表情"/>

        <EditText
            android:id="@+id/edt_msg"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>

        <Button
            android:id="@+id/btn_send"
            android:layout_width="55dp"
            android:layout_height="wrap_content"
            android:text="发送"/>
    </LinearLayout>
    <!--表情面板-->
    <FrameLayout
        android:id="@+id/fl_emoji"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        >

        <android.support.v4.view.ViewPager
            android:id="@+id/vp_emoji"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="10dp"
            />

        <LinearLayout
            android:id="@+id/ll_point"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_marginBottom="10dp"
            android:gravity="center"
            android:orientation="horizontal"></LinearLayout>

    </FrameLayout>
</LinearLayout>

MainActivity代码如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Button mEmojiBtn, mSendBtn;//表情按钮和发送按钮
    private EditText mMsgEdt;//输入框
    private TextView mInfoTv;//展示界面
    private ViewPager mEmojiVp;//表情ViewPager
    private FrameLayout mEmojiFl;//表情面板
    private LinearLayout mVpPointLl;//表情ViewPager指示器
    //输入法和表情平滑切换的辅助类
    private EmotionKeyboardSwitchHelper mEmotionKeyboardSwitchHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEmotionKeyboardSwitchHelper = EmotionKeyboardSwitchHelper.with(this);
        initView();
        initListener();
    }

    private void initListener() {
        mSendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mInfoTv.append(mMsgEdt.getText() + "\r\n");
                mMsgEdt.setText("");
            }
        });
        mEmotionKeyboardSwitchHelper.bind(mInfoTv, mMsgEdt, mEmojiBtn, mEmojiFl);
    }

    private void initView() {
        mEmojiBtn = (Button) findViewById(R.id.btn_emoji);
        mSendBtn = (Button) findViewById(R.id.btn_send);
        mMsgEdt = (EditText) findViewById(R.id.edt_msg);
        mInfoTv = (TextView) findViewById(R.id.tv_info);
        mEmojiVp = (ViewPager) findViewById(R.id.vp_emoji);
        mEmojiFl = (FrameLayout) findViewById(R.id.fl_emoji);
        mVpPointLl = (LinearLayout) findViewById(R.id.ll_point);
        initViewPager();
    }

    /**
     * 设置ViewPager表情
     */
    private void initViewPager() {
        EmojiVpAdapter adapter = new EmojiVpAdapter(this);
        mEmojiVp.setAdapter(adapter);
        //表情点击监听
        adapter.setOnEmojiClickListener(new EmojiVpAdapter.OnEmojiClickListener() {
            @Override
            public void onClick(String emoji) {
                if ("del".equals(emoji)) {
                    //表示点击的是删除按钮
                    KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
                    mMsgEdt.onKeyDown(KeyEvent.KEYCODE_DEL, event);
                } else {
                    mMsgEdt.append(emoji);
                }
            }
        });
        mEmojiVp.setCurrentItem(0);
        //关联指示器点
        adapter.setupWithPagerPoint(mEmojiVp, mVpPointLl);
    }


    @Override
    public void onBackPressed() {
        if (mEmotionKeyboardSwitchHelper.onBackPress()) {
            super.onBackPressed();
        }
    }
}

emoji ViewPager

public class EmojiVpAdapter extends PagerAdapter {
    private Context mContext;
    private String[] mEmojis;//216个表情字符
    private List<View> mPagers;//展示的页面
    private OnEmojiClickListener mEmojiClickListener;//表情点击监听接口

    public EmojiVpAdapter(Context ctx) {
        this.mContext = ctx;
        this.mEmojis = getEmojis();
        this.mPagers = getPagerList();

    }

    @Override
    public int getCount() {
        return null == mPagers ? 0 : mPagers.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = mPagers.get(position);
        if (null != view) {
            container.addView(view);
        }
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    /**
     * 从assets目录下获取所有表情
     *
     * @return
     */
    public String[] getEmojis() {
        BufferedReader br = null;
        String emojis[] = null;
        try {
            InputStream is = mContext.getAssets().open("emoji.json");
            StringBuffer sb = new StringBuffer();
            br = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while (null != (line = br.readLine())) {
                sb.append(line).append("\r\n");
            }
            JSONArray emojiArray = new JSONArray(sb.toString());
            if (null != emojiArray && emojiArray.length() > 0) {
                emojis = new String[emojiArray.length()];
                for (int i = 0; i < emojiArray.length(); i++) {
                    emojis[i] = emojiArray.optString(i);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return emojis;
    }

    /**
     * 获取所有表情GridView页面的集合
     *
     * @return
     */
    public List<View> getPagerList() {
        List<View> pagers = null;
        String[] eachPageEmojis = null;
        if (null != mEmojis && mEmojis.length > 0) {
            pagers = new ArrayList<>();
            int pageCount = mEmojis.length / 27;//共8页表情
            for (int i = 0; i < pageCount; i++) {
                GridView gridView = new GridView(mContext);
                gridView.setNumColumns(7);
                gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));
                gridView.setCacheColorHint(Color.TRANSPARENT);
                gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
                gridView.setGravity(Gravity.CENTER);
                eachPageEmojis = new String[28];
                //总共216个表情字符,索引变化为:0-26,27-53,54-80,81-107,108-134,135-161,162-188,189-215
                System.arraycopy(mEmojis, i * 27, eachPageEmojis, 0, 27);
                eachPageEmojis[27] = "del";//第28是删除按钮,用特殊字符串表示
                gridView.setAdapter(new EmojiGvAdapter(mContext, eachPageEmojis));
                //点击表情监听
                gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        //获取选中的表情字符
                        String emoji = (String) parent.getAdapter().getItem(position);
                        if (null != mEmojiClickListener) {
                            mEmojiClickListener.onClick(emoji);
                        }
                    }
                });
                pagers.add(gridView);
            }
        }
        return pagers;
    }

    /**
     * 关联指示器点
     *
     * @param viewPager
     * @param pointLayout
     */
    public void setupWithPagerPoint(ViewPager viewPager, final LinearLayout pointLayout) {
        //初始表情指示器
        int pageCount = getCount();
        for (int i = 0; i < pageCount; i++) {
            ImageView point = new ImageView(mContext);
            point.setImageResource(R.drawable.shape_vp_dot_unselected);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-2, -2);
            params.rightMargin = (int) mContext.getResources().getDimension(R.dimen.dp10);
            if (i == 0) {
                point.setImageResource(R.drawable.shape_vp_dot_selected);
            }
            pointLayout.addView(point, params);
        }
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                //切换指示器
                if (null != pointLayout && pointLayout.getChildCount() > 0) {
                    for (int i = 0; i < pointLayout.getChildCount(); i++) {
                        ((ImageView) pointLayout.getChildAt(i)).setImageResource(R.drawable.shape_vp_dot_unselected);
                    }
                    ((ImageView) pointLayout.getChildAt(position)).setImageResource(R.drawable.shape_vp_dot_selected);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    /**
     * 表情点击监听器
     */
    public interface OnEmojiClickListener {
        void onClick(String emoji);
    }

    public void setOnEmojiClickListener(OnEmojiClickListener l) {
        this.mEmojiClickListener = l;
    }
}

emoji GridView

public class EmojiGvAdapter extends BaseAdapter {
    private Context mContext;
    private String[] mEmojis;

    public EmojiGvAdapter(Context context, String[] eachPageEmojis) {
        this.mContext = context;
        this.mEmojis = eachPageEmojis;
    }

    @Override
    public int getCount() {
        return null == mEmojis ? 0 : mEmojis.length;
    }

    @Override
    public String getItem(int position) {
        return null == mEmojis ? "" : mEmojis[position];
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (null == convertView) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_emoji, null);
            holder.emojiTv = (TextView) convertView.findViewById(R.id.tv_emoji);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        if (position == 27) {
            //第28个显示删除按钮
            holder.emojiTv.setBackgroundResource(R.drawable.ic_emojis_delete);
            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) holder.emojiTv.getLayoutParams();
            lp.bottomMargin = (int) mContext.getResources().getDimension(R.dimen.dp12);
        } else {
            holder.emojiTv.setText(getItem(position));
        }
        return convertView;
    }

    private static class ViewHolder {
        private TextView emojiTv;
    }


}

源码下载

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Android 中实现 emoji 表情选择的 View,一般可以采用以下两种方式: 1. 使用第三方库 可以使用一些开源的第三方库,如: - Emoji-Keyboard:https://github.com/rockerhieu/emojicon - EmojiEditText:https://github.com/kimoBiko/EmojiEditText - EmojiCompat:https://developer.android.com/topic/libraries/support-library/packages#emoji-compat 这些库都提供了丰富的 emoji 表情选择界面和相关的实现方法,可以方便地集成到项目中。 2. 自定义 View 如果需要更灵活地实现 emoji 表情选择的 View,可以自己实现一个自定义 View。具体实现步骤如下: 1. 准备 emoji 表情资源 首先需要准备 emoji 表情的资源,可以自己设计或者使用现成的资源。将这些资源放在项目的 res 目录下。 2. 自定义 View 自定义 View 可以继承自 LinearLayout,包含一个 EditText 和一个 GridView。 在 EditText 的右侧添加一个按钮,点击按钮时显示 emoji 表情选择的 GridView,点击表情后将表情插入到 EditText 中。 3. 实现表情选择的 GridView GridView 中的每个表情可以使用 ImageView 显示,可以通过设置表情资源的 ID 来显示不同的表情。在表情选择界面的底部可以添加一个删除按钮,点击删除按钮可以删除 EditText 中的最后一个字符或者最后一个表情。 4. 实现点击表情插入到 EditText 的功能 当用户点击 GridView 中的表情时,可以将表情插入到 EditText 中。可以通过在 EditText 中插入一个 SpannableString 来实现,其中 SpannableString 中包含了表情的资源 ID。 以上就是实现 emoji 表情选择的 View 的一般步骤,可以根据具体需求进行自定义实现。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值