鸿蒙开发:自定义一个搜索模版

程序员一鸣
• 阅读 55

前言

代码案例基于Api13。

在之前的文章中,我们简单分析了弹性布局Flex,并使用Flex实现了一个简单的流式布局,今天这篇文章,我们就结合搜索框,完成一个常见的搜索页面,具体的效果如下图所示:

鸿蒙开发:自定义一个搜索模版

这样的一个模版,可以简单的分为,三个部分,分别是上边的搜索框,中间的历史搜索和下边的热门搜索,搜索框,我们直接可以使用系统的组件Search,历史搜索,由于是内容不一的搜索的内容,这里使用弹性布局Flex,下边的热门搜索,条目规格一致,这里我们直接使用Grid网格组件。

快速使用

目前已经上传到了中心仓库,大家可以直接远程依赖使用,当然,你也可以下载源码进行使用。

远程依赖方式,有两种方式可供选择,分别如下:

方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。

建议:在使用的模块路径下进行执行命令。

ohpm install @abner/search

方式二:在工程的oh-package.json5中设置三方包依赖,配置示例如下:

"dependencies": { "@abner/search": "^1.0.0"}

代码使用

总体来说就是一个UI组件,在需要的页面直接调用SearchLayout组件即可,相关代码如下:

import { HotBean, SearchLayout } from '@abner/search';

@Entry
  @Component
  struct Index {
    @State hotList: HotBean[] = []

    aboutToAppear(): void {
      this.hotList.push(new HotBean("程序员一鸣", { bgColor: Color.Red }))
      this.hotList.push(new HotBean("AbnerMing", { bgColor: Color.Orange }))
      this.hotList.push(new HotBean("鸿蒙干货铺", { bgColor: Color.Pink }))
      this.hotList.push(new HotBean("程序员一哥", { bgColor: Color.Gray }))
    }

    build() {
      RelativeContainer() {
        SearchLayout({
          hotList: this.hotList,
          onItemClick: (text: string) => {
            console.log("===条目点击:" + text)
          },
          onSearchAttribute: (attr) => {
            attr.onSubmit = (text) => {
              console.log("===点击搜索:" + text)
            }
          }
        })
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
      }
      .height('100%')
        .width('100%')
    }
  }

源码分析

搜索组件

顶部的搜索组件直接使用系统的Search组件,虽然系统的已经满足了大部分的场景,但是考虑到其它的一些特殊场景,这里也暴露了左右两个自定义视图,可以在搜索组件的左右设置自己需要的组件,这里需要注意,关于Search组件的一些属性,我们该暴露的暴露,方便调用者进行使用。

RelativeContainer() {

        Column() {
          if (this.searchLeftView != undefined) {
            this.searchLeftView()
          }
        }.id("search_left")
        .height("100%")
        .justifyContent(FlexAlign.Center)

        Search({
          placeholder: this.searchAttribute.placeholder,
          value: this.searchText,
          icon: this.searchAttribute.icon,
          controller: this.controller
        })
          .placeholderFont(this.searchAttribute.placeholderFont)
          .placeholderColor(this.searchAttribute.placeholderColor)
          .textFont(this.searchAttribute.textFont)
          .textAlign(this.searchAttribute.textAlign)
          .copyOption(this.searchAttribute.copyOption)
          .searchIcon(this.searchAttribute.searchIcon)
          .cancelButton(this.searchAttribute.cancelButton)
          .fontColor(this.searchAttribute.fontColor)
          .caretStyle(this.searchAttribute.caretStyle)
          .enableKeyboardOnFocus(this.searchAttribute.enableKeyboardOnFocus)
          .selectionMenuHidden(this.searchAttribute.selectionMenuHidden)
          .maxLength(this.searchAttribute.maxLength)
          .enterKeyType(this.searchAttribute.enterKeyType)
          .type(this.searchAttribute.type)
          .alignRules({
            left: { anchor: "search_left", align: HorizontalAlign.End },
            right: { anchor: "search_right", align: HorizontalAlign.Start },
            center: { anchor: "__container__", align: VerticalAlign.Center }
          })
          .onSubmit((text: string) => {

            this.submit(text)
          })
          .onChange((value) => {
            this.searchResult = value
          })

        Column() {
          if (this.searchRightView != undefined) {
            this.searchRightView()
          }
        }.id("search_right")
        .height("100%")
        .alignRules({
          center: { anchor: "__container__", align: VerticalAlign.Center },
          right: { anchor: "__container__", align: HorizontalAlign.End }
        }).justifyContent(FlexAlign.Center)

      }.width("100%")
      .height(this.searchAttribute.height)
      .margin(this.searchAttribute.margin)

历史搜索

由于历史搜索的内容,每次的长度是不一样的,这里,我们使用弹性布局Flex来实现,设置wrap属性为FlexWrap.Wrap,支持多行展示。

需要注意的是,历史搜索需要把搜索的记录进行持久化存储,也就是用户退出应用再次进来,还是能够看到之前的搜索记录的,这里使用的用户首选项preferences.Preferences,在用户执行搜索的时候,先用临时变量用于存储,待页面退出的时候,进行存储,页面初始化的时候再进行取出展示。

在实际的开发中,每个历史搜索的条目,需要支持点击,方便调用者执行逻辑,这里需要把条目的点击事件进行暴露。

为了更好的展示UI视图,可以根据当前是否有历史记录进行动态的展示历史搜索组件。

RelativeContainer() {

        Text(this.historyTagAttribute.title)
          .fontColor(this.historyTagAttribute.fontColor)
          .fontSize(this.historyTagAttribute.fontSize)
          .fontWeight(this.historyTagAttribute.fontWeight)

        Image(this.historyTagAttribute.deleteSrc)
          .width(this.historyTagAttribute.imageWidth)
          .width(this.historyTagAttribute.imageHeight)
          .alignRules({
            center: { anchor: "__container__", align: VerticalAlign.Center },
            right: { anchor: "__container__", align: HorizontalAlign.End }
          }).onClick(() => {
          //删除
          this.historyList = []
          PreferencesUtil.getPreferencesUtil().delete("searchList")
        })

      }.margin(this.historyTagAttribute.margin)
      .height(this.historyTagAttribute.height)
      .visibility(this.historyList.length == 0 ? Visibility.None : Visibility.Visible)

      Flex({
        direction: FlexDirection.Row, wrap: FlexWrap.Wrap,
        space: { main: LengthMetrics.vp(10), cross: LengthMetrics.vp(10) }
      }) {
        ForEach(this.historyList, (item: string) => {
          Text(item)
            .padding(this.historyItemAttribute.padding)
            .borderRadius(this.historyItemAttribute.borderRadius)
            .fontColor(this.historyItemAttribute.fontColor)
            .fontSize(this.historyItemAttribute.fontSize)
            .fontWeight(this.historyItemAttribute.fontWeight)
            .backgroundColor(this.historyItemAttribute.backgroundColor)
            .onClick(() => {
              //历史搜索点击
              if (this.onItemClick != undefined) {
                this.onItemClick(item)
              }
            })

        })
      }
      .margin({ top: this.historyViewMarginTop, bottom: this.historyViewMarginBottom })
      .visibility(this.historyList.length == 0 ? Visibility.None : Visibility.Visible)

热门搜索

热门搜索就比较的简单的,就是一个Grid网格列表,需要注意的就是,条目的UI样式,这里使用的对象数据传递,方便前缀的label设置,当然,在实际的开发中,大家可以把子条目的UI暴露出去,由调用者传递,这样针对UI的展示则更加的灵活。

 Text(this.hotTagAttribute.title)
        .fontColor(this.hotTagAttribute.fontColor)
        .fontSize(this.hotTagAttribute.fontSize)
        .fontWeight(this.hotTagAttribute.fontWeight)
        .margin(this.hotTagAttribute.margin)

      Grid() {
        ForEach(this.hotList, (item: HotBean) => {
          GridItem() {
            Row() {
              Text(item.label)
                .backgroundColor(item.labelBgColor)
                .width(this.hotItemAttribute.labelSize)
                .height(this.hotItemAttribute.labelSize)
                .textAlign(TextAlign.Center)
                .borderRadius(this.hotItemAttribute.labelSize)
                .margin({ right: this.hotItemAttribute.labelMarginRight })

              Text(item.name)
                .fontSize(this.hotItemAttribute.fontSize)
                .fontColor(this.hotItemAttribute.fontColor)
                .fontWeight(this.hotItemAttribute.fontWeight)
            }
            .width("100%")
            .backgroundColor(this.hotItemAttribute.backgroundColor)
            .justifyContent(FlexAlign.Start)
            .onClick(() => {
              //历史搜索点击
              if (this.onItemClick != undefined) {
                this.onItemClick(item.name!)
              }
            })
          }
        })
      }.columnsTemplate(this.hotItemAttribute.columnsTemplate)
      .margin({ top: this.hotViewMarginTop })
      .rowsGap(this.hotItemAttribute.rowsGap)

相关总结

在日常的组件封装中,如果把所有的属性,都统一暴露至自定义组件一级的属性中,我们会发现,属性设置的是非常之多,再有小组件独立的情况下,也显得杂乱不堪,针对这种情况,其实我们可以把单独的小组件属性,独立的封装出来,使用回调函数的形式进行逐一设置即可。就比如我们这个自定义搜索模版,里面就分了很多个小组件属性。

onSearchAttribute?: (attribute: SearchViewAttribute) => void //搜索属性
private searchAttribute: SearchViewAttribute = new SearchViewAttribute()

在需要设置搜索小组件属性的时候,直接调用onSearchAttribute即可:

SearchLayout({
        hotList: this.hotList,
        onItemClick: (text: string) => {
          console.log("===条目点击:" + text)
        },
        onSearchAttribute: (attr) => {
          //搜索属性
          attr.placeholder = "搜索"
          attr.onSubmit = (text) => {
            console.log("===点击搜索:" + text)
          }
        }
      })

有一点需要注意,在使用回调函数设置属性的时候,一定要记得初始化设置,也就是把我们初始化的属性回调出去,接收调用者的设置。

aboutToAppear(): void {

    if (this.onSearchAttribute != undefined) {
      this.onSearchAttribute(this.searchAttribute)
    }

  }
点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
ListView的属性详解和探究
在我们的日常开发中,ListView是一个最常用的组件,所以我们非常有必要对它的属性进行全面的了解。现在就以一个简单的实例,对ListView的属性做一个简单的讲解。          首先我们给出简单的布局文件,就一个简单的ListView列表    :         <LinearLayout x
Stella981 Stella981
3年前
Lightning Web Components html_templates(三)
LightningWebComponents强大之处在于模版系统,使用了虚拟dom进行智能高效的组件渲染。使用简单语法以声明方式将组件的模板绑定到组件的JavaScript类中的数据数据绑定我们可以使用{property}绑定组件模版属性到一个组件js类中的属性一个简单的例子组件class
陈杨 陈杨
6天前
鸿蒙5莓创雷达图表series属性详解
大家好,欢迎回来鸿蒙5莓创图表组件的专场,我们这一期来讲解雷达图(McRadarChart)的series属性详细用法。作为图表数据展示的核心配置,series属性直接影响数据呈现形式和交互体验,下面我们逐一拆解每个属性的用法。一、name属性作用:定义数
陈杨 陈杨
6天前
鸿蒙5莓创图表组件折线类型的属性讲解-Title
大家好,欢迎回来鸿蒙5莓创图表组件的专场,很多小伙伴都不知道每个图表类型中的属性到底是干嘛的,怎么用。所以我们将详细去讲解每个属性,跟我一起学习吧。我们这一期来讲解McLineChart折线图组件中title属性的详细用法。这个属性控制着图表的标题显示,包
陈杨 陈杨
6天前
鸿蒙5莓创折线与柱状图legend属性详解
大家好,欢迎回来鸿蒙5莓创图表组件的专场,我们这一期来讲解组合图组件McLineBarChart中legend属性的详细用法。1.show属性作用:控制是否显示图例类型:Boolean默认值:true可选值:true|false场景:当需要隐藏图例时设置为
陈杨 陈杨
6天前
鸿蒙5莓创折线与柱状图yAxis属性详解
大家好,欢迎回来鸿蒙5莓创图表组件的专场,我们这一期来讲解组合图组件中yAxis属性的详细用法。yAxis是图表中非常重要的配置项,它决定了Y轴的显示方式、样式和行为。下面我们将全面解析yAxis的各个属性及其子属性。基础属性type作用:指定Y轴的类型类
陈杨 陈杨
6天前
鸿蒙莓创横向柱状图dataZoom详解
大家好,欢迎回来鸿蒙5莓创图表组件的专场,我们这一期来讲解McHorBarChart横向柱状图中非常实用的dataZoom属性。dataZoom属性概述dataZoom属性是McHorBarChart组件中用于实现区域缩放的核心配置项,它可以让用户自由关注
程序员一鸣 程序员一鸣
6天前
鸿蒙开发:实现Popup气泡提示
原生的bindPopup属性,不仅仅支持单一的文字提示,也支持自定义组件的形式,已经可以满足正常的需求开发,能用原生的就用原生,之所以dialog库中增加了一个popup气泡弹窗,是因为当时封装的时候,原生还不支持自定义组件形式,如今已经支持了,大家可以放心的使用原生即可。
GeorgeGcs GeorgeGcs
4天前
【HarmonyOS 5】如何开启DevEco Studio热更新调试应用模式
鸿蒙开发能力HarmonyOSSDK应用服务鸿蒙金融类应用(金融理财一、AttributeModifier和AttributeUpdater的定义和作用1.AttributeModifier是ArkUI组件的动态属性,提供属性设置功能。开发者可使用attr
陈杨 陈杨
6天前
鸿蒙5横向柱状图series属性解析
大家好,欢迎回来鸿蒙5莓创图表组件的专场,我们这一期来讲解McHorBarChart(横向柱状图)组件中series属性的详细用法。series属性是控制柱状图数据系列的核心配置项,掌握好这些属性可以让你轻松创建各种样式的柱状图效果。1.name属性作用: