
Method | Description |
audienceView(_:onCreateLiveView liveView:for:) | View Creation Callback. Returns the newly instantiated AudienceLiveView. Use for static style customization determined in advance. Because the container preloads the next room, the view may not be visible yet when this callback fires. Typically, use liveView here to replace built-in components, configure fixed buttons, and perform one-time layout operations. |
audienceView(_:liveViewDidAppear liveView:for:) | View Display Callback. Returns the AudienceLiveView currently visible on screen. Use for dynamic adjustments based on real-time status or signaling. Usually, record the currently active liveView instance here. When business signaling is received (such as product listing notifications), you can accurately update the UI currently on screen, or start room-specific timers and animations. |
audienceView(_:liveViewDidDisappear liveView:for:) | View Hide Callback. Triggered when the audience swipes out of the room or closes the interface. Use for state reset and resource cleanup. Typically, clear the active liveView record here, destroy custom business panels shown in the room, stop animations, or clean up timers. |
Method/Property | Description |
topRightItems | Flexible configuration for the set of buttons in the top right corner of the live room. Add custom buttons or adjust the layout of built-in buttons. |
bottomItems | Flexible configuration for the set of buttons at the bottom of the live room. Add custom buttons or adjust the layout of built-in buttons. |
replace(node:with:) | Replace the default component at a specified location (such as the top info area or bottom action bar) with a fully custom view. |
overlayView | A dedicated widget layer for adding global business UI that floats above the video. |
perform(action:) | Directly trigger built-in default logic from custom views, such as displaying the default audience list or the default co-host management panel. |
import UIKitimport TUILiveKitimport SnapKitclass AudienceViewController: UIViewController {weak var currentLiveView: AudienceLiveView?override func viewDidLoad() {super.viewDidLoad()// Step 1: Initialize AudienceView and add it to the current controllerlet audienceView = AudienceView(roomId: "your_room_id")audienceView.delegate = selfview.addSubview(audienceView)audienceView.frame = view.bounds}// Business method: Show product list pagefunc showProductListPanel() {print("Show product list page...")}// Business method: Simulate receiving IM product push notificationfunc onReceiveProductPushMessage() {// Step 5: When dynamically updating UI via signaling, operate on the currently displayed liveViewguard let liveView = currentLiveView else { return }let productCard = AudienceProductCardView() // Custom product card viewlet productTap = UITapGestureRecognizer(target: self, action: #selector(onProductCardTapped))productCard.addGestureRecognizer(productTap)liveView.overlayView.addSubview(productCard)productCard.snp.makeConstraints { make inmake.trailing.equalToSuperview().offset(-12)make.bottom.equalToSuperview().offset(-100)make.width.equalTo(150)}}}extension AudienceViewController: AudienceViewDelegate {// Step 2: Perform static UI style configuration in the creation callbackfunc audienceView(_ audienceView: AudienceView, onCreateLiveView liveView: AudienceLiveView, for liveInfo: LiveInfo) {// Configure bottom action bar: Hide co-host feature and add custom "shopping cart" buttonlet shopCartBtn = UIButton(type: .custom)shopCartBtn.setImage(UIImage(named: "shop_cart_icon"), for: .normal)shopCartBtn.addTarget(self, action: #selector(onShopCartTapped), for: .touchUpInside)// Rearrange the bottom bar: Keep gift and like, insert shopping cart button (not declaring .coGuest hides co-host)liveView.bottomItems = [.gift, .like, .custom(shopCartBtn)]}// Step 3: Record the currently active view in the display callback for dynamic signaling updatesfunc audienceView(_ audienceView: AudienceView, liveViewDidAppear liveView: AudienceLiveView, for liveInfo: LiveInfo) {self.currentLiveView = liveView}// Step 4: Clean up business state or destroy popups in the hide callback to prevent state confusion caused by view reusefunc audienceView(_ audienceView: AudienceView, liveViewDidDisappear liveView: AudienceLiveView, for liveInfo: LiveInfo) {if self.currentLiveView === liveView {self.currentLiveView = nil}}// Step 6: Handle business click events@objc func onShopCartTapped() { showProductListPanel() }@objc func onProductCardTapped() { showProductListPanel() }}class AudienceProductCardView: UIView {// Custom product card}

func audienceView(_ audienceView: AudienceView,onCreateLiveView liveView: AudienceLiveView,for liveInfo: LiveInfo) {// Step 1: Prepare custom button viewlet shopButton = UIButton(type: .custom)shopButton.setImage(UIImage(named: "shop_cart"), for: .normal)// Step 2: Update the bottom button array, keep gift, hide co-host, add product buttonliveView.bottomItems = [.gift,.custom(shopButton)]}

func audienceView(_ audienceView: AudienceView,onCreateLiveView liveView: AudienceLiveView,for liveInfo: LiveInfo) {// Step 1: Prepare custom button viewlet reportButton = UIButton(type: .custom)reportButton.setImage(UIImage(named: "report_btn"), for: .normal)// Step 2: Update the top button array (keep audience count and close, add report)liveView.topRightItems = [.audienceCount, .custom(reportButton), .close]}
AudienceNode | Description |
liveInfo | Top left area displaying host and room information. |
topRightButtons | Top right area for system control buttons. |
networkInfo | Network status indicator area. |
bottomRightBar | Bottom right area for business action bar. |
barrageInput | Bottom left area for live comments input trigger. |
class MyInfoView: UIView {init() {super.init(frame: .zero)let label = UILabel()label.text = "Live now"addSubview(label)label.snp.makeConstraints { make inmake.edges.equalToSuperview().inset(12) // Child view expands the parent view}}}
class MyInfoView: UIView {override var intrinsicContentSize: CGSize {CGSize(width: 200, height: 44)}}
func audienceView(_ audienceView: AudienceView,onCreateLiveView liveView: AudienceLiveView,for liveInfo: LiveInfo) {// Step 1: Initialize custom view following layout ruleslet customInfoView = MyInfoView()customInfoView.backgroundColor = .darkGray// Step 2: Call the replace interface to update the specific nodeliveView.replace(node: .liveInfo, with: customInfoView)}
func audienceView(_ audienceView: AudienceView,onCreateLiveView liveView: AudienceLiveView,for liveInfo: LiveInfo) {let btn = MyGiftButton()btn.liveView = liveViewliveView.bottomItems = [.custom(btn)]}class MyGiftButton: UIButton {weak var liveView: AudienceLiveView? // Weak referenceoverride init(frame: CGRect) {super.init(frame: frame)setImage(UIImage(named: "custom_gift"), for: .normal)addTarget(self, action: #selector(onTap), for: .touchUpInside)}required init?(coder: NSCoder) { fatalError() }@objc func onTap() {// Pop up the default Gift PanelliveView?.perform(.showGiftPanel)// Or trigger custom logic// presentCustomPanel()}}
import AtomicXCore // Introduce underlying data interface for business development// Step 1: Build custom audience list viewclass CustomAudienceListView: UIView {override init(frame: CGRect) {super.init(frame: frame)self.backgroundColor = .whitesetupUI()bindLiveData()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupUI() {// Add your custom UI controls here, such as displaying audience avatars, user levels, etc.}private func bindLiveData() {// Use AtomicXCore's core interface to get current room status or user data// After obtaining core data, refresh the custom UI built above}}// Example scenario: Slide up a fully custom panel from the bottom of the screen, occupying half the screen heightfunc presentBusinessPanel(from parentViewController: UIViewController) {// Step 2: Configure popup container parameterslet config = AtomicPopover.AtomicPopoverConfig(position: .bottom,height: .ratio(0.5),animation: .slideFromBottom)// Step 3: Pop up custom viewlet audienceListView = CustomAudienceListView()let popover = AtomicPopover(contentView: audienceListView, configuration: config)parentViewController.present(popover, animated: true)}
Feature Description | Reference Documentation |
Implement audience co-host management panel: co-host application/invite/accept/reject, co-host member permission control (microphone/camera), status synchronization. | |
Implement host cross-room co-host panel: co-host host interaction management, initiate/accept/reject co-host. | |
Implement audience list: count audience numbers, listen to audience entry/exit events. | |
Implement audio effects panel: voice changer (child/male), reverb (KTV, etc.), monitoring adjustment, real-time effect switching. |
import UIKitimport TUILiveKitclass LiveRoomController: UIViewController {private weak var currentLiveView: AudienceLiveView? // Obtain current liveView in AudienceViewDelegate// Example scenario: Display a red packet widget floating in the top left corner, and pop up the previously defined business panel on clickfunc addRedPacketWidget() {// Step 1: Create widget view and enable interactionlet redPacketWidget = UIImageView(image: UIImage(named: "red_packet_icon"))redPacketWidget.frame = CGRect(x: 15, y: 120, width: 60, height: 60)redPacketWidget.isUserInteractionEnabled = true// Step 2: Bind click eventlet tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleRedPacketClick))redPacketWidget.addGestureRecognizer(tapGesture)// Step 3: Add to overlay layercurrentLiveView?.overlayView.addSubview(redPacketWidget)}@objc func handleRedPacketClick() {// Call the previously written presentBusinessPanel method here to pop up the deeply customized business view// presentBusinessPanel(from: self)}}
// ❌ Incorrect: Holding a shared view instance externallylet sharedBrandView = MyBrandView()public func audienceView(_ audienceView: AudienceView, onCreateLiveView liveView: AudienceLiveView, for liveInfo: LiveInfo) {// ⚠️ Warning: When preloading the next liveView, sharedBrandView will be pulled from the current screen and inserted into the next invisible liveViewliveView.replace(node: .liveInfo, with: sharedBrandView)}
public func audienceView(_ audienceView: AudienceView, onCreateLiveView liveView: AudienceLiveView, for liveInfo: LiveInfo) {// ✅ Correct: Instantiate a new custom view each time the callback is triggeredlet newBrandView = MyBrandView()liveView.replace(node: .liveInfo, with: newBrandView)}
피드백