HarmonyOS 自定义日历控件demo?

如题:HarmonyOS 自定义日历控件demo?

阅读 411
1 个回答
export interface Month {
  month: string;
  num: number;
  days: number[];
}

export class MonthDataSource implements IDataSource {
  private listeners: DataChangeListener[] = [];
  private dataArray: Month[] = [];

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

  public getData(index: number): Month {
    return this.dataArray[index];
  }

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

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener');
      this.listeners.splice(pos, 1);
    }
  }

  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);
    })
  }

  public addData(index: number, data: Month): void {
    this.dataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  public pushData(data: Month | Month[]): void {
    if (Array.isArray(data)) {
      this.dataArray.push(...data);
    } else {
      this.dataArray.push(data);
    }
    this.notifyDataAdd(this.dataArray.length - 1);
  }

}

export function getMonthDate(specifiedMonth: number, specifiedYear: number) {
  let currentFirstWeekDay: number = 0;
  let currentLastWeekDay: number = 0;
  let currentAllDay: number[] = [];
  let totalDays = new Date(specifiedYear, specifiedMonth, 0).getDate();
  currentFirstWeekDay = new Date(specifiedYear, specifiedMonth - 1, 1).getDay();
  currentLastWeekDay = new Date(specifiedYear, specifiedMonth - 1, totalDays).getDay();

  for (let item = 0; item < currentFirstWeekDay; item++) {
    currentAllDay[item] = 0;
  }

  for (let item = 1; item <= totalDays; item++) {
    currentAllDay.push(item);
  }

  for (let item = 0; item < 6 - currentLastWeekDay; item++) {
    currentAllDay.push(0);
  }
  return currentAllDay;
}

const MONDAY = '一';
const TUESDAY = '二';
const WEDNESDAY = '三';
const THURSDAY = '四';
const FRIDAY = '五';
const SATURDAY = '六';
const SUNDAY = '日';

const MONTHS = 12;
const JANUARY = 1;
const MONTH_NUMBER = 35;
const GRID_HEIGHT_L = 360;
const GRID_HEIGHT_M = 300;

@Entry
@Component
struct CustomCalendarPicker {
  @State contentData: MonthDataSource = new MonthDataSource();
  @State date: number[] = [];
  @State currentDay: number = 1;
  @State currentMonth: number = 1;
  @State isSeleted:boolean = false
  @State isFillColor:boolean = false
  @State record:number[] = [1,4,8,9,3]
  @State fillColor:string = '#E5000000'
  @State currentYear: number = 1;
  @State currentWeekDay: number = 0;
  @State currentMonthDay: number[] = [];
  @State nextMonth: number = 1;
  @State nextYear: number = 1;
  @State nextMonthDay: number[] = [];
  private week: string[] = [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY];


  aboutToAppear(): void {
    let nowDate = new Date();
    this.currentMonth = nowDate.getMonth() + 1;
    this.currentDay = nowDate.getDate();
    this.currentYear = nowDate.getFullYear();
    this.currentWeekDay = new Date(this.currentYear, this.currentMonth - 1, this.currentDay).getDay();
    this.date.push(this.currentYear)
    this.date.push(this.currentMonth);
    this.date.push(this.currentDay);
    this.date.push(this.currentWeekDay);
    this.currentMonthDay = getMonthDate(this.currentMonth, this.currentYear);

    if (this.currentMonth == MONTHS) {
      this.nextMonth = JANUARY;
      this.nextYear = this.currentYear + 1;
    }

    else {
      this.nextMonth = this.currentMonth + 1;
      this.nextYear = this.currentYear;
    }
    this.nextMonthDay = getMonthDate(this.nextMonth, this.nextYear);

    let months: Month[] = [
      {

        month: '',
        num: this.currentMonth,
        days: this.currentMonthDay
      }
    ]
    this.contentData.pushData(months);
  }

  build() {
    Column(){
      Text(this.date[0] + '-' + this.date[1] +' ^')
        .fontSize(20)
        .fontColor(Color.Black)

      List() {
        ForEach(this.week, (weekInfomation: string) => {
          ListItem() {
            Text(weekInfomation)
              .textAlign(TextAlign.Center)
              .width('100%')
              .height(20)
          }
          .width('14.3%')
        })
      }
      .width('100%')
      .height(20)
      .listDirection(Axis.Horizontal)
      .scrollBar(BarState.Off)


      List() {
        LazyForEach(this.contentData, (monthItem: Month) => {
          ListItemGroup() {
            ListItem() {
              Stack() {
                Grid() {

                  ForEach(monthItem.days, (day: number) => {
                    GridItem() {
                      Column(){
                        if(day > 0){
                          Text(day.toString())
                            .fontSize(20)
                            .fontColor(day < this.currentDay && monthItem.num === this.currentMonth ||  day == this.currentDay && this.isFillColor ? '#99000000' : this.fillColor)

                          if(day < this.currentDay && monthItem.num === this.currentMonth){
                            Circle()
                              .width(10)
                              .height(10)
                              .fill((day < this.currentDay && monthItem.num === this.currentMonth || this.isSeleted) && this.record.indexOf(day) >= 0  ? '#4cddd0': '#fc2c4c')
                          }else if(day == this.currentDay && this.isSeleted){

                            Circle()
                              .width(10)
                              .height(10)
                              .fill('#4cddd0')
                          }
                        }



                      }

                    }
                    .borderRadius(12)
                  })
                }
                .backgroundColor('#FFFFFF')
                .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
                .rowsTemplate(monthItem.days.length > MONTH_NUMBER ? '1fr 1fr 1fr 1fr 1fr 1fr' : '1fr 1fr 1fr 1fr 1fr')
                .height(monthItem.days.length > MONTH_NUMBER ? GRID_HEIGHT_L : GRID_HEIGHT_M)

              }
            }
          }
        })

      }
      .height('50%')
      .width('100%')
      .edgeEffect(EdgeEffect.None)
      .scrollBar(BarState.Off)
      .sticky(StickyStyle.Header)
    }
  }
}