HarmonyOS 5.0應用開發——仿微信聊天介面

高心星發表於2024-12-09

【高心星出品】

仿微信聊天介面

閒暇之餘開發了一個基於HarmonyOS5.0的仿微信聊天介面,裡面主要用到了ArkUI的技術。

List佈局:列表是一種複雜的容器,當列表項達到一定數量,內容超過螢幕大小時,可以自動提供滾動功能。它適合用於呈現同類資料型別或資料型別集,例如圖片和文字。在列表中顯示資料集合是許多應用程式中的常見要求(如通訊錄、音樂列表、購物清單等)。

Grid佈局:網格佈局是由“行”和“列”分割的單元格所組成,透過指定“專案”所在的單元格做出各種各樣的佈局。網格佈局具有較強的頁面均分能力,子元件佔比控制能力,是一種重要自適應佈局,其使用場景有九宮格圖片展示、日曆、計算器等。

Swiper佈局:Swiper本身是一個容器元件,當設定了多個子元件後,可以對這些子元件進行輪播顯示。通常,在一些應用首頁顯示推薦的內容時,需要用到輪播顯示的能力。

LazyForeach懶載入:LazyForEach從提供的資料來源中按需迭代資料,並在每次迭代過程中建立相應的元件。當在滾動容器中使用了LazyForEach,框架會根據滾動容器可視區域按需建立元件,當元件滑出可視區域外時,框架會進行元件銷燬回收以降低記憶體佔用。

執行效果:

開發步驟:

專案結構

聊天標題

聊天標題是一個水平佈局,包括左邊的箭頭,使用者名稱稱和功能圖片。其中左邊的箭頭是由線性佈局旋轉之後外邊框繪製而來。

 titlebar() {
    Row() {
      if (this.badgevalue > 0) {
        //  生成箭頭
        this.arrow(ArrowType.LEFT)
        Badge({
          value: '' + this.badgevalue,
          position: BadgePosition.Right,
          style: { badgeSize: 24, badgeColor: Color.Gray, borderColor: Color.Gray }
        }) {
          Text(' ')
        }
      } else {
        this.arrow(ArrowType.LEFT)
      }
      Blank()
      if (this.title) {
        Text(this.title).fontSize(22).fontColor(Color.Black)
      }
      Blank()
      Image($r('app.media.sangedian')).width('6%').aspectRatio(1)


    }
    .width('100%')
    .padding('5%')
    .border({ width: { bottom: 1 }, color: this.divdercolor })
    .margin({ bottom: 5 })
  }
  //繪製左右箭頭
  @Builder
  arrow(type: ArrowType) {
    if (type == ArrowType.LEFT) {
      Row()
        .rotate({ angle: -45 })
        .border({ width: { top: 2, left: 2 }, color: Color.Black })
        .width('5%')
        .height('5%')
        .aspectRatio(1)
        .margin({ right: 20 })
    } else if (type == ArrowType.RIGHT) {
      Row()
        .rotate({ angle: 45 })
        .border({ width: { top: 2, left: 2 }, color: Color.Black })
        .width('5%')
        .height('5%')
        .aspectRatio(1)
        .margin({ right: 20 })
    }
  }
聊天內容

聊天內容整體是一個list,裡面的listitem會根據訊息來源來進行調整,發出的訊息採取右側佈局,接受的訊息左側佈局。

// 訊息展示區域
  @Builder
  content() {
    List() {
      LazyForEach(this.chats, (item: ChatInfo) => {
        ListItem() {
          if (item.type == ChatType.TIME) {
            this.itemtime(item)
          } else {
            this.itemmsg(item)
          }
        }
      })
    }.layoutWeight(1)
  }
  // 發訊息和收訊息的子佈局
  @Builder
  itemmsg(chat: ChatInfo) {
    if (chat.from === currentuser) {
      //發出的訊息
      Row() {
        Text(chat.message)
          .padding({
            left: '4%',
            right: '4%',
            top: '2%',
            bottom: '2%'
          })
          .backgroundColor('rgba(200,200,200,0.5)')
          .fontSize(18)
          .borderRadius({
            topLeft: 10,
            bottomLeft: 10,
            topRight: 15,
            bottomRight: 15
          })
        Image($r('app.media.Bellboy'))
          .width(35)
          .height(35)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)
          .margin({ left: 10 })
      }.width('100%')
      .padding('2%')
      .justifyContent(FlexAlign.End)
    } else {
      //接受的訊息
      Row() {
        Image($r('app.media.girl')).width(35).height(35).objectFit(ImageFit.Fill).borderRadius(8)
        Text(chat.message)
          .padding({
            left: '4%',
            right: '4%',
            top: '2%',
            bottom: '2%'
          })
          .backgroundColor('rgba(200,200,200,0.5)')
          .fontSize(18)
          .borderRadius({
            topLeft: 15,
            bottomLeft: 15,
            topRight: 10,
            bottomRight: 10
          })
          .margin({ left: 10 })
      }.width('100%')
      .padding('2%')
    }
  }
  // 展示時間的子佈局
  @Builder
  itemtime(msg: ChatInfo) {
    Column() {
      Text(msg.time).fontSize(16).fontColor(Color.Gray)

    }.width('100%').padding('3%')
  }
發訊息佈局

發訊息佈局採取的是水平線性佈局,從左至右分別是語音圖示,輸入框,圖示和新增圖示。

 // 發訊息佈局
  @Builder
  msgbar() {
    Column() {
      Row({ space: 10 }) {
        Image($r('app.media.voicemessage')).width(40).height(40).objectFit(ImageFit.Fill)
        TextInput().layoutWeight(1).borderRadius(10).backgroundColor(Color.White)
        Image($r('app.media.smile')).width(40).height(40).objectFit(ImageFit.Fill)
        Image($r('app.media.add')).width(40).height(40).objectFit(ImageFit.Fill)
          .onClick(() => {
            animateTo({curve:curves.springMotion()},()=>{
              this.showhidebar = !this.showhidebar

            })
          })
      }.padding('3%').width('100%')
      .border({ width: { top: 1 }, color: this.divdercolor })

      // 隱藏欄
      this.hidebar()
    }.width('100%')
  }
隱藏功能卡片佈局

隱藏功能卡片區是用了swiper佈局裡面巢狀了Grid網格佈局。

  @Builder
  hidebar() {
    if (this.showhidebar) {
      Swiper() {
        this.gongnengpage(gongnengs.slice(0, 8))
        this.gongnengpage(gongnengs.slice(8))
      }
      .border({width:{top:1},color:this.divdercolor})
    }
  }

  // 功能頁面
  @Builder
  gongnengpage(gongnengs: GongnengType[]) {
    Grid() {
      ForEach(gongnengs, (gongneng: GongnengType) => {
        GridItem() {
          this.card(gongneng)
        }
      })
    }.columnsTemplate('1fr 1fr 1fr 1fr')
    .width('100%')
    .height('30%')

    .rowsGap('10%')
    .margin({top:'10%'})
  }
  // 功能也的功能卡片
  @Builder
  card(gongneng: GongnengType) {
    Column() {
      Row() {
        Image(gongneng.icon)
          .width(40)
          .height(40)
          .objectFit(ImageFit.Fill)
      }.width(60).height(60).backgroundColor(Color.White).justifyContent(FlexAlign.Center)
      .borderRadius(8)
      Text(gongneng.name).fontSize(14).margin({top:10})
    }.margin({ bottom: '5%' })
  }
資料來源的填充

填充訊息的時候還要考慮,訊息之間的時間間隔。訊息之間時間間隔如果比較小就不會顯示時間,如果時間間隔比較大,就需要增加一個時間顯示列表項。

// 如果上下兩個訊息之間時間間隔超過1個小時 增加一個時間
  adddata(data: ChatInfo) {
    if (this.datas.length > 0) {
      let time = data.time
      let time2 = this.datas[this.datas.length-1].time
      let hour = Number.parseInt(time.slice(time.indexOf(' ') + 1, time.indexOf(':')))
      let hour2 = Number.parseInt(time2.slice(time.indexOf(' ') + 1, time.indexOf(':')))
      if (Math.abs(hour - hour2) >= 1) {
        this.datas.push({ type: ChatType.TIME, time: data.time })
      }
    }
    this.datas.push(data)
  }

專案倉庫Gitee

倉庫地址: https://gitee.com/gxx01/zwechatroom/

相關文章