页面结构示意图
一、准备工作
在开始调整开播页界面前,请先参考 主播开播 完成主流程的搭建。
二、功能概览
AnchorView 提供的核心自定义接口与属性:
| 方法/属性 | 描述 |
| topRightItems | 用于灵活配置直播间右上角的按钮集合,支持自由添加自定义按钮或调整内置按钮的布局。 |
| bottomItems | 用于灵活配置直播间底部的按钮集合,支持自由添加自定义按钮或调整内置按钮的布局。 |
| replace(node: AnchorNode, view: View?) | 用于将指定位置的默认组件(例如顶部信息区、底部操作栏),替换为开发者自定义的全新视图。 |
| overlayView | 专属挂件图层,方便开发者自由添加需要在视频画面上方悬浮展示的全局业务 UI。 |
| perform(action: AnchorAction) | 用于在自定义视图中直接触发内置默认逻辑,例如显示默认观众列表,显示默认连麦管理面板等。 |
三、快速开始
下面示例快速搭建一个秀场主播工作台:
·底部栏添加美颜按钮。
·替换直播信息节点为自己业务风格的样式。
·添加“人气榜”悬浮活动挂件。
import android.view.Viewimport android.widget.Buttonimport android.widget.FrameLayoutimport com.trtc.uikit.livekit.features.anchorview.*fun setupUI(anchorView: AnchorView) { val context = anchorView.context // 步骤1:创建美颜按钮,配置按钮顺序 val beautyButton = Button(context).apply { text = "美颜" } // 依次排列:主播连麦(CoHost)、PK(Battle)、自定义美颜按钮、更多(More) anchorView.bottomItems = listOf( AnchorBottomItem.CoHost, AnchorBottomItem.Battle, AnchorBottomItem.Custom(beautyButton), AnchorBottomItem.More ) // 步骤2:调整直播间信息视图 LiveInfo 样式 val customLiveInfoView = CustomLiveInfoView(context) anchorView.replace(AnchorNode.LIVE_INFO, customLiveInfoView) // 步骤3:添加“人气榜”浮层挂件 val rankWidget = RankWidgetView(context) // 设置布局参数,贴靠在左上角下方 val params = FrameLayout.LayoutParams(dp2px(70f), dp2px(30f)).apply { topMargin = dp2px(120f) leftMargin = dp2px(12f) } // 将挂件视图添加到专属的挂件图层 anchorView.overlayView.addView(rankWidget, params)}// 辅助工具方法(示例)fun dp2px(dpValue: Float): Int { val scale = Resources.getSystem().displayMetrics.density return (dpValue * scale + 0.5f).toInt()}
四、调整底部操作按钮
底部工具栏是主播进行互动操作的核心区域。目前从左到右默认显示“主播 PK”、“连观众”、“更多”三个按钮,开发者可以通过 AnchorBottomItem.Custom(View) 插入自定义按钮,或通过 bottomItems 属性灵活增删内置功能、调整按钮顺序。
五、实现步骤
步骤1:准备自定义按钮视图。按需创建自定义按钮视图对象。
步骤2:更新底部按钮数组。组装包含 AnchorBottomItem 密封类的集合,并重新赋值给组件属性。
// 示例场景:在底部工具栏仅保留连麦功能(CoHost),并新增一个商品列表触发按钮fun adjustBottomBar(anchorView: AnchorView) { val context = anchorView.context // 步骤1:准备自定义按钮视图 val goodsButton = ImageView(context).apply { setImageResource(R.drawable.shop_cart) } // 步骤2:更新底部按钮数组 anchorView.bottomItems = listOf( AnchorBottomItem.CoHost, AnchorBottomItem.Custom(goodsButton) )}
六、调整顶部操作按钮
顶部区域通常用于展示关键的房间信息和操作。目前从左到右默认显示“观众人数、“悬浮窗”、“关闭”三个按钮,开发者可以通过 topRightItems 属性精简或增加顶部右上角的控制按钮。
七、实现步骤
·步骤 1:准备自定义按钮视图。按需创建自定义按钮视图对象。
·步骤 2:更新顶部按钮数组。组装包含 AnchorTopRightItem 密封类的集合,并重新赋值给组件属性。
// 示例场景:在右上角保留观众人数、关闭房间按钮,新增一个“举报”按钮fun adjustTopRightBar(anchorView: AnchorView) { val context = anchorView.context // 步骤1:准备自定义按钮视图 val reportButton = ImageView(context).apply { setImageResource(R.drawable.report_btn) } // 步骤2: 根据显示顺序更新顶部按钮数组 anchorView.topRightItems = listOf( AnchorTopRightItem.AudienceCount, AnchorTopRightItem.Custom(reportButton), AnchorTopRightItem.Close )}
八、替换界面指定区域视图
当调整按钮无法满足结构性修改需求(例如把页面左下角的弹幕输入框改成其他按钮)时,可使用 replace 接口整体替换指定区域的视图。
组件内部通过 AnchorNode 枚举定义了 5 个支持自定义替换的 UI 区域,可以结合开头的“页面结构示意图”理解:
| AnchorNode | 说明 |
| LIVE_INFO | 左上角的主播与房间信息展示区域。 |
| TOP_RIGHT_BUTTONS | 右上角的系统控制按钮区域。 |
| NETWORK_INFO | 网络状态指示区域。 |
| BOTTOM_RIGHT_BAR | 右下角的业务操作栏区域。 |
| BARRAGE_INPUT | 左下角的弹幕输入框触发区域。 |
九、实现步骤
·步骤 1:创建自定义视图对象。
·步骤 2:调用 AnchorView 组件的 replace 接口,传入需要替换的节点枚举和新建的自定义视图。
// 示例场景:使用自定义的直播信息视图替换默认区域fun replaceLiveInfoNode(anchorView: AnchorView) { val context = anchorView.context // 步骤1:初始化符合业务需求的自定义视图 val customInfoView = MyInfoView(context).apply { setBackgroundColor(Color.DKGRAY) } // 步骤2:调用替换接口更新特定节点 anchorView.replace(AnchorNode.LIVE_INFO, customInfoView)}
十、自定义视图布局规则
replace 接口会将自定义视图放入指定的区域。在 Android 中,你替换的 View 的尺寸通常由你为其设置的 LayoutParams 或其自身的 onMeasure 决定。推荐在自定义 View 内部使用 WRAP_CONTENT 或明确的宽高尺寸,以便它能自适应地撑开容器:
class MyInfoView(context: Context) : FrameLayout(context) { init { val label = TextView(context).apply { text = "直播中" setPadding(24, 24, 24, 24) } // 使用 WRAP_CONTENT 适应文字大小 val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) addView(label, params) }}
十一、绑定事件与触发逻辑
当开发者使用自定义视图替换了默认按钮或局部节点后,需要自行接管该视图的交互事件。在事件响应方法中,开发者可以执行专属业务逻辑,也可以使用 perform 方法快速触发 LiveKit 内部的默认逻辑。
十二、实现步骤
·步骤 1:为自定义视图绑定事件,使用 setOnClickListener 或手势识别器为视图添加点击事件。
·步骤 2:触发内置逻辑或执行业务代码,在事件回调中调用 perform 方法传入 AnchorAction 枚举,或执行其他业务代码。
// 示例场景:为自定义的直播信息视图绑定点击事件,并复用 SDK 内置的主播信息面板fun setupCustomLiveInfoNode(anchorView: AnchorView) { val customLiveInfoView = MyInfoView(anchorView.context) // 步骤1:开启用户交互并添加点击事件 customLiveInfoView.isClickable = true customLiveInfoView.setOnClickListener { // 步骤2:点击逻辑依然复用内置的主播信息弹窗 anchorView.perform(AnchorAction.SHOW_LIVE_INFO) // 或者在此处弹出你自己实现的主播信息弹窗 } anchorView.replace(AnchorNode.LIVE_INFO, customLiveInfoView)}
十三、深度定制业务弹窗
当使用 perform 触发的内置默认面板无法满足具体的业务需求时,开发者可以彻底接管这部分逻辑,基于底层数据接口 AtomicXCore 构建全新的业务面板。
十四、核心思路
开发者可使用底层数据接口 AtomicXCore 获取房间、用户及状态数据。完全自主地完成自定义视图的搭建与交互绑定。在完成自定义视图的构建后,建议使用内部封装的 AtomicPopover 组件将其弹出,以确保你的自定义面板也能获得与 SDK 内置面板一致的背景遮罩、圆角风格及平滑的进出场动画。
十五、实现步骤
·步骤 1:构建自定义业务视图。创建一个独立的 View,并在其内部引入底层核心数据接口(如 LiveAudienceStore),用于拉取或监听业务数据以驱动 UI 更新。
·步骤 2:实例化弹窗容器。实例化 AtomicPopover 对象,并指定其弹出位置(BOTTOM 或 CENTER)。
·步骤 3:配置并展示自定义视图。设置弹窗的高度模式(如按屏幕比例),将你的自定义视图通过 setContent 传入容器,最后调用 show() 进行展示。
import android.content.Contextimport android.graphics.Colorimport android.widget.FrameLayoutimport io.trtc.tuikit.atomicx.widget.basicwidget.popover.AtomicPopover// 引入底层数据接口进行业务开发import io.trtc.tuikit.atomicxcore.api.live.LiveAudienceStore // 步骤1:构建自定义业务视图(例如:观众列表)class CustomAudienceListView(context: Context) : FrameLayout(context) { init { setBackgroundColor(Color.WHITE) setupUI() bindLiveData() } private fun setupUI() { // 在此添加你的自定义 UI 控件,例如展示观众头像、用户等级等列表 } private fun bindLiveData() { // 使用 AtomicXCore 提供的核心接口获取当前房间状态或用户数据 // 例如:LiveAudienceStore.create(liveID)… // 拿到核心数据后刷新上方构建的自定义 UI }}// 示例场景:从屏幕底部向上滑出一个高度占屏幕 50% 的完全自定义面板fun presentBusinessPanel(context: Context) { // 步骤2:实例化弹窗容器,指定从底部弹出 val popover = AtomicPopover(context, AtomicPopover.PanelGravity.BOTTOM) // 步骤3:配置并展示自定义视图 // 设置面板高度为屏幕高度的 50%(也可以使用 WrapContent 自适应高度) popover.setPanelHeight(AtomicPopover.PanelHeight.Ratio(0.5f)) // 实例化自定义业务视图 val audienceListView = CustomAudienceListView(context) // 将视图填入 Popover 并展示 popover.setContent(audienceListView) popover.show()}
请参考以下文档,使用 AtomicXCore 接口实现自定义功能面板页
| 功能描述 | 参考文档 |
| 实现观众连线管理面板:连麦申请 / 邀请 / 同意 / 拒绝,连麦成员权限控制(麦克风 / 摄像头),状态同步。 | 观众连线 |
| 实现主播跨房连线面板:连线主播互动管理,发起 / 接受 / 拒绝连线。 | 主播连线和 PK |
| 实现观众列表:统计观众数量,监听观众进出事件。 | 观众列表 |
| 实现音频特效面板:变声(童声 / 男声)、混响(KTV 等)、耳返调节,实时切换特效。 | 音效 |
十六、添加自定义悬浮挂件
复杂的直播场景常需要在视频画面上方悬浮展示活动图标或互动贴纸。这类需要定位于视频层之上且独立于基础布局的视图,要添加到 overlayView 图层中。
在实际业务中,悬浮挂件通常作为某个活动面板的入口。你可以将其与上一节介绍的 AtomicPopover 结合使用:给挂件绑定点击事件,并在点击后弹出你的自定义业务弹窗。
十七、实现步骤
·步骤 1:创建挂件视图并开启交互。实例化悬浮控件,设置其尺寸与位置。
·步骤 2:绑定点击事件。为挂件添加点击事件,用于响应主播的点击操作。
·步骤 3:添加至覆盖图层并联动弹窗。将挂件添加至 overlayView 中,并在点击回调中调用前文定义的自定义弹窗逻辑。
// 示例场景:在画面左上角悬浮显示红包挂件,点击后联动弹出前文定义的业务面板fun addRedPacketWidget(anchorView: AnchorView) { val context = anchorView.context // 步骤 1:创建挂件视图并开启交互 val redPacketWidget = ImageView(context).apply { setImageResource(R.drawable.red_packet_icon) isClickable = true } // 步骤 2:绑定点击事件 redPacketWidget.setOnClickListener { presentBusinessPanel(context) } // 步骤 3:设置布局属性并添加至覆盖图层 val params = FrameLayout.LayoutParams(dp2px(60f), dp2px(60f)).apply { leftMargin = dp2px(15f) topMargin = dp2px(120f) } anchorView.overlayView.addView(redPacketWidget, params)}
十九、添加的自定义按钮为什么点击无响应
使用 AnchorBottomItem.Custom() 或自定义节点传入视图后,点击无法触发事件,通常是由以下原因引起的:
排查建议:
1. 检查交互属性:如果是原生的 ImageView 或普通的 View,确保已设置 isClickable = true(部分控件默认是不可点击的)。
2. 检查手势作用域/布局大小:确认 LayoutParams 是否正确设置。如果自定义视图的宽/高为 0,或展示范围超出了其父容器的边界,点击事件将无法被正确拦截。
3. 确认事件绑定:确认是否正确调用了 setOnClickListener 。
20、动态隐藏或显示操作按钮
在实际业务中,可能需要根据主播的等级或房间状态(例如 PK 阶段隐藏连麦按钮),动态调整底部或顶部的工具栏。
实现方案:AnchorView 的 bottomItems 和 topRightItems 属性支持响应式更新。只需组装一个新的列表集合(List)并重新赋值给该属性,SDK 内部会自动触发视图刷新,无需手动调用 invalidate() 等重绘方法。
21、替换视图后出现尺寸异常或不显示
请确保你传入的主视图通过 LayoutParams 明确了宽高(推荐使用 WRAP_CONTENT 由内部子控件撑开,或者指定明确的 dp 尺寸),避免因父容器无法计算尺寸导致不渲染。