描述: 在使用腾讯Im的时候,表情库是图片+配置文件, 因为当时项目要上国际版,所以需要更换表情库,特在此记录一下. 主要是找到对应的图片库,替换成自己的, 还有关于布局样式做一些适配调整
第一步: String文件中
<string name="emojin">["😄", "😀", "😁", "😂", "😃", "😅", "😆", "😇", "😉", "😊", "😋", "😌", "😍", "😎", "😏", "😐", "😑", "😒", "😓", "😔", "😕", "😖", "😗", "😘", "😙", "😚", "😛", "😜", "😝", "😞", "😟", "😠", "😡", "😢", "😣", "😤", "😥", "😦", "😧", "😨", "😩", "😪", "😫", "😬", "😭", "😮", "😯", "😰", "😱", "😲", "😳", "😴", "😵", "😶", "😷", "💩", "👼", "😸", "😹", "😺", "😻", "😼", "😽", "😾", "😿", "🙀", "🙅", "🙆", "🙇", "🙋", "🙌", "🙍", "🙎", "🙏", "👦", "👧", "👨", "👩", "👪", "👫", "👬", "👭", "👮", "👯", "👰", "👱", "👲", "👳", "👴", "👵", "👶", "👷", "👸", "💁", "💂", "💏", "💑", "🚶", "👽", "👻", "👹", "👺", "😈", "👿", "🙈", "🙉", "🙊", "💓", "💔", "💕", "💖", "💗", "💘", "💙", "💚", "💛", "💜", "💝", "💞", "💟", "💠", "💡", "🌸", "🌹", "🌺", "🌻", "👀", "👂", "👃", "👄", "👅", "👆", "👇", "👈", "👉", "👊", "👋", "👌", "👍", "👎", "👏", "🖖", "✊", "✋", "💪"]</string>
第二步: 腾讯的FaceManager类中进行表情库的替换,这里只帖部分代码
public class FaceManager { private static final int drawableWidth = ScreenUtil.getPxByDp(32); private static ArrayList<Emoji> emojiList = new ArrayList<>(); private static LruCache<String, Bitmap> drawableCache = new LruCache(1024); private static Context context = TUIKit.getAppContext(); private static String[] emojiFilters = context.getResources().getStringArray(R.array.emoji_filter); private static ArrayList<String> list=new ArrayList<>(); private static ArrayList<FaceGroup> customFace = new ArrayList<>(); public static ArrayList<Emoji> getEmojiList() { return emojiList; } public static ArrayList<FaceGroup> getCustomFaceList() { return customFace; } public static Bitmap getCustomBitmap(int groupId, String name) { for (int i = 0; i < customFace.size(); i++) { FaceGroup group = customFace.get(i); if (group.getGroupId() == groupId) { ArrayList<Emoji> faces = group.getFaces(); for (int j = 0; j < faces.size(); j++) { Emoji face = faces.get(j); if (face.getFilter().equals(name)) { return face.getIcon(); } } } } return null; } public static void loadFaceFiles() { new Thread() { @Override public void run() { // for (int i = 0; i < emojiFilters.length; i++) { // loadAssetBitmap(emojiFilters[i], "emoji/" + emojiFilters[i] + "@2x.png", true); // } //图片表情,这里用了string文件里的表情库 String emgion=context.getString(R.string.emojin); Gson gson = new Gson(); list = gson.fromJson(emgion, new TypeToken<List<String>>() {}.getType()); for(int i=0;i<list.size();i++){ Emoji emoji=new Emoji(); emoji.setImgEmojistr(list.get(i)); emojiList.add(emoji); } // CustomFaceConfig config = TUIKit.getConfigs().getCustomFaceConfig(); // if (config == null) { // return; // } // List<CustomFaceGroup> groups = config.getFaceGroups(); // if (groups == null) { // return; // } // for (int i = 0; i < groups.size(); i++) { // CustomFaceGroup groupConfigs = groups.get(i); // FaceGroup groupInfo = new FaceGroup(); // groupInfo.setGroupId(groupConfigs.getFaceGroupId()); // groupInfo.setDesc(groupConfigs.getFaceIconName()); // groupInfo.setPageColumnCount(groupConfigs.getPageColumnCount()); // groupInfo.setPageRowCount(groupConfigs.getPageRowCount()); // groupInfo.setGroupIcon(loadAssetBitmap(groupConfigs.getFaceIconName(), groupConfigs.getFaceIconPath(), false).getIcon()); // ArrayList<CustomFace> customFaceArray = groupConfigs.getCustomFaceList(); // ArrayList<Emoji> faceList = new ArrayList<>(); // for (int j = 0; j < customFaceArray.size(); j++) { // CustomFace face = customFaceArray.get(j); // Emoji emoji = loadAssetBitmap(face.getFaceName(), face.getAssetPath(), false); // emoji.setWidth(face.getFaceWidth()); // emoji.setHeight(face.getFaceHeight()); // faceList.add(emoji); // // } // groupInfo.setFaces(faceList); // customFace.add(groupInfo); // } } }.start(); } private static Emoji loadAssetBitmap(String filter, String assetPath, boolean isEmoji) { InputStream is = null; try { Emoji emoji = new Emoji(); Resources resources = context.getResources(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inDensity = DisplayMetrics.DENSITY_XXHIGH; options.inScreenDensity = resources.getDisplayMetrics().densityDpi; options.inTargetDensity = resources.getDisplayMetrics().densityDpi; context.getAssets().list(""); is = context.getAssets().open(assetPath); Bitmap bitmap = BitmapFactory.decodeStream(is, new Rect(0, 0, drawableWidth, drawableWidth), options); if (bitmap != null) { drawableCache.put(filter, bitmap); emoji.setIcon(bitmap); emoji.setFilter(filter); if (isEmoji) { emojiList.add(emoji); } } return emoji; } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } 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); } public static boolean isFaceChar(String faceChar) { return drawableCache.get(faceChar) != null; } public static void handlerEmojiText(TextView comment, String content, boolean typing) { SpannableStringBuilder sb = new SpannableStringBuilder(content); String regex = "\\[(\\S+?)\\]"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(content); boolean imageFound = false; while (m.find()) { String emojiName = m.group(); // Bitmap bitmap = drawableCache.get(emojiName); if (emojiName != null) { imageFound = true; sb.setSpan(emojiName, m.start(), m.end(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } } // 如果没有发现表情图片,并且当前是输入状态,不再重设输入框 if (!imageFound && typing) { return; } int selection = comment.getSelectionStart(); comment.setText(sb); if (comment instanceof EditText) { ((EditText) comment).setSelection(selection); } } public static Bitmap getEmoji(String name) { return drawableCache.get(name); } } 第二步: 在Emoji 类中重新声明一个变量,用来存放String对应的emgion
第三步: FaceFragment 里进行表情库的替换
public class FaceFragment extends BaseInputFragment implements View.OnClickListener { ViewPager faceViewPager; EmojiIndicatorView faceIndicator; FaceGroupIcon faceFirstSetTv; FaceGroupIcon mCurrentSelected; LinearLayout faceGroup; ArrayList<View> ViewPagerItems = new ArrayList<>(); ArrayList<Emoji> emojiList; ArrayList<Emoji> recentlyEmojiList; ArrayList<FaceGroup> customFaces; private int mCurrentGroupIndex = 0; private int columns = 7; private int rows = 3; private int vMargin = 0; private OnEmojiClickListener listener; private RecentEmojiManager recentManager; public static FaceFragment Instance() { FaceFragment instance = new FaceFragment(); Bundle bundle = new Bundle(); instance.setArguments(bundle); return instance; } 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 = FaceManager.getEmojiList(); try { 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); ViewGroup.LayoutParams params = view.getLayoutParams(); params.height = SoftKeyBoardUtil.getSoftKeyBoardHeight(); view.setLayoutParams(params); faceViewPager = view.findViewById(R.id.face_viewPager); faceIndicator = view.findViewById(R.id.face_indicator); faceFirstSetTv = view.findViewById(R.id.face_first_set); faceGroup = view.findViewById(R.id.face_view_group); initViews(); return view; } private void initViews() { initViewPager(emojiList, 7, 3); mCurrentSelected = faceFirstSetTv; faceFirstSetTv.setSelected(true); faceFirstSetTv.setOnClickListener(this); customFaces = FaceManager.getCustomFaceList(); int width = ScreenUtil.getPxByDp(70); for (int i = 0; i < customFaces.size(); i++) { final FaceGroup group = customFaces.get(i); FaceGroupIcon faceBtn = new FaceGroupIcon(getActivity()); faceBtn.setFaceTabIcon(group.getGroupIcon()); faceBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mCurrentSelected != v) { mCurrentGroupIndex = group.getGroupId(); ArrayList<Emoji> faces = group.getFaces(); mCurrentSelected.setSelected(false); initViewPager(faces, group.getPageColumnCount(), group.getPageRowCount()); mCurrentSelected = (FaceGroupIcon) v; mCurrentSelected.setSelected(true); } } }); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, LinearLayout.LayoutParams.MATCH_PARENT); faceGroup.addView(faceBtn, params); } } private void initViewPager(ArrayList<Emoji> list, int columns, int rows) { this.columns = columns; this.rows = rows; if (list.size() > 0) { vMargin = (SoftKeyBoardUtil.getSoftKeyBoardHeight() - (ScreenUtil.getPxByDp(40 + 20) + list.get(0).getHeight() * rows)) / 4; } intiIndicator(list); ViewPagerItems.clear(); int pageCont = getPagerCount(list); for (int i = 0; i < pageCont; 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 (mCurrentSelected != v) { mCurrentGroupIndex = 0; mCurrentSelected.setSelected(false); mCurrentSelected = (FaceGroupIcon) v; initViewPager(emojiList, 7, 3); mCurrentSelected.setSelected(true); } } } /** * 根据表情数量以及GridView设置的行数和列数计算Pager数量 * * @return */ private int getPagerCount(ArrayList<Emoji> list) { int count = list.size(); int dit = 1; if (mCurrentGroupIndex > 0) dit = 0; return count % (columns * rows - dit) == 0 ? count / (columns * rows - dit) : count / (columns * rows - dit) + 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 = layout.findViewById(R.id.chart_face_gv); /** * 注:因为每一页末尾都有一个删除图标,所以每一页的实际表情columns * rows - 1; 空出最后一个位置给删除图标 * */ final List<Emoji> subList = new ArrayList<>(); int dit = 1; if (mCurrentGroupIndex > 0) dit = 0; subList.addAll(list.subList(position * (columns * rows - dit), (columns * rows - dit) * (position + 1) > list .size() ? list.size() : (columns * rows - dit) * (position + 1))); /** * 末尾添加删除图标 * */ if (mCurrentGroupIndex == 0 && subList.size() < (columns * rows - dit)) { for (int i = subList.size(); i < (columns * rows - dit); i++) { subList.add(null); } } if (mCurrentGroupIndex == 0) { Emoji deleteEmoji = new Emoji(); deleteEmoji.setIcon(BitmapFactory.decodeResource(getResources(), 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 (mCurrentGroupIndex > 0) { listener.onCustomFaceClick(mCurrentGroupIndex, subList.get(position)); } else { 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(); } } public interface OnEmojiClickListener { void onEmojiDelete(); void onEmojiClick(Emoji emoji); void onCustomFaceClick(int groupIndex, Emoji emoji); } 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; Emoji emoji = list.get(position); if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(mContext).inflate(R.layout.item_face, null); holder.iv = convertView.findViewById(R.id.face_image); FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) holder.iv.getLayoutParams(); if (emoji != null) { params.width = emoji.getWidth(); params.height = emoji.getHeight(); } if (position / columns == 0) { params.setMargins(0, vMargin, 0, 0); } else if (rows == 2) { params.setMargins(0, vMargin, 0, 0); } else { if (position / columns < rows - 1) { params.setMargins(0, vMargin, 0, vMargin); } else { params.setMargins(0, 0, 0, vMargin); } } holder.iv.setLayoutParams(params); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } if (emoji != null) { if(position == columns * rows - 1){ /** * 说明此时是删除按钮的位置下标,单独设置图片 */ holder.iv.setBackground(mContext.getResources().getDrawable(R.drawable.face_delete)); }else { holder.iv.setText(emoji.getImgEmojistr()); } } return convertView; } class ViewHolder { TextView 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); } } }