224df162创建于 2021年10月28日历史提交
/*
 * Copyright (c) 2025-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  $r, Row, Text, List, Axis, Area, Flex, Color, Stack, Length, Button, ICurve, Column, Scroll, 
  Canvas, Builder, ForEach, Padding, Resource, ListItem, BarState, Position, FlexWrap, 
  BlendMode, BlurStyle, Alignment, Component, TouchType, FontWeight, ClickEvent, HoverEvent, 
  TouchEvent, Visibility, ButtonType, EdgeEffect, SymbolGlyph, BorderStyle, ResourceStr, 
  ScrollState, EffectScope, VoidCallback, TextOverflow, CommonMethod, BuilderParam, 
  AnimateParam, ButtonOptions, LengthMetrics, FlexDirection, VerticalAlign, BlendApplyType, 
  LocalizedMargin, HorizontalAlign, TransitionEffect, LocalizedPadding, OnScrollCallback, 
  ReplaceSymbolEffect, AccessibilityRoleType, RenderingContextSettings, CanvasRenderingContext2D, 
  VisibleAreaChangeCallback
} from '@ohos.arkui.component';
import { ObjectLink, Observed, State, PropRef, Watch } from '@ohos.arkui.stateManagement';
import EnvironmentCallback from '@ohos.app.ability.EnvironmentCallback';
import ApplicationContext from 'application.ApplicationContext';
import { UIContext, MeasureUtils ,Context} from "@ohos.arkui.UIContext";
import { Configuration } from '@ohos.app.ability.Configuration';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import resourceManager from "@ohos.resourceManager";
import accessibility from '@ohos.accessibility';
import common from "@ohos.app.ability.common";
import { BusinessError } from '@ohos.base';
import curves from '@ohos.curves';
import hilog from '@ohos.hilog';

const TEXT_HOT_AREA_WIDTH: number = 8;
const LIST_ROW_HEIGHT: number = 40;
const ARROW_IMG_SIZE: number = 24;
const MULTI_LINE_PADDING: number = 24;
const BAR_ANIMATION_DURATION: int = 150;
const ARROW_ANIMATION_DURATION: int = 200;
const ANIMATION_DURATION_250: int = 250;
const ANIMATION_DURATION_100: int = 100;
const FILTER_TOP_PADDING: number = 8;
const FILTER_BAR_MARGIN: number = 8;
const SEPARATOR_HEIGHT: number = 16;
const SEPARATOR_WIDTH: number = 1;
const FLOAT_OPACITY: number = 0.95;
const FILTER_FONT_SIZE: number = 12;
const FOCUS_BORDER_WIDTH: number = 2;
const ARROW_SHOW_DELAY: int = 300;
const PERCENT_100: Length = '100%';
const SHARP_CUBIC_BEZIER = curves.cubicBezierCurve(0.33, 0, 0.67, 1);
const INTER_POLATING_SPRING = curves.interpolatingSpring(0, 1, 328, 34);
const FRICTION_CUBIC_BEZIER = curves.cubicBezierCurve(0.2, 0, 0.2, 1);
const TRANS_COLOR: string = '#00FFFFFF';
const GRADIENT_WIDTH: number = 16;
const MAX_FONT_SCALE: number = 2;
const ERROR_CODE: int = 0x3900;
const SYMBOL_SIZE: number = 24;
const MAX_SYMBOL_FONT_SCALE: number = 1.45;
const MIN_SYMBOL_FONT_SCALE: number = 1;
const DEFAULT_SYMBOL_FONT_SCALE: number = 1;

export enum FilterType {
  MULTI_LINE_FILTER,
  LIST_FILTER
}

export enum FilterAccessibilityType {
  ACCESSIBILITY_TEXT,
  ACCESSIBILITY_DESC,
  SEND_ACCESSIBILITY,
}

export interface FilterParams {
  name: ResourceStr;
  options: Array<ResourceStr>;
}

export interface FilterResult {
  name: ResourceStr;
  index: int;
  value: ResourceStr;
}

type FontWeightArray = Array<FontWeight>;

type ResourceArray = Array<Resource>;

type BooleanArray = Array<boolean>;

@Observed
export class ObservedBoolean {
  public value: boolean;

  constructor(value: boolean) {
    this.value = value;
  }
}

@Observed
export class ObservedNumber {
  public value: number;

  constructor(value: number) {
    this.value = value;
  }
}

@Observed
export class FilterAccessibilityText {
  public accessibilitySelectedText: string = '';
  public accessibilityExpand: string = '';
  public accessibilityCollapse: string = '';
  public accessibilityExpanded: string = '';
  public accessibilityCollapsed: string = '';
  public accessibilityUnselectedText: string = '';
  public accessibilityFilters: string = '';
  public accessibilitySelectedDesc: string = '';
  public accessibilityUnselectedDesc: string = '';
  public accessibilityExpandDesc: string = '';
}

@Component
struct GradientMask {
  x0: number = 0;
  y0: number = 0;
  x1: number = 0;
  y1: number = 0;
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context2D: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

  build() {
    Column() {
      Canvas(this.context2D)
        .width(GRADIENT_WIDTH)
        .height(LIST_ROW_HEIGHT)
        .onReady(() => {
          let grad = this.context2D.createLinearGradient(this.x0, this.y0, this.x1, this.y1)
          grad.addColorStop(0.0, '#ffffffff')
          grad.addColorStop(1, '#00ffffff')
          this.context2D.fillStyle = grad
          this.context2D.fillRect(0, 0, GRADIENT_WIDTH, LIST_ROW_HEIGHT)
        } as VoidCallback)
    }
    .blendMode(BlendMode.DST_OUT, BlendApplyType.FAST)
    .width(GRADIENT_WIDTH)
    .height(LIST_ROW_HEIGHT)
  }
}

@Component
struct ListFilterRow {
  @PropRef colorRow: ResourceArray;
  @PropRef fontWeightRow: FontWeightArray;
  @PropRef backgroundColorRow: ResourceArray;
  @PropRef isBackgroundHoverRow: BooleanArray;
  @PropRef isSelectedRow: BooleanArray;
  @ObjectLink filterAccessibilityText: FilterAccessibilityText;
  filterRow: FilterParams = { name: '', options: [], } as FilterParams;
  onItemClick: (colIndex: number) => void = () => {
  };
  rowIndex: number = 0;
  maxAppFontScale: number = 1;
  isFollowingSystemFontScale: boolean = false;
  bundleName: string = '';
  filterId: number = this.getUniqueId().toDouble();

  aboutToAppear() {
    try {
      let uiContent: UIContext = this.getUIContext();
      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
      this.maxAppFontScale = uiContent.getMaxFontScale();
    } catch (err) {
      let code: number | undefined = (err as ClassCastError).code;
      let message: string | undefined = (err as ClassCastError).message;
      hilog.error(ERROR_CODE, 'Ace',
        `Failed to init fontsizescale info, cause, code: ${code}, message: ${message}`);
    }
    if (this.getUIContext().getHostContext()) {
      this.bundleName = ((this.getUIContext().getHostContext()) as common.UIAbilityContext).abilityInfo.bundleName;
    }
  }

  updateFontScale(): number {
    let uiContent: UIContext = this.getUIContext();
    let systemFontScale: number = 1;
    if (uiContent.getHostContext()) {
      systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
    }
    if (!this.isFollowingSystemFontScale) {
      return 1;
    }
    return Math.min(systemFontScale, this.maxAppFontScale);
  }

  getAccessibilityText(resource: ResourceStr | undefined, selected: boolean, type: FilterAccessibilityType): string {
    let accessibilityText: string = '';
    try {
      let resourceString: string = '';
      if (resource == undefined) {
        resourceString = '';
      } else if (typeof resource === 'string') {
        resourceString = resource as string;
      } else {
        let uiContent: Context | undefined = UIContext.resolveUIContext()?.getHostContext();
        resourceString = (uiContent as common.UIAbilityContext).resourceManager
          .getStringSync((resource as Resource).id) as string;
      }
      switch (type) {
        case FilterAccessibilityType.ACCESSIBILITY_TEXT:
          accessibilityText = selected ? this.filterAccessibilityText.accessibilitySelectedText : resourceString;
          break;
        case FilterAccessibilityType.ACCESSIBILITY_DESC:
          accessibilityText = selected ? resourceString : '';
          break;
        case FilterAccessibilityType.SEND_ACCESSIBILITY:
          accessibilityText =
            selected ? `${this.filterAccessibilityText.accessibilitySelectedText},${resourceString}` : '';
          break;
        default:
          break;
      }
    } catch (error) {
      let code: number | undefined = (error as ClassCastError).code;
      let message: string | undefined = (error as ClassCastError).message;
      hilog.error(0x3900, 'Ace',
        `Filter getAccessibilityText error, code: ${code}, message: ${message}`);
    }
    return accessibilityText;
  }

  sendAccessibility(resource: ResourceStr | undefined, selected: boolean): void {
    let eventInfo: accessibility.EventInfo =
      new accessibility.EventInfo('announceForAccessibility', this.bundleName, 'common');
    eventInfo.textAnnouncedForAccessibility =
      this.getAccessibilityText(resource, selected, FilterAccessibilityType.SEND_ACCESSIBILITY);
    accessibility.sendAccessibilityEvent(eventInfo).then(() => {
      hilog.info(0x3900, 'Ace',
        `ListFilter sendAccessibility send event, event info is ${JSON.stringify(eventInfo)}`);
    })
  }

  build() {
    Stack({ alignContent: Alignment.End }) {
      Stack({ alignContent: Alignment.Start }) {
        List() {
          ForEach(this.filterRow.options as Array<ResourceStr>, (option: ResourceStr, colIndex: int) => {
            if (colIndex === 0) {
              ListItem()
                .width($r('sys.float.ohos_id_max_padding_start'))
                .height(LIST_ROW_HEIGHT)
            }
            ListItem() {
              Text(option)
                .fontSize($r('sys.float.ohos_id_text_size_body3'))
                .minFontScale(1)
                .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
                .fontColor(this.colorRow[colIndex.toInt()])
                .fontWeight(this.fontWeightRow[colIndex.toInt()])
                .focusable(true)
            }
            .accessibilityText(this.getAccessibilityText(option,
              this.isSelectedRow[colIndex.toInt()], FilterAccessibilityType.ACCESSIBILITY_TEXT))
            .accessibilityDescription(this.getAccessibilityText(option,
              this.isSelectedRow[colIndex.toInt()], FilterAccessibilityType.ACCESSIBILITY_DESC))
            .id(`filterListFilterRow_${this.filterId}_${this.rowIndex}`)
            .height(PERCENT_100)
            .onClick((event?: ClickEvent) => {
              this.onItemClick(colIndex.toDouble())
              this.sendAccessibility(option, true);
            })
            .focusable(true)
            .stateStyles({
              focused: (instance: CommonMethod) => {
                instance
                  .border({
                    radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                    width: FOCUS_BORDER_WIDTH,
                    color: $r('sys.color.ohos_id_color_focused_outline'),
                    style: BorderStyle.Solid
                  })
                  .padding({
                    start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH),
                    end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH)
                  } as LocalizedPadding)
              },
              normal: (instance: CommonMethod) => {
                instance
                  .border({
                    radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                    width: 0
                  })
                  .padding({
                    start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH),
                    end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH)
                  } as LocalizedPadding)
              }
            })
            .backgroundColor(this.isBackgroundHoverRow[colIndex.toInt()] ? this.backgroundColorRow[colIndex.toInt()] :
              TRANS_COLOR)
            .onHover((isHover: boolean, event: HoverEvent) => {
              this.getUIContext()?.animateTo({
                curve: FRICTION_CUBIC_BEZIER as ICurve,
                duration: ANIMATION_DURATION_250
              } as AnimateParam, () => {
                if (isHover) {
                  this.backgroundColorRow[colIndex.toInt()] = $r('sys.color.ohos_id_color_hover')
                  this.isBackgroundHoverRow[colIndex.toInt()] = true
                } else {
                  this.isBackgroundHoverRow[colIndex.toInt()] = false
                }
              })
            })
            .onTouch((event?: TouchEvent) => {
              if (event?.type === TouchType.Down) {
                this.getUIContext()?.animateTo({
                  curve: SHARP_CUBIC_BEZIER as ICurve,
                  duration: ANIMATION_DURATION_100
                } as AnimateParam, () => {
                  this.backgroundColorRow[colIndex.toInt()] = $r('sys.color.ohos_id_color_click_effect')
                  this.isBackgroundHoverRow[colIndex.toInt()] = true
                })
              } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
                this.getUIContext()?.animateTo({
                  curve: SHARP_CUBIC_BEZIER as ICurve,
                  duration: ANIMATION_DURATION_100
                } as AnimateParam, () => {
                  this.isBackgroundHoverRow[colIndex.toInt()] = false
                })
              }
            })
            .margin({ start: LengthMetrics.vp(colIndex === 0 ? -TEXT_HOT_AREA_WIDTH : 0) } as LocalizedMargin)
            .tabIndex(colIndex === 0 ? 1 : -1)
          })
        }
        .listDirection(Axis.Horizontal)
        .scrollBar(BarState.Off)
        .width(PERCENT_100)
        .height(LIST_ROW_HEIGHT)
        .align(Alignment.Start)

        GradientMask({
          x0: 0,
          y0: LIST_ROW_HEIGHT / 2,
          x1: GRADIENT_WIDTH,
          y1: LIST_ROW_HEIGHT / 2
        })
      }

      GradientMask({
        x0: GRADIENT_WIDTH,
        y0: LIST_ROW_HEIGHT / 2,
        x1: 0,
        y1: LIST_ROW_HEIGHT / 2
      })
    }.blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
  }
}

@Component
struct MultiFilterRow {
  @PropRef colorRow: ResourceArray;
  @PropRef fontWeightRow: FontWeightArray;
  @PropRef backgroundColorRow: ResourceArray;
  @PropRef isBackgroundHoverRow: BooleanArray;
  @ObjectLink twoLineModeItemNumRow: ObservedNumber;
  @ObjectLink twoLineModeItemNumRecordRow: ObservedNumber;
  @ObjectLink arrowShowStateRow: ObservedBoolean;
  @ObjectLink isArrowIconDown: ObservedBoolean;
  @PropRef isSelectedRow: BooleanArray;
  @ObjectLink filterAccessibilityText: FilterAccessibilityText;
  filterRow: FilterParams | null = null;
  onItemClick: (colIndex: number) => void = () => {
  };
  @State arrowBgColorRow: Resource = $r('sys.color.ohos_id_color_hover');
  @State isArrowBgHoverRow: boolean = false;
  @PropRef fontSizeScale: number | undefined;
  @State replaceEffect: int = 0;
  @State isSendArrowAccessibility: boolean = false;
  private filterColumnWidth: number = 0;
  private lastFilterColumnWidth: number = 0;
  private rowIndex: number = 0;
  maxAppFontScale: number = 1;
  isFollowingSystemFontScale: boolean = false;
  bundleName: string = '';
  filterId: number = this.getUniqueId().toDouble();

  aboutToAppear() {
    try {
      let uiContent: UIContext = this.getUIContext();
      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
      this.maxAppFontScale = uiContent.getMaxFontScale();
    } catch (err) {
      let code: number | undefined = (err as ClassCastError).code;
      let message: string | undefined = (err as ClassCastError).message;
      hilog.error(ERROR_CODE, 'Ace',
        `Failed to init fontsizescale info, cause, code: ${code}, message: ${message}`);
    }
    if (this.getUIContext().getHostContext()) {
      this.bundleName = ((this.getUIContext().getHostContext()) as common.UIAbilityContext).abilityInfo.bundleName;
    }
  }

  updateFontScale(): number {
    let uiContent: UIContext = this.getUIContext();
    let systemFontScale: number = 1;
    if (uiContent.getHostContext()) {
      systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
    }
    if (!this.isFollowingSystemFontScale) {
      return 1;
    }
    return Math.min(systemFontScale, this.maxAppFontScale);
  }

  private calcMultiFilterRowItemNum() {
    let curLineRetainWidth: number = this.filterColumnWidth;
    let curLineSum: number = 0;
    let curLine: number = 1;
    if (this.filterRow) {
      for (let i: number = 0; i < (this.filterRow?.options as Array<ResourceStr>).length; i++) {
        let option = this.filterRow?.options[i.toInt()];
        let measureUtils = this.getUIContext().getMeasureUtils();
        let itemWidth = measureUtils.measureText({
          textContent: option as ResourceStr,
          fontSize: `${FILTER_FONT_SIZE * Math.min(this.updateFontScale(), MAX_FONT_SCALE)}vp`,
        })
        if (i === 0) {
          continue;
        } else {
          itemWidth += this.getUIContext().vp2px(TEXT_HOT_AREA_WIDTH * 2);
        }
        if (curLineRetainWidth - itemWidth >= 0) {
          curLineRetainWidth -= itemWidth;
          curLineSum += 1;
        } else {
          if (curLineSum === 0) {
            curLineSum++;
            curLineRetainWidth = 0;
          }
          if (curLine === 1) {
            curLine += 1;
            curLineRetainWidth =
              this.filterColumnWidth -
              this.getUIContext().vp2px(ARROW_IMG_SIZE * (this.fontSizeScale ?? DEFAULT_SYMBOL_FONT_SCALE));
            i--;
          } else {
            break;
          }
        }
      }
    }
    return curLineSum;
  }

  getAccessibilityText(resource: ResourceStr | undefined, selected: boolean, type: FilterAccessibilityType): string {
    let accessibilityText: string = '';
    try {
      let resourceString: string = '';
      if (resource == undefined) {
        resourceString = '';
      } else if (typeof resource === 'string') {
        resourceString = resource as string;
      } else {
        let uiContent: Context | undefined = UIContext.resolveUIContext()?.getHostContext();
        resourceString = (uiContent as common.UIAbilityContext).resourceManager
          .getStringSync((resource as Resource).id) as string;
      }
      switch (type) {
        case FilterAccessibilityType.ACCESSIBILITY_TEXT:
          accessibilityText = selected ? this.filterAccessibilityText.accessibilitySelectedText : resourceString;
          break;
        case FilterAccessibilityType.ACCESSIBILITY_DESC:
          accessibilityText = selected ? resourceString : '';
          break;
        case FilterAccessibilityType.SEND_ACCESSIBILITY:
          accessibilityText =
            selected ? `${this.filterAccessibilityText.accessibilitySelectedText},${resourceString}` : '';
          break;
        default:
          break;
      }
    } catch (err) {
      let code: number | undefined = (err as ClassCastError).code;
      let message: string | undefined = (err as ClassCastError).message;
      hilog.error(0x3900, 'Ace',
        `Filter getAccessibilityText error, code: ${code}, message: ${message}`);
    }
    return accessibilityText;
  }

  private sendAccessibility(resource: ResourceStr | undefined, selected: boolean): void {
    let eventInfo: accessibility.EventInfo =
      new accessibility.EventInfo('announceForAccessibility', this.bundleName, 'common')
    eventInfo.textAnnouncedForAccessibility =
      this.getAccessibilityText(resource, selected, FilterAccessibilityType.SEND_ACCESSIBILITY)
    accessibility.sendAccessibilityEvent(eventInfo);
  }

  private sendArrowAccessibility(id: string): void {
    if (this.isSendArrowAccessibility) {
      let eventInfo: accessibility.EventInfo =
        new accessibility.EventInfo('requestFocusForAccessibility', this.bundleName, 'common')
      eventInfo.customId = id
      accessibility.sendAccessibilityEvent(eventInfo)
        .then(() => {
          setTimeout(() => {
            this.isSendArrowAccessibility = false;
          }, 200);
        });
    }
  }

  @Builder
  DownAndUpArrow() {
    Row() {
      Button() {
        SymbolGlyph(this.isArrowIconDown.value ? $r('sys.symbol.chevron_down') : $r('sys.symbol.chevron_up'))
          .fontSize(`${(this.fontSizeScale ?? DEFAULT_SYMBOL_FONT_SCALE) * SYMBOL_SIZE}vp`)
          .height(LIST_ROW_HEIGHT)
          .fontColor([$r('sys.color.ohos_id_color_tertiary')])
          .symbolEffect(new ReplaceSymbolEffect(EffectScope.WHOLE), this.replaceEffect)
          .focusable(true)
          .draggable(false)
          .stateStyles({
            focused: (instance: CommonMethod) => {
              instance
                .border({
                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                  width: FOCUS_BORDER_WIDTH,
                  color: $r('sys.color.ohos_id_color_focused_outline'),
                  style: BorderStyle.Solid
                })
                .offset({ x: -FOCUS_BORDER_WIDTH } as Position)
            },
            normal: (instance: CommonMethod) => {
              instance
                .border({
                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                  width: 0
                })
                .offset({ x: 0 } as Position)
            }
          })
          .tabIndex(-1)
      }
      .stateEffect(false)
      .type(ButtonType.Normal)
      .border({
        radius: $r('sys.float.ohos_id_corner_radius_clicked')
      })
      .height(LIST_ROW_HEIGHT)
      .backgroundColor(this.isArrowBgHoverRow ? this.arrowBgColorRow : TRANS_COLOR)
      .focusable(true)
      .accessibilityGroup(true)
      .accessibilityText(this.isSendArrowAccessibility ?
        (this.isArrowIconDown?.value ? this.filterAccessibilityText.accessibilityCollapsed :
          this.filterAccessibilityText.accessibilityExpanded) :
        (this.isArrowIconDown?.value ? this.filterAccessibilityText.accessibilityExpand :
          this.filterAccessibilityText.accessibilityCollapse))
      .accessibilityDescription(this.isSendArrowAccessibility ? ' ' : '')
      .accessibilityRole(this.isSendArrowAccessibility ? AccessibilityRoleType.ROLE_NONE : AccessibilityRoleType.BUTTON)
      .id(`filterDownAndUpArrow_${this.getUniqueId()}_${this.rowIndex}`)
      .visibility(this.arrowShowStateRow.value ? Visibility.Visible : Visibility.Hidden)

      .onHover((isHover: boolean, event: HoverEvent) => {
        this.getUIContext()?.animateTo({
          curve: FRICTION_CUBIC_BEZIER as ICurve,
          duration: ANIMATION_DURATION_250
        } as AnimateParam, () => {
          if (isHover) {
            this.arrowBgColorRow = $r('sys.color.ohos_id_color_hover')
            this.isArrowBgHoverRow = true
          } else {
            this.isArrowBgHoverRow = false
          }
        })
      })
      .onTouch((event?: TouchEvent) => {
        if (event?.type === TouchType.Down) {
          this.getUIContext()?.animateTo({
            curve: SHARP_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_100
          } as AnimateParam, () => {
            this.arrowBgColorRow = $r('sys.color.ohos_id_color_click_effect')
            this.isArrowBgHoverRow = true
          })
        } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
          this.getUIContext()?.animateTo({
            curve: SHARP_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_100
          } as AnimateParam, () => {
            this.isArrowBgHoverRow = false;
          })
        }
      })
      .onClick((event?: ClickEvent) => {
        this.isSendArrowAccessibility = true;
        this.replaceEffect += 1;
        if (this.isArrowIconDown.value) {
          this.isArrowIconDown.value = false;
          this.arrowShowStateRow.value = false;
          this.getUIContext()?.animateTo({
            curve: INTER_POLATING_SPRING as ICurve,
          } as AnimateParam, () => {
            this.twoLineModeItemNumRow.value = this.filterRow?.options.length.toDouble() as number;
          })

          this.getUIContext()?.animateTo({
            delay: 300,
            duration: ARROW_ANIMATION_DURATION,
            curve: SHARP_CUBIC_BEZIER as ICurve
          } as AnimateParam, () => {
            this.arrowShowStateRow.value = true;
          })
        } else {
          this.isArrowIconDown.value = true;
          this.arrowShowStateRow.value = false;

          this.getUIContext()?.animateTo({
            curve: INTER_POLATING_SPRING as ICurve,
          } as AnimateParam, () => {
            this.twoLineModeItemNumRow.value = this.twoLineModeItemNumRecordRow.value;
          })
          this.getUIContext()?.animateTo({
            delay: ARROW_SHOW_DELAY,
            duration: ARROW_ANIMATION_DURATION,
            curve: SHARP_CUBIC_BEZIER as ICurve
          } as AnimateParam, () => {
            this.arrowShowStateRow.value = true;
          })
        }
        this.sendArrowAccessibility(`filterDownAndUpArrow_${this.getUniqueId()}_${this.rowIndex}`);
      })
    }
    .height(LIST_ROW_HEIGHT)
  }

  build() {
    Flex() {
      if (this.filterRow?.options && (this.filterRow?.options as Array<ResourceStr>).length > 0) {
        Text(this.filterRow?.options[0] as ResourceStr)
          .height(LIST_ROW_HEIGHT)
          .margin({ start: LengthMetrics.vp(-TEXT_HOT_AREA_WIDTH) } as LocalizedMargin)
          .fontSize($r('sys.float.ohos_id_text_size_body3'))
          .minFontScale(1)
          .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
          .maxLines(1)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .fontColor(this.colorRow[0])
          .fontWeight(this.fontWeightRow[0])
          .backgroundColor(this.isBackgroundHoverRow[0] ? this.backgroundColorRow[0] :
            TRANS_COLOR)
          .accessibilityText(this.getAccessibilityText(this.filterRow?.options[0],
            this.isSelectedRow[0], FilterAccessibilityType.ACCESSIBILITY_TEXT))
          .accessibilityDescription(this.getAccessibilityText(this.filterRow?.options[0],
            this.isSelectedRow[0], FilterAccessibilityType.ACCESSIBILITY_DESC))
          .onClick((event?: ClickEvent) => {
            this.onItemClick(0);
            this.sendAccessibility(this.filterRow?.options[0], true);
          })
          .id(`filterMultiFilterRow_${this.filterId}_${this.rowIndex}`)
          .focusable(true)
          .onHover((isHover: boolean, event: HoverEvent) => {
            this.getUIContext()?.animateTo({
              curve: FRICTION_CUBIC_BEZIER as ICurve,
              duration: ANIMATION_DURATION_250
            } as AnimateParam, () => {
              if (isHover) {
                this.backgroundColorRow[0] = $r('sys.color.ohos_id_color_hover');
                this.isBackgroundHoverRow[0] = true;
              } else {
                this.isBackgroundHoverRow[0] = false;
              }
            })
          })
          .onTouch((event?: TouchEvent) => {
            if (event?.type === TouchType.Down) {
              this.getUIContext()?.animateTo({
                curve: SHARP_CUBIC_BEZIER as ICurve,
                duration: ANIMATION_DURATION_100
              } as AnimateParam, () => {
                this.backgroundColorRow[0] = $r('sys.color.ohos_id_color_click_effect');
                this.isBackgroundHoverRow[0] = true;
              })
            } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
              this.getUIContext()?.animateTo({
                curve: SHARP_CUBIC_BEZIER as ICurve,
                duration: ANIMATION_DURATION_100
              } as AnimateParam, () => {
                this.isBackgroundHoverRow[0] = false;
              })
            }
          })
          .stateStyles({
            focused: (instance: CommonMethod) => {
              instance
                .border({
                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                  width: FOCUS_BORDER_WIDTH,
                  color: $r('sys.color.ohos_id_color_focused_outline'),
                  style: BorderStyle.Solid
                })
                .padding({
                  start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH),
                  end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH)
                } as LocalizedPadding)
            },
            normal: (instance: CommonMethod) => {
              instance
                .border({
                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                  width: 0
                })
                .padding({
                  start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH),
                  end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH)
                } as LocalizedPadding)
            }
          })
          .constraintSize({ maxWidth: '50%' })
          .flexShrink(0)
          .tabIndex(1)
      }
      Row() {
        Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
          ForEach((this.filterRow?.options as Array<ResourceStr>)
            .slice(0, this.twoLineModeItemNumRow.value.toInt() + 1),
            (option: ResourceStr, colIndex: int) => {
              if (colIndex > 0) {
                Text(option)
                  .transition(TransitionEffect.OPACITY, (transitionIn: boolean) => {
                  })
                  .fontSize($r('sys.float.ohos_id_text_size_body3'))
                  .minFontScale(1)
                  .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
                  .maxLines(1)
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .height(LIST_ROW_HEIGHT)
                  .fontColor(this.colorRow[colIndex.toInt()])
                  .fontWeight(this.fontWeightRow[colIndex.toInt()])
                  .accessibilityText(this.getAccessibilityText(option,
                    this.isSelectedRow[colIndex.toInt()], FilterAccessibilityType.ACCESSIBILITY_TEXT))
                  .accessibilityDescription(this.getAccessibilityText(option,
                    this.isSelectedRow[colIndex.toInt()], FilterAccessibilityType.ACCESSIBILITY_DESC))
                  .backgroundColor(this.isBackgroundHoverRow[colIndex.toInt()] ?
                    this.backgroundColorRow[colIndex.toInt()] : TRANS_COLOR)
                  .onClick((event?: ClickEvent) => {
                    this.onItemClick(colIndex.toDouble())
                    this.sendAccessibility(option, true);
                  })
                  .onHover((isHover: boolean, event: HoverEvent) => {
                    this.getUIContext()?.animateTo({
                      curve: FRICTION_CUBIC_BEZIER as ICurve,
                      duration: ANIMATION_DURATION_250
                    } as AnimateParam, () => {
                      if (isHover) {
                        this.backgroundColorRow[colIndex.toInt()] = $r('sys.color.ohos_id_color_hover');
                        this.isBackgroundHoverRow[colIndex.toInt()] = true;
                      } else {
                        this.isBackgroundHoverRow[colIndex.toInt()] = false;
                      }
                    })
                  })
                  .onTouch((event?: TouchEvent) => {
                    if (event?.type === TouchType.Down) {
                      this.getUIContext()?.animateTo({
                        curve: SHARP_CUBIC_BEZIER as ICurve,
                        duration: ANIMATION_DURATION_100
                      } as AnimateParam, () => {
                        this.backgroundColorRow[colIndex.toInt()] = $r('sys.color.ohos_id_color_click_effect')
                        this.isBackgroundHoverRow[colIndex.toInt()] = true
                      })
                    } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
                      this.getUIContext()?.animateTo({
                        curve: SHARP_CUBIC_BEZIER as ICurve,
                        duration: ANIMATION_DURATION_100
                      } as AnimateParam, () => {
                        this.isBackgroundHoverRow[colIndex.toInt()] = false;
                      })
                    }
                  })
                  .focusable(true)
                  .stateStyles({
                    focused: (instance: CommonMethod) => {
                      instance
                        .border({
                          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                          width: FOCUS_BORDER_WIDTH,
                          color: $r('sys.color.ohos_id_color_focused_outline'),
                          style: BorderStyle.Solid
                        })
                        .padding({
                          start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH),
                          end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH)
                        } as LocalizedPadding)
                    },
                    normal: (instance: CommonMethod) => {
                      instance
                        .border({
                          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                          width: 0
                        })
                        .padding({
                          start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH),
                          end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH)
                        } as LocalizedPadding)
                    }
                  })
                  .tabIndex(-1)
              }
            })
          if (this.arrowShowStateRow.value) {
            this.DownAndUpArrow()
          }
        }
      }.width(PERCENT_100)
      .onAreaChange((_oldValue: Area, newValue: Area) => {
        this.filterColumnWidth = this.getUIContext().vp2px(parseInt(newValue.width.toString(), 0))
        if (this.twoLineModeItemNumRow.value === 0) {
          let curLineSum: number = this.calcMultiFilterRowItemNum();
          this.twoLineModeItemNumRow.value = curLineSum;
          this.twoLineModeItemNumRecordRow.value = curLineSum;
          if (this.filterRow && curLineSum < (this.filterRow?.options as Array<ResourceStr>).length - 1) {
            this.arrowShowStateRow.value = true;
          } else {
            this.arrowShowStateRow.value = false;
          }
        } else if (this.filterColumnWidth !== this.lastFilterColumnWidth) {
          let curLineSum: number = this.calcMultiFilterRowItemNum();
          if (this.filterRow && curLineSum < (this.filterRow?.options as Array<ResourceStr>).length - 1) {
            if (!this.arrowShowStateRow.value || this.isArrowIconDown.value) {
              this.arrowShowStateRow.value = true;
              this.isArrowIconDown.value = true;
              this.twoLineModeItemNumRow.value = curLineSum;
            }
          } else {
            this.arrowShowStateRow.value = false;
            this.isArrowIconDown.value = false;
            this.twoLineModeItemNumRow.value = curLineSum;
          }
          this.twoLineModeItemNumRecordRow.value = curLineSum;
        }
        this.lastFilterColumnWidth = this.filterColumnWidth;
      })

    }.width(PERCENT_100)
    .padding({
      start: LengthMetrics.resource($r('sys.float.ohos_id_max_padding_start')),
      end: LengthMetrics.resource($r('sys.float.ohos_id_max_padding_end'))
    } as LocalizedPadding)
  }
}

export class EnvironmentCallbackEntry implements EnvironmentCallback {
  filter: Filter;

  constructor(filter: Filter) {
    this.filter = filter;
  }

  onConfigurationUpdated(config: Configuration) {
    this.filter.fontSizeScale = Math.min(this.filter.updateFontScale(), MAX_SYMBOL_FONT_SCALE);
    this.filter.fontSizeScale = Math.max(this.filter.fontSizeScale as number, MIN_SYMBOL_FONT_SCALE);
    this.filter.initAccessibilityResource()
  }

  onMemoryLevel(level: AbilityConstant.MemoryLevel) {

  }
}

@Component
export struct Filter {
  @BuilderParam container: () => void = this.defaultContentBuilder;
  @PropRef multiFilters: Array<FilterParams> = [] as Array<FilterParams>;
  @PropRef additionFilters: FilterParams | undefined = undefined
  onFilterChanged: ((filterResults: Array<FilterResult>) => void) = () => {
  }
  @PropRef filterType: FilterType = FilterType.LIST_FILTER
  private selectedFilters: Array<FilterResult> | null = null;
  private colorArrNew: ResourceArray = new ResourceArray();
  private fontWeightArrNew: FontWeightArray = new FontWeightArray();
  private backgroundColorArrNew: ResourceArray = new ResourceArray();
  private isBackgroundHoverNew: BooleanArray = new BooleanArray();
  private downArrowShowStateNew: ObservedBoolean = new ObservedBoolean(false);
  private twoLineModeItemNumNew: ObservedNumber = new ObservedNumber(0);
  private isSelectedArrNew: BooleanArray = new BooleanArray();
  private twoLineModeItemNumRecordNew: ObservedNumber = new ObservedNumber(0);
  private isArrowIconDownArrNew: ObservedBoolean = new ObservedBoolean(false);
  @State private colorArr: Array<ResourceArray> | undefined = undefined;
  @State private fontWeightArr: Array<FontWeightArray> | undefined = undefined;
  @State private backgroundColorArr: Array<ResourceArray> | undefined = undefined;
  @State private isBackgroundHover: Array<BooleanArray> | undefined = undefined;
  @State private floatArrowBgColor: Resource | undefined = undefined;
  @State private isFloatArrowBgHover: boolean = false;
  @State private isArrowIconDownArr: Array<ObservedBoolean> | undefined = undefined;
  @State private additionColorArr: Array<Resource> | undefined = undefined;
  @State private additionFontWeightArr: Array<FontWeight> | undefined = undefined;
  @State private additionBackgroundColorArr: Array<Resource> | undefined = undefined;
  @State private isAdditionBackgroundHover: Array<boolean> | undefined = undefined;
  @State private isSelectedArr: Array<BooleanArray> | undefined = undefined;
  @State colorRefresh: boolean = false;
  @State @Watch('updateFocusForAccessibility') isFloatBarShow: boolean = false;
  isFloatBarShowWithoutAnimation: boolean = false;
  @State isFloatShowAllFilter: boolean = false;
  isFloatShowAllFilterWithoutAnimation: boolean = false;
  @State floatFilterPosition: number = 0;
  @State floatFilterBarHeight: number = 0;
  @State floatFilterBarPosition: number = 0;
  filterDynamicHeight: number = 0;
  @State twoLineModeItemNum: Array<ObservedNumber> | undefined = undefined;
  @State twoLineModeItemNumRecord: Array<ObservedNumber> | undefined = undefined;
  @State downArrowShowState: Array<ObservedBoolean> | undefined = undefined;
  @State floatFilterBarText: string = '';
  maxAppFontScale: number = 1;
  isFollowingSystemFontScale: boolean = false;
  @State fontSizeScale: number | undefined = undefined;
  private callbackId: number | undefined = undefined;
  private callbacks: EnvironmentCallbackEntry = new EnvironmentCallbackEntry(this);
  @State additionFiltersSelectedIndex?: number = -1;
  @State floatFilterBarAccessibilityText: string = '';
  @State filterAccessibilityText: FilterAccessibilityText = new FilterAccessibilityText();
  bundleName: string = '';
  private filterId: number = this.getUniqueId().toDouble();
  applicationContext: ApplicationContext = new ApplicationContext();

  @Builder
  defaultContentBuilder(): void {
  }

  textColor(rowIndex: number, colIndex: number) {
    if (this.selectedFilters && (this.selectedFilters as Array<FilterResult>).length > rowIndex &&
      ((this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index.toDouble()) === colIndex) {
      return $r('sys.color.ohos_id_color_text_primary_activated');
    }
    return $r('sys.color.ohos_id_color_text_primary');
  }

  aboutToAppear() {
    this.initParams();
    this.initAccessibilityResource();
    try {
      let uiContent: UIContext = this.getUIContext();
      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
      this.maxAppFontScale = uiContent.getMaxFontScale();
      this.fontSizeScale = Math.min(this.updateFontScale(), MAX_SYMBOL_FONT_SCALE);
      this.fontSizeScale = Math.max(this.fontSizeScale as number, MIN_SYMBOL_FONT_SCALE);
      if (uiContent.getHostContext() !== undefined) {
        let hostContext: common.UIAbilityContext = uiContent.getHostContext() as common.UIAbilityContext
        this.applicationContext = hostContext.getApplicationContext();
        this.callbackId = this.applicationContext.onEnvironment(this.callbacks);
      }

    } catch (err) {
      let code: number | undefined = (err as ClassCastError).code;
      let message: string | undefined = (err as ClassCastError).message;
      hilog.error(ERROR_CODE, 'Ace',
        `Failed to init fontsizescale info, cause, code: ${code}, message: ${message}`);
    }
  }

  aboutToDisappear(): void {
    if (this.callbackId) {
      let context: UIContext = this.getUIContext();
      if (context.getHostContext() !== undefined) {
        this.applicationContext.offEnvironment(this.callbackId!.toInt(),
          (err: BusinessError<void> | null): void => {
            hilog.info(0x0000, 'testTag', `applicationContext off environment err: code ${err?.code}`);
          })
      }
      this.callbackId = undefined;
    }
  }

  initAccessibilityResource(): void {
    try {
      if (this.getUIContext().getHostContext()) {
        this.bundleName = ((this.getUIContext().getHostContext()) as common.UIAbilityContext).abilityInfo.bundleName;
      }
      let resourceMan = resourceManager.getSysResourceManager()
      this.filterAccessibilityText.accessibilitySelectedText =
        resourceMan?.getStringByNameSync('filter_accessibility_selected') as string;
      this.filterAccessibilityText.accessibilityUnselectedText =
        resourceMan?.getStringByNameSync('filter_accessibility_unselected') as string;
      this.filterAccessibilityText.accessibilityFilters =
        resourceMan?.getStringByNameSync('filter_accessibility_filters') as string;
      this.filterAccessibilityText.accessibilitySelectedDesc =
        resourceMan?.getStringByNameSync('filter_accessibility_select_desc') as string;
      this.filterAccessibilityText.accessibilityUnselectedDesc =
        resourceMan?.getStringByNameSync('filter_accessibility_unselect_desc') as string;
      this.filterAccessibilityText.accessibilityExpandDesc =
        resourceMan?.getStringByNameSync('filter_accessibility_expand_desc') as string;
      this.filterAccessibilityText.accessibilityExpanded =
        resourceMan?.getStringByNameSync('filter_accessibility_expanded') as string;
      this.filterAccessibilityText.accessibilityCollapsed =
        resourceMan?.getStringByNameSync('filter_accessibility_collapsed') as string;
      this.filterAccessibilityText.accessibilityExpand =
        resourceMan?.getStringByNameSync('filter_accessibility_expand') as string;
      this.filterAccessibilityText.accessibilityCollapse =
        resourceMan?.getStringByNameSync('filter_accessibility_collapse') as string;
    } catch (err) {
      let code: number | undefined = (err as ClassCastError).code;
      let message: string | undefined = (err as ClassCastError).message;
      hilog.error(ERROR_CODE, 'Ace',
        `Filter failed to initAccessibilityResource, code: ${code}, message: ${message}`);
    }
  }

  updateFocusForAccessibility(name: string): void {
    if (this.isFloatBarShow) {
      let eventInfo: accessibility.EventInfo =
        new accessibility.EventInfo('requestFocusForAccessibility', this.bundleName, 'common')
      eventInfo.customId = `FiliterFloatFilterBar_${this.getUniqueId()}`
      accessibility.sendAccessibilityEvent(eventInfo);
    }
  }

  updateFontScale(): number {
    let uiContent: UIContext = this.getUIContext();
    let systemFontScale: number = 1;
    if (uiContent.getHostContext()) {
      systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
    }
    if (!this.isFollowingSystemFontScale) {
      return 1;
    }
    return Math.min(systemFontScale, this.maxAppFontScale);
  }

  getAccessibilityText(resource: ResourceStr | undefined, selected: boolean, type: FilterAccessibilityType): string {
    let accessibilityText: string = '';
    try {
      let resourceString: string = '';
      if (resource == undefined) {
        resourceString = '';
      } else if (typeof resource === 'string') {
        resourceString = resource as string;
      } else {
        let uiContent: Context | undefined = UIContext.resolveUIContext()?.getHostContext();
        resourceString = (uiContent as common.UIAbilityContext).resourceManager
          .getStringSync((resource as Resource).id) as string;
      }
      switch (type) {
        case FilterAccessibilityType.ACCESSIBILITY_TEXT:
          accessibilityText = selected ? `${this.filterAccessibilityText.accessibilitySelectedText},${resourceString}` :
            resourceString;
          break;
        case FilterAccessibilityType.ACCESSIBILITY_DESC:
          accessibilityText = selected ? this.filterAccessibilityText.accessibilityUnselectedDesc :
            this.filterAccessibilityText.accessibilitySelectedDesc;
          break;
        case FilterAccessibilityType.SEND_ACCESSIBILITY:
          accessibilityText = selected ? `${this.filterAccessibilityText.accessibilitySelectedText},${resourceString}` :
            `${this.filterAccessibilityText.accessibilityUnselectedText},${resourceString}`;
          break;
        default:
          break;
      }
    } catch (error) {
      let code: number | undefined = (error as ClassCastError).code;
      let message: string | undefined = (error as ClassCastError).message;
      hilog.error(0x3900, 'Ace',
        `Filter getAccessibilityText error, code: ${code}, message: ${message}`);
    }
    return accessibilityText;
  }

  private sendAccessibility(resource: ResourceStr | undefined, selected: boolean): void {
    let eventInfo: accessibility.EventInfo =
      new accessibility.EventInfo('announceForAccessibility', this.bundleName, 'common')
    eventInfo.textAnnouncedForAccessibility =
      this.getAccessibilityText(resource, selected, FilterAccessibilityType.SEND_ACCESSIBILITY)
    accessibility.sendAccessibilityEvent(eventInfo).then(() => {
      hilog.info(0x3900, 'Ace',
        `ListFilter sendAccessibility send event, event info is ${JSON.stringify(eventInfo)}`);
    })
  }

  private filterItemClick(rowIndex: number, colIndex: number): void {
    let selectedFilterValue = (this.multiFilters as Array<FilterParams>)[rowIndex.toInt()].options[colIndex.toInt()];
    if (this.selectedFilters && colIndex !== (this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index) {
      if (this.colorArr) {
        ((this.colorArr as Array<ResourceArray>)[rowIndex.toInt()] as ResourceArray)[colIndex.toInt()] =
          $r('sys.color.ohos_id_color_text_primary_activated');
        ((this.colorArr as Array<ResourceArray>)[rowIndex.toInt()] as ResourceArray)
        [((this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index.toInt())] =
          $r('sys.color.ohos_id_color_text_primary');
      }
      if (this.fontWeightArr) {
        (this.fontWeightArr as Array<FontWeightArray>)[rowIndex.toInt()][colIndex.toInt()] =
          FontWeight.Medium as FontWeight;
        (this.fontWeightArr as Array<FontWeightArray>)[rowIndex.toInt()]
        [(this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index.toInt()] = FontWeight.Regular;
      }
      if (this.isSelectedArr) {
        (this.isSelectedArr as Array<BooleanArray>)[rowIndex.toInt()][colIndex.toInt()] = true;
        (this.isSelectedArr as Array<BooleanArray>)[rowIndex.toInt()]
        [(this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index.toInt()] = false;
      }
      this.colorRefresh = (!this.colorRefresh) as boolean;
      (this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].value = selectedFilterValue as ResourceStr;
      (this.selectedFilters as Array<FilterResult>)[rowIndex.toInt()].index = colIndex.toInt();
      let filterChanged: ((filterResults: Array<FilterResult>) => void) | null = this.onFilterChanged;
      if (filterChanged) {
        filterChanged(this.selectedFilters as Array<FilterResult>);
      }
    }
    this.refreshFloatFilterBarText();
  }

  private refreshFloatFilterBarText(): void {
    this.floatFilterBarText = '';
    this.floatFilterBarAccessibilityText = '';
    if (this.selectedFilters) {
      const selectedValueFilters = this.selectedFilters?.filter(item => item?.value !== undefined)
        .map((item: FilterResult): ResourceStr => {
          if (typeof item.value !== 'string') {
            let uiContent: Context | undefined = UIContext.resolveUIContext()?.getHostContext();
            try {
              return (uiContent as common.UIAbilityContext).resourceManager
                .getStringSync((item.value as Resource).id as Long)
            } catch (error) {
              let code: number | undefined = (error as BusinessError).code;
              let message: string | undefined = (error as BusinessError).message;
              hilog.error(0x3900, 'Filter', `getStringSync failed, code: ${code}, message: ${message}`);
              return '';
            }
          } else {
            return item.value;
          }
        });
      this.floatFilterBarText = selectedValueFilters?.join('/') as string;
      this.floatFilterBarAccessibilityText = selectedValueFilters?.join(' ') as string;
    }
  }

  private getFloatAccessibilityText(resource: ResourceStr | undefined, type: FilterAccessibilityType): string {
    let accessibilityText: string = '';
    let accessibilityFilters: string = this.filterAccessibilityText.accessibilityFilters;
    let accessibilityCollapsed: string = this.filterAccessibilityText.accessibilityCollapsed;
    try {
      let resourceString: string = '';
      if (typeof resource === 'string') {
        resourceString = resource as string;
      } else {
        let uiContent: Context | undefined = UIContext.resolveUIContext()?.getHostContext();
        resourceString = (uiContent as common.UIAbilityContext).resourceManager.
        getStringSync((resource as Resource).id as Long)
      }
      switch (type) {
        case FilterAccessibilityType.ACCESSIBILITY_TEXT:
          accessibilityText =
            `${accessibilityFilters},${accessibilityCollapsed},${resourceString}`;
          break;
        case FilterAccessibilityType.ACCESSIBILITY_DESC:
          accessibilityText = this.filterAccessibilityText.accessibilityExpandDesc;
          break;
        case FilterAccessibilityType.SEND_ACCESSIBILITY:
          accessibilityText = this.filterAccessibilityText.accessibilityExpanded;
          break;
        default:
          break;
      }
    } catch (error) {
      let code: number | undefined = (error as ClassCastError).code;
      let message: string | undefined = (error as ClassCastError).message;
      hilog.error(0x3900, 'Ace',
        `Filter getAccessibilityText error, code: ${code}, message: ${message}`);
    }
    return accessibilityText;
  }

  private sendFloatAccessibility(resource: ResourceStr | undefined): void {
    let eventInfo: accessibility.EventInfo =
      new accessibility.EventInfo('announceForAccessibility', this.bundleName, 'common')
    eventInfo.textAnnouncedForAccessibility =
      this.getFloatAccessibilityText(resource, FilterAccessibilityType.SEND_ACCESSIBILITY)
    accessibility.sendAccessibilityEvent(eventInfo);
    if (this.multiFilters && (this.multiFilters as Array<FilterParams>).length > 0) {
      if (this.filterType === FilterType.LIST_FILTER) {
        let requestFocusEventInfo: accessibility.EventInfo =
          new accessibility.EventInfo('requestFocusForAccessibility', this.bundleName, 'common')
        eventInfo.customId = `filterListFilterRow_${this.filterId}_0`
        accessibility.sendAccessibilityEvent(requestFocusEventInfo);
      } else if (this.filterType === FilterType.MULTI_LINE_FILTER) {
        let requestFocusEventInfo: accessibility.EventInfo =
          new accessibility.EventInfo('requestFocusForAccessibility', this.bundleName, 'common')
        eventInfo.customId = `filterMultiFilterRow_${this.filterId}_0`
        accessibility.sendAccessibilityEvent(requestFocusEventInfo);
      }
    } else if (this.additionFilters && this.additionFilters?.name) {
      let requestFocusEventInfo: accessibility.EventInfo =
        new accessibility.EventInfo('requestFocusForAccessibility', this.bundleName, 'common')
      eventInfo.customId = `filterAdditionFiltersName_${this.filterId}`
      accessibility.sendAccessibilityEvent(requestFocusEventInfo);
    }
  }

  private initParams(): void {
    if (!this.selectedFilters) {
      this.selectedFilters = [];
      for (let filter of (this.multiFilters as Array<FilterParams>)) {
        let result: FilterResult = { name: filter.name, index: -1, value: '' } as FilterResult;
        if (filter.options.length > 0) {
          result.index = 0;
          result.value = filter.options[0];
        }
        this.selectedFilters?.push(result);
      }
      if (this.additionFilters && this.additionFilters?.name) {
        let result: FilterResult =
          { name: this.additionFilters?.name as ResourceStr, index: -1, value: '' } as FilterResult;
        this.selectedFilters?.push(result);
      }
      this.refreshFloatFilterBarText();
    }
    if (!this.colorArr) {
      this.colorArr = [];
      this.backgroundColorArr = [];
      this.isBackgroundHover = [];
      this.fontWeightArr = [];
      this.isArrowIconDownArr = [];
      this.isSelectedArr = [];
      this.floatArrowBgColor = $r('sys.color.ohos_id_color_background');
      for (let filter of (this.multiFilters as Array<FilterParams>)) {
        let colorRow = new ResourceArray();
        let fontWeightRow = new FontWeightArray();
        let backgroundColorRow = new ResourceArray();
        let isBackgroundHoverRow = new BooleanArray();
        let isSelectedRow = new BooleanArray();
        for (let index of filter.options.keys()) {
          if (index === 0) {
            colorRow.push($r('sys.color.ohos_id_color_text_primary_activated'));
            fontWeightRow.push(FontWeight.Medium);
            isSelectedRow.push(true);
          } else {
            colorRow.push($r('sys.color.ohos_id_color_text_primary'));
            fontWeightRow.push(FontWeight.Regular);
            isSelectedRow.push(false);
          }
          backgroundColorRow.push($r('sys.color.ohos_id_color_hover'));
          isBackgroundHoverRow.push(false);
        }
        this.colorArr?.push(colorRow);
        this.fontWeightArr?.push(fontWeightRow);
        this.backgroundColorArr?.push(backgroundColorRow);
        this.isBackgroundHover?.push(isBackgroundHoverRow);
        this.isArrowIconDownArr?.push(new ObservedBoolean(true));
        this.isSelectedArr?.push(isSelectedRow);
      }
    }
    if (this.additionFilters && this.additionFilters?.options) {
      this.additionColorArr = [];
      this.additionFontWeightArr = [];
      this.additionBackgroundColorArr = [];
      this.isAdditionBackgroundHover = [];
      for (let i: number = 0; i < (this.additionFilters?.options as Array<ResourceStr>).length; i++) {
        this.additionColorArr?.push($r('sys.color.ohos_id_color_text_primary'));
        this.additionFontWeightArr?.push(FontWeight.Regular);
        this.additionBackgroundColorArr?.push($r('sys.color.ohos_id_color_hover'));
        this.isAdditionBackgroundHover?.push(false);
      }
    }
    if (!this.twoLineModeItemNum) {
      this.twoLineModeItemNum = [];
      this.twoLineModeItemNumRecord = [];
      this.downArrowShowState = [];

      for (let filter of (this.multiFilters as Array<FilterParams>)) {
        let optionsLength: number = filter.options.length;
        this.twoLineModeItemNum?.push(new ObservedNumber(optionsLength));
        this.twoLineModeItemNumRecord?.push(new ObservedNumber(optionsLength));
        this.downArrowShowState?.push(new ObservedBoolean(false));
      }
    }
  }

  @Builder
  ListFilter() {
    Column() {
      ForEach((this.multiFilters as Array<FilterParams>), (filter: FilterParams, rowIndex: int) => {
        ListFilterRow({
          colorRow: this.colorArr ? (this.colorArr as Array<ResourceArray>)[rowIndex.toInt()] : this.colorArrNew,
          fontWeightRow: this.fontWeightArr ?
            (this.fontWeightArr as Array<FontWeightArray>)[rowIndex.toInt()] : this.fontWeightArrNew,
          backgroundColorRow: this.backgroundColorArr ?
            (this.backgroundColorArr as Array<ResourceArray>)[rowIndex.toInt()] : this.backgroundColorArrNew,
          isBackgroundHoverRow: this.isBackgroundHover ?
            (this.isBackgroundHover as Array<BooleanArray>)[rowIndex.toInt()] : this.isBackgroundHoverNew,
          isSelectedRow: this.isSelectedArr ?
            (this.isSelectedArr as Array<BooleanArray>)[rowIndex.toInt()] : this.isSelectedArrNew,
          filterRow: filter,
          onItemClick: (colIndex: number) => {
            this.filterItemClick(rowIndex.toDouble(), colIndex);
          },
          rowIndex: rowIndex.toDouble(),
          filterAccessibilityText: this.filterAccessibilityText
        })
      },(filter: FilterParams)=>{return filter.name.toString()})
    }.width(PERCENT_100)
    .align(Alignment.Start)
    .onAreaChange((_oldValue: Area, newValue: Area) => {
      if (!this.isFloatShowAllFilterWithoutAnimation && !this.isFloatBarShowWithoutAnimation) {
        if (this.additionFilters !== null) {
          this.filterDynamicHeight =
            parseInt(newValue.height.toString(), 0) + LIST_ROW_HEIGHT + FILTER_TOP_PADDING;
        } else {
          this.filterDynamicHeight = parseInt(newValue.height.toString(), 0) + FILTER_TOP_PADDING;
        }
        this.floatFilterPosition = -this.filterDynamicHeight;
      }
    })
  }

  @Builder
  MultiLineFilter() {
    Column() {
      ForEach((this.multiFilters as Array<FilterParams>), (filterItem: FilterParams, rowIndex: int) => {
        MultiFilterRow({
          colorRow: this.colorArr ?
            (this.colorArr as Array<ResourceArray>)[rowIndex.toInt()] : this.colorArrNew,
          fontWeightRow: this.fontWeightArr ?
            (this.fontWeightArr as Array<FontWeightArray>)[rowIndex.toInt()] : this.fontWeightArrNew,
          backgroundColorRow: this.backgroundColorArr ?
            (this.backgroundColorArr as Array<ResourceArray>)[rowIndex.toInt()] : this.backgroundColorArrNew,
          isBackgroundHoverRow: this.isBackgroundHover ?
            (this.isBackgroundHover as Array<BooleanArray>)[rowIndex.toInt()] : this.isBackgroundHoverNew,
          arrowShowStateRow: this.downArrowShowState ?
            (this.downArrowShowState as Array<ObservedBoolean>)[rowIndex.toInt()] : this.downArrowShowStateNew,
          twoLineModeItemNumRow: this.twoLineModeItemNum ?
            (this.twoLineModeItemNum as Array<ObservedNumber>)[rowIndex.toInt()] : this.twoLineModeItemNumNew,
          isSelectedRow: this.isSelectedArr ?
            (this.isSelectedArr as Array<BooleanArray>)[rowIndex.toInt()] : this.isSelectedArrNew,
          twoLineModeItemNumRecordRow: this.twoLineModeItemNumRecord ?
            (this.twoLineModeItemNumRecord as Array<ObservedNumber>)[rowIndex.toInt()] :
            this.twoLineModeItemNumRecordNew,
          isArrowIconDown: this.isArrowIconDownArr ?
            (this.isArrowIconDownArr as Array<ObservedBoolean>)[rowIndex.toInt()] : this.isArrowIconDownArrNew,
          filterRow: filterItem,
          onItemClick: (colIndex: number) => {
            this.filterItemClick(rowIndex.toDouble(), colIndex);
          },
          rowIndex: rowIndex.toDouble(),
          fontSizeScale: this.fontSizeScale,
          filterId: this.filterId,
          filterAccessibilityText: this.filterAccessibilityText
        })
      },(filterItem: FilterParams)=>{return filterItem.name.toString()})
    }.width(PERCENT_100)
    .onAreaChange((_oldValue: Area, newValue: Area) => {
      if (this.additionFilters !== null) {
        this.filterDynamicHeight =
          parseInt(newValue.height.toString(), 0) + LIST_ROW_HEIGHT + FILTER_TOP_PADDING
      } else {
        this.filterDynamicHeight = parseInt(newValue.height.toString(), 0) + FILTER_TOP_PADDING
      }
      if (!this.isFloatBarShowWithoutAnimation && !this.isFloatShowAllFilterWithoutAnimation) {
        this.floatFilterPosition = -this.filterDynamicHeight
      }
    })
  }

  private additionItemClick(index: number): void {
    let additionRowIndex: number = (this.multiFilters as Array<FilterParams>).length
    if (this.selectedFilters &&
      (this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index !== index) {
      this.additionColorArr &&
        ((this.additionColorArr as Array<Resource>)[index.toInt()] =
          $r('sys.color.ohos_id_color_text_primary_activated'));
      this.additionFontWeightArr &&
        ((this.additionFontWeightArr as Array<FontWeight>)[index.toInt()] = FontWeight.Medium);
      if ((this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index === -1) {
        (this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].value =
          this.additionFilters ? this.additionFilters?.options[index.toInt()] as ResourceStr : '' as ResourceStr;
        (this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index = index.toInt();
        this.additionFiltersSelectedIndex = index;
      } else {
        let lastIndex: number = (this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index;
        this.additionColorArr && ((this.additionColorArr as Array<Resource>)[lastIndex.toInt()] =
          $r('sys.color.ohos_id_color_text_primary'));
        this.additionFontWeightArr &&
          ((this.additionFontWeightArr as Array<FontWeight>)[lastIndex.toInt()] = FontWeight.Regular);
        this.selectedFilters &&
          ((this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].value = this.additionFilters ?
            this.additionFilters?.options[index.toInt()] as ResourceStr : '');
        this.selectedFilters &&
          ((this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index = index.toInt());
        this.additionFiltersSelectedIndex = index;
      }
    } else {
      this.additionColorArr &&
        ((this.additionColorArr as Array<Resource>)[index.toInt()] = $r('sys.color.ohos_id_color_text_primary'));
      this.additionFontWeightArr &&
        ((this.additionFontWeightArr as Array<FontWeight>)[index.toInt()] = FontWeight.Regular);
      this.selectedFilters && ((this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].value = '');
      this.selectedFilters && ((this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index = -1);
      this.additionFiltersSelectedIndex = -1;
    }
    if (this.selectedFilters) {
      if (this.onFilterChanged) {
        (this.onFilterChanged as
        ((filterResults: Array<FilterResult>) => void))(this.selectedFilters as Array<FilterResult>);
      }
    }
    this.colorRefresh = !this.colorRefresh;
    this.refreshFloatFilterBarText();
  }

  private getSelected(index: number): boolean {
    let additionRowIndex: number = (this.multiFilters as Array<FilterParams>).length;
    if (this.selectedFilters &&
      (this.selectedFilters as Array<FilterResult>)[additionRowIndex.toInt()].index !== index) {
      return false;
    } else {
      return true;
    }
  }

  @Builder
  AdditionFilterList() {
    if (this.additionFilters && this.additionFilters?.name && this.additionFilters?.options &&
      this.additionFilters?.options.length !== 0) {
      Stack({ alignContent: Alignment.End }) {
        Stack({ alignContent: Alignment.Start }) {
          List() {
            ListItem() {
              Row() {
                Text(this.additionFilters?.name)
                  .fontSize($r('sys.float.ohos_id_text_size_body3'))
                  .minFontScale(1)
                  .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
                  .fontColor($r('sys.color.ohos_id_color_text_secondary'))
                  .margin({
                    start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH),
                    end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH)
                  } as LocalizedMargin)
                  .padding({
                    start: LengthMetrics.resource($r('sys.float.ohos_id_max_padding_start'))
                  } as LocalizedPadding)
                  .id(`filterAdditionFiltersName_${this.filterId}`)
                Row()
                  .width(SEPARATOR_WIDTH)
                  .height(SEPARATOR_HEIGHT)
                  .backgroundColor($r('sys.color.ohos_id_color_list_separator'))
              }
            }.height(PERCENT_100)
            .margin({ start: LengthMetrics.vp(-TEXT_HOT_AREA_WIDTH) } as LocalizedMargin)

            ForEach(this.additionFilters?.options as Array<ResourceStr>, (option: ResourceStr, index: int) => {
              ListItem() {
                Text(option)
                  .fontSize($r('sys.float.ohos_id_text_size_body3'))
                  .minFontScale(1)
                  .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
                  .fontColor(this.additionColorArr ? (this.additionColorArr as Array<Resource>)[index.toInt()] :
                    '#e6182431')
                  .fontWeight(this.additionFontWeightArr ?
                    (this.additionFontWeightArr as Array<FontWeight>)[index.toInt()] : FontWeight.Normal)
                  .focusable(true)
              }
              .accessibilityText(this.getAccessibilityText(option,
                this.additionFiltersSelectedIndex === index, FilterAccessibilityType.ACCESSIBILITY_TEXT))
              .accessibilityDescription(this.getAccessibilityText(option,
                this.additionFiltersSelectedIndex === index, FilterAccessibilityType.ACCESSIBILITY_DESC))
              .height(PERCENT_100)
              .backgroundColor(this.isAdditionBackgroundHover &&
              (this.isAdditionBackgroundHover as Array<boolean>)[index.toInt()] ?
                this.additionBackgroundColorArr ? (this.additionBackgroundColorArr as Array<Resource>)[index.toInt()] :
                  '' : TRANS_COLOR)
              .onHover((isHover: boolean, event: HoverEvent) => {
                this.getUIContext()?.animateTo({
                  curve: FRICTION_CUBIC_BEZIER as ICurve,
                  duration: ANIMATION_DURATION_250
                } as AnimateParam, () => {
                  if (isHover) {
                    this.additionBackgroundColorArr &&
                      ((this.additionBackgroundColorArr as Array<Resource>)[index.toInt()] =
                        $r('sys.color.ohos_id_color_hover'));
                    this.isAdditionBackgroundHover &&
                      ((this.isAdditionBackgroundHover as Array<boolean>)[index.toInt()] = true);
                  } else {
                    this.isAdditionBackgroundHover &&
                      ((this.isAdditionBackgroundHover as Array<boolean>)[index.toInt()] = false);
                  }
                })
              })
              .onTouch((event?: TouchEvent) => {
                if (event?.type === TouchType.Down) {
                  this.getUIContext()?.animateTo({
                    curve: SHARP_CUBIC_BEZIER as ICurve,
                    duration: ANIMATION_DURATION_100
                  } as AnimateParam, () => {
                    this.additionBackgroundColorArr &&
                      ((this.additionBackgroundColorArr as Array<Resource>)[index.toInt()] =
                        $r('sys.color.ohos_id_color_click_effect'));
                    this.isAdditionBackgroundHover &&
                      ((this.isAdditionBackgroundHover as Array<boolean>)[index.toInt()] = true);
                  })
                } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
                  this.getUIContext()?.animateTo({
                    curve: SHARP_CUBIC_BEZIER as ICurve,
                    duration: ANIMATION_DURATION_100
                  } as AnimateParam, () => {
                    this.isAdditionBackgroundHover &&
                      ((this.isAdditionBackgroundHover as Array<boolean>)[index.toInt()] = false);
                  })
                }
              })
              .focusable(true)
              .stateStyles({
                focused: (instance: CommonMethod) => {
                  instance
                    .border({
                      radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                      width: FOCUS_BORDER_WIDTH,
                      color: $r('sys.color.ohos_id_color_focused_outline'),
                      style: BorderStyle.Solid
                    })
                    .padding({
                      start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH),
                      end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH - FOCUS_BORDER_WIDTH)
                    } as LocalizedPadding)
                },
                normal: (instance: CommonMethod) => {
                  instance
                    .border({
                      radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                      width: 0
                    })
                    .padding({
                      start: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH),
                      end: LengthMetrics.vp(TEXT_HOT_AREA_WIDTH)
                    } as LocalizedPadding)
                }
              })
              .onClick((event?: ClickEvent) => {
                this.additionItemClick(index.toDouble())
                this.sendAccessibility(option, this.getSelected(index.toDouble()));
              })
              .tabIndex(index === 0 ? 1 : -1)
            })
          }
          .listDirection(Axis.Horizontal)
          .scrollBar(BarState.Off)
          .width(PERCENT_100)
          .height(LIST_ROW_HEIGHT)

          GradientMask({
            x0: 0,
            y0: LIST_ROW_HEIGHT / 2,
            x1: GRADIENT_WIDTH,
            y1: LIST_ROW_HEIGHT / 2
          })
        }

        GradientMask({
          x0: GRADIENT_WIDTH,
          y0: LIST_ROW_HEIGHT / 2,
          x1: 0,
          y1: LIST_ROW_HEIGHT / 2
        })
      }
      .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
    }
  }

  @Builder
  FilterHeader() {
    Column() {
      if (this.filterType === FilterType.LIST_FILTER) {
        this.ListFilter()
      } else {
        this.MultiLineFilter()
      }
      this.AdditionFilterList()
    }.padding({ top: FILTER_TOP_PADDING } as Padding)

    .onVisibleAreaChange([0.0, 1.0], (_isVisible: boolean, currentRatio: number) => {
      if (currentRatio > 0) {
        this.isFloatShowAllFilter = false;
        this.isFloatShowAllFilterWithoutAnimation = false;
        this.isFloatBarShowWithoutAnimation = false;
        this.getUIContext()?.animateTo({
          curve: INTER_POLATING_SPRING as ICurve,
          onFinish: () => {
            if (!this.isFloatBarShowWithoutAnimation) {
              this.isFloatBarShow = false;
            }
          }
        } as AnimateParam, () => {
          this.floatFilterBarHeight = 0;
        })
      } else {
        this.isFloatBarShow = true;
        this.isFloatBarShowWithoutAnimation = true;
        this.getUIContext()?.animateTo({
          curve: INTER_POLATING_SPRING as ICurve
        } as AnimateParam, () => {
          this.floatFilterBarPosition = 0;
          this.floatFilterBarHeight = LIST_ROW_HEIGHT + FILTER_TOP_PADDING;
        })
      }
    } as VisibleAreaChangeCallback)
  }

  @Builder
  FloatFilterHeader() {
    Column() {
      Scroll() {
        Column() {
          if (this.filterType === FilterType.LIST_FILTER) {
            this.ListFilter();
          } else {
            this.MultiLineFilter();
          }
          this.AdditionFilterList();
        }
      }
    }
    .padding({ top: FILTER_TOP_PADDING } as Padding)
    .width(PERCENT_100)
    .constraintSize({ maxHeight: '80%' })
    .clip(true)
    .backgroundColor($r('sys.color.ohos_id_color_background'))
    .opacity(FLOAT_OPACITY)
    .backgroundBlurStyle(BlurStyle.Thin, undefined, { disableSystemAdaptation: true })
    .visibility(this.isFloatShowAllFilter ? Visibility.Visible : Visibility.Hidden)
    .position({ x: 0, y: this.floatFilterPosition } as Position)
    .zIndex(2)
  }

  @Builder
  FloatFilterBar() {
    Row() {
      Column() {
        Row() {
          Row() {
            Text(this.floatFilterBarText)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
              .fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
              .fontSize($r('sys.float.ohos_id_text_size_body3'))
              .minFontScale(1)
              .maxFontScale(Math.min(this.updateFontScale(), MAX_FONT_SCALE))
              .constraintSize({ maxWidth: '85%' })
              .maxLines(1)

            SymbolGlyph($r('sys.symbol.chevron_down'))
              .fontSize(`${(this.fontSizeScale ?? DEFAULT_SYMBOL_FONT_SCALE) * SYMBOL_SIZE}vp`)
              .fontColor([$r('sys.color.ohos_id_color_text_primary_activated')])
              .focusable(true)
              .draggable(false)
          }
          .height(LIST_ROW_HEIGHT)
          .margin({ start: LengthMetrics.vp(FILTER_BAR_MARGIN) } as LocalizedMargin)
          .focusable(true)
        }.height(PERCENT_100)
        .alignItems(VerticalAlign.Center)
      }
      .id(`FiliterFloatFilterBar_${this.getUniqueId()}`)
      .accessibilityText(this.getFloatAccessibilityText(this.floatFilterBarAccessibilityText,
        FilterAccessibilityType.ACCESSIBILITY_TEXT))
      .accessibilityDescription(this.getFloatAccessibilityText(this.floatFilterBarAccessibilityText,
        FilterAccessibilityType.ACCESSIBILITY_DESC))
      .backgroundColor(this.isFloatArrowBgHover ? this.floatArrowBgColor as undefined | Color | int | ResourceStr :
        TRANS_COLOR)
      .stateStyles({
        focused: (instance: CommonMethod) => {
          instance.border({
            radius: $r('sys.float.ohos_id_corner_radius_clicked'),
            width: FOCUS_BORDER_WIDTH,
            color: $r('sys.color.ohos_id_color_focused_outline'),
            style: BorderStyle.Solid
          })
        },
        normal: (instance: CommonMethod) => {
          instance.border({
            radius: $r('sys.float.ohos_id_corner_radius_clicked'),
            width: 0
          })
        }
      })
      .alignItems(HorizontalAlign.Center)
      .width(PERCENT_100)
      .height(LIST_ROW_HEIGHT)

      .onTouch((event?: TouchEvent) => {
        if (event?.type === TouchType.Down) {
          this.getUIContext()?.animateTo({
            curve: SHARP_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_100
          } as AnimateParam, () => {
            this.floatArrowBgColor = $r('sys.color.ohos_id_color_click_effect');
            this.isFloatArrowBgHover = true;
          })
        } else if (event?.type === TouchType.Up || event?.type === TouchType.Cancel) {
          this.getUIContext()?.animateTo({
            curve: SHARP_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_100
          } as AnimateParam, () => {
            this.isFloatArrowBgHover = false;
          })
        }
      })
      .onClick((event?: ClickEvent) => {
        this.getUIContext()?.animateTo({
          duration: BAR_ANIMATION_DURATION,
          curve: SHARP_CUBIC_BEZIER as ICurve
        } as AnimateParam, () => {
          this.isFloatBarShow = false;
          this.isFloatBarShowWithoutAnimation = false;
        })
        this.isFloatShowAllFilter = true
        this.isFloatShowAllFilterWithoutAnimation = true
        this.getUIContext()?.animateTo({
          curve: INTER_POLATING_SPRING as ICurve,
          onFinish: () => {
            this.floatFilterBarPosition = 0
          }
        } as AnimateParam, () => {
          this.floatFilterPosition = 0;
          this.floatFilterBarPosition = this.filterDynamicHeight;
        })
        this.sendFloatAccessibility(this.floatFilterBarAccessibilityText);
      })
      .onHover((isHover: boolean, event: HoverEvent) => {
        if (isHover) {
          this.getUIContext()?.animateTo({
            curve: FRICTION_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_250
          } as AnimateParam, () => {
            this.floatArrowBgColor = $r('sys.color.ohos_id_color_hover');
            this.isFloatArrowBgHover = true;
          })
        } else {
          this.getUIContext()?.animateTo({
            curve: FRICTION_CUBIC_BEZIER as ICurve,
            duration: ANIMATION_DURATION_250
          } as AnimateParam, () => {
            this.isFloatArrowBgHover = false;
          })
        }
      })
    }
    .width(PERCENT_100)
    .height(this.floatFilterBarHeight)
    .padding({
      start: LengthMetrics.vp(FOCUS_BORDER_WIDTH),
      end: LengthMetrics.vp(FOCUS_BORDER_WIDTH)
    } as LocalizedPadding)
    .backgroundColor($r('sys.color.ohos_id_color_background'))
    .opacity(FLOAT_OPACITY)
    .clip(true)
    .backgroundBlurStyle(BlurStyle.Thin, undefined, { disableSystemAdaptation: true })
    .visibility(this.isFloatBarShow ? Visibility.Visible : Visibility.Hidden)
    .alignItems(VerticalAlign.Bottom)
    .position({ x: 0, y: this.floatFilterBarPosition } as Position)
    .zIndex(1)
  }

  build() {
    Stack({ alignContent: Alignment.Top }) {
      this.FloatFilterBar();
      this.FloatFilterHeader();
      Column() {
        List({ initialIndex: 0 }) {
          ListItem() {
            this.FilterHeader()
          }.focusable(true)
          ListItem() {
            this.container()
          }.focusable(true)
        }
        .listDirection(Axis.Vertical)
        .width(PERCENT_100)
        .height(PERCENT_100)
        .edgeEffect(EdgeEffect.Spring)

        .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
          if (this.isFloatShowAllFilterWithoutAnimation && scrollState === ScrollState.Scroll) {
            this.isFloatBarShowWithoutAnimation = true
            this.isFloatShowAllFilterWithoutAnimation = false
            this.getUIContext()?.animateTo({
              duration: BAR_ANIMATION_DURATION,
              curve: SHARP_CUBIC_BEZIER as ICurve
            } as AnimateParam, () => {
              this.isFloatBarShow = true;
            })

            this.getUIContext()?.animateTo({
              curve: INTER_POLATING_SPRING as ICurve,
              onFinish: () => {
                if (!this.isFloatShowAllFilterWithoutAnimation) {
                  this.isFloatShowAllFilter = false;
                }
              }
            } as AnimateParam, () => {
              this.floatFilterPosition = -this.filterDynamicHeight;
              this.floatFilterBarPosition = 0;
            })
          }
        } as OnScrollCallback)
      }.zIndex(0)
    }.clip(true)
  }
}