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

添加城市:

侧滑删除

批量删除

相关推荐
坚果派·白晓明5 小时前
AI驱动的命令行工具集x-cmd鸿蒙化适配后通过DevBox安装使用
人工智能·华为·harmonyos
柒儿吖5 小时前
命令行ninja在鸿蒙PC上的使用方法
华为·harmonyos
hqk10 小时前
鸿蒙ArkUI:状态管理、应用结构、路由全解析
android·前端·harmonyos
ezeroyoung11 小时前
鸿蒙MindSpore Lite 离线模型转换指南
华为·大模型·harmonyos
大土豆的bug记录12 小时前
鸿蒙实现自定义类似活体检测功能
数码相机·华为·harmonyos·鸿蒙
奔跑的露西ly12 小时前
【HarmonyOS NEXT】顶象验证码 SDK 接入实践
华为·harmonyos
ezeroyoung12 小时前
环信em_chat_uikit(Flutter)适配鸿蒙
flutter·华为·harmonyos
wyw000013 小时前
鸿蒙开发-如何将C++侧接收的PixelMap转换成cv::mat格式
c++·华为·harmonyos
云空14 小时前
《当机器人有了“鸿蒙大脑”:M-Robots OS如何重构产业生态?》
重构·机器人·harmonyos
讯方洋哥15 小时前
应用冷启动优化
前端·harmonyos