从零开始纯血鸿蒙天气预报-城市管理页面(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)
        }
      }
    })
)

添加城市:

侧滑删除

批量删除

相关推荐
zd2005726 分钟前
我给x86版本开源鸿蒙系统装上了 Homebrew,还塞了整个 Node 和 opencode 进去
华为·开源·harmonyos
song50113 分钟前
React Native for OpenHarmony 实战:三方库 react-native-popup-menu 的鸿蒙化适配指南
css·深度学习·react native·react.js·transformer·harmonyos
打工仔折腾 AI26 分钟前
鸿蒙版ToDesk远控实测:蓝牙键鼠、双模式鼠标与跨端剪贴板怎么用
后端·python·华为·性能优化·计算机外设·harmonyos·ai agent 实战
特立独行的猫a40 分钟前
仓颉语言实现强大的Modbus调试工具Modbus Poll:cj-tauri项目介绍与实战
harmonyos·tauri·modbus·仓颉·modbus poll
m0_7381858212 小时前
Flutter 鸿蒙化实战:screen_protector 适配 OpenHarmony,防截屏/防泄露
flutter·华为·harmonyos·鸿蒙
CV工程师丁Sir13 小时前
# ArkWeb 手记 03|本地资源加载与 $rawfile 路径踩坑
harmonyos
OH_TPC21 小时前
HarmonyOS APP开发---"菜谱汇"美食菜谱App,需要用到这个库
harmonyos
老陈说编程1 天前
2. 鸿蒙(HarmonyOS)超级终端与生态
华为·harmonyos
2501_919749031 天前
华为鸿蒙免费时钟工具—小羊时钟
华为·harmonyos