ArkUI栅格布局

前言:

在UI方面,为了适应不同尺寸的设备(主要是sm,md,lg),使用Grid布局,尺寸默认为四种(xm,sm.md,lg),可以支持六种(xm,sm,md,lg,xl,xxl)。
1.在内容的音乐列表中,也用到了List组件的line组件,以父组件传递的breakpoints属性值来决定lines括号中的值,总体上就是先布局,然后再往里面写内容
在TS方面,单独声明了音乐信息类和操作类,以及单独做了一个假的数据库,和单独的播放列表(默认是所有音乐,没有实现增删改功能),以便点击音乐列表使底部的播放栏显示对应的音乐信息

效果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码

viewmodel/Option

export default
class Option{
  key:string
  value:string
  imgSrc:Resource

  constructor(key:string,value:string,imgSrc:Resource) {
    this.key = key
    this.value = value
    this.imgSrc = imgSrc
  }
}

viewmodel/SongInfo


@Observed
export default class SongInfo{
  name:string
  singer:string
  songCover:string|Resource
  vipImgSrc:string|Resource

  constructor(name:string,singer:string,songCover:string|Resource,vipImgSrc:string|Resource) {
    this.name = name
    this.singer = singer
    this.songCover = songCover
    this.vipImgSrc = vipImgSrc
  }
}

database/Songinfos

import SongInfo from '../viewmodel/SongInfo'

 let SongInfos: SongInfo[] = [
  new SongInfo("不称职的天才", '王以太',$r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("不知道你为了什么而来", '江懿',$r('app.media.app_icon'), $r('app.media.wodeVIP')),
  new SongInfo("谁能避开恋爱这事情", '张天赋/姚焯菲', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("大鱼", '周深', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("有我呢", '派派',$r('app.media.app_icon'), $r('app.media.wodeVIP')),
  new SongInfo("不得不爱", '潘玮柏', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("雨下一整夜", 'ICE杨长青',$r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("散了,断了,疯了", '磨尖的粉笔', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("不识字的作词家", '不蓝', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("巨鹿", '华晨宇/田燚', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("很远的地方", '张学友', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("天意", '刘德华', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("坏杀手", '探长', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("但我正在想你", '王铮亮', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("青花瓷", '周杰伦', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("虹之间", '金贵晟', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("我好想你", '苏打绿', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("突然想起你", '林宥嘉', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("冬眠", '阿YueYue/刘兆宇', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
  new SongInfo("主角", 'Mario', $r('app.media.app_icon'),$r('app.media.wodeVIP')),
]
export default SongInfos

database/PlayList

import SongInfo from '../viewmodel/SongInfo'

let playList:SongInfo[] = []
export default playList

pages/index

import MusicHeader from '../components/MuiscHeader'
import MusicContent from '../components/MusicContent'
import MusicPlayer from '../components/MusicPlayer'
import playList from '../datebase/PlayList'
import SongInfos from '../datebase/SongInfos'

@Entry
@Component
struct Index{
  aboutToAppear(): void {
    for(let i = 0;i<SongInfos.length;i++){
      playList.push(SongInfos[i])
    }
  }
  @Provide currentIndex:number = 0
  build() {
    Column(){
      //header
      MusicHeader()
      //content
      MusicContent()
      //bottom player
      MusicPlayer()
    }
    .width('100%')
    .height('100%')
  }
}

components/MusicHeader

@Component
export default struct MusicHeader{
  @State color:string = '#e4eaf6'
  build() {
    GridRow(){
      //left
      GridCol({span:{sm:6,md:6,lg:4}}){
        Row({space:8}){
          Image($r('app.media.fanhui'))
            .width(25)
          Text('歌单')
        }
        .width('100%')
        .height(80)
        .backgroundColor('#e4eaf6')
        .padding(8)
      }
      //right
      GridCol({span:{sm:6,md:6,lg:8}}){
        Row(){
          Image($r('app.media.gengduo'))
            .width(40)
        }
        .width('100%')
        .height(80)
        .justifyContent(FlexAlign.End)
        .padding(8)
        .backgroundColor(this.color)
      }
    }
    .onBreakpointChange((breakpoints)=>{
        if(breakpoints == 'sm'){
          this.color = '#e4eaf6'
        }
        else{
          this.color ='#f8f8f8'
        }
    })
  }
}

components/MusicContent

import MusicList from './MusicList'
import MusicListCover from './MusicListCover'

@Component
export default
struct MusicContent {
  @State breakpoints:string = 'sm'

  build() {
    Column(){
        GridRow(){
          GridCol({span:{sm:12,md:6,lg:4}}){
            MusicListCover({breakpoints:this.breakpoints})
          }
          GridCol({span:{sm:12,md:6,lg:8}}){
            MusicList({breakpoints:this.breakpoints})
          }
        }
        .onBreakpointChange((breakpoints)=>{
          this.breakpoints = breakpoints
        })
      }.layoutWeight(1)
  }
}

components/MusicCover

import Option from '../viewmodel/Option'
@Component
export default
struct MusicListCover {
  @Link breakpoints:string
  @State coverHeight:number = 0
  @State options:Option[] = [
    new Option('点赞','999+',$r('app.media.xiaiaixindianzan')),
    new Option('下载','下载',$r('app.media.xiazai')),
    new Option('评论','评论',$r('app.media.comment')),
    new Option('分享','分享',$r('app.media.fenxiang_m'))
  ]

  @Builder Cover(){
    Stack({alignContent:Alignment.BottomStart}){
      Image($r('app.media.head'))
        .width('100%')
        .borderRadius(15)
        .onAreaChange((oldArea,newArea)=>{
          this.coverHeight = newArea.height as number
        })
      Text($r('app.string.collection_num'))
        .fontColor(Color.White)
    }
    .padding(this.breakpoints==='sm'?10:0)
    .width('100%')
  }

  @Builder TitleAndDescription(){
    Column({space:8}){
      Text($r('app.string.list_name'))
        .fontSize(20)
        .fontWeight(700)
      Text($r('app.string.playlist_Introduction'))
    }
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .padding(this.breakpoints=='sm'?{left:10,right:20}:{})
    .height(this.breakpoints == 'sm'?this.coverHeight:70)
    .margin(this.breakpoints=='sm'?{}:{top:20,bottom:20})
  }

  @Builder Operations(){
    Row(){
      ForEach(this.options,(item:Option,index:number)=>{
        Column({space:2}){
          Image(item.imgSrc)
            .width(24)
          Text(item.value)
        }
      })
    }
    .margin({top:20,bottom:30})
    .width('100%')
    .justifyContent(this.breakpoints=='sm'?FlexAlign.SpaceAround:FlexAlign.SpaceBetween)
  }
  build() {
    Column(){
      GridRow(){
        GridCol({span:{sm:4,md:10},offset:{sm:0,md:1}}){
          //Cover
          this.Cover()
        }
        GridCol({span:{sm:8,md:10},offset:{sm:0,md:2}}){
          //title and description
          this.TitleAndDescription()
        }
        GridCol({span:{sm:12,md:10},offset:{sm:0,md:2}}){
          //options
        this.Operations()
        }
      }
    }

    .layoutWeight(this.breakpoints=='sm'?0:1)
    .backgroundColor('#e4eaf6')

  }
}

components/MusicList

import playList from '../database/PlayList'
import SongInfos from '../database/SongInfos'
import SongInfo from '../viewmodel/SongInfo'

@Component
export default struct MusicList {
  //dateBase
  @Consume currentIndex: number
  @State songNum: number = SongInfos.length
  @Link breakpoints: string
  @Builder
  playAll() {
    Row({ space: 8 }) {
      Image($r('app.media.music_top_player'))
        .width(20)
        .fillColor(Color.Red)
        .onClick(() => {
          this.currentIndex = 0
        })
      Text(`播放全部(${this.songNum})`)
        .fontSize(20)
    }
  }

  @Builder
  orderAndSelectMore() {
    Row({ space: 10 }) {
      Image($r('app.media.music_orderButton'))
        .width(20)
      Image($r('app.media.music_selectMoreButton'))
        .width(20)
    }
  }

  @Builder
  songItem(item: SongInfo,index:number) {
    Row() {
      Column({ space: 5 }) {
        Text(item.name)
        Row({ space: 3 }) {
          Image(item.vipImgSrc)
            .width(20)
          Text(item.singer)
            .fontSize(10)
        }
        .width('100%')
      }
      .alignItems(HorizontalAlign.Start)
      .height('100%')

      Image($r('app.media.music_songItem_more'))
        .width(25)
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .padding(20)
    .height(70)
    .onClick(() => {
      this.currentIndex = index
    })
  }

  build() {
    Column() {
      //listHeader
      Row() {
        this.playAll()
        this.orderAndSelectMore()
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .padding({
        top: 30,
        left: 20,
        right: 20,
        bottom: 30
      })
      .width('100%')
      .borderRadius(20)

      //songList
      List({ space: 10 }) {
        ForEach(SongInfos, (item: SongInfo, index) => {
          if (SongInfos.length - 1) {
            ListItem() {
              this.songItem(item,index)
            }
          }
        })
      }
      .divider({
        strokeWidth: 1,
        color: '#ccc',
        startMargin: 20
      })
      .width('100%')
      .layoutWeight(1)
      .lanes(this.breakpoints == 'lg' ? 2 : 1)
    }
  }
}

components/MusicPlayer

import playList from '../database/PlayList'
import SongInfo from '../viewmodel/SongInfo'

@Component
export default
struct MusicPlayer {
  @Consume currentIndex:number
  @Builder leftSongInfo(){
    Row(){
      //SongCover
      Image(playList[this.currentIndex].songCover)
        .height('90%')
      //songInfo
      Column({space:8}){
        Text(playList[this.currentIndex].name)
          .fontSize(20)
        Row(){
          Image(playList[this.currentIndex].vipImgSrc)
            .width(20)
          Text(playList[this.currentIndex].singer)
            .fontSize(10)
        }
      }.alignItems(HorizontalAlign.Start)
    }
    .layoutWeight(1)
    .height('100%')

  }
  @Builder rightOption(){
    Row(){
      Image($r('app.media.music_top_player'))
        .width(20)
        .fillColor(Color.Red)
      Image($r('app.media.bofangxiayishou'))
        .width(20)
        .fillColor(Color.Red)
        .onClick(() => {
          this.currentIndex +=1
          this.currentIndex %= playList.length
        })
      Image($r('app.media.music_bottom_playList'))
        .width(20)
        .fillColor(Color.Red)

    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width(80)
    .height('100%')
  }

  build() {
    Row(){
      //left:songInfo
      this.leftSongInfo()
      //right:options
      this.rightOption()
    }
    .height('10%')
    .width('100%')
    .padding({top:10,left:20,right:20,bottom:10})
    .justifyContent(FlexAlign.SpaceBetween)
  }
}
  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值