音樂專輯頁
本小節(jié)將以音樂專輯頁為例,介紹如何使用自適應(yīng)布局能力和響應(yīng)式布局能力適配不同尺寸窗口。
頁面設(shè)計
音樂專輯頁的頁面設(shè)計如下。
同樣觀察音樂專輯的頁面設(shè)計,不同斷點下的頁面設(shè)計有較多相似的地方。
據(jù)此,我們可以將頁面分拆為多個組成部分。
- 標題欄
- 歌單封面
- 歌單列表
- 播放控制欄
- 開發(fā)前請熟悉鴻蒙開發(fā)指導(dǎo)文檔 :[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]點擊或者復(fù)制轉(zhuǎn)到。
標題欄
不同斷點下,標題欄始終只顯示“返回按鈕”、“歌單”以及“更多按鈕”,但“歌單”與“更多按鈕”之間的間距不同。由于不同斷點下標題欄的背景色也有較大差異,因此無法使用拉伸能力實現(xiàn),此場景更適合使用柵格實現(xiàn)。我們可以將標題欄劃分為“返回按鈕及歌單”和“更多按鈕”兩部分,這兩部分在不同斷點下占據(jù)的列數(shù)如下圖所示。另外,還可以借助OnBreakpointChange事件,調(diào)整不同斷點下這兩部分的背景色。
@Component
export struct Header {
@State moreBackgroundColor: Resource = $r('app.color.play_list_cover_background_color');
build() {
GridRow() {
GridCol({span: {sm:6, md: 6, lg:4}}) {
Row() {
Image($r('app.media.ic_back')).height('24vp').width('24vp')
}
.width('100%')
.height('50vp')
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Center)
.padding({left:$r('app.float.default_margin')})
.backgroundColor($r('app.color.play_list_cover_background_color'))
}
GridCol({span: {sm:6, md: 6, lg:8}}) {
Row() {
Image($r('app.media.ic_add')).height('24vp').width('24vp')
}
.width('100%')
.height('50vp')
.justifyContent(FlexAlign.End)
.alignItems(VerticalAlign.Center)
.padding({right:$r('app.float.default_margin')})
.backgroundColor(this.moreBackgroundColor)
}
}.onBreakpointChange((currentBreakpoint) = > {
// 調(diào)整不同斷點下返回按鈕及歌單的背景色
if (currentBreakpoint === 'sm') {
this.moreBackgroundColor = $r('app.color.play_list_cover_background_color');
} else {
this.moreBackgroundColor = $r('app.color.play_list_songs_background_color');
}
}).height('100%').width('100%')
}
}
歌單封面
歌單封面由封面圖片、歌單介紹及常用操作三部分組成,這三部分的布局在md和lg斷點下完全相同,但在sm斷點下有較大差異。此場景同樣可以用柵格實現(xiàn)。
import { optionList } from '../model/SongList'
@Component
export default struct PlayListCover {
@State imgHeight: number = 0;
@StorageProp('coverMargin') coverMargin: number = 0;
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm';
@StorageProp('fontSize') fontSize: number = 0;
@Builder
CoverImage() {
Stack({ alignContent: Alignment.BottomStart }) {
Image($r('app.media.pic_album'))
.width('100%')
.aspectRatio(1)
.borderRadius(8)
.onAreaChange((oldArea: Area, newArea: Area) = > {
this.imgHeight = newArea.height as number
})
Text($r('app.string.collection_num'))
.letterSpacing(1)
.fontColor('#fff')
.fontSize(this.fontSize - 4)
.translate({ x: 10, y: '-100%' })
}
.width('100%')
.height('100%')
.aspectRatio(1)
}
@Builder
CoverIntroduction() {
Column() {
Text($r('app.string.list_name'))
.opacity(0.9)
.fontWeight(500)
.fontColor('#556B89')
.fontSize(this.fontSize + 2)
.margin({ bottom: 10 })
Text($r('app.string.playlist_Introduction'))
.opacity(0.6)
.width('100%')
.fontWeight(400)
.fontColor('#556B89')
.fontSize(this.fontSize - 2)
}
.width('100%')
.height(this.currentBreakpoint === 'sm' ? this.imgHeight : 70)
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.Center)
.padding({ left: this.currentBreakpoint === 'sm' ? 20 : 0 })
.margin({
top: this.currentBreakpoint === 'sm' ? 0 : 30,
bottom: this.currentBreakpoint === 'sm' ? 0 : 20
})
}
@Builder
CoverOptions() {
Row() {
ForEach(optionList, item = > {
Column({ space: 4 }) {
Image(item.image).height(30).width(30)
Text(item.text)
.fontColor('#556B89')
.fontSize(this.fontSize - 1)
}
})
}
.width('100%')
.height(70)
.padding({
left: this.currentBreakpoint === 'sm' ? 20 : 0,
right: this.currentBreakpoint === 'sm' ? 20 : 0
})
.margin({
top: this.currentBreakpoint === 'sm' ? 15 : 0,
bottom: this.currentBreakpoint === 'sm' ? 15 : 0
})
.justifyContent(FlexAlign.SpaceBetween)
}
build() {
Column() {
// 借助柵格組件實現(xiàn)總體布局
GridRow() {
// 歌單圖片
GridCol({ span: { sm: 4, md: 10 }, offset: { sm: 0, md: 1, lg: 1 } }) {
this.CoverImage()
}
// 歌單介紹
GridCol({ span: { sm: 8, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {
this.CoverIntroduction()
}
// 歌單操作
GridCol({ span: { sm: 12, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {
this.CoverOptions()
}.margin({
top: this.currentBreakpoint === 'sm' ? 15 : 0,
bottom: this.currentBreakpoint === 'sm' ? 15 : 0
})
}
.margin({ left: this.coverMargin, right: this.coverMargin })
}
.height('100%')
.padding({ top: this.currentBreakpoint === 'sm' ? 50 : 70 })
}
}
歌單列表
不同斷點下,歌單列表的樣式基本一致,但sm和md斷點下是歌單列表是單列顯示,lg斷點下是雙列顯示。可以通過[List組件]的lanes屬性實現(xiàn)這一效果。
import { songList } from '../model/SongList';
import MyDataSource from '../model/SongModule'
@Component
export default struct PlayList {
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm';
@StorageProp('fontSize') fontSize: number = 0;
@Consume coverHeight: number;
@Builder
PlayAll() {
Row() {
Image($r("app.media.ic_play_all"))
.height(23)
.width(23)
Text($r('app.string.play_all'))
.maxLines(1)
.padding({ left: 10 })
.fontColor('#000000')
.fontSize(this.fontSize)
Blank()
Image($r('app.media.ic_order_play'))
.width(24)
.height(24)
.margin({ right: 16 })
Image($r('app.media.ic_sort_list'))
.height(24)
.width(24)
}
.height(60)
.width('100%')
.padding({ left: 12, right: 12 })
}
@Builder
SongItem(title: string, label: Resource, singer: string) {
Row() {
Column() {
Text(title)
.fontColor('#000000')
.fontSize(this.fontSize)
.margin({ bottom: 4 })
Row() {
Image(label)
.width(16)
.height(16)
.margin({ right: 4 })
Text(singer)
.opacity(0.38)
.fontColor('#000000')
.fontSize(this.fontSize - 4)
}
}
.alignItems(HorizontalAlign.Start)
Blank()
Image($r('app.media.ic_list_more'))
.height(24)
.width(24)
}
.height(60)
.width('100%')
}
build() {
Column() {
this.PlayAll()
Scroll() {
List() {
LazyForEach(new MyDataSource(songList), item = > {
ListItem() {
this.SongItem(item.title, item.label, item.singer)
}
})
}
.width('100%')
.height('100%')
// 配置不同斷點下歌單列表的列數(shù)
.lanes(this.currentBreakpoint === 'lg' ? 2 : 1)
}
.backgroundColor('#fff')
.margin({ top: 50, bottom: this.currentBreakpoint === 'sm' ? this.coverHeight : 0 })
}
.padding({top: 50,bottom: 48})
}
}
播放控制欄
在不同斷點下,播放控制欄顯示的內(nèi)容完全一致,唯一的區(qū)別是歌曲信息與播放控制按鈕之間的間距有差異,這是典型的拉伸能力的使用場景。
@Component
export default struct Player {
@StorageProp('fontSize') fontSize: number = 0;
build() {
Row() {
Image($r('app.media.pic_album')).height(32).width(32).margin({right: 12})
Column() {
Text($r('app.string.song_name'))
.fontColor('#000000')
.fontSize(this.fontSize - 1)
Row() {
Image($r('app.media.ic_vip'))
.height(16)
.width(16)
.margin({ right: 4 })
Text($r('app.string.singer'))
.fontColor('#000000')
.fontSize(this.fontSize - 4)
.opacity(0.38)
}
}
.alignItems(HorizontalAlign.Start)
// 通過Blank組件實現(xiàn)拉伸能力
Blank()
Image($r('app.media.icon_play')).height(26).width(26).margin({right: 16})
Image($r('app.media.ic_next')).height(24).width(24).margin({right: 16})
Image($r('app.media.ic_Music_list')).height(24).width(24)
}
.width('100%')
.height(48)
.backgroundColor('#D8D8D8')
.alignItems(VerticalAlign.Center)
.padding({left: 16, right: 16})
}
}
運行效果
將頁面中的四部分組合在一起,即可顯示完整的頁面。
其中歌單封面和歌單列表這兩部分的相對位置,在sm斷點下是上下排布,在md和lg斷點下是左右排布,也可以用柵格來實現(xiàn)目標效果。
import PlayListCover from '../common/PlayListCover';
import PlayList from '../common/PlayList';
@Component
export default struct Content {
// ...
build() {
GridRow() {
// 歌單封面
GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 4 } }) {
PlayListCover()
}
// 歌單列表
GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 8 } }) {
PlayList()
}
}
.height('100%')
}
}
最后將頁面各部分組合在一起即可。
import Header from '../common/Header';
import Player from '../common/Player';
import Content from '../common/Content';
@Entry
@Component
struct Index {
build() {
Column() {
// 標題欄
Header()
// 歌單
Content()
// 播放控制欄
Player()
}.width('100%').height('100%')
}
}
`HarmonyOS與OpenHarmony鴻蒙文檔籽料:mau123789是v直接拿`
音樂專輯頁面的運行效果如下所示。
-
HarmonyOS
+關(guān)注
關(guān)注
79文章
1973瀏覽量
30143 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3713瀏覽量
16256 -
鴻蒙OS
+關(guān)注
關(guān)注
0文章
188瀏覽量
4383
發(fā)布評論請先 登錄
相關(guān)推薦
評論