1# 应用市场首页 2 3 4本小节将以应用市场首页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/code/SuperFeature/MultiDeviceAppDev/AppMarket)中开源,读者可以根据需要自行下载源码并运行及查看效果。 5 6 7## 页面设计 8 9一个典型的应用市场首页的UX设计如下所示。 10 11 | sm | md | lg | 12| -------- | -------- | -------- | 13| ![zh-cn_image_0000001328579522](figures/zh-cn_image_0000001328579522.png) | ![zh-cn_image_0000001328259918](figures/zh-cn_image_0000001328259918.png) | ![zh-cn_image_0000001379179861](figures/zh-cn_image_0000001379179861.png) | 14 15观察应用市场首页的页面设计,不同断点下的页面设计有较多相似的地方。 16 17据此,我们可以将页面分拆为多个组成部分。 18 191. 底部/侧边导航栏 20 212. 标题栏与搜索栏 22 233. 运营横幅 24 254. 快捷入口 26 275. 精品应用 28 29 | sm | md | lg | 30| -------- | -------- | -------- | 31| ![zh-cn_image_0000001379299533](figures/zh-cn_image_0000001379299533.png) | ![zh-cn_image_0000001328259922](figures/zh-cn_image_0000001328259922.png) | ![zh-cn_image_0000001379179865](figures/zh-cn_image_0000001379179865.png) | 32 33接下来我们逐一分析各部分的实现。 34 35 36## 底部/侧边导航栏 37 38在sm和md断点下,导航栏在底部;在lg断点下,导航栏在左侧。可以通过[Tab组件](../../reference/arkui-ts/ts-container-tabs.md)的barPosition和vertical属性控制TabBar的位置,同时还可以通过barWidth和barHeight属性控制TabBar的尺寸。 39 40 41``` 42@Entry 43@Component 44struct Index { 45 ... 46 build() { 47 // 设置TabBar在主轴方向起始或结尾位置 48 Tabs({ barPosition: this.currentBreakpoint === "lg" ? BarPosition.Start : BarPosition.End }) { 49 // 首页 50 TabContent() { 51 Home() 52 }.tabBar(this.tabItem1) 53 TabContent() {}.tabBar(this.tabItem2) 54 TabContent() {}.tabBar(this.tabItem3) 55 TabContent() {}.tabBar(this.tabItem4) 56 TabContent() {}.tabBar(this.tabItem5) 57 } 58 .backgroundColor('#F1F3F5') 59 .barMode(BarMode.Fixed) 60 .barWidth(this.currentBreakpoint === "lg" ? 96 : '100%') 61 .barHeight(this.currentBreakpoint === "lg" ? '60%' : 56) 62 // 设置TabBar放置在水平或垂直方向 63 .vertical(this.currentBreakpoint === "lg") 64 } 65} 66``` 67 68另外在sm及lg断点下,TabBar中各个Item的图标和文字是按照垂直方向排布的,在md断点下,TabBar中各个Item的图标和文字是按照水平方向排布的。 69 70 71``` 72@Component 73export default struct TabBarItem { 74 ... 75 build() { 76 if (this.currentBreakpoint !== 'md' ) { 77 // sm及lg断点下,tabBarItem中的图标和文字垂直排布 78 Column() { 79 ... 80 }.justifyContent(FlexAlign.Center).height('100%').width('100%') 81 } else { 82 // md断点下,tabBarItem中的图标和文字水平排布 83 Row() { 84 .... 85 }.justifyContent(FlexAlign.Center).height('100%').width('100%') 86 } 87 } 88} 89``` 90 91 92## 标题栏与搜索栏 93 94标题栏和搜索栏,在sm和md断点下分两行显示,在lg断点下单行显示,可以通过栅格实现。在sm和md断点下,标题栏和搜索栏占满12列,此时会自动换行显示。在lg断点下,标题栏占8列而搜索栏占4列,此时标题栏和搜索栏在同一行中显示。 95 96 | | sm/md | lg | 97| -------- | -------- | -------- | 98| 效果图 | ![zh-cn_image_0000001379385785](figures/zh-cn_image_0000001379385785.png) | ![zh-cn_image_0000001379464977](figures/zh-cn_image_0000001379464977.jpg) | 99| 栅格布局图 | ![zh-cn_image_0000001379464981](figures/zh-cn_image_0000001379464981.png) | ![zh-cn_image_0000001328745102](figures/zh-cn_image_0000001328745102.png) | 100 101 102``` 103@Component 104export default struct IndexHeader { 105 ... 106 build() { 107 // 借助栅格实现标题栏和搜索栏在不同断点下的不同布局效果。 108 GridRow() { 109 GridCol({ span: { xs: 12, lg: 8 } }) { 110 this.titleBar() 111 } 112 GridCol({ span: { xs: 12, lg: 4 } }) { 113 this.searchBar() 114 } 115 } 116 .width('100%') 117 } 118} 119``` 120 121 122## 运营横幅 123 124不同断点下的运营横幅,sm断点下显示一张图片,md断点下显示两张图片,lg断点下显示三张图片。可以通过[Swiper组件的displayCount属性](../../reference/arkui-ts/ts-container-swiper.md)实现目标效果。 125 126 127``` 128@Component 129export default struct IndexSwiper { 130 ... 131 @Builder swiperItem(imageSrc) { 132 Image(imageSrc) 133 .width('100%') 134 .aspectRatio(2.5) 135 .objectFit(ImageFit.Fill) 136 } 137 138 build() { 139 Swiper() { 140 this.swiperItem($r('app.media.ic_public_swiper1')) 141 this.swiperItem($r('app.media.ic_public_swiper2')) 142 this.swiperItem($r('app.media.ic_public_swiper3')) 143 ... 144 } 145 .autoPlay(true) 146 .indicator(false) 147 .itemSpace(10) 148 // 配置不同断点下运行横幅中展示的图片数量 149 .displayCount(this.currentBreakpoint === 'sm' ? 1 : (this.currentBreakpoint === 'md' ? 2 : 3)) 150 .width('100%') 151 .padding({ left: 12, right: 12, bottom: 16, top: 16 }) 152 } 153} 154``` 155 156 157## 快捷入口 158 159在不同的断点下,快捷入口的5个图标始终均匀排布,这是典型的均分能力使用场景。 160 161 162``` 163@Component 164@Component 165export default struct IndexEntrance { 166 build() { 167 // 将justifyContent参数配置为FlexAlign.SpaceEvenly实现均分布局 168 Row() { 169 ForEach(entranceIcons, (icon: AllIcons) => { 170 // 各快捷入口的图标及名称 171 Column() { ... } 172 }) 173 } 174 .width('100%') 175 .height(64) 176 .justifyContent(FlexAlign.SpaceEvenly) 177 .padding({ left: 12, right: 12 }) 178 } 179} 180``` 181 182 183## 精品应用 184 185随着可用显示区域的增加,精品应用中显示的图标数量也不断增加,这是典型的延伸能力使用场景。精品游戏的实现与精品应用类似,不再展开分析。 186 187 188``` 189@Component 190@Component 191export default struct IndexApps { 192 ... 193 build() { 194 Column() { 195 this.appListHeader() 196 // 借助List组件能力,实现延伸能力场景 197 List({ space: this.currentBreakpoint === 'lg' ? 44 : 20}) { 198 LazyForEach(new MyAppSource(this.apps), app => { 199 ListItem() { 200 // 每个应用的图标、名称及安装按钮 201 this.appListItem(app) 202 } 203 }, app => app.id) 204 } 205 .width('100%') 206 .height(this.currentBreakpoint === 'lg' ? 140 : 120) 207 .listDirection(Axis.Horizontal) 208 } 209 .width('100%') 210 .height(this.currentBreakpoint === 'lg' ? 188 : 164) 211 .padding({ bottom: 8, left: 12, right: 12 }) 212 } 213} 214``` 215 216 217## 运行效果 218 219将上述各页面主要部分组合在一起后,即可完成整体页面开发。 220 221 222``` 223@Component 224struct IndexContent { 225 ... 226 build() { 227 List() { 228 // 运营横幅 229 ListItem() { 230 IndexSwiper() 231 } 232 // 快捷入口 233 ListItem() { 234 IndexEntrance() 235 } 236 // 精品应用 237 ListItem() { 238 IndexApps({ title: $r('app.string.boutique_application'), apps: appList }) 239 } 240 // 精品游戏 241 ListItem() { 242 IndexApps({ title: $r('app.string.boutique_game'), apps: gameList }) 243 } 244 } 245 .width("100%") 246 } 247} 248 249@Component 250export default struct Home { 251 ... 252 build() { 253 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) { 254 // 标题栏和搜索栏 255 IndexHeader() 256 // 运营横幅、快捷入口、精品应用、精品游戏等 257 IndexContent() 258 } 259 .height('100%') 260 .backgroundColor("#F1F3F5") 261 } 262} 263``` 264 265本页面的实际运行效果如下图所示。 266 267 | sm | md | lg | 268| -------- | -------- | -------- | 269| ![zh-cn_image_0000001334345550](figures/zh-cn_image_0000001334345550.jpg) | ![zh-cn_image_0000001385105477](figures/zh-cn_image_0000001385105477.jpg) | ![zh-cn_image_0000001384985569](figures/zh-cn_image_0000001384985569.jpg) | 270 271<!--no_check-->