鸿蒙---应用开发首页

308 阅读2分钟

鸿蒙---应用开发首页

上次用登录模板搞了个登录的界面,登录成功后,该跳转到应用首页了。 因为页面都是再同一个UIAbility里,所以跳转直接用的路由导航router

    router.replaceUrl({
        url: 'pages/MainPage'
    });
首页页面搭建:
  1. 底部导航栏
        build() {
          Column() {
            Tabs({
              barPosition: BarPosition.End, // 导航栏再底部显示
              index: 0,
              controller: this.controller // 控制器 可切换item
            }) {
              TabContent(){
                HomeComponent()  // 首页
              }.tabBar(this.TabBuilder(0)) // tab组件
      
            TabContent(){
              ListComponent()  // 列表页
            }.tabBar(this.TabBuilder(1))
      
            TabContent(){
              MinePageContentComponent()  // 我的
            }.tabBar(this.TabBuilder(2))
        }
        .vertical(false) // 横向tabs
        .scrollable(true) // 页面可滚动切换
        .barMode(BarMode.Fixed) // 导航栏不可滚动
        .onChange((index) => {
          console.log('tab index:: ' + index)
          this.currentIndex = index  
        })
        .backgroundColor('#F1F3F5')
        }.width('100%');
      }
      
      
      @Builder TabBuilder(index: number) {
          Column() {
            Image(this.currentIndex == index ? this.iconPressMedia[index] : this.iconMedia[index])
              .width('28vp')
              .height('28vp')
              .margin({bottom: 4})
              .objectFit(ImageFit.Contain)
      
            Text(this.tabText[index])
              .fontColor(this.currentIndex == index ? this.selectedColor : this.fontColor)
              .fontSize('16fp')
              .fontWeight(500)
              .lineHeight(20)
          }.width('100%')
      }
    
    
首页轮播图
   Swiper(this.controller) {
     ForEach(this.bannerList,(item,index) => {  // 循环渲染
       Image(item)
         .width('100%')
         .height('100%')
         .objectFit(ImageFit.Fill)
     },(item,index) => { return `${index}` })
   }
   .width('100%')
   .aspectRatio(1.5) // 横纵比
   .autoPlay(true) // 自动轮播
   .loop(true) // 循环
   .cachedCount(1) // 预加载组件个数
懒加载列表
  1. 创建数据源

    export class BasicDataSource<T> implements IDataSource {
       
        private listeners: DataChangeListener[] = [];
        private originDataArray: T[] = [];
       
       unregisterDataChangeListener(listener: DataChangeListener): void {
         const pos = this.listeners.indexOf(listener);
         if (pos >= 0) {
           console.info('remove listener');
           this.listeners.splice(pos, 1);
         }
       }
       
      // 框架测调用 数据源变化通过listener通知
       registerDataChangeListener(listener: DataChangeListener): void {
         if (this.listeners.indexOf(listener) < 0) {
          console.info('add listener');
          this.listeners.push(listener);
         }
       }
       
      // 获取子项
       getData(index: number): T {
         return this.originDataArray[index];
       }
       
       // 总共子项
       totalCount(): number {
         return originDataArray.length;
       }
       
       // 重新加载数据时调用
     notifyDataReload(): void {
        this.listeners.forEach(listener => {
         listener.onDataReloaded();
        })
     }
       
     // 添加数据时调用
     notifyDataAdd(index: number): void {
       this.listeners.forEach(listener => {
         listener.onDataAdd(index);
       })
    }
       
    // 改变数据时调用
     notifyDataChange(index: number): void {
        this.listeners.forEach(listener => {
          listener.onDataChange(index);
        })
     }
       
      // 删除数据时调用
      notifyDataDelete(index: number): void {
         this.listeners.forEach(listener => {
           listener.onDataDelete(index);
         })
     }
    
    }
    
  2. LazyForEach 渲染

       LazyForEach(this.dataSource,(item,index) => {
        ListItem() {
          this.buildKeyItem() // 构建子项item
        }
      },(item) => item.toString())  // 子项唯一key
    
  3. 数据源变化

    调用dataSource的notify等方法通知LazyForEach更新UI

    当构建子项需要index作为参数时,需要注意当数据源发生变化时(增删),后续index也会相应的变化,即需要重新构建变化项

  4. @ObjectLink和@Observed

    使用@ObjectLink和@Observed单独刷新数据源子属性变化的组件,避免其它组件更新时造成闪烁

    用@Observed标注数据bean,用@ObjectLink标注数据源

       @Observed
       class StringData {
           message: string;
           imgSrc: Resource;
           constructor(message: string, imgSrc: Resource) {
              his.message = message;
              this.imgSrc = imgSrc;
           }  
       }
    
       @Component
       struct ChildComponent {
          @ObjectLink data: StringData
          build() {
                Column() {
                     Text(this.data.message).fontSize(50)
                      .onAppear(() => {
                             console.info("appear:" + this.data.message)
                       })
                      Image(this.data.imgSrc)
                       .width(500)
                        .height(200)
                }.margin({ left: 10, right: 10 })
          }
      }
    

注:@ObjectLink装饰的成员变量仅能监听到其子属性的变化,再深入嵌套的属性便无法观测到了

用户授权权限
  1. 配置权限

    reason:原因 abilities:使用该权限的Ability when:inuse-前台使用 always-前后台

    {
    "name": "ohos.permission.READ_MEDIA",
    "reason": "$string:read_image_permission",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
      "when": "inuse"
    }
    }
    
  2. 检查权限

      async function checkAccessToken(permission: Permissions) : Promise<abilityAccessCtrl.GrantStatus> {
          let atManager = abilityAccessCtrl.createAtManager()
          let grantStatus : abilityAccessCtrl.GrantStatus
    
          let tokenId: number
          try {
               let bundleInfo : bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
               let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo
               tokenId = appInfo.accessTokenId
          } catch(err) {
               console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
          }
    
          try {
              grantStatus = await atManager.checkAccessToken(tokenId, permission)
          } catch (err) {
              console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
          }
    
          return grantStatus
      }
    
  3. 请求权限

       async reqPermissionFromUser() {
         let context = getContext(this) as common.UIAbilityContext
         let atManager = abilityAccessCtrl.createAtManager()
    
         let permission : Array<Permissions> = ["ohos.permission.READ_MEDIA"]
         let grantStatus = await checkAccessToken(permission[0])
         if (grantStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
             console.log("request permission::","grand image video permission")
             this.readFile() // 同意权限后的操作
         } else {
             console.log("request permission::","denied permission")
    
             // 请求权限
             atManager.requestPermissionsFromUser(context,permission).then((data) => {
                    let grant = data.authResults[0]
                    if (grant === 0) { // 同意
                      console.log("request permission::","grand image video permission")
                      this.readFile()
                   } else {
                      console.log("request permission::","denied permission")
                      return
                   }
            }).catch(err => {
              console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`);
            })
    
        }
     }
    
弹窗
  1. 警告弹窗
    showWarnDialog() {
     AlertDialog.show({
        title: '测试',
        message: '内容',
        alignment: DialogAlignment.Center, // 弹窗显示位置  默认居中
         // confirm: {}   一个按钮
        primaryButton: {
          value: 'confirm',
          fontColor: '#00ff00',
          action: () => {
            console.log('dismiss dialog')
          }
        },
        secondaryButton: {
          value: 'cancel',
          fontColor: '#ff0000',
          action: () => {
            console.log('dismiss dialog')
          }
        },
         autoCancel: false, // 点击遮罩是否关闭弹窗
        gridCount: 4
     })
    }
    
  2. 列表选择弹窗
      showListDialog() {
        ActionSheet.show({
          title: '标题',
          message: '',
          sheets: [
            {
            title: '选项1',
            action: () => {
              console.log('click one')
            }
          },
          {
            title: '选项2',
            action: () => {
              console.log('click two')
            }
         },
         {
           title: '选项3',
           action: () => {
              console.log('click three')
           }
        }
      ]
     })
    }
    
  3. 自定义弹窗
      private controller: CustomDialogController
    
        showCustomDialog() {
           // 定义struct并用@CustomDialog标注  注意组件中需要有一个CustomDialogController属性
           this.controller = new CustomDialogController({
              builder: CustomDialogExample()
           })
    
           this.controller.open() // 调用close关闭弹窗
        } 
    
  4. 日期选择器
        showDatePicker() {
           DatePickerDialog.show({
              start: new Date('2023-10-10'),
              end: new Date('2024-10-10'),
              selected: new Date('2023-12-23'),
              lunar: false,  // 是否显示农历
              onAccept: (result) => { // 确认
                 console.log(result.year+'-'+result.month+'-'+result.day) // month+1
              },
              onCancel: () => {
    
              }
           })
      } 
    
  5. 时间选择器
       showTimePicker() {
          TimePickerDialog.show({
            selected: new Date('2023-12-23 11:02'),
            useMilitaryTime: false, // 是否24小时制
            onAccept: (result) => {
               console.log(result.hour+':'+result.minute) // 返回时间24h制
            },
            onCancel: () => {
    
            }
         })
      }
    
  6. 文本选择器
        showTextPicker() {
           TextPickerDialog.show({
              range: ['test1','test2','test3','test4'],
              selected: 1,
              onAccept: (value) => {
                  console.log(value.value + ':::' + value.index)
              },
              onCancel: () => {
    
              }
           })
      }