Xây Dựng Giao Diện Trình Phát Nhạc Đa Phương Tiện Trên OpenHarmony

Trong hệ sinh thái OpenHarmony, việc xây dựng giao diện người dùng dựa trên khung khai báo ArkUI cho phép tách biệt rõ ràng giữa logic xử lý nghiệp vụ và thành phần hiển thị. Dưới đây là hướng dẫn chi tiết về cách tổ chức bố cục giao diện trình phát nhạc đa phương tiện, kèm theo các đoạn mã minh họa đã được tối ưu hóa cấu trúc và biến thể để phù hợp với tiêu chuẩn phát triển hiện đại.

1. Kiến trúc bố cục giao diện chính

Giao diện trình phát nhạc được thiết kế theo mô hình phân lớp dọc (Vertical Stack). Thành phần bao quát sử dụng `Column` kết hợp với hiệu ứng chuyển màu nền (Linear Gradient). Các phần tử con được phân chia thành ba khu vực chính: khu vực ảnh bìa và thông tin bài hát, vùng điều khiển tiến trình, và nhóm nút chức năng tương tác. Việc sử dụng `Blank().height('1fr')` giúp đẩy các thành phần điều khiển xuống đáy màn hình một cách linh hoạt.


@Entry
@Component
struct MediaPlayerInterface {
  @State trackInfo: { title: string, artist: string, cover: Resource } = {
    title: "Hòa Âm Ánh Sáng",
    artist: "Nghệ Sĩ Ẩn Danh",
    cover: $r("app.media.cover_art")
  }
  @State playProgress: number = 0
  @State timeDisplay: string = "00:00"

  build() {
    Column() {
      Row() {
        Image($r("app.media.ic_share"))
          .width(28).height(28)
          .onClick(() => this.handleShare())
      }
      .width('100%').justifyContent(FlexAlign.End).padding({ right: 16 })

      Image(this.trackInfo.cover)
        .width(320).height(320)
        .borderRadius(16)
        .margin({ top: 24, bottom: 24 })

      Text(this.trackInfo.title)
        .fontSize(24).fontWeight(FontWeight.Bold)
        .fontColor("#1A1A1A")
      Text(this.trackInfo.artist)
        .fontSize(16).fontColor("#666666")
        .margin({ top: 8 })

      Blank().height('1fr')

      Column() {
        this.ProgressControl()
        this.ActionToolbar()
      }
      .width('100%').padding({ bottom: 40 })
    }
    .width('100%').height('100%')
    .linearGradient({
      angle: 90,
      direction: GradientDirection.Bottom,
      colors: [[0xFF4A00E0, 0.0], [0xFF4A00E0, 1.0]]
    })
    .padding(24)
  }

  handleShare(): void {
    // Kích hoạt logic chia sẻ nội dung
  }
}

2. Thành phần hiển thị tiến trình phát lại

Phần thanh trượt tiến trình (Progress Slider) được đóng gói thành hàm `@Builder` riêng biệt. Điều này giúp tái sử dụng mã nguồn và giảm độ phức tạp khi cập nhật trạng thái phát lại. Thanh trượt được đồng bộ với biến trạng thái `@State` để tự động cập nhật giao diện khi người dùng thao tác kéo thả, đồng thời kích hoạt hàm tính toán thời gian tương ứng.


@Builder ProgressControl() {
  Row() {
    Text(this.timeDisplay)
      .fontSize(12).fontColor("#333333")
      .width(36).textAlign(TextAlign.Start)
    Slider({
      value: this.playProgress,
      min: 0,
      max: 100,
      step: 1
    })
      .width('64%')
      .onChange((val: number) => {
        this.playProgress = val
        this.syncTimeDisplay(val)
      })
    Text("03:45")
      .fontSize(12).fontColor("#333333")
      .width(36).textAlign(TextAlign.End)
  }
  .alignItems(VerticalAlign.Center)
  .justifyContent(FlexAlign.SpaceBetween)
  .margin({ bottom: 24 })
}

syncTimeDisplay(progress: number): void {
  const totalSeconds: number = 225 // Tổng thời gian bài hát (3:45)
  const currentSeconds: number = Math.floor((progress / 100) * totalSeconds)
  const minutes: string = String(Math.floor(currentSeconds / 60)).padStart(2, '0')
  const seconds: string = String(currentSeconds % 60).padStart(2, '0')
  this.timeDisplay = `${minutes}:${seconds}`
}

3. Mô-đun nút điều khiển tương tác

Các nút bấm như yêu thích, tải xuống, bình luận được bố trí ngang với khoảng cách đều nhau nhờ thuộc tính `SpaceEvenly`. Mỗi nút được gắn sẵn sự kiện nhấp chuột để kích hoạt logic nghiệp vụ tương ứng mà không làm ảnh hưởng đến vòng đời hoặc hiệu suất vẽ lại của thành phần cha. Việc tách biệt các mô-đun này giúp mã nguồn dễ bảo trì và mở rộng trong các phiên bản phát triển sau.


@Builder ActionToolbar() {
  Row() {
    Image($r("app.media.ic_heart"))
      .onClick(() => console.info("Yêu thích bài hát"))
    Image($r("app.media.ic_download"))
      .onClick(() => console.info("Bắt đầu tải xuống"))
    Image($r("app.media.ic_comment"))
      .onClick(() => console.info("Mở cửa sổ bình luận"))
    Image($r("app.media.ic_menu"))
      .onClick(() => console.info("Hiển thị menu tùy chọn"))
  }
  .justifyContent(FlexAlign.SpaceEvenly)
  .width('100%').height(48)
  .padding({ top: 10, bottom: 10 })
}

Thẻ: openharmony ArkUI typescript DeclarativeUI MediaPlayback

Đăng vào ngày 5 tháng 9 lúc 07:11