Android之Emoji表情开源库

news/2024/11/24 18:57:38/

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

图片描述

这其实就是一个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;}@Overridepublic void onAttach(Activity activity) {if (activity instanceof OnEmojiClickListener) {this.listener = (OnEmojiClickListener) activity;}recentManager = RecentEmojiManager.make(activity);super.onAttach(activity);}@Overridepublic 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);}@Overridepublic 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;@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {faceIndicator.playBy(oldPosition, position);oldPosition = position;}@Overridepublic void onPageScrollStateChanged(int state) {}});}private void intiIndicator(ArrayList<Emoji> list) {faceIndicator.init(getPagerCount(list));}@Overridepublic 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() {@Overridepublic 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);}}@Overridepublic 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;}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn list.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn list.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic 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;}@Overridepublic void destroyItem(View arg0, int arg1, Object arg2) {((ViewPager) arg0).removeView((View) (arg2));}@Overridepublic int getCount() {return views.size();}// 初始化arg1位置的界面@Overridepublic Object instantiateItem(View arg0, int arg1) {((ViewPager) arg0).addView(views.get(arg1));return views.get(arg1);}// 判断是否由对象生成界@Overridepublic 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月,一起开发的我们--谢遥,唐荣意,史琪锴。


http://www.ppmy.cn/news/520747.html

相关文章

富文本转换字符串 php,layedit 富文本编辑器 php下字符与表情转换

在使用富文本编辑器layedit的时候&#xff0c;在添加表情的时候&#xff0c;编辑器会自动将表情拼成img标签展示。 当我们保存的时候就很尴尬了&#xff0c;一个表情占用了几十个字符&#xff0c;造成了大量的浪费。 所以&#xff0c;我们的需要保存成特定的字符&#xff0c;展…

vue 项目中使用 评论功能 带emoji表情包

先看下效果&#xff1a; 由于项目中需要做一个 评论的功能&#xff0c;思索一番 准备自己写&#xff0c;但打开度娘 一下就看到这个vue评论插件&#xff0c;带表情包 挺好的&#xff0c;还带表情 刚好满足需求 1.安装 2.引入插件3.使用 就不在介绍 上面的链接有 记录下我在项…

新浪微博表情代码以及对应的gif图片url

新浪微博表情代码以及对应的gif图片url api&#xff1a;https://api.weibo.com/2/emotions.json?source1362404091 var c [{icon : "http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/7a/shenshou_thumb.gif",value : "[草泥马]"}, {i…

自定义可存数据的jquery 表情输入框

jquery 表情输入框&#xff0c;可存数据库 前两天优化博客的时候&#xff0c;想在留言评论版块插入表情输入功能&#xff0c;并且用户能够存入数据库&#xff0c;并且可以在前台读取展示&#xff0c;于是研究了一下表情包&#xff0c;解决方法如下&#xff1a; 下载表情包gif图…

超全的表情包

// 新浪表情包api https://api.weibo.com/2/emotions.json?source1362404091 export const sina [{alt: [坏笑],src: http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/4d/2018new_huaixiao_org.png},{alt: [笑cry],src: http://img.t.sinajs.cn/t4/appstyle/expre…

华为OD机试真题B卷 Java 实现【删除字符串中出现次数最少的字符】,附详细解题思路

一、题目描述 删除字符串中出现次数最少的字符&#xff0c;如果多个字符出现次数一样则都删除。 二、输入描述 一个字符串。 三、输出描述 删除字符串中出现次数最少的字符&#xff0c;如果多个字符出现次数一样则都删除&#xff0c;如果都被删除 则换为empty。 四、解题…

「Java核心技术大会2023」——AIC送书第三期

共同深入探讨 Java 生态&#xff01;直播预约&#xff1a;视频号“IT阅读排行榜” 大会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家&#xff1b;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近…

apple与android传数据线,可以同时插安卓和苹果的数据线

原标题&#xff1a;可以同时插安卓和苹果的数据线 问题&#xff1a;如何清理iPhone垃圾? 答案&#xff1a;微信公众号&#xff1a;果粉之家回复 4 现在手机线分为两大种&#xff1a;iPhone / iPad 专用的 Lightning 线&#xff0c;以及大部分 Android 装置使用的 microUSB 线。…