上次做了一个表情的控件,不敢私藏,给大家分享
效果图如下,图片是新浪微博的,该有的功能应该都有了。

图片描述

这其实就是一个Fragment,所以用起来很方便,只要

FaceFragment faceFragment = FaceFragment.Instance();
getSupportFragmentManager().beginTransaction().add(R.id.Container,faceFragment).commit();

就可以显示效果图上的效果了。

FaceFragment源码如下:

public class FaceFragment extends Fragment implements View.OnClickListener {

    public static FaceFragment Instance() {
        FaceFragment instance = new FaceFragment();
        Bundle bundle = new Bundle();
        instance.setArguments(bundle);
        return instance;
    }

    ViewPager faceViewPager;
    EmojiIndicatorView faceIndicator;
    TextView faceRecentTv;
    TextView faceFirstSetTv;

    ArrayList<View> ViewPagerItems = new ArrayList<>();
    ArrayList<Emoji> emojiList;
    ArrayList<Emoji> recentlyEmojiList;
    private int columns = 7; //每一行的表情数量
    private int rows = 3;  //设置总共有几行

    private OnEmojiClickListener listener;
    private RecentEmojiManager recentManager;

    public void setListener(OnEmojiClickListener listener) {
        this.listener = listener;
    }

    @Override
    public void onAttach(Activity activity) {
        if (activity instanceof OnEmojiClickListener) {
            this.listener = (OnEmojiClickListener) activity;
        }
        recentManager = RecentEmojiManager.make(activity);
        super.onAttach(activity);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        emojiList = EmojiUtil.getEmojiList();
        try {
            //用SharedPerference来保存我们最近使用的表情
            if (recentManager.getCollection(RecentEmojiManager.PREFERENCE_NAME) != null) {
                recentlyEmojiList = (ArrayList<Emoji>) recentManager.getCollection(RecentEmojiManager.PREFERENCE_NAME);
            } else {
                recentlyEmojiList = new ArrayList<>();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_face, container, false);
        faceViewPager = (ViewPager) view.findViewById(R.id.face_viewPager);
        faceIndicator = (EmojiIndicatorView) view.findViewById(R.id.face_indicator);
        faceRecentTv = (TextView) view.findViewById(R.id.face_recent);
        faceFirstSetTv = (TextView) view.findViewById(R.id.face_first_set);
        initViews();
        return view;
    }

    private void initViews() {
        initViewPager(emojiList);
        faceFirstSetTv.setSelected(true);
        faceFirstSetTv.setOnClickListener(this);
        faceRecentTv.setOnClickListener(this);
    }

    private void initViewPager(ArrayList<Emoji> list) {
        intiIndicator(list);
        ViewPagerItems.clear();
        for (int i = 0; i < getPagerCount(list); i++) {
            ViewPagerItems.add(getViewPagerItem(i, list));
        }
        FaceVPAdapter mVpAdapter = new FaceVPAdapter(ViewPagerItems);
        faceViewPager.setAdapter(mVpAdapter);
        faceViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            int oldPosition = 0;

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                faceIndicator.playBy(oldPosition, position);
                oldPosition = position;
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    private void intiIndicator(ArrayList<Emoji> list) {
        faceIndicator.init(getPagerCount(list));
    }

    @Override
    public void onClick(View v) {
            if(v.getId() == R.id.face_first_set){
                if (faceIndicator.getVisibility() == View.GONE) {
                    faceIndicator.setVisibility(View.VISIBLE);
                }
                if (!faceFirstSetTv.isSelected()) {
                    faceFirstSetTv.setSelected(true);
                    initViewPager(emojiList);
                }
                faceRecentTv.setSelected(false);
            }else if (v.getId() == R.id.face_recent){
                if (faceIndicator.getVisibility() == View.VISIBLE) {
                    faceIndicator.setVisibility(View.GONE);
                }
                if (!faceRecentTv.isSelected()) {
                    faceRecentTv.setSelected(true);
                    initViewPager(recentlyEmojiList);
                }
                faceFirstSetTv.setSelected(false);
            }

    }

    /**
     * 根据表情数量以及GridView设置的行数和列数计算Pager数量
     *
     * @return
     */
    private int getPagerCount(ArrayList<Emoji> list) {
        int count = list.size();
        return count % (columns * rows - 1) == 0 ? count / (columns * rows - 1)
                : count / (columns * rows - 1) + 1;
    }

    private View getViewPagerItem(int position, ArrayList<Emoji> list) {
        LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.layout_face_grid, null);//表情布局
        GridView gridview = (GridView) layout.findViewById(R.id.chart_face_gv);
        /**
         * 注:因为每一页末尾都有一个删除图标,所以每一页的实际表情columns * rows - 1; 空出最后一个位置给删除图标
         * */
        final List<Emoji> subList = new ArrayList<>();
        subList.addAll(list.subList(position * (columns * rows - 1),
                (columns * rows - 1) * (position + 1) > list
                        .size() ? list.size() : (columns
                        * rows - 1)
                        * (position + 1)));
        /**
         * 末尾添加删除图标
         * */
        if (subList.size() < (columns * rows - 1)) {
            for (int i = subList.size(); i < (columns * rows - 1); i++) {
                subList.add(null);
            }
        }
        Emoji deleteEmoji = new Emoji();
        deleteEmoji.setImageUri(R.drawable.face_delete);
        subList.add(deleteEmoji);
        FaceGVAdapter mGvAdapter = new FaceGVAdapter(subList, getActivity());
        gridview.setAdapter(mGvAdapter);
        gridview.setNumColumns(columns);
        // 单击表情执行的操作
        gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == columns * rows - 1) {
                    if(listener != null){
                        listener.onEmojiDelete();
                    }
                    return;
                }
                if(listener != null){
                    listener.onEmojiClick(subList.get(position));
                }
                insertToRecentList(subList.get(position));
            }
        });

        return gridview;
    }

    private void insertToRecentList(Emoji emoji) {
        if (emoji != null) {
            if (recentlyEmojiList.contains(emoji)) {
                //如果已经有该表情,就把该表情放到第一个位置
                int index = recentlyEmojiList.indexOf(emoji);
                Emoji emoji0 = recentlyEmojiList.get(0);
                recentlyEmojiList.set(index, emoji0);
                recentlyEmojiList.set(0, emoji);
                return;
            }
            if (recentlyEmojiList.size() == (rows * columns - 1)) {
                //去掉最后一个
                recentlyEmojiList.remove(rows * columns - 2);
            }
            recentlyEmojiList.add(0, emoji);
        }
    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        try {
            recentManager.putCollection(RecentEmojiManager.PREFERENCE_NAME, recentlyEmojiList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    class FaceGVAdapter extends BaseAdapter {
        private List<Emoji> list;
        private Context mContext;

        public FaceGVAdapter(List<Emoji> list, Context mContext) {
            super();
            this.list = list;
            this.mContext = mContext;
        }


        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return list.size();
        }

        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return list.get(position);
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(mContext).inflate(R.layout.item_face, null);
                holder.iv = (ImageView) convertView.findViewById(R.id.face_image);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            if (list.get(position) != null) {
                    holder.iv.setImageBitmap(EmojiUtil.decodeSampledBitmapFromResource(getActivity().getResources(), list.get(position).getImageUri(),
                            EmojiUtil.dip2px(getActivity(), 32), EmojiUtil.dip2px(getActivity(), 32)));
            }
            return convertView;
        }

        class ViewHolder {
            ImageView iv;
        }
    }

    class FaceVPAdapter extends PagerAdapter {
        // 界面列表
        private List<View> views;

        public FaceVPAdapter(List<View> views) {
            this.views = views;
        }

        @Override
        public void destroyItem(View arg0, int arg1, Object arg2) {
            ((ViewPager) arg0).removeView((View) (arg2));
        }

        @Override
        public int getCount() {
            return views.size();
        }

        // 初始化arg1位置的界面
        @Override
        public Object instantiateItem(View arg0, int arg1) {
            ((ViewPager) arg0).addView(views.get(arg1));
            return views.get(arg1);
        }

        // 判断是否由对象生成界
        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return (arg0 == arg1);
        }
    }
    
    让你的Activity实现(Fragment中set接口)这个接口来处理emoji的点击事件
    public interface OnEmojiClickListener {
        void onEmojiDelete();

        void onEmojiClick(Emoji emoji);
    }
}

你可以在EmojiUtil这个类中定义你的emoji编码去符合你的项目需求以及你需要在TextView中显示的Span大小。

public class EmojiUtil {
    private static ArrayList<Emoji> emojiList;

    public static ArrayList<Emoji> getEmojiList() {
        if (emojiList == null) {
            emojiList = generateEmojis();
        }
        return emojiList;
    }

    private static ArrayList<Emoji> generateEmojis() {
        ArrayList<Emoji> list = new ArrayList<>();
        for (int i = 0; i < EmojiResArray.length; i++) {
            Emoji emoji = new Emoji();
            emoji.setImageUri(EmojiResArray[i]);
            emoji.setContent(EmojiTextArray[i]);
            list.add(emoji);
        }
        return list;
    }


    public static final int[] EmojiResArray = {
            R.drawable.d_aini,
            R.drawable.d_aoteman,
            R.drawable.d_baibai,
            R.drawable.d_beishang,
            R.drawable.d_bishi,
            R.drawable.d_bizui,
            R.drawable.d_chanzui,
            R.drawable.d_chijing,
            R.drawable.d_dahaqi,
            R.drawable.d_dalian,
            R.drawable.d_ding,
            R.drawable.d_doge,
            R.drawable.d_feizao,
            R.drawable.d_ganmao,
            R.drawable.d_guzhang,
            R.drawable.d_haha,
            R.drawable.d_haixiu,
            R.drawable.d_han,
            R.drawable.d_hehe,
            R.drawable.d_heixian,
            R.drawable.d_heng,
            R.drawable.d_huaxin,
            R.drawable.d_jiyan,
            R.drawable.d_keai,
            R.drawable.d_kelian,
            R.drawable.d_ku,
            R.drawable.d_kun,
            R.drawable.d_landelini,
            R.drawable.d_lei,
            R.drawable.d_madaochenggong,
            R.drawable.d_miao,
            R.drawable.d_nanhaier,
            R.drawable.d_nu,
            R.drawable.d_numa,
            R.drawable.d_numa,
            R.drawable.d_qian,
            R.drawable.d_qinqin,
            R.drawable.d_shayan,
            R.drawable.d_shengbing,
            R.drawable.d_shenshou,
            R.drawable.d_shiwang,
            R.drawable.d_shuai,
            R.drawable.d_shuijiao,
            R.drawable.d_sikao,
            R.drawable.d_taikaixin,
            R.drawable.d_touxiao,
            R.drawable.d_tu,
            R.drawable.d_tuzi,
            R.drawable.d_wabishi,
            R.drawable.d_weiqu,
            R.drawable.d_xiaoku,
            R.drawable.d_xiongmao,
            R.drawable.d_xixi,
            R.drawable.d_xu,
            R.drawable.d_yinxian,
            R.drawable.d_yiwen,
            R.drawable.d_youhengheng,
            R.drawable.d_yun,
            R.drawable.d_zhajipijiu,
            R.drawable.d_zhuakuang,
            R.drawable.d_zhutou,
            R.drawable.d_zuiyou,
            R.drawable.d_zuohengheng,
            R.drawable.f_geili,
            R.drawable.f_hufen,
            R.drawable.f_jiong,
            R.drawable.f_meng,
            R.drawable.f_shenma,
            R.drawable.f_v5,
            R.drawable.f_xi,
            R.drawable.f_zhi,
            R.drawable.h_buyao,
            R.drawable.h_good,
            R.drawable.h_haha,
            R.drawable.h_lai,
            R.drawable.h_ok,
            R.drawable.h_quantou,
            R.drawable.h_ruo,
            R.drawable.h_woshou,
            R.drawable.h_ye,
            R.drawable.h_zan,
            R.drawable.h_zuoyi,
            R.drawable.l_shangxin,
            R.drawable.l_xin,
            R.drawable.o_dangao,
            R.drawable.o_feiji,
            R.drawable.o_ganbei,
            R.drawable.o_huatong,
            R.drawable.o_lazhu,
            R.drawable.o_liwu,
            R.drawable.o_lvsidai,
            R.drawable.o_weibo,
            R.drawable.o_weiguan,
            R.drawable.o_yinyue,
            R.drawable.o_zhaoxiangji,
            R.drawable.o_zhong,
            R.drawable.w_fuyun,
            R.drawable.w_shachenbao,
            R.drawable.w_taiyang,
            R.drawable.w_weifeng,
            R.drawable.w_xianhua,
            R.drawable.w_xiayu,
            R.drawable.w_yueliang,
    };

    public static final String[] EmojiTextArray = {
            "[爱你]",
            "[奥特曼]",
            "[拜拜]",
            "[悲伤]",
            "[鄙视]",
            "[闭嘴]",
            "[馋嘴]",
            "[吃惊]",
            "[哈欠]",
            "[打脸]",
            "[顶]",
            "[doge]",
            "[肥皂]",
            "[感冒]",
            "[鼓掌]",
            "[哈哈]",
            "[害羞]",
            "[汗]",
            "[微笑]",
            "[黑线]",
            "[哼]",
            "[色]",
            "[挤眼]",
            "[可爱]",
            "[可怜]",
            "[酷]",
            "[困]",
            "[白眼]",
            "[泪]",
            "[马到成功]",
            "[喵喵]",
            "[男孩儿]",
            "[怒]",
            "[怒骂]",
            "[女孩儿]",
            "[钱]",
            "[亲亲]",
            "[傻眼]",
            "[生病]",
            "[草泥马]",
            "[失望]",
            "[衰]",
            "[睡]",
            "[思考]",
            "[太开心]",
            "[偷笑]",
            "[吐]",
            "[兔子]",
            "[挖鼻]",
            "[委屈]",
            "[笑cry]",
            "[熊猫]",
            "[嘻嘻]",
            "[嘘]",
            "[阴险]",
            "[疑问]",
            "[右哼哼]",
            "[晕]",
            "[炸鸡啤酒]",
            "[抓狂]",
            "[猪头]",
            "[最右]",
            "[左哼哼]",
            "[给力]",
            "[互粉]",
            "[囧]",
            "[萌]",
            "[神马]",
            "[威武]",
            "[喜]",
            "[织]",
            "[NO]",
            "[good]",
            "[haha]",
            "[来]",
            "[OK]",
            "[拳头]",
            "[弱]",
            "[握手]",
            "[耶]",
            "[赞]",
            "[作揖]",
            "[伤心]",
            "[心]",
            "[蛋糕]",
            "[飞机]",
            "[干杯]",
            "[话筒]",
            "[蜡烛]",
            "[礼物]",
            "[绿丝带]",
            "[围脖]",
            "[围观]",
            "[音乐]",
            "[照相机]",
            "[钟]",
            "[浮云]",
            "[沙尘暴]",
            "[太阳]",
            "[微风]",
            "[鲜花]",
            "[下雨]",
            "[月亮]",
    };

    static {
        emojiList = generateEmojis();
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
                                            int reqWidth, int reqHeight) {
        // 源图片的高度和宽度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            // 计算出实际宽高和目标宽高的比率
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {
        // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        // 调用上面定义的方法计算inSampleSize值
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // 使用获取到的inSampleSize值再次解析图片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }


    public static int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
    
    //传递进来你所需要显示emoji的TextView即可
    public static void handlerEmojiText(TextView comment, String content, Context context) throws IOException {
        SpannableStringBuilder sb = new SpannableStringBuilder(content);
        String regex = "\\[(\\S+?)\\]";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(content);
        Iterator<Emoji> iterator;
        Emoji emoji = null;
        while (m.find()) {
            iterator = emojiList.iterator();
            String tempText = m.group();
            while (iterator.hasNext()) {
                emoji = iterator.next();
                if (tempText.equals(emoji.getContent())) {
                    //转换为Span并设置Span的大小
                    sb.setSpan(new ImageSpan(context, decodeSampledBitmapFromResource(context.getResources(), emoji.getImageUri()
                                    , dip2px(context, 18), dip2px(context, 18))),
                            m.start(), m.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    break;
                }
            }
        }
        comment.setText(sb);
    }
}

具体操作方法:

GitHub地址:https://github.com/shiqikai/y...

或者直接

compile'com.tb.emoji:yykEmoji:1.0.0'

谨此纪念那9月,一起开发的我们--谢遥,唐荣意,史琪锴。


象山炎亚纶
1.5k 声望13 粉丝

明天你好~