【Android技术分享| 开源Demo any自习室布局架构】大鹏一日同风起,扶摇直上九万里。这篇文章主要讲述Android技术分享| 开源Demo any自习室布局架构相关的知识,希望能为你提供帮助。
需求
文章图片
文章图片
分析
- 布局分为横竖屏
- 涉及到视频窗口的大小、位置切换
- 4个视频窗口
- 1个title,显示「XX号房间」
- 1个ViewGroup,放置「头像,头像,头像,N个观众」
- 另1个ViewGroup,放置聊天窗口相关
文章图片
< p style=" color: #999999; font-size: 12px; text-align: center; " > (请无视中间那个小眼睛)< /p>
但因为横屏之后依然有聊天功能,不调用系统的旋转,输入法依然还是竖屏的形式弹出来的。暂时没有查到解决办法。无奈改为使用系统的横竖屏切换,切换时通知ViewGroup重新计算测量、布局子View。
实现
首先我们复写
onMeasure
方法,遍历子View测量,指定为我们计算后的宽高,Mode设置为EXACTLY。override fun onMeasure(widthSpace: Int, heightSpace: Int) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)isVertical = height >
widthif (!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 (child.tag == null) {
val location = createAndCalcCoordinates(child, i, width, height)
if (location.fromLeft == 0 &
&
location.fromRight == 0) location.run {
fromLeft = toLeft
fromTop = toTop
fromRight = toRight
fromBottom = toBottom
}
location
} else {
child.tag as ViewLocation
}child.tag = location
child.measure(
MeasureSpec.makeMeasureSpec(location.right - location.left, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(location.bottom - location.top, MeasureSpec.EXACTLY)
)
}setMeasuredDimension(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
)
}
其中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 = child.tag as ViewLocationchild.layout(location.left, location.top, location.right, location.bottom)
}
}
计算子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 = -1val videoWidth = measuredWidth.shr(1)
val videoHeight = (videoWidth.toFloat() * 0.6882f).toInt()val arr = arrayOfNulls<
ViewLocation>
(childCount)
for (i in 0 until childCount) {
val location = getChildLocationAndResetFromLocations(i)
arr[i] = locationval remainder = (i % 2)
when (i) {
in 0..3 ->
location.run {
toLeft = remainder * videoWidth + remainder * videoViewSpacing.shr(1)
toTop = (if (i >
= 2) i / 2 else 0) * (videoViewSpacing + videoHeight) + titleHeight
toRight = toLeft + videoWidth - ((i + 1) % 2) * videoViewSpacing.shr(1)
toBottom = toTop + videoHeight
}
5 ->
location.run {
toTop = titleHeight + videoHeight.shl(1) + videoViewSpacing
toBottom = toTop + titleHeight
}
6 ->
location.run {
toTop = titleHeight.shl(1) + videoHeight.shl(1) + videoViewSpacing
}
}
}post(AnimRunnable(arr.map { it!! }.toTypedArray(), mDuration = 200L, isRotation = false))
}
最终效果
文章图片
推荐阅读
- 网络--七层,五层,协议,封装,解封装,UDP,设备对应关系
- 九大数据分析方法之(周期性分析法)
- 浅析 DDD 领域驱动设计
- 赵强老师史上最详细的PostgreSQL体系架构介绍
- 精品RestTemplate工具类及使用
- 百度短视频推荐系统的目标设计
- 你知道怎么修改pycharm编辑器嘛(简单的四步教你搞定界面风格修改)
- 职责链的应用
- 红帽Linux入门指南第五期(Linux文件权限管理)