ZhCarouselLayout01.ets 11.9 KB
import { CompDTO, ContentDTO } from 'wdBean';
import { BreakpointConstants, CommonConstants } from 'wdConstant';
import { BreakPointType, Logger } from 'wdKit';
import { CompUtils } from '../../utils/CompUtils';
import { ProcessUtils } from 'wdRouter';
import { EmptyComponent } from '../view/EmptyComponent';
import { CardMediaInfo } from '../cardCommon/CardMediaInfo';
import { onlyWifiLoadImg } from '../../utils/lazyloadImg';
import { Notes } from '../cardview/notes';
import { getNotesContentWidth } from '../../utils/FuncUtils'
import { InfomationCardClick } from '../../utils/infomationCardClick'
import font from '@ohos.font';

const TAG = 'Zh_Carousel_Layout-01';


/**
 * 轮播组件,即Banner/轮播大图/焦点图/自动滑动
 * 样式:
 * 'Zh_Carousel_Layout-01', // 通用轮播卡:视频、直播、活动、专题、榜单、外链
 */


class MyDataSource implements IDataSource {
  private list: number[] = []

  constructor(list: number[]) {
    this.list = list
  }

  totalCount(): number {
    return this.list.length
  }

  getData(index: number): number {
    return this.list[index]
  }

  registerDataChangeListener(listener: DataChangeListener): void {
  }

  unregisterDataChangeListener() {
  }
}

@Component
export struct ZhCarouselLayout01 {
  @State pageId: string = '';
  @State pageName: string = '';
  @StorageLink('currentBreakpoint') @Watch('watchCurrentBreakpoint') currentBreakpoint: string =
    BreakpointConstants.BREAKPOINT_XS;
  @State compDTO: CompDTO = {} as CompDTO

  @State firstWd: number = 0
  @State SecondWd: number = 0
  @State swiperIndex: number = 0

  private data: MyDataSource = new MyDataSource([])

  watchCurrentBreakpoint() {
    Logger.info(TAG, `watchCurrentBreakpoint, this.currentBreakpoint: ${this.currentBreakpoint}`);
  }

  aboutToAppear() {
    Logger.info(TAG,
      `aboutToAppear, beanList:${this.compDTO?.operDataList?.length}, currentBreakpoint:${this.currentBreakpoint}`);
    let list: number[] = []
    for (let i = 1; i <= this.compDTO?.operDataList?.length; i++) {
      list.push(i);
    }
    this.data = new MyDataSource(list)

    font.registerFont({
      familyName: 'BebasNeue',
      familySrc: $rawfile('font/BebasNeue.ttf')
    })
  }

  isAutoPlay() {
    if (this.compDTO.extraData) {
      return JSON.parse(this.compDTO.extraData).autoplay == 1
    } else {
      return false
    }
  }

  build() {

    if (this.compDTO?.operDataList?.length) {
      if (this.compDTO?.operDataList.length > 1) {
        Stack() {
          Swiper() {
            ForEach(this.compDTO?.operDataList, (item: ContentDTO, index: number) => {
              CarouselLayout01CardView({
                item: item,
                length: this.compDTO.operDataList.length,
                showPicBorderRadius: this.compDTO.operDataList.length == 1
              })
                .onClick((event: ClickEvent) => {
                  InfomationCardClick.track(this.compDTO, item, this.pageId, this.pageName)
                  Logger.info(TAG, `ZhCarouselLayout01 onClick event index: ${index}`)
                  ProcessUtils.processPage(item)
                })
            })
          }
          .borderRadius($r('app.float.image_border_radius'))
          .displayCount(this.buildDisplayCount()) // 仅展示1个图片
          .cachedCount(2)
          .index(0) // The default index of Swiper.
          .indicator(false)
          .loop(true)
          .vertical(false)
          .curve(Curve.Linear)
          .autoPlay(this.isAutoPlay())
          .onAnimationStart((index: number, targetIndex: number) => {
            // Logger.info(TAG, `Swiper onAnimationStart index : ${index}, targetIndex: ${targetIndex}`);
            this.swiperIndex = targetIndex
          })
          .onChange((index: number) => {
            // Logger.info(TAG, `Swiper onChange index : ${index}`);

          })
          .onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
            this.firstWd = 12
            setTimeout(() => {
              this.SecondWd = 12
            }, 2000)
            // console.info("onAnimationEnd, index: " + index)
          })

          if (this.compDTO?.operDataList.length > 1) {
            // 自定义indicator
            GridRow({
              columns: this.data.totalCount(),
              gutter: { x: 2 }
            }) {
              LazyForEach(this.data, (item: string, index: number) => {
                GridCol() {
                  if (index === this.swiperIndex) {
                    indicatorAnimations({
                      index: index,
                      isAutoPlay: this.isAutoPlay()
                    })
                  } else {
                    Row() {
                      Image($r('app.media.swiper_indicator_gray'))
                        .width('100%')
                        .height(2)
                    }
                  }
                }
              }, (item: string) => item)
            }
            .width(CommonConstants.FULL_PARENT)
            .padding({
              left: 10,
              right: 10,
              top: 12,
              bottom: 12
            })
            .alignItems(ItemAlign.End)
          }
        }
        .alignContent(Alignment.BottomEnd)
        .padding({
          left: 10,
          right: 10,
          top: $r('app.float.card_comp_pagePadding_tb'),
          bottom: $r('app.float.card_comp_pagePadding_tb')
        })
        .backgroundColor(0xffffff)
        .width(CommonConstants.FULL_WIDTH)
      } else {
        CarouselLayout01CardView({
          item: this.compDTO.operDataList[0],
          length: 1,
          showPicBorderRadius: this.compDTO.operDataList.length == 1
        })
          .onClick((event: ClickEvent) => {
            InfomationCardClick.track(this.compDTO, this.compDTO.operDataList[0], this.pageId, this.pageName)
            ProcessUtils.processPage(this.compDTO.operDataList[0])
          })
          .padding({
            left: 10,
            right: 10,
            top: $r('app.float.card_comp_pagePadding_tb'),
            bottom: $r('app.float.card_comp_pagePadding_tb')
          })
          .backgroundColor(0xffffff)
          .width(CommonConstants.FULL_WIDTH)
          .borderRadius($r('app.float.image_border_radius'))
      }
    } else {
      EmptyComponent({ emptyHeight: 200 })
    }
  }

  public buildDisplayCount(): number {
    return new BreakPointType({
      xs: 1,
      sm: 1,
      md: 2,
      lg: 3
    }).getValue(this.currentBreakpoint)
  }
}


@Component
struct CarouselLayout01CardView {
  @State loadImg: boolean = false;
  private item: ContentDTO = new ContentDTO();
  private length: number = 1; // 轮播图数量
  private showPicBorderRadius: boolean = false;

  async aboutToAppear(): Promise<void> {
    this.loadImg = await onlyWifiLoadImg();
  }

  build() {
    Stack() {
      Image(this.loadImg ? this.item.coverUrl : '')
        .width(CommonConstants.FULL_PARENT)
        .height(CommonConstants.FULL_PARENT)
        .objectFit(ImageFit.Cover)
        .backgroundColor(0xf5f5f5)
        .borderRadius(this.showPicBorderRadius ? $r('app.float.image_border_radius') : 0)
        .borderStyle(BorderStyle.Solid)
        .borderWidth(0.5)
        .borderColor($r('app.color.color_0D000000'))

      Stack() {
        Row()
          .width(CommonConstants.FULL_PARENT)
          .height(60)
          .linearGradient({
            direction: GradientDirection.Top, // 渐变方向:to Top/从下往上
            colors: [[0x7508111A, 0.0], [0x7508111A, 0.3], [Color.Transparent, 1.0]]
          })
          .position({
            bottom: 0
          })
          .borderRadius($r('app.float.image_border_radius'))
      }
      .width(CommonConstants.FULL_PARENT)
      .height(CommonConstants.FULL_PARENT)
      .alignContent(Alignment.Bottom)

      Column() {
        // 这里用于展示轮播图右上角信息,这里只对直播类型的展示
        if (this.item.objectType === '2' || this.item.objectType === '4') {
          // 2024-05-28 给CardMediaInfo组件添加beused的字段让其知道被哪个组件使用,不传默认为空
          CardMediaInfo({ contentDTO: this.item,livePeopleNum:false ,beused:'Zh_Carousel_Layout_01'})
            .width(CommonConstants.FULL_PARENT)
        }
        Blank()
        // 文本信息
        Stack() {
          if(this.item.objectType == '5'){
            Notes({ objectType: this.item.objectType,objectLevel:this.item.objectLevel, marginTop: 4 })
          } else {
            if (this.item.seoTags) {
              Notes({ newTags: this.item.seoTags, marginTop: 4 })
            }
            if (this.item.newTags) {
              Notes({ newTags: this.item.newTags, marginTop: 4 })
            }
          }
          Text(`${this.item.newsTitle}`)
            .width(CommonConstants.FULL_PARENT)
            .fontColor(Color.White)
            .fontSize($r('app.float.font_size_18'))
            .lineHeight(25)
            .fontWeight(FontWeight.Medium)
            .textAlign(TextAlign.Start)
            .align(Alignment.Bottom)
            .maxLines(CompUtils.MAX_LINES_2)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .textIndent(
              getNotesContentWidth(
                this.item.seoTags || this.item.newTags,
                this.item.objectType,
                this.item.objectLevel,
                this.item.top
              )
            )
        }
        // .height(39)
        .padding({
          left: 10,
          right: 10
        })
        .margin({
          bottom: this.length > 1 ? 28 : 10
        })
        .alignContent(Alignment.TopStart)

      }
      .width(CommonConstants.FULL_PARENT)
      .height(CommonConstants.FULL_PARENT)
    }
    .width(CommonConstants.FULL_WIDTH)
    .aspectRatio(CompUtils.ASPECT_RATIO_16_9)
    .alignContent(Alignment.Top)
    .hoverEffect(HoverEffect.Scale)
  }
}


@Component
struct indicatorAnimations {
  @Prop index: number = 0
  @Prop isAutoPlay: boolean = true
  @State leftW: number | string = 0
  @State rightW: number | string = 0
  @State centerFontSize: number = 0

  aboutToAppear(): void {
    if (this.isAutoPlay) {
      setTimeout(() => {
        this.leftW = '100%'
        this.centerFontSize = 10
      }, 0)
      setTimeout(() => {
        this.rightW = '100%'
      }, 1500)
    } else {
      this.leftW = '100%'
      this.centerFontSize = 10
      this.rightW = '100%'
    }

  }

  build() {
    Flex({ alignItems: ItemAlign.End }) {
      Stack() {
        // Image($r('app.media.swiper_indicator_gray'))
        //   .width('100%')
        //   .height(2)

        Image($r('app.media.swiper_indicator_gray'))
          .objectFit(ImageFit.Contain)
          .width('96%')
          .height(2)
        Image($r('app.media.swiper_indicator_white'))
          .width(this.leftW)
          .height(2)
          .animation({
            duration: 1500,
            curve: Curve.EaseOut,
            playMode: PlayMode.Normal
          })
      }
      .width('100%')
      .alignContent(Alignment.Start)

      Text(this.index + 1 < 10 ? `0${this.index + 1}` : `${this.index + 1}`)
        .fontSize(this.centerFontSize)
        .fontColor($r('app.color.white'))
        .width(11)
        .textAlign(TextAlign.Center)
        .margin({
          bottom: -2
        })
        .fontFamily('BebasNeue')
        .flexShrink(0)
        .animation({
          duration: 300,
          curve: Curve.EaseOut,
          playMode: PlayMode.Normal
        })
      Stack() {
        // Image($r('app.media.swiper_indicator_gray'))
        //   .width('100%')
        //   .height(2)
        Image($r('app.media.swiper_indicator_gray'))
          .objectFit(ImageFit.Contain)
          .width('96%')
          .height(2)
        Image($r('app.media.swiper_indicator_white'))
          .width(this.rightW)
          .height(2)
          .animation({
            duration: 1500,
            curve: Curve.EaseOut,
            playMode: PlayMode.Normal
          })
      }
      .width('100%')
      .alignContent(Alignment.Start)
    }
    .height(14)
  }
}