DEV Community

Cover image for ArkUI Video Playback Tutorial
liu yang
liu yang

Posted on

ArkUI Video Playback Tutorial

ArkUI Video Playback Tutorial

Code Implementation

Main Page with Swiper

Below is the code for implementing a main page with a Swiper component:

// @ts-nocheck

import { TopBar } from '../view/common/TopBar';
import { PageAll } from '../view/tabcontent/PageAll';
import { CommonConstants } from '../common/constants/CommonConstant';
import { PageEntertainment } from '../view/tabcontent/PageEntertainment';
import { PageMovie } from '../view/tabcontent/PageMovie';
import PageAnime, { PageAnime } from '../view/tabcontent/PageAnime';
import PageTV, { PageTV } from '../view/tabcontent/PageTV';

@Entry
@Component
struct SwiperIndex {
  @State index: number = 0;

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
      TopBar({ index: $index });
      Swiper() {
        PageAll();
        PageMovie();
        PageTV();
        PageEntertainment();
        PageAnime();
      }
      .index(this.index)
      .indicator(false)
      .loop(false)
      .duration(CommonConstants.DURATION_PAGE)
      .onChange((index: number) => {
        this.index = index;
      });
    }
    .backgroundColor($r('app.color.start_window_background'));
  }
}
Enter fullscreen mode Exit fullscreen mode

TopBar Component

Here's the implementation of the TopBar component:

import { TopBarItem } from '../../common/bean/TopBarItem';
import { initializeOnStartup } from '../../viewmodel/TopBarViewModel';
import { CommonConstants } from '../../common/constants/CommonConstant';

@Component
export struct TopBar {
  @Link index: number;
  private tabArray: Array<TopBarItem> = initializeOnStartup();

  build() {
    Row({ space: CommonConstants.SPACE_TOP_BAR }) {
      ForEach(this.tabArray, (item: TopBarItem) => (
        Text(item.name)
          .fontSize(this.index === item.id ? CommonConstants.FONT_SIZE_CHECKED : CommonConstants.FONT_SIZE_UNCHECKED)
          .fontColor(Color.Black)
          .textAlign(TextAlign.Center)
          .fontWeight(this.index === item.id ? FontWeight.Bold : FontWeight.Regular)
          .onClick(() => {
            this.index = item.id;
          })
      ));
    }
    .margin({ left: CommonConstants.ADS_LEFT })
    .width(CommonConstants.FULL_WIDTH)
    .height(CommonConstants.TOP_BAR_HEIGHT);
  }
}
Enter fullscreen mode Exit fullscreen mode

TV Page Implementation

Here's the implementation of the TV page:

import { CommonConstants } from '../../common/constants/CommonConstant';
import { PositionDataSource } from '../../viewmodel/PositionDataSource';

@Component
export default struct PageTV {
  @Provide positionListData: PositionDataSource = new PositionDataSource();
  private startTouchOffsetY: number = 0;
  private endTouchOffsetY: number = 0;
  private username: String = "";
  private title: String = "";

  build() {
    Row() {
      List({ space: CommonConstants.LIST_ITEM_SPACE }) {
        LazyForEach(this.positionListData, (item) => (
          ListItem() {
            Row() {
              Column() {
                Image(item?.logo)
                  .width(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT)
                  .height(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT);
              }
              .width(CommonConstants.GOODS_IMAGE_WIDTH)
              .height(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT);
              Column() {
                Row() {
                  Text(item?.name)
                    .fontSize(CommonConstants.NORMAL_FONT_SIZE)
                    .margin({ top: CommonConstants.BIGGER_FONT_SIZE });
                }
                .justifyContent(FlexAlign.Start)
                .width(CommonConstants.GOODS_LIST_WIDTH);

                Row() {
                  Text(item?.cname)
                    .fontColor($r('app.color.black_text_color'))
                    .fontSize(CommonConstants.GOODS_EVALUATE_FONT_SIZE);
                  Text(item?.size)
                    .fontSize(CommonConstants.NORMAL_FONT_SIZE)
                    .fontColor($r('app.color.login_blue_text_color'))
                    .margin({ left: 10 });
                }
                .justifyContent(FlexAlign.Start)
                .width(CommonConstants.GOODS_LIST_WIDTH)
                .margin({ top: 20 });

                Row() {
                  Text('Time')
                    .fontSize(CommonConstants.NORMAL_FONT_SIZE)
                    .fontColor($r('app.color.red'));
                  Text(item?.salary)
                    .fontSize(CommonConstants.GOODS_EVALUATE_FONT_SIZE)
                    .fontColor($r('app.color.login_blue_text_color'))
                    .margin({ left: 10 });
                }
                .justifyContent(FlexAlign.Start)
                .width(CommonConstants.GOODS_LIST_WIDTH)
                .margin({ top: 20 });
              }
              .padding(CommonConstants.GOODS_LIST_PADDING)
              .width(CommonConstants.GOODS_FONT_WIDTH)
              .height(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT);
            }
            .justifyContent(FlexAlign.SpaceBetween)
            .height(CommonConstants.GOODS_LIST_HEIGHT)
            .width(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT)
            .onTouch((event: TouchEvent) => {
              switch (event.type) {
                case TouchType.Down:
                  this.startTouchOffsetY = event.touches[0].y;
                  break;
                case TouchType.Move:
                  this.endTouchOffsetY = event.touches[0].y;
                  if (this.startTouchOffsetY - this.endTouchOffsetY > 0) {
                    this.positionListData.pushData();
                  }
                  break;
              }
            });
          }
        });
      }
      .width(CommonConstants.GOODS_LIST_WIDTH);
    }
    .justifyContent(FlexAlign.Center)
    .width(CommonConstants.LAYOUT_WIDTH_OR_HEIGHT);
  }
}
Enter fullscreen mode Exit fullscreen mode

Sample Data

Here's the code for the sample data:

export interface PositionListItemType {
  logo: Resource;
  name: Resource;
  cname: Resource;
  size: Resource;
  salary: Resource;
}

export const positionInitialList: PositionListItemType[] = [
  {
    logo: $r('app.media.fangyandexingxing'),
    name: $r('app.string.Entertainmentname1'),
    cname: $r('app.string.typesof'),
    size: $r('app.string.typesof1'),
    salary: $r('app.string.times1'),
  },
  {
    logo: $r('app.media.wohejiangshiyuehui'),
    name: $r('app.string.Entertainmentname2'),
    cname: $r('app.string.typesof'),
    size: $r('app.string.typesof2'),
    salary: $r('app.string.times2'),
  },
  {
    logo: $r('app.media.yitiantulongji'),
    name: $r('app.string.Entertainmentname3'),
    cname: $r('app.string.typesof'),
    size: $r('app.string.typesof3'),
    salary: $r('app.string.times3'),
  },
  {
    logo: $r('app.media.getoutianwang'),
    name: $r('app.string.Entertainmentname4'),
    cname: $r('app.string.typesof'),
    size: $r('app.string.typesof4'),
    salary: $r('app.string.times4'),
  },
  {
    logo: $r('app.media.xianjianqixiazhuna'),
    name: $r('app.string.Entertainmentname5'),
    cname: $r('app.string.typesof'),
    size: $r('app.string.typesof5'),
    salary: $r('app.string.times5'),
  },
];
Enter fullscreen mode Exit fullscreen mode

Lazy Loading Data Processing

Here's the code for lazy loading data processing:

import { positionInitialList, PositionListItemType } from './PositionData';

const createListRange = () => {
  let result = [];
  for (let i = 0; i < 2; i++) {
    result = [...result, ...positionInitialList];
  }
  return result;
};

class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = [];

  public totalCount(): number {
    return 0;
  }

  public getData(index: number): PositionListItemType {
    return undefined;
  }

  public getPositionData(index: number): PositionListItemType {
    return undefined;
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const position = this.listeners.indexOf(listener);
    if (position >= 0) {
      this.listeners.splice(position, 1);
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    });
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    });
  }

  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    });
  }

  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    });
  }

  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    });
  }
}

export class PositionDataSource extends BasicDataSource {
  private listData = createListRange();

  public totalCount(): number {
    return this.listData.length;
  }

  public getData(index: number): PositionListItemType {
    return this.listData[index];
  }

  public pushData(): void {
    if (this.listData.length < 12) {
      this.listData = [...this.listData, ...positionInitialList];
      this.notifyDataAdd(this.listData.length - 1);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

In this tutorial, we have implemented a video playback interface using ArkUI. The main components include:

  • SwiperIndex: The main page that integrates the TopBar and Swiper components to achieve a tabbed page switching effect.
  • TopBar: A navigation bar component that works with the Swiper component to provide a tabbed navigation experience.
  • PageTV: The implementation of the TV show page, which displays a list of TV shows with their details.
  • Sample Data: Provides initial data for the TV shows displayed on the PageTV page.
  • Lazy Loading Data Processing: Implements data lazy loading to improve performance and user experience.

Top comments (0)