自定义viewgroup的方法有什么(自定义viewgroup教程)

两种显示方式: 主播全屏,其他游客悬浮在右侧。下面简称大小屏模式。所有人等分屏幕。下面简称等分模式。 分析 最多4人连麦,明确这点方便定制坐标算法。自定义的ViewGroup最好分别提供等分模式和大小屏模式的边距设置接口,便于修改。SDK自己管理了TextureView的绘制和测量,所以ViewGroup需要复写onMeasure方法以通知TextureView测量和绘制。一个计算0.0f~1.0…

二种显示方式:

  1. 网络主播全屏幕,别的游人飘浮在右边。下边通称尺寸屏模式。
  2. 每个人等分显示屏。下边通称等分模式。
Android技术分享|自定义ViewGroup实现直播间大小屏无缝切换
Android技术分享|自定义ViewGroup实现直播间大小屏无缝切换

剖析

  • 较多4人连麦直播,确立这一点便捷定制座标优化算法。
  • 自定的 ViewGroup 最好是各自给予等分模式和尺寸屏模式的行高设定插口,有利于改动。
  • SDK 自身管理方法了 TextureView 的绘图和精确测量,因此 ViewGroup 必须复写 onMeasure 方式以通告 TextureView 精确测量和制作。
  • 一个测算 0.0f ~ 1.0f 慢慢降速的函数公式,给动画全过程做支撑点。
  • 一个纪录座标的数据模型。和一个依据目前 Child View 的数目测算二种合理布局模式下,每一个 View 放置位子的函数公式。

完成

1.界定座标数据模型

private data class ViewLayoutInfo(
    var originalLeft: Int = 0,// original开始的为动画逐渐前的起始值
    var originalTop: Int = 0,
    var originalRight: Int = 0,
    var originalBottom: Int = 0,
    var left: Float = 0.0f,// 无作为前缀的为动画全过程中的临时性值
    var top: Float = 0.0f,
    var right: Float = 0.0f,
    var bottom: Float = 0.0f,
    var toLeft: Int = 0,// to开始的为动画目标
    var toTop: Int = 0,
    var toRight: Int = 0,
    var toBottom: Int = 0,
    var progress: Float = 0.0f,// 进展 0.0f ~ 1.0f,用以操纵 Alpha 动画
    var isAlpha: Boolean = false,// 全透明动画,新加入的实行此动画
    var isConverted: Boolean = false,// 操纵 progress 翻转的标识
    var waitingDestroy: Boolean = false,// 完毕后消毁 View 的标识
    var pos: Int = 0// 纪录自身数据库索引,便于消毁
) {
    init {
        left = originalLeft.toFloat()
        top = originalTop.toFloat()
        right = originalRight.toFloat()
        bottom = originalBottom.toFloat()
    }
}

以上,纪录了实行动画和消毁View需要的数据信息。(于源代码中第352行)

2.测算不一样展现模式下View座标的函数公式

if (layoutTopicMode) {
    var index = 0
    for (i in 1 until childCount) if (i != position) (getChildAt(i).tag as ViewLayoutInfo).run {
        toLeft = measuredWidth - maxWidgetPadding - smallViewWidth
        toTop = defMultipleVideosTopPadding   index * smallViewHeight   index * maxWidgetPadding
        toRight = measuredWidth - maxWidgetPadding
        toBottom = toTop   smallViewHeight
        index  
    }
} else {
    var posOffset = 0
    var pos = 0
    if (childCount == 4) {
        posOffset = 2
        pos  
        (getChildAt(0).tag as ViewLayoutInfo).run {
            toLeft = measuredWidth.shr(1) - multiViewWidth.shr(1)
            toTop = defMultipleVideosTopPadding
            toRight = measuredWidth.shr(1)   multiViewWidth.shr(1)
            toBottom = defMultipleVideosTopPadding   multiViewHeight
        }
    }
    for (i in pos until childCount) if (i != position) {
        val topFloor = posOffset / 2
        val leftFloor = posOffset % 2
        (getChildAt(i).tag as ViewLayoutInfo).run {
            toLeft = leftFloor * measuredWidth.shr(1)   leftFloor * multipleWidgetPadding
            toTop = topFloor * multiViewHeight   topFloor * multipleWidgetPadding   defMultipleVideosTopPadding
            toRight = toLeft   multiViewWidth
            toBottom = toTop   multiViewHeight
        }
        posOffset  
    }
}

post(AnimThread(
    (0 until childCount).map { getChildAt(it).tag as ViewLayoutInfo }.toTypedArray()
))

Demo源码中的add、remove、toggle方式反复编码太多,未都还没提升。这儿只另附 addVideoView 中的测算一部分(于源码中第141行),只需略微改动就可以适用add、remove和toggle。(也可参照 CDNLiveVM 中的 calcPosition 方式,为通过改进的版本号)layoutTopicMode = true 时,为尺寸屏模式。

因为是定制优化算法,只有适用这一种合理布局,故不写注解。只需确立一点,此方式最后目标是为了更好地测算出每一个View现阶段应当发生的部位,储存到上边定位的数据模型中并打开动画(最终一行 post AnimThread 为打开动画的编码,我这里是根据 post 一个进程来升级每一帧)。

可依据不一样的要求写不一样的完成,最后合乎界定的数据模型就可以。

3.慢慢降速的优化算法,使动画实际效果看上去更当然。

private inner class AnimThread(
    private val viewInfoList: Array<ViewLayoutInfo>,
    private var duration: Float = 180.0f,
    private var processing: Float = 0.0f
) : Runnable {
    private val waitingTime = 9L
    override fun run() {
        var progress = processing / duration
        if (progress > 1.0f) {
            progress = 1.0f
        }
        for (viewInfo in viewInfoList) {
            if (viewInfo.isAlpha) {
                viewInfo.progress = progress
            } else viewInfo.run {
                val diffLeft = (toLeft - originalLeft) * progress
                val diffTop = (toTop - originalTop) * progress
                val diffRight = (toRight - originalRight) * progress
                val diffBottom = (toBottom - originalBottom) * progress                left = originalLeft   diffLeft
                top = originalTop   diffTop
                right = originalRight   diffRight
                bottom = originalBottom   diffBottom
            }
        }
        requestLayout()
        if (progress < 1.0f) {
            if (progress > 0.8f) {
                var offset = ((progress - 0.7f) / 0.25f)
                if (offset > 1.0f)
                    offset = 1.0f
                processing  = waitingTime - waitingTime * progress * 0.95f * offset
            } else {
                processing  = waitingTime
            }
            postDelayed(this@AnimThread, waitingTime)
        } else {
            for (viewInfo in viewInfoList) {
                if (viewInfo.waitingDestroy) {
                    removeViewAt(viewInfo.pos)
                } else viewInfo.run {
                    processing = 0.0f
                    duration = 0.0f
                    originalLeft = left.toInt()
                    originalTop = top.toInt()
                    originalRight = right.toInt()
                    originalBottom = bottom.toInt()
                    isAlpha = false
                    isConverted = false
                }
            }
            animRunning = false
            processing = duration
            if (!taskLink.isEmpty()) {
                invokeLinkedTask()// 此方式实行已经准备中的每日任务,从源代码里能见到,remove、add等函数公式必须先后实行,前一个动漫未实行结束就开展下一个动漫很有可能会致使不能预见的不正确。
            }
        }
    }
}

以上编码除开给予降速优化算法,还一并升级了相匹配View数据库系统的中心值,也就是实体模型界定种的 left, top, right, bottom 。

根据降速优化算法给予的进展值,乘于总体目标座标与开始座标的间隔,得到正中间值。

慢慢降速的优化算法重要编码为:

if (progress > 0.8f) {
    var offset = ((progress - 0.7f) / 0.25f)
    if (offset > 1.0f)
        offset = 1.0f
    processing  = waitingTime - waitingTime * progress * 0.95f * offset
} else {
    processing  = waitingTime
}

这一优化算法完成的有缺陷,因为它立即改动了进展時间,大概率会造成实行结束的时间段与设定的预估時间(如设定200ms实行结束,具体很有可能超出200ms)不符合。文尾我能给予一个提升的降速优化算法。

自变量 waitingTime 表明等候多长时间实行下一帧动画。用每秒钟1000ms测算就可以,假如方向为60刷新频率的动漫,设定为1000 / 60 = 16.66667就可以(近似值)。

测算并储存每一个 View 的中心值后,启用 requestLayout() 通告操作系统的 onMeasure 和 onLayout 方式,再次放置 View 。

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    if (childCount == 0)
        return
    for (i in 0 until childCount) {
        val child = getChildAt(i)
        val layoutInfo = child.tag as ViewLayoutInfo
        child.layout(
            layoutInfo.left.toInt(),
            layoutInfo.top.toInt(),
            layoutInfo.right.toInt(),
            layoutInfo.bottom.toInt()
        )
        if (layoutInfo.isAlpha) {
            val progress = if (layoutInfo.isConverted)
                1.0f - layoutInfo.progress
            else
                layoutInfo.progress
            child.alpha = progress
        }
    }
}

4.界定行高有关的自变量,供简易的订制改动

/**
 * @param multipleWidgetPadding : 等分方式载入
 * @param maxWidgetPadding : 尺寸屏合理布局载入
 * @param defMultipleVideosTopPadding : 间距顶端变距
 */
private var multipleWidgetPadding = 0
private var maxWidgetPadding = 0
private var defMultipleVideosTopPadding = 0
init {
    viewTreeObserver.addOnGlobalLayoutListener(this)
    attrs?.let {
        val typedArray = resources.obtainAttributes(it, R.styleable.AnyVideoGroup)
        multipleWidgetPadding = typedArray.getDimensionPixelOffset(
            R.styleable.AnyVideoGroup_between23viewsPadding, 0
        )
        maxWidgetPadding = typedArray.getDimensionPixelOffset(
            R.styleable.AnyVideoGroup_at4smallViewsPadding, 0
        )
        defMultipleVideosTopPadding = typedArray.getDimensionPixelOffset(
            R.styleable.AnyVideoGroup_defMultipleVideosTopPadding, 0
        )
        layoutTopicMode = typedArray.getBoolean(
            R.styleable.AnyVideoGroup_initTopicMode, layoutTopicMode
        )
        typedArray.recycle()
    }
}

取名字时对这三个自变量的岗位职责界定,与撰写逻辑性时的界定有出入,因此有点儿词不达意,需参照注解。

因为这仅仅订制化的自变量,并不重要,可依据领域模型自主随便改动。

5.复写 onMeasure 方式,这儿主要是通告 TextureView 升级尺寸。

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val widthSize = MeasureSpec.getSize(widthMeasureSpec)
    val heightSize = MeasureSpec.getSize(heightMeasureSpec)
    multiViewWidth = widthSize.shr(1)
    multiViewHeight = (multiViewWidth.toFloat() * 1.33334f).toInt()
    smallViewWidth = (widthSize * 0.3125f).toInt()
    smallViewHeight = (smallViewWidth.toFloat() * 1.33334f).toInt()
    for (i in 0 until childCount) {
        val child = getChildAt(i)
        val info = child.tag as ViewLayoutInfo
        child.measure(
            MeasureSpec.makeMeasureSpec((info.right - info.left).toInt(), MeasureSpec.EXACTLY),
            MeasureSpec.makeMeasureSpec((info.bottom - info.top).toInt(), MeasureSpec.EXACTLY)
        )
    }
    setMeasuredDimension(
        MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)
    )
}

汇总

1.确立数据模型,一般情形下纪录开始前后左右坐标、总体目标前后左右坐标、和进展百分数就足够了。

2.依据要求确立动漫算法,这儿填补一下提升的降速算法:

factor = 1.0
if (factor == 1.0)
    (1.0 - (1.0 - x) * (1.0 - x))
else
    (1.0 - pow((1.0 - x), 2 * factor))
// x = time.

3.依据算法计算出来的值升级 layout 合理布局就可以。

该类 ViewGroup 完成简易便捷,只涉及到好多个基本上系统软件API。如不愿写 onMeasure 方式可承继 FrameLayout 等已写好 onMeasure 完成的 ViewGroup 。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

(0)
上一篇 2022年5月8日 上午10:37
下一篇 2022年5月8日 上午10:39

相关推荐

  • 电话机器人怎么样,其使用效果及收费标准介绍

    人们对于价格的认识总是需要一个锚点,一个新产品一个新事物,价格总会是乱的。 如果把人工的价格作为锚点,那么一个机器人20万每年都可以,因为它的价值确实是可以达到,一个机器人就相当于4个人工作量,一个人工每年算5万,那么机器人每年20万也是说的过去的。 但是充分竞争的市场经济下,往往会考虑到成本及竞争的因素来确定价格。下面我们可以看看市场上都有多少价格产品(都是首次报价的价格,具体谈价格不知道是否可…

    2022年6月5日
    650
  • 为什么微信聊天记录会消失,教你一招快速恢复

    苹果微信聊天记录一下子就不见了,发现了个神奇方法解决?说起微信大家再熟悉不过了,使用微信的用户也在逐年增长。微信的小程序在不断开发,相信不少朋友在使用了吧!在使用微信的过程中,如果遇到聊天记录误删的情况大家会怎么做呢?怎样才能将它找回呢? 第一步:在电脑上安装最新版本的iTunes软件,使用该软件备份苹果手机数据。 第二步:打开安装好的互盾苹果恢复大师,在主界面可以看到两种恢复模式。因为已经用iT…

    2022年6月19日
    1040
  • 虚拟主机怎么用,虚拟主机的功能及正确使用方法介绍

    我们常在需要制作网站的时候,询问专业的公司或者技术,都需要购买一个虚拟主机用来放置网站系统。那么,虚拟主机究竟是什么呢? 某数据中心机柜 虚拟主机,也叫“网站虚拟空间”,就是把一台运行在互联网上的物理服务器或云服务器划分成多个小型的“虚拟”服务器。 虚拟主机相较于独立的服务器而言,价格成本及迅速上架的效率都相对较高。因为其方便快捷,小型网站的快速上线,使用虚拟主机更为方便。 一般虚拟主机主要分为独…

    2022年7月24日
    850
  • 滴滴打车网站网址是什么,嘀嘀打车商业模式介绍

    9月6日消息,亿邦动力网获悉,日前滴滴打车APP主页面更换新海报,上面写着滴滴再见,只为和你走更远。相约9月9日,不见不散。据悉,滴滴打车将更换品牌名和LOGO。 据亿邦动力网了解,滴滴打车公司成立于2012年6月6日,其APP上线于同年9月9日,2015年9月9日恰逢滴滴打车APP上线三周年纪念日。 业内人士分析,此次滴滴更换品牌名及LOGO,意在扩大战略方向,涉及全部出行领域。更换的新品牌名,…

    2022年8月25日
    590
  • 苹果歌曲怎么下载到本地,只需一招就能搞定

    如何用iPhone下载网页上视频、音乐等资源? 如果想把网页上的视频或者音乐等资源下载到iPhone,今天推荐你几款可用的工具:FoxFM-FileManager、DManager、DocumentsbyReaddle。 以FoxFM-FileManager为例,安装之后打开软件自带的“浏览器”,进入任意页面并播放视频,软件会自动弹出下载提示框,点击下载即可;按照同样的操作,你也可以下载音频文件。…

    2022年9月30日
    1830
  • 学术推广是干什么的,简述学术推广和医药代表的区别

    这是一场非常独特的直播课程 非常契合当下时疫形势 由三甲医院在职主任分享 完全公立、不推荐任何线上学术平台 实打实告诉你现在医院的真实情况 企业开展学术机会点、突破点 以及线上线下融合的学术推广策略 主任拥有药企工作经历 曾为多家知名中外药企提供学术指导 他从医院临床医学、药学角度出发的学术策略 是原始的、真实的、有针对性的市场策略 非常适合处方药企业销售、市场、医学部门人员组团学习 本课结束后将…

    2022年6月20日
    810
  • 如何做品牌定位,品牌的六大理论

    品牌定位是对细分市场的产品或服务在目标顾客的脑海里确定一个合理的位置。定位的基本原则不是去创造某种新奇的或与众不同的东西,而是去操纵人们心中原本的想法,去打开联想之结。 品牌定位的目的就是将产品或服务转化为品牌,为品牌确定一个适当的市场位置,反映品牌在顾客头脑中形成具体而确切的含义,使产品或服务在顾客的心智中占领一个独特的地位。 品牌定位能够使企业与顾客建立长期稳定的关系,为企业产品或服务的开发和…

    2022年7月30日
    450
  • 小米否认裁员10%(创业至今未出现过裁员情况)

    Tech星球2月14日消息,近日,有传闻称小米计划裁员10%,HR已经开始约谈。在此传闻之前已经有小米员工在网上吐槽,企业年终考核强制将绩效分为C的比例,设为强制性的10%的消息。 对此,网易科技向小米方面求证,对方表示小米创业至今尚未出现过裁员的情况,而且目前小米有超过4000个热门岗位依然在广纳贤才,小米欢迎优秀人才的加入。 不仅如此,此前小米的离职老员工近日还收到短信消息称小米的大门永远敞开…

    2022年5月12日
    820
  • app推广获客的方法有哪些,4种推广获客渠道介绍

    随着App开发技术的发展与开发成本的降低,越来越多的互联网企业都会开发属于自己的App,现在打开iOS或者Android的应用商店,都能看到各种各样数不清的App应用,但是决定App发展的关键在于新用户的获取,也就是拉新,App能否获得用户的信赖,才是App发展的根本。本文分享的是关于APP推广的主流获客渠道和方法,找准目标用户群体,转化为自己产品的用户,实现APP的快速发展。 主流的App获客渠…

    2022年5月26日
    630
  • 市场营销学什么专业,市场营销专业的前景分析

    一、市场营销的定义: 市场营销(Marketing),又称作市场学、市场行销或行销学,MBA、EMBA等经典商管课程均将市场营销作为对管理者进行管理和教育的重要模块包含在内。 市场营销是在创造、沟通、传播和交换产品中,为顾客、客户、合作伙伴以及整个社会带来经济价值的活动、过程和体系。主要是指营销人员针对市场开展经营活动、销售行为的过程。 二、市场营销的特点: 1)市场营销的第一目的是创造顾客,获取…

    2022年6月19日
    640

发表回复

登录后才能评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信