从零开始纯血鸿蒙天气预报-城市管理页面(1)

易得天气

目前做了城市列表的展示、添加城市、删除城市、批量删除城市。城市列表的拖动排序还未做

由于代码量上来了,只贴关键代码,等做完了会开源出来

CityManagerViewModel类管理城市管理页面的状态

less 复制代码
// 管理页面是否是编辑模式
@Trace isEditMode: boolean = false
// 编辑模式下被选中的城市
@Trace selectedList: Array<CityData> = []
// 城市列表滑动时标题栏的透明度
@Trace titleOpacity: number = 0

标题的显示根据isEditMode和selectedList共同决定

kotlin 复制代码
@Computed
get title() {
  return this.cityManagerVm.isEditMode ?
    (ArrayUtil.isEmpty(this.cityManagerVm.selectedList) ? '请选择项目' :
      '已选择' + this.cityManagerVm.selectedList.length + '项') : '城市管理'
}

中间的标题

scss 复制代码
@Builder
centerTitle() {
  Text(this.title)
    .fontSize(18)
    .fontColor($r('app.color.black'))
    .opacity(this.cityManagerVm.titleOpacity)
}

右侧的按钮显示逻辑、点击事件

kotlin 复制代码
@Builder
rightIcon() {
  Image(this.cityManagerVm.isEditMode ? $r('app.media.ic_select_all_icon') : $r('app.media.ic_search_icon'))
    .width(20)
    .height(20)
    .colorFilter(this.cityManagerVm.isEditMode ?
    ColorUtils.translateColor(this.cityManagerVm.isSelectedAll(this.addedCityData) ? $r('app.color.app_main') :
    $r('app.color.special_black')) : undefined)
    .onClick(() => {
      if (this.cityManagerVm.isEditMode) {
        if (this.cityManagerVm.isSelectedAll(this.addedCityData)) {
          this.cityManagerVm.clearSelected()
        } else {
          this.cityManagerVm.selectedAll(this.addedCityData)
        }
      } else {
        ZRouter.getInstance()
          .push(RouterConstants.SELECT_CITY_PAGE)
      }
    })
}

内容区域

scss 复制代码
@Builder
contentView() {
  Stack({ alignContent: Alignment.Bottom }) {
    // 城市列表
    this.cityList()
    // 底部删除按钮
    this.bottomOperateButton()
  }
  .width('100%')
  .layoutWeight(1)
}

城市列表,其中标题的透明度变化在onDidScroll回调函数进行,swipeAction是侧滑按钮,transition是会执行List删除动画

kotlin 复制代码
@Builder
cityList() {
  List({ scroller: this.listScroller }) {
    ListItem() {
      Text(this.title)
        .fontSize(28)
        .fontColor($r('app.color.black'))
        .opacity(1 - this.cityManagerVm.titleOpacity)
        .padding({ left: 16, top: 12 })
        .height(60)
    }

    ForEach(this.addedCityData, (cityData: CityData) => {
      ListItem() {
        CityManagerItem({
          cityData: cityData,
          isEditMode: this.cityManagerVm.isEditMode,
          isSelected: this.cityManagerVm.isSelected(cityData),
          toEditMode: (cityData) => {
            this.cityManagerVm.toEditMode(this.addedCityData?.length ?? 0, cityData)
          },
          onItemClick: (cityData) => {
            if (this.cityManagerVm.isEditMode) {
              this.cityManagerVm.selected(cityData)
            }
          }
        })
      }
      .swipeAction({
        end: !cityData.isLocationCity && !this.cityManagerVm.isEditMode ? () => {
          this.itemEnd(cityData)
        } : undefined,
      })
      .transition(TransitionEffect.SLIDE)
    }, (cityData: CityData): string => {
      return cityData.cityid ?? ''
    })
    ListItem() {
      Divider()
        .width('100%')
        .height(px2vp(AppUtil.getNavigationIndicatorHeight()) + (this.cityManagerVm.isEditMode ? 54 : 0))
        .color($r('app.color.transparent'))
    }
  }
  .width('100%')
  .height('100%')
  .divider({ strokeWidth: 12, color: $r('app.color.transparent') })
  .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true })
  .onDidScroll(() => {
    const yOffset = this.listScroller.currentOffset().yOffset
    const percent = fixPercent(yOffset / 72)
    this.cityManagerVm.changeTitleOpacity(percent)
  })
}

CityManagerItem是城市列表每一项item

kotlin 复制代码
// 定位的城市不支持编辑
if (!this.isLocationCity) {
  this.editItem()
}
this.cityItem()

editItem,其中animatableEditItem让item支持动画

scss 复制代码
@Builder
editItem() {
  Row() {
    Image($r('app.media.ic_menu_icon'))
      .width(24)
      .height(24)
      .colorFilter(ColorUtils.translateColor($r('app.color.special_white')))
    Image(this.isSelected ? $r('app.media.ic_checked_icon') : $r('app.media.ic_check_icon'))
      .width(22)
      .height(22)
      .colorFilter(ColorUtils.translateColor(this.isSelected ? $r('app.color.app_main') :
      $r('app.color.special_white')))
      .backgroundColor(this.isEditMode && this.isSelected ? $r('app.color.special_white') :
      $r('app.color.transparent'))
      .borderRadius(100)
  }
  .width('100%')
  .padding({ left: 16, right: 16 })
  .animatableEditItem(this.isEditMode ? 1 : 0)
  .animation({ duration: 200, curve: Curve.Linear })
  .justifyContent(FlexAlign.SpaceBetween)
}
css 复制代码
@AnimatableExtend(Row)
function animatableEditItem(visibility: number) {
  .opacity(visibility)
  .visibility(visibility <= 0 ? Visibility.Hidden : Visibility.Visible)
}

cityItem编辑模式下的动画

kotlin 复制代码
.animatableCityItemPadding(this.isEditMode && !this.isLocationCity ? 52 : 16)
.animation({ duration: 200, curve: Curve.Linear })
less 复制代码
@AnimatableExtend(Row)
function animatableCityItemPadding(padding: number) {
  .padding({ left: padding, right: padding })
}

添加长按手势进入编辑模式

javascript 复制代码
.gesture(
  LongPressGesture()
    .onAction((event: GestureEvent | undefined) => {
      if (event) {
        if (this.toEditMode) {
          this.toEditMode(this.cityData)
        }
      }
    })
)

添加城市:

侧滑删除

批量删除

相关推荐
康康这名还挺多4 小时前
鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
数据结构·list·harmonyos·lazyforeach
晚秋大魔王8 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——nettle库
linux·开源·harmonyos
python算法(魔法师版)11 小时前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
bestadc13 小时前
鸿蒙 UIAbility组件与UI的数据同步和窗口关闭
harmonyos
枫叶丹414 小时前
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
华为·harmonyos·deveco studio·harmonyos next
乱世刀疤18 小时前
深度 |国产操作系统“破茧而出”:鸿蒙电脑填补自主生态空白
华为·harmonyos
沙振宇1 天前
【Web】使用Vue3开发鸿蒙的HelloWorld!
前端·华为·harmonyos
bestadc2 天前
鸿蒙 所有API缩略图鉴
harmonyos
马剑威(威哥爱编程)2 天前
HarmonyOS 5.0 分布式数据协同与跨设备同步
分布式·华为·harmonyos·arkts·harmonyos-next