Android仿微信多人音视频通话界面
程序员文章站
2022-04-28 17:45:52
工作中需要实现一个类似微信多人视频通话功能的界面,分别使用自定义viewgroup和自定义layoutmanager的方式进行了实现。最终工作中采用了layoutmanag...
工作中需要实现一个类似微信多人视频通话功能的界面,分别使用自定义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; } @override protected 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); } } } @override protected 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(); } @override public 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.customgridlayoutmanager import android.content.res.resources import android.support.v7.widget.recyclerview import java.lang.illegalargumentexception class multichatlayoutmanager : recyclerview.layoutmanager() { private var leftmargin = 0 private var rightmargin = 0 private var mscreenwidth = 0 override 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.layoutparams leftmargin = params.leftmargin rightmargin = params.rightmargin detachandscrapattachedviews(recycler) layoutitem(recycler) } private fun layoutitem(recycler: recyclerview.recycler) { if (itemcount > 9) { throw illegalargumentexception("${javaclass.simplename}最多支持9个item布局, 请检查你的item个数是否正确") } mscreenwidth = resources.getsystem().displaymetrics.widthpixels val 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 = 0 for (i in 0 until itemcount) { val view = recycler.getviewforposition(i) addview(view) // 因为detach过所以重新添加 measurechildwithmargins(view, 0, 0) if (i % 3 == 0) { currentwidth = 0 layoutdecoratedwithmargins(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 } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: flutter发送验证码功能
下一篇: Angular2搜索和重置按钮过场动画