欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿微信多人音视频通话界面

程序员文章站 2022-04-28 17:45:52
工作中需要实现一个类似微信多人视频通话功能的界面,分别使用自定义viewgroup和自定义layoutmanager的方式进行了实现。最终工作中采用了layoutmanag...

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

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

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

Android仿微信多人音视频通话界面

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
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。