Building HarmonyOS Audiobook App: Discover Page Implementation

This tutorial walks through implementing the Discover page for a HarmonyOS audiobook app, covering title bar setup with HdsNavDestination, hot tags layout using Flex wrap, featured playlists with Row and ForEach, and a bottom audio info bar with space-between alignment.

51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
Building HarmonyOS Audiobook App: Discover Page Implementation

The article demonstrates how to build the Discover page of a HarmonyOS audiobook app. The page consists of three main sections: a title bar, a content list, and a currently playing audio info bar.

Title Bar Implementation

The title bar uses HdsNavDestination with a gradual blur scroll effect. It hides the back button, sets the background color, adds top padding from AppStorage.get('topHeight'), and configures a title bar with main title "发现" (Discover) and a single menu button using a search icon resource.

HdsNavDestination(){ … }.padding({top:AppStorage.get('topHeight') as number}).backgroundColor(this.backColor).hideBackButton(true).titleBar({ style:{ scrollEffectOpts:{ scrollEffectType: ScrollEffectType.GRADUAL_BLUR } }, content:{ title:{ mainTitle:'发现' }, menu:{ value:[ { content:{ label:'', icon:$r('app.media.sjSearch') } } ] } })

A screenshot shows the rendered title bar.

Content List and Navigation Bar Avoidance

Because HdsNavDestination is used, the first list item must manually avoid the title bar height. A Blank component with height 56 is inserted at the top of the list.

ListItem(){ Row(){ Blank().height(56) } }

Hot Tags Section with Flex Wrap

Hot tags are implemented using a Flex container with direction: FlexDirection.Row, wrap: FlexWrap.Wrap, and main-axis spacing of 10vp. Each tag is a Text component styled with white font, 13px size, centered alignment, horizontal padding 10, vertical padding 6, semi-transparent gray background, 4px border radius, and top margin 10. The tags array contains eight categories: "心理成长", "历史", "商业财经", "文学小说", "科幻", "悬疑推理", "自我提升", "传记".

@State tags:string[] = ['心理成长','历史','商业财经','文学小说','科幻','悬疑推理','自我提升','传记'] Flex({direction:FlexDirection.Row,wrap:FlexWrap.Wrap,space:{main:{value:10,unit:LengthUnit.VP}}}){ ForEach(this.tags,(str:string,index)=>{ Text(str).fontColor(Color.White).fontSize(13).textAlign(TextAlign.Center).padding({left:10,right:10,top:6,bottom:6}).backgroundColor('rgba(200,200,200,0.3)').borderRadius(4).margin({top:10}) }) }

A screenshot illustrates the wrap layout resembling a horizontal waterfall flow.

Featured Playlists Horizontal Row

The "精选播单" (Featured Playlists) section displays three items horizontally without scrolling. A Row with justifyContent: FlexAlign.SpaceAround and top padding 10 contains a ForEach over this.bds. Each item is a Column (spacing 7) with an Image (width 100%, height 143, border radius 12, objectFit Fill), a bold white title (14px), a gray content line (13px), and a gray count line (13px). The column aligns items start and has fixed width 100.

Row(){ ForEach(this.bds,(item:BDClass,index)=>{ Column({space:7}){ Image(item.img).width('100%').height(143).borderRadius(12).objectFit(ImageFit.Fill) Text(item.title).fontColor(Color.White).fontSize(14).fontWeight(FontWeight.Bold) Text(item.content).fontColor('rgb(200,200,200)').fontSize(13) Text(item.count).fontColor('rgb(200,200,200)').fontSize(13) }.alignItems(HorizontalAlign.Start).width(100) }) }.width('100%').justifyContent(FlexAlign.SpaceAround).padding({top:10})

A screenshot shows the three-card layout.

Currently Playing Audio Info Bar

The bottom audio bar uses a Row with alignItems: VerticalAlign.Center, justifyContent: FlexAlign.SpaceBetween, full width, height 50, background color rgb(106,87,65), and horizontal padding 14. The left side is a Row (space 6) containing a 35x35 cover image and a Column with two white/gray texts: book title "瓦尔登湖" (13px) and chapter "第3章 自然之声" (13px, gray). The right side is a Row (space 10) with two 32x32 icon images for play and list.

Row(){ Row({space:6}){ Image($r('app.media.bodan2')).width(35).height(35) Column(){ Text('瓦尔登湖').fontColor(Color.White).fontSize(13) Text('第3章 自然之声').fontColor('rgb(200,200,200)').fontSize(13) }.alignItems(HorizontalAlign.Start) } Row({space:10}){ Image($r('app.media.barPlay')).width(32).height(32) Image($r('app.media.sjList')).width(32).height(32) } }.alignItems(VerticalAlign.Center).justifyContent(FlexAlign.SpaceBetween).width('100%').height(50).backgroundColor('rgb(106,87,65)').padding({left:14,right:14})

A final screenshot shows the complete page with all sections combined.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

UI DevelopmentArkUIFlex LayoutRow LayoutAudiobook AppDiscover PageHdsNavDestination
51CTO HarmonyOS Developer Community
Written by

51CTO HarmonyOS Developer Community

The HarmonyOS Developer Community is a learning-oriented community for developers to learn, communicate, ask questions, and share.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.