LiveCoreView is a cross-platform core component for video live streaming that provides essential features such as starting a stream, watching, co-hosting, and host PK. With its widget mechanism, you can display real-time custom information—like username, level, and PK progress bar—directly in the video area. This guide shows you how to quickly customize video widget UIs on Android by implementing the required interfaces.Co-hosting Video Widget | PK Video Widget |
![]() | ![]() |
LiveCoreView enables custom view rendering through the VideoViewAdapter delegate. When the live streaming scenario changes (for example, when a user joins the stream or starts a PK), LiveCoreView invokes delegate methods to determine which view to display. Implement the corresponding interface methods and return your custom View instances.Method | Description | Business Scenario |
createCoGuestView | Creates the widget view for audience co-hosting. | Audience co-hosting, invite to co-hosting. |
createCoHostView | Creates the widget view for cross-room co-hosting (host co-hosting). | Host co-hosting |
createBattleView | Creates the widget view for a single user in the PK scenario (e.g., avatar, score). | Host PK |
createBattleContainerView | Creates the overall container view for the PK scenario (e.g., background, PK score bar). | Host PK |

import android.content.Contextimport android.view.Viewimport android.widget.FrameLayoutimport android.widget.ImageViewimport android.widget.TextViewclass CustomInfoView(context: Context, name: String, isMuted: Boolean) : FrameLayout(context) {private val nameTextView = TextView(context)private val muteIcon = ImageView(context)init {nameTextView.text = namemuteIcon.visibility = if (isMuted) View.VISIBLE else View.GONEaddView(nameTextView)addView(muteIcon)// Layout parameter setup code omitted here}}
import android.content.Contextimport android.widget.FrameLayoutimport android.widget.ImageViewimport android.widget.TextViewclass EmptySeatView(context: Context) : FrameLayout(context) {private val addIcon = ImageView(context)private val addLabel = TextView(context)init {addLabel.text = "Invite to co-host"// Image resource loading and layout parameter setup code omitted here}}
import android.content.Contextimport android.widget.FrameLayoutimport android.widget.ImageViewclass CustomAvatarView(context: Context, avatarURL: String) : FrameLayout(context) {private val avatarImageView = ImageView(context)init {// In actual projects, use an image loading library like Glide to load avatarURLaddView(avatarImageView)// Layout parameter setup code omitted here}}
VideoViewAdapter interface methods createCoGuestView (for audience connecting) and createCoHostView (for host connecting), returning your custom views.createCoGuestView method in VideoViewAdapter to return the audience connecting video widget.import android.content.Contextimport android.view.Viewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStatusimport io.trtc.tuikit.atomicxcore.api.live.SeatInfoimport io.trtc.tuikit.atomicxcore.api.view.VideoViewAdapterimport io.trtc.tuikit.atomicxcore.api.view.ViewLayerclass VideoWidgetAdapter(private val context: Context) : VideoViewAdapter {override fun createCoGuestView(seatInfo: SeatInfo, viewLayer: ViewLayer): View? {val isUserOnSeat = seatInfo.userInfo.userID.isNotEmpty()return when (viewLayer) {ViewLayer.FOREGROUND -> {if (isUserOnSeat) {// Non-empty seat: return custom foreground viewCustomInfoView(context, seatInfo.userInfo.userName, seatInfo.userInfo.microphoneStatus == DeviceStatus.OFF)} else {// Empty seat: return custom empty seat viewEmptySeatView(context)}}ViewLayer.BACKGROUND -> {if (isUserOnSeat) {// Return custom background view (shown when camera is off)CustomAvatarView(context, seatInfo.userInfo.avatarURL)} else {null}}}}}
createCoHostView method in VideoViewAdapter to return the host connecting video widget.import android.content.Contextimport android.view.Viewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStatusimport io.trtc.tuikit.atomicxcore.api.live.SeatInfoimport io.trtc.tuikit.atomicxcore.api.view.VideoViewAdapterimport io.trtc.tuikit.atomicxcore.api.view.ViewLayerclass VideoWidgetAdapter(private val context: Context) : VideoViewAdapter {override fun createCoHostView(seatInfo: SeatInfo, viewLayer: ViewLayer): View? {val isUserOnSeat = seatInfo.userInfo.userID.isNotEmpty()return when (viewLayer) {ViewLayer.FOREGROUND -> {if (isUserOnSeat) {// Return custom foreground view; you can use a different style from audience connectingCustomInfoView(context, seatInfo.userInfo.userName, seatInfo.userInfo.microphoneStatus == DeviceStatus.OFF)} else {// Return custom empty seat view; you can use a different style from audience connectingEmptySeatView(context)}}ViewLayer.BACKGROUND -> {if (isUserOnSeat) {// Return custom background view (shown when camera is off); you can use a different style from audience connectCustomAvatarView(context, seatInfo.userInfo.avatarURL)} else {null}}}}}
Parameter | Type | Description |
seatInfo | SeatInfo | Seat information object containing detailed info about the user on the seat. |
seatInfo.userInfo.userName | String | Nickname of the user on the seat. |
seatInfo.userInfo.avatarURL | String | Avatar URL of the user on the seat. |
seatInfo.userInfo.microphoneStatus | DeviceStatus | Microphone status of the user on the seat. |
seatInfo.userInfo.cameraStatus | DeviceStatus | Camera status of the user on the seat. |
viewLayer | ViewLayer | View layer enum. .foreground indicates the foreground widget view, always displayed on top of the video..background indicates the background widget view, located beneath the foreground view, only shown when the user has no video stream (e.g., camera is off), typically used to display the user's default avatar or placeholder image. |

import android.content.Contextimport android.widget.FrameLayoutimport android.widget.ImageView// Example: Single user score barclass MyBattleScoreView(context: Context) : FrameLayout(context) {// Internal score display logic}// Example: Global VS panelclass MyBattleContainer(context: Context) : FrameLayout(context) {private val battleTimeView = ImageView(context)// Internal countdown and VS animation logic}
VideoWidgetAdapter, implement the remaining PK view methods.class VideoWidgetAdapter(private val context: Context) : VideoViewAdapter {// createCoGuestView / createCoHostView implementation omitted...// 1. Create PK single user info widget (displayed above each host's video)override fun createBattleView(seatInfo: SeatInfo): View? {return MyBattleScoreView(context)}// 2. Create PK global container widget (displayed above the entire video area)override fun createBattleContainerView(): View? {return MyBattleContainer(context)}}
VideoWidgetAdapter with delegate logic into the core live streaming workflow.LiveCoreView and set the adapter using setVideoViewAdapter.import android.os.Bundleimport androidx.appcompat.app.AppCompatActivityimport android.view.ViewGroupimport com.trtc.uikit.livekit.features.anchorview.AnchorViewimport io.trtc.tuikit.atomicxcore.api.live.LiveInfoimport io.trtc.tuikit.atomicxcore.api.view.LiveCoreViewclass AnchorActivity : AppCompatActivity() {private lateinit var anchorView: AnchorViewprivate lateinit var widgetAdapter: VideoWidgetAdapteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// Initialize adapter objectwidgetAdapter = VideoWidgetAdapter(this)// Assume liveInfo is obtained hereval liveInfo = LiveInfo()// 1. Initialize LiveCoreView with Context onlyval videoView = LiveCoreView(this)// 2. Set the custom adaptervideoView.setVideoViewAdapter(widgetAdapter)// 3. Pass the core video component into the outer containeranchorView = AnchorView(this, liveInfo, videoView)setContentView(anchorView, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT))}}
AudienceContainerViewDelegate to handle the timing for creating the core view.import android.os.Bundleimport androidx.appcompat.app.AppCompatActivityimport io.trtc.tuikit.atomicxcore.api.live.LiveInfoimport io.trtc.tuikit.atomicxcore.api.view.LiveCoreViewclass AudienceActivity : AppCompatActivity(), AudienceContainerViewDelegate {private lateinit var audienceView: AudienceContainerViewprivate lateinit var widgetAdapter: VideoWidgetAdapteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)widgetAdapter = VideoWidgetAdapter(this)val roomId = "your_room_id"audienceView = AudienceContainerView(this, roomId)audienceView.setDelegate(this)setContentView(audienceView)}override fun onCreateCoreView(liveInfo: LiveInfo): LiveCoreView? {val view = LiveCoreView(this)// Inject adapterview.setVideoViewAdapter(widgetAdapter)return view}}
SeatInfo only provides basic seat information. To access real-time countdowns, PK scores, and other business data, connect your custom views to the core data in AtomicXCore.Store/Component | Function Description | API Documentation |
CoGuestStore | Audience connecting data: list of co-guested users, invite list, application list, etc. | |
CoHostStore | Host connecting data: list of co-hosted users, invite list, application list, etc. | |
BattleStore | PK data: current PK info, PK user list, PK score list. |
LiveCoreView before passing it into AnchorView. If AnchorView is already initialized, it will load the SDK's default widget views internally.LiveCoreView, then call setVideoViewAdapter to inject your custom UI, and finally instantiate AnchorView and pass in the configured CoreView.VideoViewAdapter operates in full takeover mode. Once you set a custom delegate, the SDK's default delegate logic inside AnchorView/AudienceView is completely overridden..FOREGROUND) are layered above the video rendering layer:CustomView has isClickable = true or a registered setOnClickListener.ViewGroup (such as FrameLayout), check whether its parent container is incorrectly intercepting touch events (for example, the outer control triggers onInterceptTouchEvent and returns true).Apakah halaman ini membantu?
Anda juga dapat Menghubungi Penjualan atau Mengirimkan Tiket untuk meminta bantuan.
masukan