Android技术分享| Android 自定义View多人视频通话控件
Posted anyRTC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android技术分享| Android 自定义View多人视频通话控件相关的知识,希望对你有一定的参考价值。
【android 自定义View】多人视频通话控件
*以上图片截自微信等待中界面
等待中界面
上图是微信多人视频通话时未接通的界面状态,可见每个人的 View 中大致需包含了以下元素。
- 头像
- 昵称
- Loading View
- 视频 View
- 音频状态 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中体现~敬请期待!
以上是关于Android技术分享| Android 自定义View多人视频通话控件的主要内容,如果未能解决你的问题,请参考以下文章
分享基于Android系统的XMPP即时通讯技术项目实战(仿微信开发架构,自定义控件)
Android技术分享| 自习室自定义View代替通知动画(完)