一看就会 微信聊天中红包、转账与分享的消息实现

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

IM聊天中如何实现红包,转账,分享等功能。

其实红包,转账,和一些自定义的消息都是给予IM的自定义消息实现。

我们知道IM的消息类型分为C2C和Group类型。那比如我在C2C中自定义一个Message对象继承IMMessage,再对自定义的Message对象设置指定的类型,封装样式与解析样式,数据的封装格式,和解析格式就大致完成了红包的定义。

大致实现效果如下:

而红包的定义比较复杂,分为几种红包,红包又分几种状态,我们先看看简单的分享和转账实现。

一、自定义分享的实现

先定义一个自定义的类型枚举

public enum CustomType {

    TYPING,
    INVALID,
    EANGBAO,
    TRANSFER,
    EANGBAO_RECEIVE,
    PARTTIME,
    FULLTIME,  
    PROMOTION, 
    REWARDS,  
    JOBTIPS,  

}
复制代码

自定义的Message用于装载IM消息体和一些显示的逻辑

/**
 * 消息数据基类
 */
public abstract class Message implements Serializable {

    TIMMessage message;

    private boolean hasTime;

    /**
     * 消息描述信息
     */
    private String desc;


    public TIMMessage getMessage() {
        return message;
    }

    /**
     * 显示消息
     *
     * @param viewHolder 界面样式
     * @param context    显示消息的上下文
     */
    public abstract void showMessage(ChatRVAdapter.ViewHolder viewHolder, Context context, boolean isShowing);


    /**
     * 获取显示气泡
     *
     * @param viewHolder 界面样式
     */
    public FrameLayout getBubbleView(ChatRVAdapter.ViewHolder viewHolder) {
       //用于展示Chat页面的气泡布局,左右布局的判断与显示
    }

    /**
     * 显示消息状态
     *
     * @param viewHolder 界面样式
     */
    public void showStatus(ChatRVAdapter.ViewHolder viewHolder) {
       //用于展示Chat页面的布局状态,发送中,已发送,发送成功,发送失败等。
    }

    /**
     * 判断是否是自己发的
     */
    public boolean isSelf() {
        return message.isSelf();
    }

    //对话的类型是单聊还是群聊
    public boolean isC2C() {
        return message.getConversation().getType() == TIMConversationType.C2C;
    }

    /**
     * 获取消息摘要
     */
    public abstract String getSummary();

    /**
     * 获取撤回之后的文本显示
     */
    String getRevokeSummary() {
        return "Recall";
    }

    /**
     * 保存消息或消息文件
     */
    public abstract void save();

    /**
     * 删除消息
     */
    public void remove() {
        //调用SDK删除消息
        TIMMessageExt ext = new TIMMessageExt(message);
        ext.remove();
    }

    /**
     * 是否需要显示时间获取
     */
    public boolean getHasTime() {
        return hasTime;
    }


    /**
     * 是否需要显示时间设置
     *
     * @param message 上一条消息
     */
    public void setHasTime(TIMMessage message) {
        if (message == null) {
            hasTime = true;
            return;
        }
        hasTime = this.message.timestamp() - message.timestamp() > 300;
    }


    /**
     * 消息是否发送失败
     */
    public boolean isSendFail() {
        return message.status() == TIMMessageStatus.SendFail;
    }

    /**
     * 清除气泡原有数据
     */
    protected void clearView(ChatRVAdapter.ViewHolder viewHolder) {
      //清除聊天页面的数据
    }

    /**
     * 显示撤回的消息
     */
    boolean checkRevoke(ChatRVAdapter.ViewHolder viewHolder) {
      //判断是否撤回消息
    }

    /**
     * 获取发送者
     */
    public String getSender() {
        if (message.getSender() == null) {
            return "";
        }
        return message.getSender();
    }

    /**
     * 获取发送者NickName
     */
    public String getSenderNickName() {
        if (message.getSender() == null) {
            return "";
        }
        return message.getSenderNickname();
    }


    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    private void showDesc(ChatRVAdapter.ViewHolder viewHolder) {
       //展示详情,
    }
}
复制代码

上面的Message是对全部的消息的自定义,我们继承这个Message,实现自己的消息类型,默认的类型TextMessage,ImageMessage就是显示出来的文本与图片展示,VoiceMessage与VideoMessage就是我们平常使用的语音消息与视频消息,而我们的分享,转账,红包等,都是类似的实现:

例如Promotion的分享类型:

public class CustomPromotionMessage extends Message {

    public static int TYPE_PROMOTION = 21;

    private CustomType type;      //当前消息的类型

    //优惠券
    public String mPromotionId;
    private String mPromotionImage;
    private String mPromotionTitle;
    private String mPromotionPlatform;
    private String mPromotionOrginalPrice;
    private String mPromotionPrice;
    private String mPromotionPercent;
    private String mSenderName;    //全部消息的发送方名字

    public CustomPromotionMessage(TIMMessage message) {
        this.message = message;
        TIMCustomElem elem = (TIMCustomElem) message.getElement(0);
        parse(elem.getData());
    }

    //优惠券
    public CustomPromotionMessage(CustomType type, String promotion_id, String sender_name, String promotion_image, String promotion_title, String promotion_platform,
                                  String promotion_original_price, String promotion_price, String promotion_discount_percent) {

        message = new TIMMessage();

        String data = "";
        JSONObject dataJson = new JSONObject();
        try {
            if (type == CustomType.PROMOTION) {
                //创建消息对象的时候赋值,优惠券的数据
                dataJson.put("userAction", TYPE_PROMOTION);
                dataJson.put("promotion_id", promotion_id);
                dataJson.put("sender_name", sender_name);
                dataJson.put("promotion_image", promotion_image);
                dataJson.put("promotion_title", promotion_title);
                dataJson.put("promotion_platform", promotion_platform);
                dataJson.put("promotion_original_price", promotion_original_price);
                dataJson.put("promotion_price", promotion_price);
                dataJson.put("promotion_discount_percent", promotion_discount_percent);
                data = dataJson.toString();
            }

        } catch (JSONException e) {
            YYLogUtils.e("generate json error");
        }
        TIMCustomElem elem = new TIMCustomElem();
        elem.setData(data.getBytes());

        message.addElement(elem);

    }

    /**
     * 解析数据
     */
    private void parse(byte[] data) {

        try {
            String str = new String(data, "UTF-8");
            JSONObject jsonObj = new JSONObject(str);
            int action = jsonObj.getInt("userAction");
            if (action == TYPE_PROMOTION) {
                //优惠券
                type = CustomType.PROMOTION;
                mPromotionId = jsonObj.getString("promotion_id");
                mSenderName = jsonObj.getString("sender_name");
                mPromotionImage = jsonObj.getString("promotion_image");
                mPromotionTitle = jsonObj.getString("promotion_title");
                mPromotionPlatform = jsonObj.getString("promotion_platform");
                mPromotionOrginalPrice = jsonObj.getString("promotion_original_price");
                mPromotionPrice = jsonObj.getString("promotion_price");
                mPromotionPercent = jsonObj.getString("promotion_discount_percent");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void showMessage(ChatRVAdapter.ViewHolder viewHolder, Context context, boolean isShowing) {
        clearView(viewHolder);
        if (checkRevoke(viewHolder)) return;

        if (getType() == CustomType.PROMOTION) {
            clearView(viewHolder);

            FrameLayout bubbleView = getBubbleView(viewHolder);
            bubbleView.setBackgroundColor(Color.TRANSPARENT);

            View inflate = CommUtils.inflate(R.layout.item_layout_promotion);
            ImageView iv_promotion_image = inflate.findViewById(R.id.iv_promotion_image);
            TextView tv_promotion_title = inflate.findViewById(R.id.tv_promotion_title);
            TextView tv_promotion_plate = inflate.findViewById(R.id.tv_promotion_plate);
            TextView tv_promotion_oprice = inflate.findViewById(R.id.tv_promotion_oprice);
            TextView tv_promotion_price = inflate.findViewById(R.id.tv_promotion_price);
            TextView tv_promotion_percent = inflate.findViewById(R.id.tv_promotion_percent);

            tv_promotion_oprice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); //中划线
            GlideImageEngine.get().imageLoad(iv_promotion_image, mPromotionImage, R.drawable.home_list_plachholder);
            tv_promotion_title.setText(mPromotionTitle);
            tv_promotion_plate.setText(mPromotionPlatform);
            tv_promotion_oprice.setText(mPromotionOrginalPrice);
            tv_promotion_price.setText(mPromotionPrice);
            tv_promotion_percent.setText(mPromotionPercent);

            getBubbleView(viewHolder).addView(inflate);

            showStatus(viewHolder);

        }
    }

    @Override
    public String getSummary() {
        String str = getRevokeSummary();
        if (str != null) return str;

        if (isC2C()) {
            return "[Promotion]";
        } else {
            return mSenderName + " : [Promotion]";
        }

    }

    @Override
    public void save() {

    }

    public CustomType getType() {
        return type;
    }

}
复制代码

这样的消息很简单,只需要定义封装数据,解析数据,与展示的样式即可。

展示的时候由于我们都是继承Message,在ChatAdapter中我们直接调用 message.showMessage() 即可展示Item的布局与点击事件

   final Message message = getItem(position);
   message.showMessage(holder, mContext, false);

    //如果是自定义消息红包或转账在这里特殊处理和其他的分享
    if (message instanceof CustomEAngbaoMessage
            || message instanceof CustomTransferMessage
            || message instanceof CustomPartTimeMessage
            || message instanceof CustomFullTimeMessage
            || message instanceof CustomPromotionMessage
            || message instanceof CustomRewardsMessage
            || message instanceof CustomJobTipsMessage) {

            //处理点击点事件
             message.getBubbleView(holder).setOnClickListener(v -> handleCustomClick(position, message));

    }

   ...

         //优惠券
        } else if (message instanceof CustomPromotionMessage) {
            if (mListener != null) mListener.onPromotionClick(((CustomPromotionMessage) message).mPromotionId);
        }

复制代码

展示出来的效果如下:

二、转账的实现

转账比分享稍微多一步就是转账消息的状态判断。判断对方收取了金额没有。

public class CustomTransferMessage extends Message {

    public static int TYPE_TRANSFER = 17;

    private CustomType type;      //当前消息的类型

    //转账
    public String mTransferId;
    public String mTransferAmount;
    public String mTransferTargetName;
    public int mTransferStatus = 1;

    public CustomTransferMessage(TIMMessage message) {
        this.message = message;
        TIMCustomElem elem = (TIMCustomElem) message.getElement(0);
        parse(elem.getData());
    }

    //发送转账
    public CustomTransferMessage(CustomType type, String id, String amount, String targetName) {
        message = new TIMMessage();

        String data = "";
        JSONObject dataJson = new JSONObject();
        try {
            if (type == CustomType.TRANSFER) {
                //创建消息对象的时候赋值,转账的数据
                dataJson.put("userAction", TYPE_TRANSFER);
                dataJson.put("tramsfer_id", id);
                dataJson.put("tramsfer_amount", amount);
                dataJson.put("tramsfer_traget_name", targetName);
                dataJson.put("tramsfer_status", 1);
                data = dataJson.toString();
            }

        } catch (JSONException e) {
            YYLogUtils.e("generate json error");
        }
        TIMCustomElem elem = new TIMCustomElem();
        elem.setData(data.getBytes());

        message.addElement(elem);
    }

    /**
     * 解析数据
     */
    private void parse(byte[] data) {

        try {
            String str = new String(data, "UTF-8");
            JSONObject jsonObj = new JSONObject(str);
            int action = jsonObj.getInt("userAction");
            if (action == TYPE_TRANSFER) {
                //转账信息
                type = CustomType.TRANSFER;
                mTransferId = jsonObj.getString("tramsfer_id");
                mTransferAmount = jsonObj.getString("tramsfer_amount");
                mTransferTargetName = jsonObj.getString("tramsfer_traget_name");
                mTransferStatus = jsonObj.getInt("tramsfer_status");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @SuppressLint("SetTextI18n")
    @Override
    public void showMessage(ChatRVAdapter.ViewHolder viewHolder, Context context, boolean isShowing) {
        clearView(viewHolder);
        if (checkRevoke(viewHolder)) return;

        if (getType() == CustomType.TRANSFER) {
            clearView(viewHolder);

            FrameLayout bubbleView = getBubbleView(viewHolder);
            bubbleView.setBackgroundColor(Color.TRANSPARENT);

            View redpackView = CommUtils.inflate(R.layout.item_layout_transfer);
            TextView tv_transfer_amount = redpackView.findViewById(R.id.tv_transfer_amount);
            TextView tv_transfer_member_name = redpackView.findViewById(R.id.tv_transfer_member_name);
            tv_transfer_amount.setText(SalaryUtils.getCurrencySignByCountry(true) + " " + NumberUtils.formatMoney(mTransferAmount));
            tv_transfer_member_name.setText(isSelf() ? "Transfer to " + mTransferTargetName : "Transfer to You");

            getBubbleView(viewHolder).addView(redpackView);

            showStatus(viewHolder);

        }
    }

    @Override
    public String getSummary() {
        String str = getRevokeSummary();
        if (str != null) return str;
        return "[Transfer] Accepted";
    }

    @Override
    public void save() {
    }

    public CustomType getType() {
        return type;
    }
}

复制代码

其他的步骤都是和分享类型一致的,内部我们可以根据状态判断是否收取金额,展示不同的布局与状态。

三、红包的实现

红包的状态比较为复杂:

  1. 消息类型分为个人红包与群组红包
  2. 群组红包分为随机红包和等额红包,
  3. 红包状态分为已发送,已领取,已过期等状态。
  4. 红包的封面又分为默认红包,封面红包,根据不同的状态我们还要改变封面红包的封面图。

消息内的红包只是涉及到静态的展示,并不涉及到撕红包动画与红包封面图片切换等效果,我们还是定义相关的消息与布局,再定义对应状态的对应的处理:

public class CustomEAngbaoMessage extends Message {

    public static final int TYPE_EANGBAO = 16;

    private CustomType type;      //当前消息的类型

    public String mRedpackId;
    public String mRedpackRemark;
    public String mRedpackCover;
    public String mRedpackOpened;
    public int mRedpackStatus = 1;

    private ImageView mIvRedpackOpen;
    private View mViewDisenable;
    private ProgressBar mProgressBar;
    private ImageView mIvRedpackCover;
    private TextView mTvRedpackStatusText;
    private TextView mTvRedpackRemark;

    public CustomEAngbaoMessage(TIMMessage message) {
        this.message = message;
        TIMCustomElem elem = (TIMCustomElem) message.getElement(0);
        parse(elem.getData());
    }

    //发送红包消息构造
    public CustomEAngbaoMessage(CustomType type, String id, String remark, String cover, String opened) {
        message = new TIMMessage();

        String data = "";
        JSONObject dataJson = new JSONObject();
        try {
            if (type == CustomType.EANGBAO) {
                //创建消息对象的时候赋值,红包的数据
                dataJson.put("userAction", TYPE_EANGBAO);
                dataJson.put("eangbao_id", id);
                dataJson.put("eangbao_remark", remark);
                dataJson.put("eangbao_cover", cover);
                dataJson.put("eangbao_opened", opened);
                dataJson.put("eangbao_status", 1);
                data = dataJson.toString();
            }

        } catch (JSONException e) {
            YYLogUtils.e("generate json error");
        }
        TIMCustomElem elem = new TIMCustomElem();
        elem.setData(data.getBytes());

        message.addElement(elem);
    }

    //解析红包数据
    private void parse(byte[] data) {

        try {
            String str = new String(data, "UTF-8");
            JSONObject jsonObj = new JSONObject(str);
            int action = jsonObj.getInt("userAction");
            if (action == TYPE_EANGBAO) {
                //红包信息
                type = CustomType.EANGBAO;
                mRedpackId = jsonObj.getString("eangbao_id");
                mRedpackRemark = jsonObj.getString("eangbao_remark");
                mRedpackCover = jsonObj.getString("eangbao_cover");
                mRedpackOpened = jsonObj.getString("eangbao_opened");
                mRedpackStatus = jsonObj.getInt("eangbao_status");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void showMessage(ChatRVAdapter.ViewHolder viewHolder, Context context, boolean isShowing) {
        clearView(viewHolder);
        if (checkRevoke(viewHolder)) return;

        //红包的样式展示
        if (getType() == CustomType.EANGBAO) {
            clearView(viewHolder);

            FrameLayout bubbleView = getBubbleView(viewHolder);
            bubbleView.setBackgroundColor(Color.TRANSPARENT);

            View redpackView = CommUtils.inflate(R.layout.item_layout_redpack);
            mIvRedpackCover = redpackView.findViewById(R.id.iv_redpack_cover);
            mProgressBar = redpackView.findViewById(R.id.progress_bar);
            mTvRedpackRemark = redpackView.findViewById(R.id.tv_redpack_remark);
            mViewDisenable = redpackView.findViewById(R.id.view_disenable);
            mIvRedpackOpen = redpackView.findViewById(R.id.iv_redpack_open);
            mTvRedpackStatusText = redpackView.findViewById(R.id.tv_redpack_status_text);

            //统一赋值动态变化的数据
            showRedpackData();

            getBubbleView(viewHolder).addView(redpackView);

            showStatus(viewHolder);

        }
    }

    /**
     * 刷新红包的状态
     */
    public void notifyRedpack() {
        showRedpackData();
    }

    /**
     * 红包的布局是动态的可以变换
     */
    private void showRedpackData() {
        if (mIvRedpackOpen != null) {

            String statusText = "";
            String imgUrl;
            if (mRedpackStatus == 2) {
                statusText = "Opened";
            } else if (mRedpackStatus == 3) {
                statusText = "Expired";
            } else if (mRedpackStatus == 4) {
                statusText = "None left";
            }

            if (mRedpackStatus == 1) {
                imgUrl = mRedpackCover;
                mIvRedpackOpen.setVisibility(View.VISIBLE);
                mViewDisenable.setVisibility(View.GONE);
                mTvRedpackStatusText.setVisibility(View.GONE);
            } else {
                imgUrl = mRedpackStatus == 5 ? mRedpackCover : mRedpackOpened;
                mIvRedpackOpen.setVisibility(View.GONE);
                mViewDisenable.setVisibility(View.VISIBLE);
                mTvRedpackStatusText.setVisibility(View.VISIBLE);
                mTvRedpackStatusText.setText(statusText);
            }

            if (!CheckUtil.isEmpty(imgUrl)) {
                mProgressBar.setVisibility(View.VISIBLE);
                GlideImageEngine.get().imageLoad(mIvRedpackCover, imgUrl, R.drawable.shape_redpack_img_bg, () -> {
                    mProgressBar.setVisibility(View.GONE);
                });

            } else {
                mIvRedpackCover.setBackgroundResource(R.drawable.shape_redpack_img_bg);
            }

            //如果是自己发的 并且 状态为1  并且是单聊 隐藏Open的图片
            if (mRedpackStatus == 1 && isSelf() && isC2C()) {
                mIvRedpackOpen.setVisibility(View.GONE);
            }

            //如果是自己发的 状态为5 隐藏灰色蒙层 显示Open按钮
            if (mRedpackStatus == 5 && isSelf() && isC2C()) {
                mIvRedpackOpen.setVisibility(View.VISIBLE);
                mViewDisenable.setVisibility(View.GONE);
            }

            mTvRedpackRemark.setVisibility(!CheckUtil.isEmpty(mRedpackRemark) ? View.VISIBLE : View.GONE);
            mTvRedpackRemark.setText(mRedpackRemark);
        }
    }

    @Override
    public String getSummary() {
        String str = getRevokeSummary();
        if (str != null) return str;
        return "eAngBao";
    }

    @Override
    public void save() {
    }

    public CustomType getType() {
        return type;
    }
}
复制代码

我们发给别人的红包,我们只能查看详情,看是否领取了红包,而我们需要监听消息类型,看别人是否领取了红包,如果监听到消息别人领取了红包,我们需要发送Event修改这个红包的状态。

如果是别人发给我的红包,那么红包的状态是由我们的红包弹窗中自己手动触发的,触发打开红包之后我们同样需要发送一个消息,告诉对方我接收红包了,对方收到消息我领取了红包,对方一样需要在消息列表上刷新这个红包消息的状态。

所以我们还需要一个红包接收的消息:

public class CustomEAngbaoReceiveMessage extends Message {

    public static int TYPE_EANGBAO_RECEIVE = 18;

    private CustomType type;      //当前消息的类型

    //接红包
    public String mRedpackId;
    private String mSenderName;    //全部消息的发送方名字
    private String mSenderMemberId;
    private String mRedpackReceiveName;
    private String mRedpackReceiveMemberId;
    private String mRedpackReceiveAmount;
    private String mRedpackReceiveTargetType;

    public CustomEAngbaoReceiveMessage(TIMMessage message) {
        this.message = message;
        TIMCustomElem elem = (TIMCustomElem) message.getElement(0);
        parse(elem.getData());
    }

    //解析红包接收数据
    private void parse(byte[] data) {
        try {
            String str = new String(data, "UTF-8");
            JSONObject jsonObj = new JSONObject(str);
            int action = jsonObj.getInt("userAction");
            if (action == TYPE_EANGBAO_RECEIVE) {
                //红包信息
                type = CustomType.EANGBAO_RECEIVE;
                mRedpackId = jsonObj.getString("eangbao_id");
                mRedpackReceiveName = jsonObj.getString("receive_name");
                mSenderName = jsonObj.getString("sender_name");
                mRedpackReceiveAmount = jsonObj.getString("receive_amount");
                mRedpackReceiveTargetType = jsonObj.getString("target_type");
                if (jsonObj.has("receive_member_id")) {
                    mRedpackReceiveMemberId = jsonObj.getString("receive_member_id");
                }
                if (jsonObj.has("sender_member_id")) {
                    mSenderMemberId = jsonObj.getString("sender_member_id");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void showMessage(ChatRVAdapter.ViewHolder viewHolder, Context context, boolean isShowing) {
        clearView(viewHolder);
        if (checkRevoke(viewHolder)) return;

        if (getType() == CustomType.EANGBAO_RECEIVE) {

            if (!CheckUtil.isEmpty(mSenderMemberId) && !CheckUtil.isEmpty(mRedpackReceiveMemberId)) {
                String myUserId = SPUtils.getInstance(CommUtils.getContext()).getString(YYConstants.CACHE_USER_ID, "");
                if (!myUserId.equals(mSenderMemberId) && !myUserId.equals(mRedpackReceiveMemberId)) {
                    //如果不相等,那么不做展示
                    viewHolder.leftPanel.setVisibility(View.GONE);
                    viewHolder.rightPanel.setVisibility(View.GONE);
                    viewHolder.systemMessage.setVisibility(View.GONE);
                    return;
                }
            }

            viewHolder.leftPanel.setVisibility(View.GONE);
            viewHolder.rightPanel.setVisibility(View.GONE);
            viewHolder.systemMessage.setVisibility(View.VISIBLE);

            Drawable tips = CommUtils.getDrawable(R.drawable.redpack_reveive_tips_iocn);
            tips.setBounds(0, 0, tips.getMinimumWidth(), tips.getMinimumHeight());
            viewHolder.systemMessage.setCompoundDrawables(tips, null, null, null);

            String content = "<font color=\"#777777\">" + mRedpackReceiveName + " opened " + mSenderName + "'s </font>" +
                    "<font color=\"#FF2F15\">eAngBao</font>";
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                viewHolder.systemMessage.setText(Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY));
            } else {
                viewHolder.systemMessage.setText(Html.fromHtml(content));
            }

        }
    }

    @Override
    public String getSummary() {
        String str = getRevokeSummary();
        if (str != null) return str;
        return "eAngBao is opened";
    }

    @Override
    public void save() {
    }

    public CustomType getType() {
        return type;
    }
}
复制代码

关于红包的消息展示和分享的消息展示类似,只是我们的消息中多一个了更新的方法,重新根据状态来展示对应的布局。

    public void notifyRedpack() {
        showRedpackData();
    }
复制代码

关于撕红包和展示金额,详情等页面其实都是与这个消息展示无关的,分别是红包弹窗和红包详情页面。我们大部分动画都是lottie效果,这个大家应该都不会有问题。

发送红包效果:

打开自己发送的红包与对方接收红包的消息效果:

Ok,红包模块在IM中的使用大致就是如此了!

定义消息-> 定义自定义消息类型 ->定义各个状态的不同布局展示 ->处理自己的红包 ->处理别人的红包 ->监听红包打开的消息。

至于群组红包和个人红包只是发送消息的时候区别type为C2C还是Group就行了,关于红包处理的

        Bundle bundle = new Bundle();
        bundle.putString("identify", identify);
        bundle.putString("redpackId", redpackId);
        bundle.putString("remark", remark);
        bundle.putString("cover", cover);
        bundle.putString("opened", opened);
        if (type == 2) {
            bundle.putSerializable("type", TIMConversationType.Group);
        } else {
            bundle.putSerializable("type", TIMConversationType.C2C);
        }
        YYChatSuperActivity.startInstance(ChatFragment.class, bundle);
复制代码

一样的通过sendMessage方法发送消息,只是这个会话变成了group类型而已

 conversation.sendMessage(message, new TIMValueCallBack<TIMMessage>() {
            @Override
            public void onError(int code, String desc) {
                //发送消息失败
                view.onSendMessageFail(code, desc, message);
            }

            @Override
            public void onSuccess(TIMMessage msg) {
                //发送消息成功,消息状态已在sdk中修改,此时只需更新界面
                MessageEvent.getInstance().onNewMessage(null);  //这里在observe中接受到通知,会去刷新adapter的
            }
        });
复制代码

群组红包还剩下多少红包,当前红包的状态等,这些都是与消息本身无关的,我们拿到红包的id,请求服务器数据展示对应的数据,根据状态刷新对应的布局即可。

大致逻辑如下:

  /**
     * 根据状态展示不同的数据
     */
    private void showDataWithStatus(int status) {
        if (mRedpackInfoStatus == null) return;

        String redpackImage = "";
        String message = "";

        if (status == 1) {
            //可以领
            changeStatus(STATUS_CEN_OPEN);
            redpackImage = mRedpackInfoStatus.cover.cover;
            message = mRedpackInfoStatus.remark;
            mTvViewDetails.setVisibility(GONE);

        } else if (status == 2) {
            //已经领了
            changeStatus(STATUS_OPENED);
            redpackImage = mRedpackInfoStatus.cover.opened;
            message = mRedpackInfoStatus.remark;
            mTvViewDetails.setVisibility(VISIBLE);

        } else if (status == 3) {
            //已经过期
            changeStatus(STATUS_EXPIRED);
            redpackImage = mRedpackInfoStatus.cover.cover;
            message = "The eAngBao has been expired!";
            mTvViewDetails.setVisibility(VISIBLE);

        } else if (status == 4) {
            //已被领光
            changeStatus(STATUS_NEXT_TIME);
            redpackImage = mRedpackInfoStatus.cover.cover;
            message = "Better luck next time!";
            mTvViewDetails.setVisibility(VISIBLE);
        }

        if (!CheckUtil.isEmpty(redpackImage)) {

            //加载红包图片
            GlideImageEngine.get().imageLoad(mIvRedpackTop, redpackImage, R.drawable.yypay_redpack_top_red, () -> {
                mProgressBar.setVisibility(GONE);
            });

            mLlRedpaclInfo.setVisibility(GONE);
            mTvRedpackTips.setVisibility(GONE);

        } else {
            mProgressBar.setVisibility(GONE);
        }
        ...
复制代码

以接口的数据和状态为主,我们会把当前红包的状态同步到会话列表上。

具体的效果图在最上面,就不重复发图了。到处红包,转账,分享等自定义消息就大致完成!具体的细节都是细枝末节一些UI的布局和动画效果之类的,都是比较基础的。

本文测试机为华为畅想3 5寸大屏 已是我司最低端手机了。

本文的效果基于腾讯TIM的实现,如果大家使用的环信或者阿里的IM-SDK,大家都是大差不差逻辑思想都是一样的。当然如果你们是自研的通讯SDK,那更好了,都不需要使用自定义消息来开发了,你们可以直接把这些类型定义为消息类型。

源码关联了业务代码不便开源,其实只要思路是对的,使用哪一个IM工具都是类似的。希望对大家有所帮助。

如有不同的思路,欢迎讨论,如果有疑问也可以评论区指出,还请大家多多点赞支持!

猜你喜欢

转载自juejin.im/post/7106028957677387783
今日推荐