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

背景:

最近公司新上的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: 表情tab
DefaultExtensionModule: 表情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);    }}

这样一来, 就功败垂成啦. 增加好了一套属于本人的表情包!