• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-->