您的位置 首页 > 数码极客

[android开发框架]android界面开发框架

需求

分析

  • 布局分为横竖屏
  • 涉及到视频窗口的大小、位置切换

通过观察需求原型图可得知,横竖屏切换可以简单分成7块区域

  • 4个视频窗口
  • 1个title,显示「XX号房间」
  • 1个ViewGroup,放置「头像,头像,头像,N个观众」
  • 另1个ViewGroup,放置聊天窗口相关

横竖屏切一开始我的思路是完全不使用系统的横竖屏切换,使用rotation来切换横竖屏,切换过程添加一个转换动画,如下图所示:

(请无视中间那个小眼睛)

但因为横屏之后依然有聊天功能,不调用系统的旋转,输入法依然还是竖屏的形式弹出来的。暂时没有查到解决办法。无奈改为使用系统的横竖屏切换,切换时通知ViewGroup重新计算测量、布局子View。

实现

首先我们复写onMeasure方法,遍历子View测量,指定为我们计算后的宽高,Mode设置为EXACTLY。

override fun onMeasure(widthSpace: Int, heightSpace: Int) { val width = Mea(widthMeasureSpec) val height = Mea(heightMeasureSpec) isVertical = height > width if (!isVertical) { videosWidth = (width * 0.548f).toInt() horizontalSmallVideoWidth = (videosWidth / 3.0f).toInt() horizontalSmallVideoHeight = (horizontalSmallVideoWidth * 0.6803f).toInt() topicViewHeight = height - horizontalSmallVideoHeight - videoViewSpacing } for (i in 0 until childCount) { val child = getChildAt(i) val location = if == null) { val location = createAndCalcCoordinates(child, i, width, height) if == 0 && loca == 0) loca { fromLeft = toLeft fromTop = toTop fromRight = toRight fromBottom = toBottom } location } else { c as ViewLocation } c = location c( Mea - loca, Mea), Mea - loca, Mea) ) } setMeasuredDimension( Mea(width, Mea), Mea(height, Mea) ) }

其中ViewLocalion对象存储了View四个边的位置(left、top、right、bottom)。 首次加载时创建ViewLocation对象,并根据横竖屏计算每个View的坐标,最终对象会存储到View的tag中。再次触发onMeasure时不会重新计算布局,而是沿用之前的坐标数据。

计算子View位置的函数只会在横竖屏切换、用户点击切换视频位置或大小时调用。

在onLayout中遍历子View,通知布局并传入对应的四边位置即可。

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { for (i in 0 until childCount) { val child = getChildAt(i) val location = c as ViewLocation c(loca, loca, loca, loca) } }

计算子View位置的算法可以点击这里()查看,就不贴出来了。有一个需要注意的细节是:更新View坐标(除横竖屏切换)时,实际更改的是目标坐标,而非当前坐标,这样做的目的是为了实现动画效果。

当前坐标指的是在onMeasure和onLayout中使用的变量:left、top、right、bottom。 目标坐标表示动画执行完毕后View的位置。

执行动画与坐标计算充分解耦,无论想新增怎样的动画(平移、缩放),只需要根据需求计算好左、上、右、下的位置,发送给动画执行的Runnable即可。

如切换大屏View的计算:

fun toEquallyDividedVideos() { if (isAnimRunning) { return } if (!isVertical/* || !isSmallMode*/) { return } isAnimRunning = true isSmallMode = false topicIndex = -1 val videoWidth = mea(1) val videoHeight = () * 0.6882f).toInt() val arr = arrayOfNulls<ViewLocation>(childCount) for (i in 0 until childCount) { val location = getChildLocationAndResetFromLocations(i) arr[i] = location val remainder = (i % 2) when (i) { in 0..3 -> loca { toLeft = remainder * videoWidth + remainder * videoViewS(1) toTop = (if (i >= 2) i / 2 else 0) * (videoViewSpacing + videoHeight) + titleHeight toRight = toLeft + videoWidth - ((i + 1) % 2) * videoViewS(1) toBottom = toTop + videoHeight } 5 -> loca { toTop = titleHeight + videoHeig(1) + videoViewSpacing toBottom = toTop + titleHeight } 6 -> loca { toTop = titleHeig(1) + videoHeig(1) + videoViewSpacing } } } post(AnimRunnable { it!! }.toTypedArray(), mDuration = 200L, isRotation = false)) }

最终效果

关于作者: admin

无忧经验小编鲁达,内容侵删请Email至wohenlihai#qq.com(#改为@)

热门推荐