基于Bmob的即时通信(16)音视频布局

废话

今天我们来编写音视频布局

在上一篇中,我们写了音视频的Activity,还有它的布局文件,但是它里面的两个子View还没有讲怎么写,现在我们来慢慢分析

音视频的布局

activity_media.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.yk.mchat.app.widget.VideoLayout
        android:id="@+id/media_video_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.yk.mchat.app.widget.VoiceLayout
        android:id="@+id/media_voice_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

这个是上一篇文章写的布局,它里面有两个子View

  • VideoLayout:视频布局
  • VoiceLayout:音频布局
    我们先来看音频布局

VoiceLayout.java

package com.yk.mchat.app.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.hyphenate.chat.EMClient;
import com.hyphenate.exceptions.EMNoActiveCallException;
import com.yk.mchat.R;
import com.yk.mchat.model.contacts.User;

import de.hdodenhof.circleimageview.CircleImageView;

public class VoiceLayout extends RelativeLayout {

    public static final int TYPE_CALL = 0;

    public static final int TYPE_ANSWER = 1;

    private View mView;

    private Context mContext;

    private CircleImageView mAvatar;

    private TextView mNickname;

    private LinearLayout mDelayLayout;

    private FloatingActionButton mRejectFab;

    private FloatingActionButton mAnswerFab;

    private FloatingActionButton mEndFab;

    private int mType;

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

    public VoiceLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mView = LayoutInflater.from(context).inflate(R.layout.layout_voice, this);
        fbv();
        init();
        event();
    }

    private void fbv() {
        mAvatar = mView.findViewById(R.id.layout_voice_avatar);
        mNickname = mView.findViewById(R.id.layout_voice_nickname);
        mDelayLayout = mView.findViewById(R.id.layout_voice_delay_layout);
        mRejectFab = mView.findViewById(R.id.layout_voice_reject_fab);
        mAnswerFab = mView.findViewById(R.id.layout_voice_answer_fab);
        mEndFab = mView.findViewById(R.id.layout_voice_end_fab);
    }

    private void init() {

    }

    private void event() {
        mRejectFab.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                rejectCall();
            }
        });

        mAnswerFab.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                answerCall();
            }
        });

        mEndFab.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                endCall();
            }
        });
    }

    private void rejectCall() {
        try {
            EMClient.getInstance().callManager().rejectCall();
        } catch (EMNoActiveCallException e) {
            e.printStackTrace();
        }
    }

    private void answerCall() {
        try {
            EMClient.getInstance().callManager().answerCall();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void endCall() {
        try {
            EMClient.getInstance().callManager().endCall();
        } catch (EMNoActiveCallException e) {
            e.printStackTrace();
        }
    }

    public void setUserInfo(User user) {
        Glide.with(mContext).load(user.getAvatar().getFileUrl()).into(mAvatar);
        mNickname.setText(user.getNickname());
    }

    @SuppressLint("RestrictedApi")
    public void setType(int type) {
        mType = type;
        switch (mType) {
            case TYPE_CALL:
                mDelayLayout.setVisibility(GONE);
                mEndFab.setVisibility(VISIBLE);
                break;
            case TYPE_ANSWER:
                mDelayLayout.setVisibility(VISIBLE);
                mEndFab.setVisibility(GONE);
                break;
            default:
                break;
        }
    }

    /**
     * 电话接通
     */
    @SuppressLint("RestrictedApi")
    public void connect() {
        mDelayLayout.setVisibility(GONE);
        mEndFab.setVisibility(VISIBLE);
    }

}

layout_voice

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/layout_voice_avatar"
        android:layout_width="72dp"
        android:layout_height="72dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="72dp"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_person_black_48dp"
        app:civ_border_width="2dp"
        app:civ_border_color="@color/colorBlack"/>

    <TextView
        android:id="@+id/layout_voice_nickname"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/layout_voice_avatar"
        android:gravity="center"
        android:text="Nickname" />

    <LinearLayout
        android:id="@+id/layout_voice_delay_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:layout_marginBottom="72dp">

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/layout_voice_reject_fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"
            android:layout_marginRight="32dp"
            android:src="@drawable/ic_call_end_white_24dp"
            app:fabSize="normal"
            app:backgroundTint="@color/colorPrimary"
            app:rippleColor="@color/colorAccent"/>

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/layout_voice_answer_fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"
            android:layout_marginLeft="32dp"
            android:src="@drawable/ic_call_white_24dp"
            app:fabSize="normal"
            app:backgroundTint="@color/colorPrimary"
            app:rippleColor="@color/colorAccent"/>

    </LinearLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/layout_voice_end_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="88dp"
        android:src="@drawable/ic_call_end_white_24dp"
        app:fabSize="normal"
        app:backgroundTint="@color/colorAccent"
        app:rippleColor="@color/colorPrimary"/>

</RelativeLayout>

可以看到,音频布局比较简单:

  • 自定义布局继承自RelativeLayout
  • 布局上方是用户头像和昵称
  • 下方是三个按钮:拒接、挂断、接听

接下来我们来看视频界面

VideoLayout.java

package com.yk.mchat.app.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class VideoLayout extends ViewGroup {

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

    public VideoLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int childCount = getChildCount();
        if (childCount == 1) {
            measureOne(widthMeasureSpec, heightMeasureSpec);
        } else if (childCount == 2) {
            measureTwo(widthMeasureSpec, heightMeasureSpec);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void measureOne(int widthMeasureSpec, int heightMeasureSpec) {
        View child = getChildAt(0);
        child.measure(widthMeasureSpec, heightMeasureSpec);
    }

    private void measureTwo(int widthMeasureSpec, int heightMeasureSpec) {
        View remoteChild = getChildAt(0);
        remoteChild.measure(widthMeasureSpec, heightMeasureSpec);

        View localChild = getChildAt(1);
        int localChildWidth = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) / 3, MeasureSpec.EXACTLY);
        int localChildHeight = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) / 4, MeasureSpec.EXACTLY);
        localChild.measure(localChildWidth,localChildHeight);
    }


    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        int childCount=getChildCount();
        if(childCount==1){
            layoutOne();
        }else if(childCount==2){
            layoutTwo();
        }
    }

    private void layoutOne() {
        View child=getChildAt(0);
        child.layout(0,0,child.getMeasuredWidth(),child.getMeasuredHeight());
    }

    private void layoutTwo() {
        View remoteChild=getChildAt(0);
        remoteChild.layout(0,0,remoteChild.getMeasuredWidth(),remoteChild.getMeasuredHeight());

        View localChild=getChildAt(1);
        localChild.layout(localChild.getMeasuredWidth()*2,localChild.getMeasuredHeight()*3,localChild.getMeasuredWidth()*3,localChild.getMeasuredHeight()*4);
    }
}

视频界面只是用于显示双方视频,所有就没有xml文件

可以看到,我们重写了ViewGroup的onMeasure和onLayout方法,这两个方法分别是测量和布局,为什么要重写这两个方法呢,因为当我们在视频通话的时候有两种情况,一是呼叫中,二是接通,呼叫中我们只需要显示,也只可以显示自己的画面,接通时两方的画面都要有,所有我们要做动态的改变画面的显示。

今天就到这里。

猜你喜欢

转载自blog.csdn.net/weixin_34217773/article/details/88108249