如何开放UI实现到组件外部,由外部自由定制一个或多个封装好的UI内容,使其可以被跨组件或跨页面调用?
实现思路如下:UI内容由全局@Builder自定义构建函数进行封装。通过注册表注册一个WrappedBuilder数组来管理UI,在组件中通过ForEach的方式渲染这个WrappedBuilder数组,这样可以通过管理该WrappedBuilder数组来动态渲染定制的UI内容。
- export interface IBookUIComponent {
- // 获取UI构建器
- getUIBuilder: WrappedBuilder<[]>;
- // 组件名称
- componentName?: string;
- }
- export class EllaBookUIView {
- private static instance: EllaBookUIView | null = null;
- private components: IBookUIComponent[] = [];
-
- private constructor() {
- }
-
- // 获取单例
- public static getInstance(): EllaBookUIView {
- if (!EllaBookUIView.instance) {
- EllaBookUIView.instance = new EllaBookUIView();
- }
- return EllaBookUIView.instance;
- }
-
- // 注册组件
- public registerComponent(component: IBookUIComponent): void {
- this.components.push(component);
- console.info(`[BookUIRegistry] 组件注册成功: ${component.componentName || '未命名组件'}`);
- }
-
- // 获取所有组件构建器
- public getAllBuilders(): WrappedBuilder<[]>[] {
- return this.components.map(component => component.getUIBuilder);
- }
-
- // 清除所有组件
- public clearComponents(): void {
- this.components = [];
- console.info('[BookUIRegistry] 所有组件已清除');
- }
- }
- @Component
- struct ControlButtons {
- @State isPlaying: boolean = true; // 播放状态
-
- // 退出书籍
- private exitBook() {
- console.info('退出书籍');
- }
-
- // 切换播放状态
- private togglePlay() {
- this.isPlaying = !this.isPlaying;
- console.info(this.isPlaying ? '播放中' : '已暂停');
- }
-
- // 上一页
- private prevPage() {
- console.info('上一页');
- }
-
- // 下一页
- private nextPage() {
- console.info('下一页');
- }
-
- build() {
- Stack({ alignContent: Alignment.BottomStart }) {
- // 顶部控制栏
- Row() {
- // 1.顶部最左侧---退出按钮
- Button() {
- Image($r('app.media.xmark'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(20)
- .onClick(() => {
- // 退出逻辑
- this.exitBook();
- });
-
- Blank();
- // 2.顶部最右侧---播放/暂停按钮
- Button() {
- if (this.isPlaying) {
- Image($r('app.media.pause'))
- .objectFit(ImageFit.Contain);
- } else {
- Image($r('app.media.play'))
- .objectFit(ImageFit.Contain);
- }
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(20)
- .onClick(() => {
- this.togglePlay();
- });
- }
- .width('100%')
- .padding(10)
- .position({ x: 0, y: 0 });
-
- // 底部控制栏
- Row() {
- // 3.底部最左侧---上一页按钮
- Button() {
- Image($r('app.media.chevron_left'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(25)
- .onClick(() => {
- this.prevPage();
- });
-
- Blank();
- // 4.底部最右侧---下一页按钮
- Button() {
- Image($r('app.media.chevron_right'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(25)
- .onClick(() => {
- this.nextPage();
- });
- }
- .width('100%')
- .padding(10);
- }
- .width('100%')
- .height('100%');
- };
- }
-
- // 创建UI构建器
- @Builder
- function controlBuilder() {
- ControlButtons();
- }
- export class BookUIComponents implements IBookUIComponent {
- componentName: string = '书籍控制组件';
- getUIBuilder: WrappedBuilder<[]> = wrapBuilder(controlBuilder);
- }
- Stack({ alignContent: Alignment.TopStart }) {
- Column({ space: 16 }) {
- Button('打开书籍控制器控件')
- .onClick(() => {
- ellaBookUIView.registerComponent(new BookUIComponents());
- this.uiBuilders = ellaBookUIView.getAllBuilders();
- });
- Button('关闭书籍控制器控件')
- .onClick(() => {
- ellaBookUIView.clearComponents();
- this.uiBuilders = ellaBookUIView.getAllBuilders();
- });
- }.height('100%').width('100%');
-
- ForEach(this.uiBuilders,
- (builder: WrappedBuilder<[]>) => {
- // 使用公共属性传递索引
- BuilderComponent({ builder: builder })
- .hitTestBehavior(HitTestMode.Transparent);
- }
- );
- };
完整示例如下:
- // 书籍UI组件接口
- export interface IBookUIComponent {
- // 获取UI构建器
- getUIBuilder: WrappedBuilder<[]>;
- // 组件名称
- componentName?: string;
- }
-
- // 全局UI组件注册表
- export class EllaBookUIView {
- private static instance: EllaBookUIView | null = null;
- private components: IBookUIComponent[] = [];
-
- private constructor() {
- }
-
- // 获取单例
- public static getInstance(): EllaBookUIView {
- if (!EllaBookUIView.instance) {
- EllaBookUIView.instance = new EllaBookUIView();
- }
- return EllaBookUIView.instance;
- }
-
- // 注册组件
- public registerComponent(component: IBookUIComponent): void {
- this.components.push(component);
- console.info(`[BookUIRegistry] 组件注册成功: ${component.componentName || '未命名组件'}`);
- }
-
- // 获取所有组件构建器
- public getAllBuilders(): WrappedBuilder<[]>[] {
- return this.components.map(component => component.getUIBuilder);
- }
-
- // 清除所有组件
- public clearComponents(): void {
- this.components = [];
- console.info('[BookUIRegistry] 所有组件已清除');
- }
- }
- // 导出全局单例
- export const ellaBookUIView = EllaBookUIView.getInstance();
-
- @Component
- struct ControlButtons {
- @State isPlaying: boolean = true; // 播放状态
-
- // 退出书籍
- private exitBook() {
- console.info('退出书籍');
- }
-
- // 切换播放状态
- private togglePlay() {
- this.isPlaying = !this.isPlaying;
- console.info(this.isPlaying ? '播放中' : '已暂停');
- }
-
- // 上一页
- private prevPage() {
- console.info('上一页');
- }
-
- // 下一页
- private nextPage() {
- console.info('下一页');
- }
-
- build() {
- Stack({ alignContent: Alignment.BottomStart }) {
- // 顶部控制栏
- Row() {
- // 1.顶部最左侧---退出按钮
- Button() {
- Image($r('app.media.xmark'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(20)
- .onClick(() => {
- // 退出逻辑
- this.exitBook();
- });
-
- Blank();
- // 2.顶部最右侧---播放/暂停按钮
- Button() {
- if (this.isPlaying) {
- Image($r('app.media.pause'))
- .objectFit(ImageFit.Contain);
- } else {
- Image($r('app.media.play'))
- .objectFit(ImageFit.Contain);
- }
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(20)
- .onClick(() => {
- this.togglePlay();
- });
- }
- .width('100%')
- .padding(10)
- .position({ x: 0, y: 0 });
-
- // 底部控制栏
- Row() {
- // 3.底部最左侧---上一页按钮
- Button() {
- Image($r('app.media.chevron_left'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(25)
- .onClick(() => {
- this.prevPage();
- });
-
- Blank();
- // 4.底部最右侧---下一页按钮
- Button() {
- Image($r('app.media.chevron_right'))
- .objectFit(ImageFit.Contain);
- }
- .height(24)
- .width(24)
- .backgroundColor(Color.Transparent)
- .borderRadius(25)
- .onClick(() => {
- this.nextPage();
- });
- }
- .width('100%')
- .padding(10);
- }
- .width('100%')
- .height('100%');
- };
- }
-
- // 创建UI构建器
- @Builder
- function controlBuilder() {
- ControlButtons();
- }
-
- export class BookUIComponents implements IBookUIComponent {
- componentName: string = '书籍控制组件';
- getUIBuilder: WrappedBuilder<[]> = wrapBuilder(controlBuilder);
- }
-
- @Entry
- @Component
- struct Page {
- @State uiBuilders: WrappedBuilder<[]>[] = [];
-
- build() {
- Column() {
- Stack({ alignContent: Alignment.TopStart }) {
- Column({ space: 16 }) {
- Button('打开书籍控制器控件')
- .onClick(() => {
- ellaBookUIView.registerComponent(new BookUIComponents());
- this.uiBuilders = ellaBookUIView.getAllBuilders();
- });
- Button('关闭书籍控制器控件')
- .onClick(() => {
- ellaBookUIView.clearComponents();
- this.uiBuilders = ellaBookUIView.getAllBuilders();
- });
- }.height('100%').width('100%');
-
- ForEach(this.uiBuilders,
- (builder: WrappedBuilder<[]>) => {
- // 使用公共属性传递索引
- BuilderComponent({ builder: builder })
- .hitTestBehavior(HitTestMode.Transparent);
- }
- );
- };
- };
- }
- }
-
- @Component
- struct BuilderComponent {
- builder?: WrappedBuilder<[]>;
-
- build() {
- if (this.builder) {
- this.builder.builder();
- } else {
- Text('暂无构建');
- }
- }
- }
实现效果如下:

合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功