写点什么

融云即时通讯 SDK 集成 -- 定制 UI(二) ——添加自定义表情库

发布于: 2021 年 03 月 15 日

背景:


最近公司新上的 app 要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目 deadline 也顶不住哇).就从各家成熟的 SDK 厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的 SDK(老板说了算 hhhh).他家的官网和文档地址: 官网:https://www.rongcloud.cn/文档:https://docs.rongcloud.cn/v4这个任务当然还是落在我的头上. 我是使用的他们家的带 UI 的 sdk,(他们家有带 UI 和不带 UI 的两种 sdk, 不带 UI 的 sdk 就是只有即时通讯能力, 所有的 UI 都需要开发者自定实现, 带 UI 的 sdk 封装了一些基本的界面,例如会话列表, 和别人聊天的会话界面.)当然这些已经集成了 UI 的 sdk 并不能完全满足一个产品的需求, 所以这篇文章跟大家讲下如何添加一套自定义的表情包.


效果如下哈:


虽然这里有点难看了哈哈, 不过是为了给大家展示方法嘛, 就不管那么多了. 可以看到底下除了默认的 emoji 的表情包, 还多了一个 tab, 我是从 QQ 表情搞了一套, 直接就加在这里了. 一个可爱的小猪猪🐷哈哈哈.


添加步骤


需要改动的有这么几个类:


AndroidEmoji: 控制 emoji 图标资源, 编码, 以及相应展示的类 RongExtension: 会话界面除去聊天气泡与 title bar 的整个下方输入区域 IEmoticonTab: 表情 tabDefaultExtensionModule: 表情 tab 的上层控件.


对于 AndroidEmoji 这个类, 可以直接照抄, 把资源文件替换成自己准备好的图标, 以及编码/描述


复制代码


public class ConversationListAdapter extends BaseAdapter<UIConversation> {
复制代码


    private final static String TAG = "ConversationListAdapter";
复制代码


    LayoutInflater mInflater;
复制代码


    Context mContext;
复制代码


复制代码


    @Override
复制代码


    public long getItemId(int position) {
复制代码


        UIConversation conversation = getItem(position);
复制代码


        if (conversation == null)
复制代码


            return 0;
复制代码


        return conversation.hashCode();
复制代码


    }
复制代码


复制代码


    protected class ViewHolder {
复制代码


        public View layout;
复制代码


        public View leftImageLayout;
复制代码


        public View rightImageLayout;
复制代码


        public View leftUnReadView;
复制代码


        public View rightUnReadView;
复制代码


        public AsyncImageView leftImageView;
复制代码


        public TextView unReadMsgCount;
复制代码


        public ImageView unReadMsgCountIcon;
复制代码


        public AsyncImageView rightImageView;
复制代码


        public TextView unReadMsgCountRight;
复制代码


        public ImageView unReadMsgCountRightIcon;
复制代码


        public ProviderContainerView contentView;
复制代码


复制代码


    }
复制代码


复制代码


    public ConversationListAdapter(Context context) {
复制代码


        super();
复制代码


        mContext = context;
复制代码


        mInflater = LayoutInflater.from(mContext);
复制代码


    }
复制代码


复制代码


    public int findGatheredItem(Conversation.ConversationType type) {
复制代码


        int index = getCount();
复制代码


        int position = -1;
复制代码


        while ((index-- > 0)) {
复制代码


            UIConversation uiConversation = getItem(index);
复制代码


            if (uiConversation.getConversationType().equals(type)) {
复制代码


                position = index;
复制代码


                break;
复制代码


            }
复制代码


        }
复制代码


        return position;
复制代码


    }
复制代码


复制代码


    public int findPosition(Conversation.ConversationType type, String targetId) {
复制代码


        int index = getCount();
复制代码


        int position = -1;
复制代码


        while (index-- > 0) {
复制代码


            if (getItem(index).getConversationType().equals(type)
复制代码


                    && getItem(index).getConversationTargetId().equals(targetId)) {
复制代码


                position = index;
复制代码


                break;
复制代码


            }
复制代码


        }
复制代码


        return position;
复制代码


    }
复制代码


复制代码


    @Override
复制代码


    protected View newView(Context context, int position, ViewGroup group) {
复制代码


        View result = mInflater.inflate(R.layout.rc_item_conversation, null);
复制代码


复制代码


        ViewHolder holder = new ViewHolder();
复制代码


        holder.layout = findViewById(result, R.id.rc_item_conversation);
复制代码


        holder.leftImageLayout = findViewById(result, R.id.rc_item1);
复制代码


        holder.rightImageLayout = findViewById(result, R.id.rc_item2);
复制代码


        holder.leftUnReadView = findViewById(result, R.id.rc_unread_view_left);
复制代码


        holder.rightUnReadView = findViewById(result, R.id.rc_unread_view_right);
复制代码


        holder.leftImageView = findViewById(result, R.id.rc_left);
复制代码


        holder.rightImageView = findViewById(result, R.id.rc_right);
复制代码


        holder.contentView = findViewById(result, R.id.rc_content);
复制代码


        holder.unReadMsgCount = findViewById(result, R.id.rc_unread_message);
复制代码


        holder.unReadMsgCountRight = findViewById(result, R.id.rc_unread_message_right);
复制代码


        holder.unReadMsgCountIcon = findViewById(result, R.id.rc_unread_message_icon);
复制代码


        holder.unReadMsgCountRightIcon = findViewById(result, R.id.rc_unread_message_icon_right);
复制代码


        result.setTag(holder);
复制代码


        return result;
复制代码


    }
复制代码


复制代码


    @Override
复制代码


    protected void bindView(View v, int position, final UIConversation data) {
复制代码


        ViewHolder holder = (ViewHolder) v.getTag();
复制代码


复制代码


        if (data == null) {
复制代码


            return;
复制代码


        }
复制代码


        /*通过会话类型,获得对应的会话provider.ex: PrivateConversationProvider*/
复制代码


        IContainerItemProvider provider = RongContext.getInstance().getConversationTemplate(data.getConversationType().getName());
复制代码


        if (provider == null) {
复制代码


            RLog.e(TAG, "provider is null");
复制代码


            return;
复制代码


        }
复制代码


复制代码


        View view = holder.contentView.inflate(provider);
复制代码


        provider.bindView(view, position, data);
复制代码


复制代码


        //设置背景色
复制代码


        if (data.isTop())
复制代码


            holder.layout.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.rc_item_top_list_selector));
复制代码


        else
复制代码


            holder.layout.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.rc_item_list_selector));
复制代码


复制代码


复制代码


        ConversationProviderTag tag = RongContext.getInstance().getConversationProviderTag(data.getConversationType().getName());
复制代码


复制代码


        int defaultId;
复制代码


        if (data.getConversationType().equals(Conversation.ConversationType.GROUP)) {
复制代码


            defaultId = R.drawable.rc_default_group_portrait;
复制代码


        } else if (data.getConversationType().equals(Conversation.ConversationType.DISCUSSION)) {
复制代码


            defaultId = R.drawable.rc_default_discussion_portrait;
复制代码


        } else {
复制代码


            defaultId = R.drawable.rc_default_portrait;
复制代码


        }
复制代码


        // 1:图像靠左显示。2:图像靠右显示。3:不显示图像。
复制代码


        if (tag.portraitPosition() == 1) {
复制代码


            holder.leftImageLayout.setVisibility(View.VISIBLE);
复制代码


复制代码


            holder.leftImageLayout.setOnClickListener(new View.OnClickListener() {
复制代码


                @Override
复制代码


                public void onClick(View v) {
复制代码


                    if (mOnPortraitItemClick != null)
复制代码


                        mOnPortraitItemClick.onPortraitItemClick(v, data);
复制代码


                }
复制代码


            });
复制代码


            holder.leftImageLayout.setOnLongClickListener(new View.OnLongClickListener() {
复制代码


                @Override
复制代码


                public boolean onLongClick(View v) {
复制代码


                    if (mOnPortraitItemClick != null)
复制代码


                        mOnPortraitItemClick.onPortraitItemLongClick(v, data);
复制代码


                    return true;
复制代码


                }
复制代码


            });
复制代码


            if (data.getConversationGatherState()) {
复制代码


                holder.leftImageView.setAvatar(null, defaultId);
复制代码


            } else {
复制代码


                if (data.getIconUrl() != null) {
复制代码


                    holder.leftImageView.setAvatar(data.getIconUrl().toString(), defaultId);
复制代码


                } else {
复制代码


                    holder.leftImageView.setAvatar(null, defaultId);
复制代码


                }
复制代码


            }
复制代码


复制代码


            if (data.getUnReadMessageCount() > 0) {
复制代码


                holder.unReadMsgCountIcon.setVisibility(View.VISIBLE);
复制代码


                setUnReadViewLayoutParams(holder.leftUnReadView, data.getUnReadType());
复制代码


                if (data.getUnReadType().equals(UIConversation.UnreadRemindType.REMIND_WITH_COUNTING)) {
复制代码


                    if (data.getUnReadMessageCount() > 99) {
复制代码


                        holder.unReadMsgCount.setText(mContext.getResources().getString(R.string.rc_message_unread_count));
复制代码


                    } else {
复制代码


                        holder.unReadMsgCount.setText(Integer.toString(data.getUnReadMessageCount()));
复制代码


                    }
复制代码


                    holder.unReadMsgCount.setVisibility(View.VISIBLE);
复制代码


                    holder.unReadMsgCountIcon.setImageResource(R.drawable.rc_unread_count_bg);
复制代码


                } else {
复制代码


                    holder.unReadMsgCount.setVisibility(View.GONE);
复制代码


                    holder.unReadMsgCountIcon.setImageResource(R.drawable.rc_unread_remind_list_count);
复制代码


                }
复制代码


            } else {
复制代码


                holder.unReadMsgCountIcon.setVisibility(View.GONE);
复制代码


                holder.unReadMsgCount.setVisibility(View.GONE);
复制代码


            }
复制代码


复制代码


            holder.rightImageLayout.setVisibility(View.GONE);
复制代码


        } else if (tag.portraitPosition() == 2) {
复制代码


            holder.rightImageLayout.setVisibility(View.VISIBLE);
复制代码


复制代码


            holder.rightImageLayout.setOnClickListener(new View.OnClickListener() {
复制代码


                @Override
复制代码


                public void onClick(View v) {
复制代码


                    if (mOnPortraitItemClick != null)
复制代码


                        mOnPortraitItemClick.onPortraitItemClick(v, data);
复制代码


                }
复制代码


            });
复制代码


            holder.rightImageLayout.setOnLongClickListener(new View.OnLongClickListener() {
复制代码


                @Override
复制代码


                public boolean onLongClick(View v) {
复制代码


                    if (mOnPortraitItemClick != null)
复制代码


                        mOnPortraitItemClick.onPortraitItemLongClick(v, data);
复制代码


                    return true;
复制代码


                }
复制代码


            });
复制代码


复制代码


            if (data.getConversationGatherState()) {
复制代码


                holder.rightImageView.setAvatar(null, defaultId);
复制代码


            } else {
复制代码


                if (data.getIconUrl() != null) {
复制代码


                    holder.rightImageView.setAvatar(data.getIconUrl().toString(), defaultId);
复制代码


                } else {
复制代码


                    holder.rightImageView.setAvatar(null, defaultId);
复制代码


                }
复制代码


            }
复制代码


复制代码


            if (data.getUnReadMessageCount() > 0) {
复制代码


                holder.unReadMsgCountRightIcon.setVisibility(View.VISIBLE);
复制代码


                setUnReadViewLayoutParams(holder.rightUnReadView, data.getUnReadType());
复制代码


                if (data.getUnReadType().equals(UIConversation.UnreadRemindType.REMIND_WITH_COUNTING)) {
复制代码


                    holder.unReadMsgCount.setVisibility(View.VISIBLE);
复制代码


                    if (data.getUnReadMessageCount() > 99) {
复制代码


                        holder.unReadMsgCountRight.setText(mContext.getResources().getString(R.string.rc_message_unread_count));
复制代码


                    } else {
复制代码


                        holder.unReadMsgCountRight.setText(Integer.toString(data.getUnReadMessageCount()));
复制代码


                    }
复制代码


                    holder.unReadMsgCountRightIcon.setImageResource(R.drawable.rc_unread_count_bg);
复制代码


                } else {
复制代码


                    holder.unReadMsgCount.setVisibility(View.GONE);
复制代码


                    holder.unReadMsgCountRightIcon.setImageResource(R.drawable.rc_unread_remind_without_count);
复制代码


                }
复制代码


            } else {
复制代码


                holder.unReadMsgCountIcon.setVisibility(View.GONE);
复制代码


                holder.unReadMsgCount.setVisibility(View.GONE);
复制代码


            }
复制代码


复制代码


            holder.leftImageLayout.setVisibility(View.GONE);
复制代码


        } else if (tag.portraitPosition() == 3) {
复制代码


            holder.rightImageLayout.setVisibility(View.GONE);
复制代码


            holder.leftImageLayout.setVisibility(View.GONE);
复制代码


        } else {
复制代码


            throw new IllegalArgumentException("the portrait position is wrong!");
复制代码


        }
复制代码


        MessageContent content = data.getMessageContent();
复制代码


        if (content != null && content.isDestruct()) {
复制代码


            RongIMClient.getInstance().getMessage(data.getLatestMessageId(), new RongIMClient.ResultCallback<Message>() {
复制代码


复制代码


                @Override
复制代码


                public void onSuccess(Message message) {
复制代码


                    if (message == null) {
复制代码


                        EventBus.getDefault().post(new Event.MessageDeleteEvent(data.getLatestMessageId()));
复制代码


                    }
复制代码


                }
复制代码


复制代码


                @Override
复制代码


                public void onError(RongIMClient.ErrorCode e) {
复制代码


复制代码


                }
复制代码


            });
复制代码


        }
复制代码


    }
复制代码


复制代码


    protected void setUnReadViewLayoutParams(View view, UIConversation.UnreadRemindType type) {
复制代码


        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
复制代码


        Context context = view.getContext();
复制代码


        if (type == UIConversation.UnreadRemindType.REMIND_WITH_COUNTING) {
复制代码


            params.width = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_18);
复制代码


            params.height = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_18);
复制代码


            params.leftMargin = (int) mContext.getResources().getDimension(R.dimen.rc_dimen_size_44);
复制代码


            params.topMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_5);
复制代码


        } else {
复制代码


            params.width = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_9);
复制代码


            params.height = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_9);
复制代码


            params.leftMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_50);
复制代码


            params.topMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_7);
复制代码


        }
复制代码


        view.setLayoutParams(params);
复制代码


    }
复制代码


复制代码


    private OnPortraitItemClick mOnPortraitItemClick;
复制代码


复制代码


    public interface OnPortraitItemClick {
复制代码


        void onPortraitItemClick(View v, UIConversation data);
复制代码


复制代码


        boolean onPortraitItemLongClick(View v, UIConversation data);
复制代码


    }
复制代码


复制代码


    public void setOnPortraitItemClick(OnPortraitItemClick onPortraitItemClick) {
复制代码


        this.mOnPortraitItemClick = onPortraitItemClick;
复制代码


    }
复制代码


}
复制代码


复制代码

集成 DefaultExtensionModule, 实现 MyExtensionModule, 重写 getEmoticonTabs()方法, 为每个图标设置监听.


@Override
复制代码


    public List<IEmoticonTab> getEmoticonTabs() {
复制代码


        List<IEmoticonTab> emoticonTabs =  super.getEmoticonTabs();
复制代码


        MyEmoticonTab myEmoticonTab =new MyEmoticonTab();
复制代码


复制代码


        myEmoticonTab.setOnItemClickListener(new IEmojiItemClickListener() {
复制代码


            @Override
复制代码


            public void onEmojiClick(String emoji) {
复制代码


复制代码


                EditText editText = MyExtensionModule.this.mEditText;
复制代码


                if (editText != null) {
复制代码


                    int start = editText.getSelectionStart();
复制代码


                    editText.getText().insert(start, emoji);
复制代码


                }
复制代码


            }
复制代码


复制代码


            @Override
复制代码


            public void onDeleteClick() {
复制代码


                EditText editText = MyExtensionModule.this.mEditText;
复制代码


                if (editText != null) {
复制代码


                    editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
复制代码


                }
复制代码


            }
复制代码


        });
复制代码


        emoticonTabs.add(myEmoticonTab);
复制代码


        return emoticonTabs;
复制代码


    }
复制代码

继承 RongExtension, 实现 MyRongExtension, 然后获取到 editText, 为其设置监听, 代码如下:


复制代码


public class MyRongExtension extends RongExtension {
复制代码


复制代码


    EditText mEditText;
复制代码


复制代码


    public MyRongExtension(Context context) {
复制代码


        super(context);
复制代码


        tryAddTextChangedAction();
复制代码


    }
复制代码


复制代码


    public MyRongExtension(Context context, AttributeSet attrs) {
复制代码


        super(context, attrs);
复制代码


复制代码


        tryAddTextChangedAction();
复制代码


复制代码


    }
复制代码


复制代码


    private void tryAddTextChangedAction() {
复制代码


        mEditText = getInputEditText();
复制代码


        TextWatcher textWatcher = new TextWatcher() {
复制代码


复制代码


            private int start;
复制代码


            private int count;
复制代码


复制代码


复制代码


            @Override
复制代码


            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
复制代码


复制代码


            }
复制代码


复制代码


            @Override
复制代码


            public void onTextChanged(CharSequence s, int start, int before, int count) {
复制代码


                this.start = start;
复制代码


                this.count = count;
复制代码


            }
复制代码


复制代码


            @Override
复制代码


            public void afterTextChanged(Editable s) {
复制代码


复制代码


                // 这块的检验规则是纯emoji的, 加其他表情的话直接给他去掉, 或者自己写规则。
复制代码


//                if (QQEmoji.isQQEmoji(s.subSequence(start, start + count).toString())) {
复制代码


                    mEditText.removeTextChangedListener(this);
复制代码


                    String resultStr = QQEmoji.replaceEmojiWithText(s.toString());
复制代码


                    mEditText.setText(QQEmoji.ensure(resultStr), TextView.BufferType.SPANNABLE);
复制代码


                    mEditText.setSelection(mEditText.getText().length());
复制代码


                    mEditText.addTextChangedListener(this);
复制代码


//                }
复制代码


            }
复制代码


        };
复制代码


        mEditText.addTextChangedListener(textWatcher);
复制代码


    }
复制代码


复制代码


复制代码


}
复制代码


复制代码

这样一来, 就大功告成啦. 添加好了一套属于自己的表情包!


用户头像

还未添加个人签名 2021.01.26 加入

还未添加个人简介

评论

发布
暂无评论
融云即时通讯SDK集成 -- 定制UI(二) ——添加自定义表情库