工作中需要实现一个类似微信多人视频通话功能的界面,分别使用自定义viewgroup和自定义layoutManager的方式进行了实现。最终工作中采用了layoutManager,因为可以使用payload更新单个布局控件,效率更好。下面放出两种具体的实现效果代码。

1、使用自定义ViewGroup方式实现

下面是三个人通话时候的效果,其他的可以参考微信多人音视频通话界面。

package com.dnaer.android.telephone.widgets;import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;import com.anbetter.log.MLog;public class MultiVideoChatLayout extends ViewGroup implements CommLayoutAdapter.OnDataChangedListener {private CommLayoutAdapter mCommLayoutAdapter;private int mScreenWidth;//人数为2,3,4状态下的宽高度private int mSizeModel1;//人数为5,6,7,8,9状态下的宽高度private int mSizeModel2;public MultiVideoChatLayout(Context context) {this(context, null);}public MultiVideoChatLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MultiVideoChatLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initialize(context);}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public MultiVideoChatLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);initialize(context);}private void initialize(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics metrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(metrics);mScreenWidth = metrics.widthPixels;mSizeModel1 = mScreenWidth / 2;mSizeModel2 = mScreenWidth / 3;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//宽度默认给屏幕的宽度,高度直接取宽度,形成一个正方形final int width = MeasureSpec.makeMeasureSpec(mScreenWidth, MeasureSpec.EXACTLY);final int height = MeasureSpec.makeMeasureSpec(mScreenWidth, MeasureSpec.EXACTLY);setMeasuredDimension(width, height);MLog.d("width: " + width + ", height:" + height);final int childWidth = MeasureSpec.makeMeasureSpec(mScreenWidth / 3, MeasureSpec.EXACTLY);final int childHeight = MeasureSpec.makeMeasureSpec(mScreenWidth / 3, MeasureSpec.EXACTLY);final int childWidth2 = MeasureSpec.makeMeasureSpec(mScreenWidth / 2, MeasureSpec.EXACTLY);final int childHeight2 = MeasureSpec.makeMeasureSpec(mScreenWidth / 2, MeasureSpec.EXACTLY);if (getChildCount() > 4) {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);child.measure(childWidth, childHeight);}} else {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);child.measure(childWidth2, childHeight2);}}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if (getChildCount() <= 4) {layoutModel1();} else {layoutModel2();}}private void layoutModel2() {int currentWidth = 0;for (int i = 0; i < getChildCount(); i++) {View item = getChildAt(i);if (i % 3 == 0) {currentWidth = 0;item.layout(0, i / 3 * mSizeModel2, mSizeModel2, i / 3 * mSizeModel2 + mSizeModel2);} else {item.layout(currentWidth + mSizeModel2, i / 3 * mSizeModel2, currentWidth + 2 * mSizeModel2, i / 3 * mSizeModel2 + mSizeModel2);currentWidth = currentWidth + mSizeModel2;}}}private void layoutModel1() {if (getChildCount() == 3) {for (int i = 0; i < getChildCount(); i++) {View item = getChildAt(i);MLog.d("width: " + item.getMeasuredWidth() + ", height: " + item.getMeasuredHeight() + ", mSizeModel1: " + mSizeModel1);if (i == 0) {item.layout(0, 0, mSizeModel1, mSizeModel1);} else if (i == 1) {item.layout(mSizeModel1, 0, mSizeModel1 * 2, mSizeModel1);} else if (i == 2) {item.layout(mSizeModel1 / 2, mSizeModel1, mSizeModel1 + mSizeModel1 / 2, mSizeModel1 * 2);}}} else {for (int i = 0; i < getChildCount(); i++) {View item = getChildAt(i);if (i % 2 == 0) {item.layout(0, i / 2 * mSizeModel1, mSizeModel1, i / 2 * mSizeModel1 + mSizeModel1);} else {item.layout(mSizeModel1, i / 2 * mSizeModel1, 2 * mSizeModel1, i / 2 * mSizeModel1 + mSizeModel1);}}}}public void setAdapter(CommLayoutAdapter adapter) {mCommLayoutAdapter = adapter;mCommLayoutAdapter.setOnDataChangedListener(this);changedAdapter();}@Overridepublic void onChanged() {changedAdapter();}private void changedAdapter() {removeAllViews();CommLayoutAdapter layoutAdapter = mCommLayoutAdapter;for (int i = 0; i < layoutAdapter.getCount(); i++) {View view = layoutAdapter.getView(this, i, layoutAdapter.getItem(i));view.setDuplicateParentStateEnabled(true);addView(view);}}
}

2、使用自定义LayoutManager方式实现

package org.fireking.customgridlayoutmanagerimport android.content.res.Resources
import android.support.v7.widget.RecyclerView
import java.lang.IllegalArgumentExceptionclass MultiChatLayoutManager : RecyclerView.LayoutManager() {private var leftMargin = 0private var rightMargin = 0private var mScreenWidth = 0override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {return RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT)}override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {super.onLayoutChildren(recycler, state)if (itemCount == 0) {detachAndScrapAttachedViews(recycler!!)return}if (childCount == 0 && state!!.isPreLayout) {return}val params = recycler!!.getViewForPosition(0).layoutParams as RecyclerView.LayoutParamsleftMargin = params.leftMarginrightMargin = params.rightMargindetachAndScrapAttachedViews(recycler)layoutItem(recycler)}private fun layoutItem(recycler: RecyclerView.Recycler) {if (itemCount > 9) {throw IllegalArgumentException("${javaClass.simpleName}最多支持9个item布局, 请检查你的item个数是否正确")}mScreenWidth = Resources.getSystem().displayMetrics.widthPixelsval itemSize = if (itemCount > 4) {mScreenWidth / 3} else {mScreenWidth / 2}if (itemCount <= 4) {if (itemCount == 3) {for (i in 0 until itemCount) {val view = recycler.getViewForPosition(i)addView(view) // 因为detach过所以重新添加measureChildWithMargins(view, 0, 0)when (i) {0 -> layoutDecoratedWithMargins(view, 0, 0, itemSize, itemSize)1 -> layoutDecoratedWithMargins(view, itemSize, 0, itemSize * 2, itemSize)else -> layoutDecoratedWithMargins(view,itemSize / 2,itemSize,itemSize + itemSize / 2,itemSize * 2)}}} else {for (i in 0 until itemCount) {val view = recycler.getViewForPosition(i)addView(view) // 因为detach过所以重新添加measureChildWithMargins(view, 0, 0)if (i % 2 == 0) {layoutDecoratedWithMargins(view, 0, i / 2 * itemSize, itemSize, i / 2 * itemSize + itemSize)} else {layoutDecoratedWithMargins(view,itemSize,i / 2 * itemSize,2 * itemSize,i / 2 * itemSize + itemSize)}}}} else {var currentWidth = 0for (i in 0 until itemCount) {val view = recycler.getViewForPosition(i)addView(view) // 因为detach过所以重新添加measureChildWithMargins(view, 0, 0)if (i % 3 == 0) {currentWidth = 0layoutDecoratedWithMargins(view, 0, i / 3 * itemSize, itemSize, i / 3 * itemSize + itemSize)} else {layoutDecoratedWithMargins(view,currentWidth + itemSize,i / 3 * itemSize,currentWidth + 2 * itemSize,i / 3 * itemSize + itemSize)currentWidth += itemSize}}}}//因为这个布局不需要有滚动,所以直接将横竖两个方向的滚动全部取消了override fun canScrollHorizontally(): Boolean {return false}override fun canScrollVertically(): Boolean {return false}
}

仿微信多人音视频通话界面相关推荐

  1. android 微信缩小通话界面_Android仿微信多人音视频通话界面

    工作中需要实现一个类似微信多人视频通话功能的界面,分别使用自定义viewgroup和自定义layoutmanager的方式进行了实现.最终工作中采用了layoutmanager,因为可以使用paylo ...

  2. linux 视频电话,多人音视频通话-Linux开发集成-SDK开发集成-音视频通话-网易云信开发文档...

    多人音视频通话 本章节介绍多人实时音视频通话的相关功能.多人实时音视频通话顾名思义是支持多个人同时进行实时音视频通话,可以选择纯音频模式,或音视频模式.在这里需要明确几个概念: 房间:房间就是用户进行 ...

  3. 基于zxing的仿微信二维码扫描界面

    基于zxing的仿微信二维码扫描界面 https://github.com/iamlocky/ZxingLite 本项目fork自yangxixi88/ZxingLite,在原项目基础上添加了本地图片 ...

  4. 基于TRTCCalling快速实现多人音视频通话

    TRTCCalling SDK 基于 TRTC 和 TSignaling ,封装了简单易用的 API,接入后可快速实现 web 和 native 互通的1v1或群实时通话. 效果展示 群视频通话 语音 ...

  5. ReactNative聊天APP实战|仿微信聊天/朋友圈/红包界面

    项目简介 最近一直在研究RN技术,想着找个项目练练手,之前就有使用vue.react技术开发过聊天项目,这次就使用reactNative技术开发个仿微信RN版.是基于 react-native+rea ...

  6. vue + node + webrtc 实现多人音视频通话

    最近在搞一个内网音视频通话的功能,最终确定前端要用webrtc去实现,网上关于webrtc的文章不是很多,想找一个demo也很难,最终在gitee上找到一个大佬写的,很符合目前需求,前端js后台是no ...

  7. 极致体验,解密微信背后的音视频通话技术

    近两年,音视频技术展现了迅猛的发展势头,在短视频.直播.在线会议.教育等行业都有亮眼的应用案例,已经逐渐成为新时代互联网的基础设施之一,从而使得市场对于视频研发人才的需求越来越旺盛. 最直观的感受就是 ...

  8. 仿微信字母快速查找联系人界面

    今天和同学用微信聊天,觉得微信联系人右边的字母快速索引挺方便快捷的.高大上.... 于是就想着自己也弄一个 首先,这个肯定是一个自定义控件,需要自己绘制A-Z等字母,其次需要自己处理触摸或点击事件 对 ...

  9. android仿微信、QQ等聊天界面,实现点击输入框弹出软键盘、点击其他区域收起软键盘,默认滑动至最低端

    如图所示,点击输入框及选择图片和发送按钮时软键盘显示且不消失,点击其他区域,则隐藏软键盘. 主要代码如下: override fun dispatchTouchEvent(ev: MotionEven ...

最新文章

  1. CSDN 给你一个薅羊毛的机会!你真的不要吗?
  2. moa 35 批量删除
  3. 推荐算法炼丹笔记:序列化推荐算法Bert4Rec
  4. 3.3亿人都在用小程序,中国首次定义的互联网标准又有新进展
  5. Django新手图文教程
  6. 最新版Eclipse下载及安装(详细)
  7. 向jre中添加安全证书
  8. 超定方程 matlab,Matlab求解超定方程组实例(精品文档)
  9. 短时傅里叶变换(Short Time Fourier Transform)
  10. 经典网页设计:10个优秀的国外企业网站设计案例
  11. C语言中的常量与变量
  12. Java基础知识笔记
  13. 爬虫3_获取汇率数据
  14. 双目立体视觉几何框架详解
  15. miui android 7.1,小米MIUI7.1稳定版固件下载 MIUI7.1稳定版完整刷机包下载
  16. 商用室内机器人才是未来机器人开发的热点与趋势
  17. TimeWheel时间轮算法原理及实现(附源码)
  18. Unknown tag (c:forEach) 未知的标签 解决方法
  19. 小程序服务商申请入口_[小程序开发服务商]第三方小程序(服务商) | 微信开放文档...
  20. 解决idea 搜狗输入法 光标不跟随问题

热门文章

  1. 数据库上机试验(二)
  2. VIO残差函数的构建以及IMU预积分和协方差传递
  3. 使用Scratch制作打弹球游戏(三 )-过关增加难度
  4. java将16进制与10进制互相转换
  5. 数据分析思维(一)|信度与效度思维
  6. Chrome找到视频缓存的方法
  7. java token guid_尝试调用Microsoft Graph客户端时出现InvalidAuthenticationToken
  8. python零基础入门书籍-零基础python入门书籍推荐读哪些书?
  9. 试用炎黄盈动Sam业务流程梳理工具
  10. Self-Attention Generative Adversarial Networks