从零开始纯血鸿蒙天气预报-城市管理页面(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 小时前
鸿蒙NEXT开发Base64工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
The 旺6 小时前
《HarmonyOS Next开发实战:从零构建响应式Todo应用的基石》
华为·harmonyos
Industio_触觉智能7 小时前
鸿蒙北向开发OpenHarmony5.0 DevEco Studio开发工具安装与配置
harmonyos·鸿蒙系统·openharmony·开源鸿蒙·鸿蒙开发·嵌入式开发板
秋叶先生_11 小时前
HarmonyOS NEXT——【鸿蒙监听网络状态变化】
华为·harmonyos·鸿蒙
东林知识库12 小时前
鸿蒙NEXT小游戏开发:围住神经猫
harmonyos
zacksleo12 小时前
鸿蒙Flutter开发故事:不,你不需要鸿蒙化
flutter·harmonyos
别说我什么都不会14 小时前
OpenHarmony解读之设备认证:sts协议-客户端发起sts end请求
物联网·嵌入式·harmonyos
悬空八只脚17 小时前
React-Native开发鸿蒙NEXT-本地与沙盒加载bundle
harmonyos
鸿蒙布道师17 小时前
鸿蒙NEXT开发日志工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
90后的晨仔17 小时前
HarmonyOS的页面生命周期 和 组件生命周期
harmonyos