请教一下关于应用分栏实现

应用分栏实现

HarmonyOS
2024-06-11 20:34:43
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
NGKSWCIDT

1、分栏场景分析

1.1 为什么要分栏

折叠屏展开,平板等屏幕较大的设备,如果还是按照手机布局展示内容,会显得页面太宽,内容太分散,不够美观,此时如果页面能够分左右两块,左边作为导航区,右侧作为内容区,体验会更佳。

1.2 分栏和未分栏效果对比

如果想直接分栏,可以设置mode属性为Split;如果不想分栏,可以设置为Stack;如果想让组件自动识别是否分栏,可以设置为Auto。 推荐使用Auto,这样应用不需要做过多分栏触发时机的识别。

1.3 分栏的场景

屏幕较大的设备,如平板、折叠屏展开、pc、车机大屏等,需要让页面内容更丰富,更方便操作。

左侧作为导航区域,右侧作为内容区域,操作方便。

2、分栏实践

2.1 左侧导航栏

导航栏作为应用一级页面,需要包在Navigation组件内:

@Entry 
@Component 
struct MainEntry { 
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack(); 
  build() {     Navigation(this.pageInfos) { 
    // 内容区,示例item 
    Row() { 
      if (this.info.icon) { 
        Image(this.info.icon) 
          .aspectRatio(1) 
          .width($r('app.float.common_size24')) 
          .borderRadius($r('app.float.common_size4')) 
          .alignSelf(ItemAlign.Center) 
          .margin({ right: $r('app.float.common_margin12') }) 
          .draggable(false) 
          .interpolation(ImageInterpolation.High) 
      } 
      Column() { 
        Text(this.info.title) 
          .fontSize($r('app.float.common_font_size16')) 
          .fontColor($r('app.color.black')) 
          .fontWeight(FontWeight.Medium) 
        Progress({ value: this.progress(), style: ProgressStyle.Linear }) 
          .width($r('app.float.common_size80')) 
          .margin({ top: $r('app.float.common_margin8') }) 
      }.justifyContent(FlexAlign.Center) 
      .alignItems(HorizontalAlign.Start) 
 
      Flex({ justifyContent: FlexAlign.End }) { 
        Text(renderSize(this.free, Constant.BYTE.STORAGE_KB) + ' ' + this.available + '/' + renderSize(this.total, Constant.BYTE.STORAGE_KB)) 
          .fontSize($r('app.float.common_font_size14')) 
          .fontColor($r('app.color.mine_title_font_color')) 
          .opacity($r('app.float.common_opacity6')) 
          .margin({ right: $r('app.float.common_margin2') }) 
          .textOverflow({ overflow: TextOverflow.Ellipsis }) 
          .textAlign(TextAlign.End) 
      } 
    }.layoutWeight(1) 
    .padding({ left: $r('app.float.common_padding8') }) 
 
    Image($r('app.media.ic_arrow_right')) 
      .objectFit(ImageFit.Contain) 
      .renderMode(ImageRenderMode.Original) 
      .aspectRatio(1) 
      .width($r('app.float.common_size12')) 
      .height($r('app.float.common_size24')) 
      .draggable(false) 
      .interpolation(ImageInterpolation.High) 
  } 
  .width('100%') 
  .height($r('app.float.common_size56')) 
  .padding({ 
    left: $r('app.float.common_padding12'), 
    right: $r('app.float.common_padding12') 
  }) 
  .stateStyles({ 
    pressed: pressedStyles, 
    normal: normalStyles 
  }) 
  .onClick(() => { 
    if (this.info.pageUri) { 
      this.pageInfos.clear(); 
      let params: StorageDeviceParamData = { 
        rootUri: this.info.rootUri, 
        title: this.info.title, 
        uuid: this.info.uuid, 
        deviceType: this.info.deviceType 
      }; 
      this.pageInfos.pushPath(new NavPathInfo('myPhone', params)); 
    } 
  }) 
  } 
  .backgroundColor($r('app.color.hicloud_hmos_bg')) 
  .navDestination(this.pageMap) 
  .mode(NavigationMode.Split) 
  .navBarWidth($r('app.float.common_size295')) 
  .hideTitleBar(true) 
  .onNavBarStateChange((isVisible: boolean) => { 
  if (isVisible) { 
    UiUtil.setWindowBackground(SYSTEM_BAR_COLOR.LIGHT_GRAY); 
    this.onPageShow(); 
  } else { 
  this.isRecentPageShow = false; 
} 
}) }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.

2.2 导航栏右侧内容区

分栏右侧内容区是导航栏的子页面,需要包在NavDestination组件内:

注意点:内容区组件不需要用@Entry修饰,build时需要包在NavDestination内。

@Component 
export struct MyPhone { 
  build() { 
    NavDestination() { 
      // 内容区 
    } 
    .onBackPressed(() => {       return this.onBackPress(); 
    }) 
    .backgroundColor($r('app.color.hicloud_hmos_bg')) 
    .hideTitleBar(true) 
    .onShown(() => this.onPageShow()) 
    .onHidden(() => this.onPageHide()) 
    .width('100%') 
    .height('100%') 
    .expandSafeArea([SafeAreaType.KEYBOARD]) 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

2.3 关联导航栏和内容区

即导航栏区域点击某个item,右侧需要显示对应内容区

首先2.1章节Navigation的navDestination需要设置子页面的映射关系,根据name去匹配加载不同的子页面。

定义this.pageMap,2.1章节有用到:

@Builder 
pageMap(name: string, params: Object) { 
  if (name === 'MyPhone') { 
    MyPhone({ pageParams: params }); 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

导航栏item点击后触发的事件在2.1章节代码onClick事件内,即往pageInfos栈内push子页面,这样就可以在右侧显示。

2.4 demo验证

为了方便理解,写了个简易demo(和业务代码有区别)把上面三步串起来:

@Entry 
@Component 
struct MainEntryTest { 
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack(); 
     onPageShow() {   
  }   
  onPageHide() {   
  }   
  build() { 
    Navigation(this.pageInfos) { 
     Row() { 
     Column() { 
       Text('内部存储') 
       .fontSize('20fp') 
       .fontColor('#000000') 
       .fontWeight(FontWeight.Medium) 
     } 
      .alignItems(HorizontalAlign.Start) 
    } 
    .padding({ left: '36vp',right: '24vp', top: '12vp'}) 
    .width('100%') 
    .height('56vp') 
    .onClick(() => { 
      let params: Record<string, string> = { 
       'rootUri': '' 
     }; 
      this.pageInfos.pushPath(new NavPathInfo('MyPhone', params)); 
    }) 
    }     .backgroundColor('#F1F3F5') 
    .navDestination(this.pageMap) 
    .mode(NavigationMode.Split) 
    .navBarWidth('295vp') 
    .title('浏览') 
    .titleMode(NavigationTitleMode.Mini) 
    .hideBackButton(true) 
    .onNavBarStateChange((isVisible: boolean) => { 
     if (isVisible) { 
     this.onPageShow(); 
    } 
   }) 
  }   
   
  @Builder   pageMap(name: string, params: Object) { 
    if (name === 'MyPhone') { 
    MyPhoneTest({ pageParams: params }); 
    } 
  } 
}   
@Component 
export struct MyPhoneTest { 
  @Consume('pageInfos') pageInfos: NavPathStack; 
  private pageParams: Object = new Object(); 
     onPageHide() { 
  } 
  onPageShow() { 
  }   
  build() { 
    NavDestination() { 
    Text('内容区') 
     .fontSize('40fp') 
    } 
    .onBackPressed(() => { 
     this.pageInfos.pop(); 
      return true; 
    }) 
    .backgroundColor('#F1F3F5') 
    .title('我的手机') 
    .onShown(() => this.onPageShow()) 
    .onHidden(() => this.onPageHide()) 
    .width('100%') 
    .height('100%') 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.

Demo效果:

分享
微博
QQ
微信
回复
2024-06-12 17:30:02


相关问题
请教一下关于Ticktimer 的疑问?
4002浏览 • 1回复 待解决
请教一下如何实现函数的重载
1506浏览 • 1回复 待解决
请教一下如何开关闪光灯
1239浏览 • 1回复 待解决
HarmonyOS 关于分栏的断点优化问题
315浏览 • 1回复 待解决
请教2个vp相关的问题,麻烦解答一下
791浏览 • 1回复 待解决
谁分享一下如何实现匿名内部类
1583浏览 • 1回复 待解决
请问一下鸿蒙的pad应用该如何签名?
8861浏览 • 1回复 待解决