MultiAudioLayout多人语音容器

82 阅读1分钟
public class MultiAudioLayout extends ViewGroup implements IUserUpdateCallback {

    private Context context;

    private int childVerticalSpace; //纵向子view间距
    private int childHorizontalSpace;   //横向子view间距
    private int maxColumnNum;  //最大列数
    private int maxRowNum; //最大行数
    private int childWidth; //子view宽度
    private int childHeight;    //子view高度

    private Map<String, AudioItemView> audioItemMap;
    private OnClickMoreMemberListener listener;
    //子view达到最大后再有数据保存至此
    private List<String> hideData;

    public MultiAudioLayout(Context context) {
        this(context, null);
    }

    public MultiAudioLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        audioItemMap = new HashMap<>();
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MultiVideoLayout);
        if (attributes != null) {
            childVerticalSpace = attributes.getDimensionPixelSize(R.styleable.MultiVideoLayout_childVerticalSpace, 0);
            maxColumnNum = attributes.getInt(R.styleable.MultiVideoLayout_maxColumnNum, 0);
            maxRowNum = attributes.getInt(R.styleable.MultiVideoLayout_maxRowNum, 0);
            attributes.recycle();
        }
        MeetingManager.getInstance().addUserUpdateCallback(this.getClass(), this);
        hideData = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int childCount = getChildCount();

        if (childCount == 0) {
            setMeasuredDimension(0, 0);
        } else {
            measureChildren(widthMeasureSpec, heightMeasureSpec);

            childWidth = getChildAt(0).getMeasuredWidth();
            childHeight = getChildAt(0).getMeasuredHeight();

            childHorizontalSpace = (width - maxColumnNum * childWidth) / (maxColumnNum - 1);

            int realWidth = width;
            int realHeight;

            if (childCount < maxColumnNum) {
                realWidth = childCount * childWidth + ((childCount - 1) * childHorizontalSpace);
            }

            int rowCount = childCount / maxColumnNum + (childCount % maxColumnNum != 0 ? 1 : 0);
            realHeight = rowCount * childHeight + (rowCount - 1) * childVerticalSpace;
            if (realHeight > height) {
                realHeight = height;
            }

            setMeasuredDimension(realWidth, realHeight);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left;
        int top;
        for (int i = 0; i < getChildCount(); i++) {
            AudioItemView audioItemView = (AudioItemView) getChildAt(i);
            left = (i % maxColumnNum) * (childWidth + childHorizontalSpace);
            top = (i / maxRowNum) * (childHeight + childVerticalSpace);
            audioItemView.layout(left, top, left + childWidth, top + childHeight);
        }
    }

    @Override
    public void addUser(String userId) {
        if (!isExistUser(userId)) {
            if (!isMax()) {
                //未达容器最大值继续添加至容器
                AudioItemView audioItemView = new AudioItemView(context);
                audioItemView.bindUser(userId);
                this.addView(audioItemView);
                audioItemMap.put(userId, audioItemView);
            } else {
                //达到容器最大值后把最后一位替换成更多,并且把最后一位和新加进入的用户保存
                AudioItemView lastAudioItemView = (AudioItemView) getChildAt(getChildCount() - 1);
                if (!TextUtils.isEmpty(lastAudioItemView.getUserId())) {
                    lastAudioItemView.setMoreView();
                    lastAudioItemView.setOnClickListener(v -> {
                        if (listener != null) {
                            listener.clickMoreMember();
                        }
                    });
                    hideData.add(lastAudioItemView.getUserId());
                    audioItemMap.remove(lastAudioItemView.getUserId());
                    //把更多成员绑定的userId置空
                    lastAudioItemView.bindUser("");
                }
                hideData.add(userId);
            }
        }
    }

    @Override
    public void updateUser(String userId) {
        if (audioItemMap.get(userId) != null) {
            audioItemMap.get(userId).updateUser();
        }
    }

    @Override
    public void removeUser(String userId) {
        if (isExistUser(userId)) {
            AudioItemView removeItem = audioItemMap.get(userId);
            //删除的view的下标
            int position = indexOfChild(removeItem);
            this.removeView(removeItem);
            audioItemMap.remove(userId);

            AudioItemView lastAudioItemView = (AudioItemView) getChildAt(getChildCount() - 1);
            if (TextUtils.isEmpty(lastAudioItemView.getUserId())) {
                //如果最后一个是更多成员,把更多替换为隐藏容器第一条数据
                if (hideData.size() > 0 && hideData.size() <= 2) {
                    lastAudioItemView.bindUser(hideData.get(0));
                    lastAudioItemView.updateUser();
                    lastAudioItemView.setOnClickListener(null);
                    audioItemMap.put(hideData.get(0), lastAudioItemView);
                    hideData.remove(0);
                    //拉取最后一条数据补上第九条
                    if (hideData.size() > 0) {
                        AudioItemView audioItemView = new AudioItemView(context);
                        audioItemView.bindUser(hideData.get(0));
                        audioItemView.updateUser();
                        this.addView(audioItemView);
                        audioItemMap.put(hideData.get(0), audioItemView);
                        hideData.clear();
                    }
                } else if (hideData.size() > 2) {
                    //暴力插入删除的位置
                    AudioItemView audioItemView = new AudioItemView(context);
                    audioItemView.bindUser(hideData.get(0));
                    audioItemView.updateUser();
                    this.addView(audioItemView, position);
                    audioItemMap.put(hideData.get(0), audioItemView);
                    hideData.remove(0);
                }
            }
        } else if (hideData.contains(userId)) {
            for (int i = 0; i < hideData.size(); i++) {
                if (userId.equals(hideData.get(i))) {
                    hideData.remove(i);
                }
            }

            //如果隐藏容器只剩下一条数据,替换更多成员
            if (hideData.size() == 1) {
                AudioItemView lastAudioItemView = (AudioItemView) getChildAt(getChildCount() - 1);
                if (TextUtils.isEmpty(lastAudioItemView.getUserId())) {
                    lastAudioItemView.bindUser(hideData.get(0));
                    lastAudioItemView.updateUser();
                    //清空点击事件
                    lastAudioItemView.setOnClickListener(null);

                    audioItemMap.put(hideData.get(0), lastAudioItemView);
                    hideData.clear();
                }
            }
        }
    }

    @Override
    public void userCameraStateUpdate(String userId) {

    }

    @Override
    public void userMicStateUpdate(String userId) {

    }

    @Override
    public void onStreamUpdate(String userId, boolean isAdd) {
        if (!isAdd) {
            MeetingManager.getInstance().stopPlay(userId);
        }
    }

    @Override
    public void onVideoStreamUpdate(String userId, boolean isAvailable) {

    }

    public AudioItemView getUser(String userId) {
        return isExistUser(userId) ? audioItemMap.get(userId) : null;
    }

    public boolean isExistUser(String userId) {
        return audioItemMap.containsKey(userId);
    }

    //达到子view最大值
    public boolean isMax() { return getChildCount() >= maxColumnNum * maxRowNum; }

    //设置在讲话的用户样式
    public void setActiveVoice(String userId) {
        if (isExistUser(userId)) {
            for (Map.Entry<String, AudioItemView> entry : audioItemMap.entrySet()) {
                if (entry.getKey().equals(userId)) {
                    entry.getValue().setMaxVoice(true);
                } else {
                    entry.getValue().setMaxVoice(false);
                }
            }
        } else {
            for (Map.Entry<String, AudioItemView> entry : audioItemMap.entrySet()) {
                entry.getValue().setMaxVoice(false);
            }
        }
    }

    public void setVisible(boolean isVisible) {
        if (isVisible) {
            if (isVisible()) {
                return;
            }
            setVisibility(View.VISIBLE);
        } else {
            if (!isVisible()) {
                return;
            }
            setVisibility(View.GONE);
        }
    }

    public boolean isVisible() {
        return getVisibility() == View.VISIBLE;
    }

    public void setOnClickMoreMemberListener(OnClickMoreMemberListener listener) {
        this.listener = listener;
    }

    public interface OnClickMoreMemberListener {

        void clickMoreMember();
    }
}