动态布局下加载loading效果实现

动态布局下加载loading效果实现

HarmonyOS
2024-06-11 20:40:40
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
blue76

应用市场需要实现加载loading效果,又因为应用市场是动态布局实现页面布局渲染的,所以加载loading需要包括2种:一是进入首页或页面跳转间的loading。二是应用内底部tab切换的loading。

原理

1. 进入首页或页面跳转间的loading:

2. 应用内底部tab切换的loading:

具体实现

(一) 进入首页或页面跳转间的loading。

1. 封装一个页面直接跳转加载的loading组件LocalStateCard。

@Component 
export struct LocalStateCard { 
  @State state: string = StatefulEvents.Send.Action.LOADING; 
  @Prop pageId: string; 
  @State payload: payloadProd = undefined; 
  private context: Context = getContext(this); 
  private callback; 
  
  aboutToAppear() { 
    this.registerEvent(); //emit注册监听事件,监听动态布局接口响应结果 
  } 
  
  aboutToDisappear() { 
    emitter.off(this.context, EmitEventIdStr.NOTICE_NETWORK_REQUEST_RESULT, this.callback); 
  } 
  
  build() { 
   LoadingProgress() 
      .color($r('sys.color.ohos_id_color_progress')) 
      .width(50) 
      .height(50) 
      .visibility(this.state === StatefulEvents.Send.Action.LOADING ? Visibility.Visible : Visibility.None) 
      .focusable(false) // 避免loading动画抢占焦点,导致loading动画结束搜索框才能获焦 
  } 
  
  private handleMessage() { 
    try { 
      if (!this.payload || this.payload?.pageId !== this.pageId) return; 
      this.state = this.payload.method; 
    } catch (err) {} 
  } 
  
  private registerEvent(){ 
    this.callback = (eventData) => { 
      this.payload = eventData.data; 
      this.handleMessage(); 
    }; 
    emitter.on(this.context, EmitEventIdStr.NOTICE_NETWORK_REQUEST_RESULT, this.callback); 
  } 
}

2. 在首页或者页面上添加LocalStateCard组件,如MainPage.ets中:即首页渲染LocalStateCard本地加载loading。

@Entry 
@Component 
struct PagePage { 
  private pageInstanceManager: PageInstanceManager | null = null; 
  @State pageId: string = 'c|xxxxxxx'; 
  
  aboutToAppear() { 
    this.pageInstanceManager = FLayoutHelper.getInstance().createPageInstanceManager(this.pageId); 
  } 
  
  build() { 
    Column() { 
      LocalStateCard({pageId: this.pageId}); 
      if (this.pageInstanceManager) { 
        Frame({ pageInstanceManager: this.pageInstanceManager }); 
      } 
    } 
    .width('100%') 
    .height('100%') 
    .backgroundColor($r('sys.color.ohos_id_color_sub_background')) 
  } 
}

3. 拦截动态布局接口响应,通过import emitter from '@ohos.events.emitter'向LocalStateCard通知请求结果。

LocalStateCard组件广播请求结果

export class PageLoadServiceImpl implements FLPageLoadService.Provider { 
    private currentEntryPageId: string = ""; 
    private isNetwork: boolean = true; 
  
    request(pageRequest: PageRequest, cardData?: FLCardData): Promise<JSONObject> { 
        return new Promise<JSONObject>((resolve,reject) => { 
            this.currentEntryPageId = pageRequest.getPageId(); 
            let retryTime = 0; 
                       const pageId: string = pageRequest.getPageId(); 
               const extra = pageRequest.getExtra(); 
               const pageSize: number = extra?.pageSize || 25; 
               let requestBean = new PageDetailRequestBean(1, pageSize, pageId); 
            new PageDetailRequest().request(requestBean).then((pageData) => {      
                resolve(pageData); 
            }).catch((err)=>{ 
                this.emitSuccess(this.currentEntryPageId, StatefulEvents.Send.Action.NONETWORK);  // 向LocalStateCard组件广播请求结果 
                reject(new FLException(err, ResponseErrorCode.ERROR, 'cardListRequest.cardListRequest request error')); 
            });;       
        }); 
    } 
  
  
    parse(pageParser: FLPageParser, data: JSONObject): Promise<FLPageBundle> { 
        return new Promise<FLPageBundle>((resolve, reject) => { 
            const pageId=data?.router?.entry; 
            let rtnCode = data?.rtnCode; 
            if (pageId) { 
                this.emitSuccess(this.currentEntryPageId, StatefulEvents.Send.Action.SUCCESS); 
                resolve(pageParser.parsePage(data.pages, pageId));           
            } else { 
                this.emitSuccess(this.currentEntryPageId, StatefulEvents.Send.Action.NONETWORK); // 向LocalStateCard组件广播请求结果 
                reject(new FLException(ResponseErrorCode.ERROR_NO_NETWORK, ResponseErrorCode.ERROR_NO_NETWORK, 'parse error ')); 
            } 
        }); 
    } 
    private emitSuccess(pageId: string, method: string) { 
        var eventData: EventData = { 
            data:{ method, pageId} 
        }; 
        const context: UIAbilityContext = getContext(); 
        emitter.emit(context, EmitEventIdStr.NOTICE_NETWORK_REQUEST_RESULT, eventData); 
    } 
} 
 

(二) 应用内底部tab切换的loading。

1. 封装一个应用内底部tab切换loading的原子卡组StatefullCard,并在动态布局中统一注册engine.registerCard(StatefullCardBuilder)engine.registerCard(StatefullCardBuilder)):

@Component 
export struct StatefullCard { 
  cardData: FLCardData; 
  private subscriberId: number = Subscriber.INVALID_ID; 
  @State statefulVisibility: Visibility = Visibility.Visible; 
  @State state: string = StatefulEvents.Send.Action.LOADING; 
  
  aboutToAppear() { 
    this.subscribe() 
  } 
  aboutToDisappear() { 
    this.unsubscribe() 
  } 
  
  private subscribe(): void { //注册监听,动态布局(id=stateful)加载成功的事件 
    this.subscriberId = EventQueue.sharedInstance.subscribe(this.subscriberId, this.cardData, function (msg:any){ 
      this.state = msg?.payload?.method; 
    }.bind(this)) 
  } 
  
  private unsubscribe(): void { 
    if (this.subscriberId != Subscriber.INVALID_ID) { 
        EventQueue.sharedInstance.unsubscribe(this.subscriberId); 
    } 
    this.subscriberId = Subscriber.INVALID_ID; 
  } 
  
  build() { 
    LoadingProgress() 
      .color($r('sys.color.ohos_id_color_progress')) 
      .width(50) 
      .height(50) 
      .visibility(this.state === StatefulEvents.Send.Action.LOADING ? Visibility.Visible : Visibility.None) 
      .focusable(false) // 避免loading动画抢占焦点,导致loading动画结束搜索框才能获焦 
  } 
  
  @Builder 
  static cardBuilder(options: BuildOptions<FLCardData>) { 
    StatefullCard({cardData: options.data} ) 
  } 
} 
  
export const StatefullCardBuilder = { 
  name: "statefullcard", 
  builder: StatefullCard.cardBuilder, 
  dataType: FLCardData 
}

2. 配置卡片模板中的loading(即id=stateful):

{ 
  "name": "com.example.xxx.appgallery.homepage", 
  "type": "page", 
  }, 
  "children": [ 
    { 
      "type": "box", 
      "style": { 
        "height": "100%" 
      }, 
      "children": [ 
        { 
          "type": "tabs", 
          "data": { 
            "defaultItem": "{{tabScope.selection}}" 
          }, 
          "style": ".tabStyle", 
          "children": [ 
            { 
              "type": "tabcontent", 
              "data": { 
                "smoothScroll": false 
              }, 
              "children": [ 
                { 
                  "type": "box", 
                  "style": { 
                    "height": "100%" 
                  }, 
                  "s-for": "{{index,item in tabScope.list}}", 
                  "children": [ 
                    { 
                      "id": "stateful", 
                      "type": "statefullcard", 
                      "if": "{{index > 0}}" 
                    }, 
                    { 
                      "type": "frame", 
                      "style": { 
                        "height": "100%" 
                      }, 
                      "data": { 
                        "pageId": "{{item.frame.pageId}}" 
                      } 
                    } 
                  ] 
                } 
              ] 
            }, 
            { 
              "type": "tabitem", 
              "style": ".tabitemStyle", 
              "children": [ 
                { 
                  "type": "tabbutton", 
                  "s-for": "{{item in tabScope.list}}", 
                  "data": { 
                    "tabName": "{{item.title}}", 
                    "icon":"{{item.icon}}" 
                  } 
                } 
              ] 
            } 
          ] 
        } 
      ] 
    } 
  ] 
}

疑问:

1. 为什么要分进入首页或页面跳转间的loading和应用内底部tab切换的loading。

答:因为应用市场是基于动态布局2.1页面级渲染的,再首次启动进入应用市场时,还未下载页面卡片模板,此时也就存在一定的空白界面。所以用首页或页面跳转间的loading,能避免启动到动态布局下载卡片模板这段时间的空白界面。

分享
微博
QQ
微信
回复
2024-06-12 17:42:00
相关问题
PopWindow的效果实现有哪些?
301浏览 • 1回复 待解决
如何通过Progress实现loading效果
41浏览 • 1回复 待解决
引导遮罩效果实现的最佳方案
339浏览 • 1回复 待解决
是否支持模块的动态加载?如何实现
973浏览 • 1回复 待解决
动态加载网络字体文件
280浏览 • 1回复 待解决
按需加载场景中加载动态模块失败
581浏览 • 1回复 待解决
ArkTS布局组件实现瀑布流式布局
367浏览 • 1回复 待解决
HAP是否提供动态加载的能力
739浏览 • 1回复 待解决
ArkTS和Native如何动态加载、卸载so
848浏览 • 1回复 待解决
基于tabs实现页面布局
201浏览 • 1回复 待解决
canvas如何实现水印效果
402浏览 • 1回复 待解决
如何实现星级评分效果
58浏览 • 1回复 待解决
ets怎么实现动态添加组件?
2226浏览 • 1回复 待解决
路由实现动态页面的跳转方案
671浏览 • 1回复 待解决