← Cloudflare Realtime / realtime / realtimekit / ui-kit
Add Custom Header
V tomto průvodci se naučíme, jak do schůzky RealtimeKit přidat vlastní hlavičku.
RealtimeKit UI poskytuje RtkHeader komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte RtkHeader s jednotlivými komponentami UI Kit a vlastními prvky.
Importujte potřebné komponenty:
import {
RtkLogo,
RtkRecordingIndicator,
RtkLivestreamIndicator,
RtkMeetingTitle,
RtkGridPagination,
RtkParticipantCount,
RtkViewerCount,
RtkClock,
} from "@cloudflare/realtimekit-ui";Ve vašem RtkUIProvider z Vytváření vlastního UI, nahraďte:
<RtkHeader />za:
<div
style={{
display: "flex",
justifyContent: "space-between",
backgroundColor: "black",
color: "white",
}}
>
<div
id="header-left"
style={{ display: "flex", alignItems: "center", height: "48px" }}
>
<RtkLogo />
<RtkRecordingIndicator />
<RtkLivestreamIndicator />
</div>
<div
id="header-center"
style={{ display: "flex", alignItems: "center", height: "48px" }}
>
<RtkMeetingTitle />
</div>
<div
id="header-right"
style={{ display: "flex", alignItems: "center", height: "48px" }}
>
<RtkGridPagination />
<RtkParticipantCount />
<RtkViewerCount />
<RtkClock />
<button onClick={handleReportBugClick}>Report Bug</button>
</div>
</div>Definujte handler kliknutí:
const handleReportBugClick = () => {
console.log("Report Bug Clicked");
};Úplný příklad najdete v příklad vlastního UI ↗ a vlastní komponenta záhlaví ↗.
RealtimeKit UI poskytuje rtk-header komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte rtk-header s jednotlivými komponentami UI Kit a vlastními prvky. V renderJoinedScreen funkce z Vytváření vlastního UI, nahraďte:
<rtk-header style="display: flex; justify-content: space-between;"></rtk-header>za:
<div
style="display: flex; justify-content: space-between; align-items: center; height: 48px; padding: 0 12px; background-color: black; color: white;"
>
<div style="display: flex; align-items: center; gap: 8px;">
<rtk-logo></rtk-logo>
<rtk-recording-indicator></rtk-recording-indicator>
<rtk-livestream-indicator></rtk-livestream-indicator>
</div>
<div style="display: flex; align-items: center;">
<rtk-meeting-title></rtk-meeting-title>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<rtk-grid-pagination></rtk-grid-pagination>
<rtk-participant-count></rtk-participant-count>
<rtk-viewer-count></rtk-viewer-count>
<rtk-clock></rtk-clock>
<button id="report-bug-button" type="button">Report Bug</button>
</div>
</div>Zaregistrujte handler kliknutí po vykreslení:
document.querySelector("#report-bug-button").addEventListener("click", () => {
console.log("Report Bug Clicked");
});Úplný příklad najdete v příklad vlastního UI ↗ a vlastní komponenta záhlaví ↗.
RealtimeKit UI poskytuje rtk-header komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte rtk-header s jednotlivými komponentami UI Kit a vlastními prvky. Vytvořte vlastní komponentu header, která přímo využívá komponenty RealtimeKit pro Angular.
Vytvoření vlastní komponenty záhlaví
import { Component, AfterViewInit } from "@angular/core";
@Component({
selector: "app-custom-header",
template: `
<div class="custom-header">
<div class="header-left">
<rtk-logo></rtk-logo>
<rtk-recording-indicator></rtk-recording-indicator>
<rtk-livestream-indicator></rtk-livestream-indicator>
</div>
<div class="header-center">
<rtk-meeting-title></rtk-meeting-title>
</div>
<div class="header-right">
<rtk-grid-pagination></rtk-grid-pagination>
<rtk-participant-count></rtk-participant-count>
<rtk-viewer-count></rtk-viewer-count>
<rtk-clock></rtk-clock>
<button
type="button"
class="report-bug-button"
(click)="onReportBugClick()"
>
Report Bug
</button>
</div>
</div>
`,
styles: [
`
.custom-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 48px;
padding: 0 12px;
background-color: black;
color: white;
}
.header-left,
.header-right {
display: flex;
align-items: center;
gap: 8px;
}
.header-center {
display: flex;
align-items: center;
}
.report-bug-button {
background: none;
border: 1px solid white;
color: white;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.report-bug-button:hover {
background-color: rgba(255, 255, 255, 0.1);
}
`,
],
})
export class CustomHeaderComponent implements AfterViewInit {
ngAfterViewInit() {
console.log("Custom header initialized");
}
onReportBugClick() {
console.log("Report Bug Clicked");
// Add your custom logic here
// For example: open a modal, navigate to a form, etc.
}
}Použití ve vaší komponentě schůzky
V šabloně hlavní komponenty schůzky nahraďte:
<rtk-header style="display: flex; justify-content: space-between;"></rtk-header>za:
<app-custom-header></app-custom-header>Kompletní příklad komponenty schůzky
import {
Component,
ElementRef,
OnInit,
OnDestroy,
ViewChild,
} from "@angular/core";
@Component({
selector: "app-meeting",
template: `
<rtk-meeting #meetingComponent id="meeting-component">
<!-- Custom header replaces rtk-header -->
<app-custom-header></app-custom-header>
<!-- Other meeting UI components -->
<rtk-grid></rtk-grid>
<rtk-sidebar></rtk-sidebar>
</rtk-meeting>
`,
})
export class MeetingComponent implements OnInit, OnDestroy {
@ViewChild("meetingComponent", { static: true }) meetingElement!: ElementRef;
meeting: any;
private authToken = "<participant_auth_token>";
async ngOnInit() {
const RealtimeKitClient =
await import("https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit@latest/dist/index.es.js");
this.meeting = await RealtimeKitClient.default.init({
authToken: this.authToken,
});
const meetingComponent = this.meetingElement.nativeElement;
meetingComponent.showSetupScreen = true;
meetingComponent.meeting = this.meeting;
}
ngOnDestroy() {
// Cleanup logic
}
}Konfigurace modulu
Nezapomeňte deklarovat svou vlastní komponentu header ve svém modulu Angular:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
import { MeetingComponent } from "./meeting.component";
import { CustomHeaderComponent } from "./custom-header.component";
@NgModule({
declarations: [AppComponent, MeetingComponent, CustomHeaderComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA], // Required for RTK web components
})
export class AppModule {}Tento přístup vám dává úplnou kontrolu nad rozvržením hlavičky, přičemž zachovává komponentovou architekturu Angularu a způsob zpracování událostí.
RealtimeKit UI poskytuje RtkMeetingHeaderView komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte RtkMeetingHeaderView s jednotlivými komponentami UI Kit a vlastními prvky.
Importujte potřebné komponenty:
import RealtimeKitUIVytvoření vlastního zobrazení záhlaví
Vytvoření vlastního zobrazení záhlaví, které přímo používá komponenty RealtimeKit iOS:
import UIKit
import RealtimeKit
import RealtimeKitUI
class CustomHeaderView: UIView {
private let meeting: RealtimeKitClient
private lazy var titleLabel: RtkMeetingTitleLabel = {
return RtkMeetingTitleLabel(meeting: meeting)
}()
private lazy var participantCountView: RtkParticipantCountView = {
return RtkParticipantCountView(meeting: meeting)
}()
private lazy var clockView: RtkClockView = {
return RtkClockView(meeting: meeting)
}()
private lazy var recordingView: RtkRecordingView = {
return RtkRecordingView(meeting: meeting)
}()
private let reportBugButton = UIButton(type: .system)
init(meeting: RealtimeKitClient) {
self.meeting = meeting
super.init(frame: .zero)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .black
// Configure report bug button
reportBugButton.setTitle("Report Bug", for: .normal)
reportBugButton.setTitleColor(.white, for: .normal)
reportBugButton.layer.borderColor = UIColor.white.cgColor
reportBugButton.layer.borderWidth = 1
reportBugButton.layer.cornerRadius = 4
reportBugButton.contentEdgeInsets = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
reportBugButton.addTarget(self, action: #selector(handleReportBugTap), for: .touchUpInside)
// Create stack views for layout
let leftStack = UIStackView(arrangedSubviews: [recordingView])
leftStack.axis = .horizontal
leftStack.spacing = 8
leftStack.alignment = .center
let centerStack = UIStackView(arrangedSubviews: [titleLabel])
centerStack.axis = .horizontal
centerStack.alignment = .center
let rightStack = UIStackView(arrangedSubviews: [
participantCountView,
clockView,
reportBugButton
])
rightStack.axis = .horizontal
rightStack.spacing = 8
rightStack.alignment = .center
let mainStack = UIStackView(arrangedSubviews: [leftStack, centerStack, rightStack])
mainStack.axis = .horizontal
mainStack.distribution = .equalSpacing
mainStack.alignment = .center
mainStack.translatesAutoresizingMaskIntoConstraints = false
addSubview(mainStack)
NSLayoutConstraint.activate([
mainStack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12),
mainStack.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12),
mainStack.topAnchor.constraint(equalTo: topAnchor),
mainStack.bottomAnchor.constraint(equalTo: bottomAnchor),
heightAnchor.constraint(equalToConstant: 48)
])
}
@objc private func handleReportBugTap() {
print("Report Bug Tapped")
// Add your custom logic here
}
}Použití ve vašem view controlleru schůzky
Ve vašem MeetingViewController, nahraďte výchozí hlavičku svou vlastní hlavičkou:
import UIKit
import RealtimeKit
import RealtimeKitUI
class MeetingViewController: UIViewController {
private var meeting: RealtimeKitClient?
private var customHeader: CustomHeaderView?
override func viewDidLoad() {
super.viewDidLoad()
setupMeeting()
}
private func setupMeeting() {
Task {
do {
let client = try await RealtimeKitClient.init(authToken: "<PARTICIPANT_AUTH_TOKEN>")
self.meeting = client
await MainActor.run {
setupCustomHeader(meeting: client)
}
} catch {
print("Failed to initialize meeting: \(error)")
}
}
}
private func setupCustomHeader(meeting: RealtimeKitClient) {
let header = CustomHeaderView(meeting: meeting)
self.customHeader = header
view.addSubview(header)
header.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
header.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
header.leadingAnchor.constraint(equalTo: view.leadingAnchor),
header.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}RealtimeKit UI poskytuje RtkMeetingHeaderView komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte RtkMeetingHeaderView s jednotlivými komponentami UI Kit a vlastními prvky.
Importujte potřebné komponenty:
import com.cloudflare.realtimekit.ui.view.headers.RtkMeetingHeaderView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
import com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
import com.cloudflare.realtimekit.ui.view.RtkGridPaginatorViewVytvoření vlastního layoutu záhlaví
Vytvoření souboru XML layoutu pro vlastní záhlaví:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingHorizontal="12dp"
android:background="@android:color/black">
<!-- Left section -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="start|center_vertical">
<com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
android:id="@+id/recordingIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
android:id="@+id/livestreamIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
</LinearLayout>
<!-- Center section -->
<com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
android:id="@+id/meetingTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white" />
<!-- Right section -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="end|center_vertical">
<com.cloudflare.realtimekit.ui.view.RtkGridPaginatorView
android:id="@+id/gridPaginator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
android:id="@+id/participantCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
<com.cloudflare.realtimekit.ui.view.RtkClockView
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
<Button
android:id="@+id/reportBugButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Report Bug"
android:textColor="@android:color/white"
android:background="@android:color/transparent"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
</LinearLayout>Vytvoření vlastní třídy zobrazení záhlaví
package com.example.meeting
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.Button
import android.widget.LinearLayout
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
class CustomHeaderView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.custom_header, this, true)
setupReportBugButton()
}
private fun setupReportBugButton() {
findViewById<Button>(R.id.reportBugButton).setOnClickListener {
Log.d("CustomHeader", "Report Bug Clicked")
// Add your custom logic here
}
}
}Použití ve vaší schůzkové Activity
Ve vašem MeetingActivity, nahraďte výchozí hlavičku svou vlastní hlavičkou:
package com.example.meeting
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.cloudflare.realtimekit.RealtimeKitClient
class MeetingActivity : AppCompatActivity() {
private lateinit var meeting: RealtimeKitClient
private lateinit var customHeader: CustomHeaderView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
customHeader = findViewById(R.id.customHeader)
initializeMeeting()
}
private fun initializeMeeting() {
RealtimeKitClient.init(
authToken = "<PARTICIPANT_AUTH_TOKEN>",
onSuccess = { client ->
meeting = client
// Configure meeting UI
},
onError = { error ->
Log.e("Meeting", "Failed to initialize: $error")
}
)
}
}RealtimeKit UI poskytuje RtkHeader komponenta pro výchozí hlavičku.
Pokud potřebujete další ovládací prvky, nahraďte RtkHeader s jednotlivými komponentami UI Kit a vlastními prvky.
Importujte potřebné komponenty:
import {
RtkLogo,
RtkRecordingIndicator,
RtkLiveStreamIndicator,
RtkMeetingTitle,
RtkGridPagination,
RtkParticipantCount,
RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
useRealtimeKitMeeting,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";Vytvoření vlastní komponenty záhlaví
Vytvoření vlastní komponenty záhlaví, která přímo používá komponenty RealtimeKit React Native. Každá komponenta vyžaduje meeting instanci jako prop, kterou získáte pomocí useRealtimeKitMeeting hook. Komponenta čeká na roomJoined před vykreslením, aby bylo zajištěno, že je stav schůzky připravený:
import React from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
import {
RtkLogo,
RtkRecordingIndicator,
RtkLiveStreamIndicator,
RtkMeetingTitle,
RtkGridPagination,
RtkParticipantCount,
RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
useRealtimeKitMeeting,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
interface CustomHeaderProps {
onReportBugPress?: () => void;
}
export function CustomHeader({ onReportBugPress }: CustomHeaderProps) {
const { meeting } = useRealtimeKitMeeting();
const { roomJoined } = useRealtimeKitSelector((state) => state.self);
const handleReportBugPress = () => {
console.log("Report Bug Pressed");
onReportBugPress?.();
};
if (!roomJoined) {
return null;
}
return (
<View style={styles.container}>
{/* Left section */}
<View style={styles.leftSection}>
<RtkLogo />
<RtkRecordingIndicator meeting={meeting} />
<RtkLiveStreamIndicator meeting={meeting} />
</View>
{/* Center section */}
<View style={styles.centerSection}>
<RtkMeetingTitle meeting={meeting} />
</View>
{/* Right section */}
<View style={styles.rightSection}>
<RtkGridPagination meeting={meeting} />
<RtkParticipantCount meeting={meeting} />
<RtkClock meeting={meeting} />
<TouchableOpacity
style={styles.reportBugButton}
onPress={handleReportBugPress}
>
<Text style={styles.reportBugText}>Report Bug</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
height: 48,
paddingHorizontal: 12,
backgroundColor: "black",
},
leftSection: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
centerSection: {
flexDirection: "row",
alignItems: "center",
},
rightSection: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
reportBugButton: {
borderWidth: 1,
borderColor: "white",
borderRadius: 4,
paddingHorizontal: 8,
paddingVertical: 4,
},
reportBugText: {
color: "white",
fontSize: 12,
},
});Použití na vaší obrazovce schůzky
Na obrazovce schůzky nahraďte výchozí RtkHeader s vlastní komponentou header:
import React, { useEffect } from "react";
import { View, StyleSheet } from "react-native";
import {
RealtimeKitProvider,
useRealtimeKitClient,
} from "@cloudflare/realtimekit-react-native";
import {
RtkGrid,
RtkControlbar,
RtkDialogManager,
} from "@cloudflare/realtimekit-react-native-ui";
import { CustomHeader } from "./CustomHeader";
function MeetingContainer() {
const [meeting, initMeeting] = useRealtimeKitClient();
useEffect(() => {
initMeeting({
authToken: "<PARTICIPANT_AUTH_TOKEN>",
});
}, [initMeeting]);
useEffect(() => {
if (!meeting) return;
meeting.join();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [meeting]);
if (!meeting) {
return null;
}
return (
<RealtimeKitProvider value={meeting}>
<View style={styles.container}>
{/* Custom header replaces RtkHeader */}
<CustomHeader
onReportBugPress={() => console.log("Report bug pressed")}
/>
{/* Meeting grid */}
<View style={styles.gridContainer}>
<RtkGrid meeting={meeting} />
</View>
{/* Control bar */}
<RtkControlbar meeting={meeting} />
</View>
{/* Required components */}
<RtkDialogManager meeting={meeting} />
</RealtimeKitProvider>
);
}
export function MeetingScreen() {
return <MeetingContainer />;
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "black",
},
gridContainer: {
flex: 1,
},
});