升级你的HarmonyOS体验:一窥功能引导与拖拽交换的独家技巧

2024-09-24 19:21:30 浏览数 (3)

前言

在当今的移动应用开发领域,为了提供更加友好和直观的用户体验,开发者们通常会集成多种交互功能来增强应用的互动性和易用性。在这些功能中,有两个功能显得尤为重要,它们分别是功能引导和元素拖拽交换。功能引导帮助用户快速熟悉应用的各种操作和特性,而元素拖拽交换则允许用户以直观的方式对界面元素进行个性化排序和布局。本文将深入探讨在HarmonyOS平台上如何实现这两个关键功能。

项目目录结构

代码语言:javascript复制
├── main
│   ├── ets
│   │   ├── entryability
│   │   │   └── EntryAbility.ets
│   │   ├── model
│   │   │   ├── AttributeModifier.ets         //  声明GridItem动态属性
│   │   │   ├── GridItemDeletionCtrl.ets      // gridItem删除管理
│   │   │   ├── headerIcon.ets                // icon 布局区域
│   │   │   └── iconInfo.ets
│   │   └── pages
│   │       └── Index.ets                     // 入口区域

开发流程

主要步骤讲解
  1. 导入模块:代码首先导入了<font style="color:rgb(26, 32, 41);">@ohos/high_light_guide</font>模块中的多个类,用于创建和管理高亮引导,以及<font style="color:rgb(26, 32, 41);">@ohos.animator</font>模块中的动画参数设置。同时,还导入了自定义的<font style="color:rgb(26, 32, 41);">HeaderApp</font>模型和<font style="color:rgb(26, 32, 41);">promptAction</font>用于显示对话框。
  2. 常量定义:定义了动画的持续时间、延迟、迭代次数、开始和结束的状态等常量。
  3. 组件定义:使用<font style="color:rgb(26, 32, 41);">@Entry</font><font style="color:rgb(26, 32, 41);">@Component</font>装饰器定义了一个名为<font style="color:rgb(26, 32, 41);">Index</font>的结构体组件。
  4. 成员变量:定义了用于构建和管理高亮引导的变量,以及动画参数、监听器等。
  5. **<font style="color:rgb(26, 32, 41);">aboutToAppear</font>**方法:在这个方法中,初始化了高亮引导构建器<font style="color:rgb(26, 32, 41);">HighLightGuideBuilder</font>,并设置了多个引导页面<font style="color:rgb(26, 32, 41);">GuidePage</font>,包括提示文本、高亮形状、动画效果等。
  6. **<font style="color:rgb(26, 32, 41);">build</font>**方法:构建了组件的UI布局,使用<font style="color:rgb(26, 32, 41);">Stack</font>布局包裹了一个<font style="color:rgb(26, 32, 41);">HighLightGuideComponent</font>,并设置了其属性和回调函数。
  7. 布局构建器:定义了多个布局构建器方法(如<font style="color:rgb(26, 32, 41);">highLightComponent</font><font style="color:rgb(26, 32, 41);">firstHigh</font><font style="color:rgb(26, 32, 41);">secondHigh</font><font style="color:rgb(26, 32, 41);">thirdHigh</font><font style="color:rgb(26, 32, 41);">endHigh</font>),用于创建具体的引导页面布局和交互逻辑。
  8. **<font style="color:rgb(26, 32, 41);">endHigh</font>**方法:在最后一个引导页面显示时,通过<font style="color:rgb(26, 32, 41);">promptAction.showDialog</font>显示一个对话框,用户确认后移除高亮引导。
关键配置

项目中我们使用了高亮插件<font style="color:rgb(64, 72, 91);">ohos_highlightguide</font> , 在终端输入 指令

ohpm install @ohos/high_light_guide

来下载依赖, 并进行相关配置, 如下图所示

Index.ets 页面讲解

Index 页面主要做的是高光处理 在页面加载的时候设定高光组件

代码语言:javascript复制
  aboutToAppear() {

    // 设定高光组件
    this.builder = new HighLightGuideBuilder()
      .setLabel('guide')
      .alwaysShow(true)// 总是显示,调试时可以打开
      .setOnGuideChangedListener(this.visibleChangeListener)
      .setOnPageChangedListener(this.pageChangeListener)
      .addGuidePage(GuidePage.newInstance()// 第一处提示 点击编辑
        .setEverywhereCancelable(true)// 允许点击任意处关闭
        .addHighLight('edit')
        .setHighLightIndicator(this.firstHigh)
        .setExitAnimation(this.exitAnimatorParam))
      .addGuidePage(GuidePage.newInstance() // 设定第二处提示
        .setEverywhereCancelable(true)// 允许点击任意处关闭
        .addHighLight( 'high', HighLightShape.OVAL , 20)
        .setHighLightIndicator(this.secondHigh)
        .setExitAnimation(this.exitAnimatorParam))
      .addGuidePage(GuidePage.newInstance()// 设定第三处提示
        .setEverywhereCancelable(false)// 要求用户点击"我知道了"才能关闭提示
        .setHighLightIndicator(this.thirdHigh)
        .setEnterAnimation(this.enterAnimatorParam)
        .setExitAnimation(this.exitAnimatorParam))
      .addGuidePage(GuidePage.newInstance()// 设定第四处提示 移除高亮引导
        .setEverywhereCancelable(false)
        .setHighLightIndicator(this.endHigh));
  }

代码中 addGuidePage 指代的是每一个高光插件, 通过setHighLightIndicator 来引用我们的高光的组件

高光组件相关

本次项目中主要用了 四个高光组件 , 每个组件都进行了不同的定义 , 从而来进行不同的高光展示

代码语言:javascript复制
@Builder
  firstHigh(){
     Column(){
       Image($r("app.media.first_high_icon")).width(20).height(30).margin({right:'20', bottom:'10'})
       Text($r('app.string.first_high_tip'))
         .textAlign(TextAlign.Center)
         .fontColor(Color.White)
         .textAlign(TextAlign.Start)
         .onClick(() => {
           if (this.controller) {
             this.controller.showPage(1);
           }
         })
     }
     .justifyContent(FlexAlign.End)
     .alignItems(HorizontalAlign.End)
     .width('50%')
     .margin({ left: $r('app.string.first_high_margin'),
       top:'50'
     })
  }

  @Builder
  secondHigh() {
    Column() {
      Text('长按可拖动')
        .textAlign(TextAlign.Center)
        .fontColor(Color.White)
        .width('70%')
        .onClick(() => {
          if (this.controller) {
            this.controller.showPage(2);
          }
        })
         Image($r("app.media.second_high_icon"))
        .width($r('app.integer.sort_order_width'))
        .height($r('app.integer.sort_order_width'))
           .margin({top:10})
           .onClick(() => {
          if (this.controller) {
            this.controller.showPage(2);
          }
        })
    }
    .width($r('app.string.percent_one_hundred'))
    .margin({top:10})
    .alignItems(HorizontalAlign.Center)
    // position坐标是以页面顶部中心为原点,不包括系统状态栏
    // .position({ x: this.PosX, y: this.PosY})
  }

  @Builder
  thirdHigh() {
    Column() {
      Text($r('app.string.third_high_tip'))
        .fontColor(Color.Black)
        .backgroundColor($r('app.color.module_back_ground'))
        .textAlign(TextAlign.Center)
        .width($r('app.integer.first_indicator_width'))
        .height($r('app.integer.first_indicator_height'))
        .borderRadius($r('app.integer.border_radius'))
   Button($r('app.string.third_high_btn'))
        .fontColor(Color.Black)
        .margin($r('app.integer.common_margin'))
        .fontSize($r('app.integer.access_font_size'))
        .backgroundColor($r('app.color.first_direct_background'))
        .border({ width: 1, color: Color.White })
        .width($r('app.integer.high_light_button_width'))
        .onClick(() => {
          if (this.controller) {
            this.controller.showPage(3);
          }
        })
    }
    .width($r('app.string.percent_one_hundred'))
    .height($r('app.string.percent_one_hundred'))
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  endHigh() {
    Column()
      .onAppear(() => {
        promptAction.showDialog({
          message: $r("app.string.end_high_tip"),
          buttons: [
            {
              text: $r('app.string.confirm_btn'),
              color: $r('app.color.toast_success_back_ground')
            }
          ],
          isModal: false
        }).then(() => {
          if (this.controller) {
            this.controller.remove();
          }
        })
      })

  }
HeaderApp

在HeaderApp 组件中主要实现的是元素切换功能 ,核心代码如下

代码语言:javascript复制
  Grid() {
        ForEach(this.AppDataArr, (item: AppInfo, index: number) => {
          GridItem() {
            IconWithNameView({ app: item })
          }
          .id(this.AppDataArr.indexOf(item) === SELECT_INDEX ? 'high' : '')
          .onAreaChange((oldValue: Area, newValue: Area) => {
            this.itemAreaWidth = Number(newValue.width);
          })
          .onTouch((event: TouchEvent) => {
            if (event.type === TouchType.Down) {
              this.movedItem = this.AppDataArr[index];
            }
          })
          .attributeModifier(this.GridItemDeletion.getModifier(item))
          .onClick(() => {
            if (!this.isEdit) {
              return;
            }
            this.GridItemDeletion.deleteGridItem(item, this.itemAreaWidth);
          })
        }, (item: AppInfo) => JSON.stringify(item))
      }
      .columnsTemplate('1fr 1fr 1fr 1fr 1fr')
      .width($r('app.string.grid_title_width'))
      .layoutWeight(1)
      .supportAnimation(true)
      .editMode(this.isEdit)
      .onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
        // 在onItemDragStart函数返回自定义组件,可在拖拽过程中显示此自定义组件。
        return this.pixelMapBuilder();
      })
      .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
        //  执行gridItem切换操作
        if (isSuccess && insertIndex < this.AppDataArr.length) {
          this.changeIndex(itemIndex, insertIndex);
        }
      })

代码中定义的id 属性 主要为了高光时的元素查找

通过 onItemDragStart 和 onItemDrop 来实现元素的切换效果

同时 IconWithNameView 定义的是每个组件相关的展示内容,代码如下

代码语言:javascript复制
@Component
struct IconWithNameView {
  private app: AppInfo = new AppInfo();
  @Consume isEdit: boolean;

  build() {
    Column() {
      Stack({ alignContent: Alignment.TopEnd }) {
        Image(this.app.icon)
          .width($r('app.string.icon_width'))
          .height($r('app.string.icon_height'))
          .interpolation(ImageInterpolation.High)
          .syncLoad(true)
          .draggable(false)
        if (this.isEdit) {
          Image($r('app.media.del_icon'))
            .width($r('app.string.del_icon_width'))
            .height($r('app.string.del_icon_height'))
            .markAnchor({ x: '-40%', y: '40%' })
            .draggable(false)
        }
      }

      Text(this.app.name)
        .width($r('app.string.icon_name_width'))
        .fontSize($r('app.string.icon_name_font_size'))
        .maxLines(1)
        .fontColor(Color.Black)
        .textAlign(TextAlign.Center)
        .margin({ top: 1 })
    }
    .width($r('app.string.icon_item_width'))
    .height($r('app.string.icon_item_height'))
    .justifyContent(FlexAlign.Center)
  }
}

好了, 以上就是该项目的核心内容讲解啦

总结

在harmonyos 逐渐强大的道路上每一份案例的支持都是尤为重要的, 期待每一位鸿蒙爱好者都贡献一份力量,共同完善harmonyos 的建设

0 人点赞