写点什么

Android 技术分享| 【Android 自定义 View】多人视频通话控件

作者:anyRTC开发者
  • 2022 年 3 月 01 日
  • 本文字数:3726 字

    阅读完需:约 12 分钟

【Android 自定义 View】多人视频通话控件


*以上图片截自微信等待中界面

等待中界面

上图是微信多人视频通话时未接通的界面状态,可见每个人的 View 中大致需包含了以下元素。


  1. 头像

  2. 昵称

  3. Loading View

  4. 视频 View

  5. 音频状态 icon


所以,我们先写好每个人的布局。如下


<merge xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#2C3033"    tools:parentTag="android.widget.RelativeLayout">        <!--视频View-->    <TextureView        android:id="@+id/video_view"        android:layout_height="match_parent"        android:layout_width="match_parent">    </TextureView>
<!--头像--> <ImageView android:id="@+id/iv_avatar" android:src="@drawable/avatar" android:layout_height="match_parent" android:layout_width="match_parent"> </ImageView>
<!--名字--> <TextView android:id="@+id/tv_user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="20dp" tools:text="UserName" android:background="@android:color/transparent" android:textColor="@android:color/white" android:textSize="14sp" />
<!--音频状态Icon--> <ImageView android:id="@+id/iv_audio_enable" android:layout_height="20dp" android:layout_width="20dp" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:layout_margin="20dp" android:src="@drawable/mic_enable"> </ImageView>
<!--Loading--> <ImageView android:id="@+id/iv_loading" android:layout_height="30dp" android:layout_width="30dp" android:layout_centerInParent="true" android:src="@drawable/loading"> </ImageView>
</merge>
复制代码


GroupUserVideoLayout


接着定义自定义 View 类,GroupUserVideoLayout 添加一些基本的方法。


/** * 多人视频通话中每个用户的布局 */class GroupUserVideoLayout @JvmOverloads constructor(mContext:Context): RelativeLayout(mContext) {
private var videoView:TextureView private var ivAvatar:ImageView private var ivAudio:ImageView private var tvName:TextView private var ivLoading:ImageView
init { val root = LayoutInflater.from(mContext).inflate(R.layout.layout_gv_layout,this) videoView = root.findViewById(R.id.video_view) ivAvatar = root.findViewById(R.id.iv_avatar) ivAudio = root.findViewById(R.id.iv_audio_enable) tvName = root.findViewById(R.id.tv_user_name) ivLoading = root.findViewById(R.id.iv_loading) } //设置昵称 fun setUserName(userName:String){ tvName.text = userName } //设置头像 fun setAvatar(avatarUrl:String){ ivAvatar.loadUrl(avatarUrl) } //设置音频图标状态 fun enableAudio(enable:Boolean){ ivAudio.visibility = if (enable) VISIBLE else GONE } //设置LoadingView状态 fun setLoadingState(open:Boolean){ ivLoading.visibility = if (open) VISIBLE else GONE }}
复制代码

接听后

​ 接听后,对应的设置每个人的头像昵称,去掉 Loading,显示视频。接下来就是要定义多个人进出时,布局的变化了。


- 2个人的时候,左右对齐均分显示- 3个人的时候品字型显示- 4个人的时候上下2个均分显示- 5个人以上则九宫格显示
复制代码
GroupVideoLayoutManager

定义 GroupVideoLayoutManager ,这个是在外部直接使用的,里面应当有查找、添加用户,移除用户,根据人数更新布局位置等功能。


class GroupVideoLayoutManager constructor(mContext: Context): RelativeLayout(mContext) {
//自己的ID var selfId:String="" private val userLayoutList = mutableListOf<LayoutEntity>() private var userCount = 0 private val MAX_USER = 8
private val oneUserParamList by lazy { LayoutUtils.get1UserParam(mContext,width,height) } private val twoUserParamList by lazy { LayoutUtils.get2UserParam(mContext,width,height) } private val threeUserParamList by lazy { LayoutUtils.get3UserParam(mContext,width,height) } private val fourUserParamList by lazy { LayoutUtils.get4UserParam(mContext,width,height) } private val nineUserParamList by lazy { LayoutUtils.get9UserParam(mContext,width,height) }
/** * 根据uid 查找对应的View */ fun findUser(uid:String):GroupUserVideoLayout?{ userLayoutList.find { it.userId==uid }?.let { layoutEntity-> layoutEntity.layout?.let { return it }?:let{ return null } }?:let{ return null } }
/** * 根据uid 添加对应的View */ fun addUser(uid:String):GroupUserVideoLayout?{ if (userCount>MAX_USER){ return null } val layout = GroupUserVideoLayout(context) userLayoutList.add(LayoutEntity(layout,uid)) userCount++ post { updateLayout() } return layout }
/** * 根据uid 移除对应View */ fun removeUser(uid:String){ userLayoutList.find { it.userId==uid }?.let { userLayoutList.remove(it) userCount-- } }
//更新布局位置 private fun updateLayout(){ if (userLayoutList.isNullOrEmpty()){ return } val paramsList:ArrayList<LayoutParams> when(userCount){ 1->{ paramsList = oneUserParamList userLayoutList[0].layout?.layoutParams = paramsList[0] return } 2->{ paramsList = twoUserParamList } 3->{ paramsList = threeUserParamList } 4->{ paramsList = fourUserParamList } else->{ paramsList = nineUserParamList } } var layoutIndex = if (selfId.isEmpty()) 0 else 1 userLayoutList.forEach { if (it.userId == selfId){ it.layout?.layoutParams = paramsList[0] }else if (layoutIndex<paramsList.size){ it.layout?.layoutParams = paramsList[layoutIndex++] } }
}
private inner class LayoutEntity { var layout: GroupUserVideoLayout? = null var userId = ""
constructor(layout: GroupUserVideoLayout?, userId: String) { this.layout = layout this.userId = userId } }

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) if (widthSize == 0 && heightSize == 0) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val minSize = Math.min(measuredWidth, measuredHeight) setMeasuredDimension(minSize, minSize) return } val size: Int size = if (widthSize == 0 || heightSize == 0) { Math.max(widthSize, heightSize) } else { Math.min(widthSize, heightSize) } val newMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY) super.onMeasure(newMeasureSpec, newMeasureSpec) }
}
复制代码


​ 以上就实现了类似微信视频通话界面的自定义 View,具体使用效果会在下一期的文章所介绍的 demo 中体现~敬请期待!



发布于: 刚刚阅读数: 3
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
Android技术分享| 【Android 自定义View】多人视频通话控件_android_anyRTC开发者_InfoQ写作平台