1/* 2* Copyright (c) 2024 Huawei Device Co., Ltd. 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15 16/** 17 * 功能描述: 18 * 1. 在搜索框中可以根据城市拼音模糊搜索出相近的城市,例如输入"a",会出现"阿尔山"、"阿勒泰地区"、"安庆"、"安阳"。 19 * 2. 下方城市列表通过AlphabetIndexer组件实现拼音索引条,通过滑动选择城市首拼,快速定位相关首拼城市。 20 * 21 * 实现原理: 22 * 1. 当用户滑动List组件,list组件onScrollIndex监听到firstIndex的改变,绑定赋值给AlphabetIndexer的selected属性,从而定位到字母索引。 23 * 2. 当点击AlphabetIndexer的字母索引时,通过scrollToIndex触发list组件滑动并指定firstIndex,从而实现List列表与AlphabetIndexer组件首字母联动吸顶展示。 24 * 25 * @param hotSelectList - 热门选择列表 26 * @param alphabetSelectList - 字母选择数据列表 27 * @param hotSelectListTitle - 热门选择列表标题 28 * @param hotSelectHandle - 点击热门选择列表项处理逻辑 29 * @param alphabetSelectHandle - 点击字母列表项处理逻辑 30 * 31 */ 32import { AlphabetListItemView, HotListItemView } from '../model/DetailData'; 33import { CommonConstants } from '../common/CommonConstants'; 34 35@Component 36export struct AlphabetListView { 37 // -------------------对外暴露变量----------------------- 38 // 热门选择列表 39 hotSelectList: HotListItemView[] = []; 40 // 字母选择数据列表 41 alphabetSelectList: AlphabetListItemView[] = []; 42 // 热门列表标题 43 hotSelectListTitle: ResourceStr = ''; 44 // 点击热门选择列表项处理逻辑 45 hotSelectHandle: (hotSelectValue: string) => void = (hotSelectValue: string = CommonConstants.INIT_VALUE) => { 46 }; 47 // 点击字母列表项处理逻辑 48 alphabetSelectHandle: (alphabetSelectValue: string ) => void = (alphabetSelectValue: string = 49 CommonConstants.INIT_VALUE) => { 50 }; 51 // --------------------私有属性---------------------------- 52 // 初始化列表index 53 @State stabIndex: number = 0; 54 // 字母索引数据 55 @State alphabetIndexer: string[] = []; 56 // 滑动控制器 57 private scroller: Scroller = new Scroller(); 58 // 搜索控制器 59 controller: SearchController = new SearchController(); 60 61 build() { 62 Stack({ alignContent: Alignment.End }) { 63 Column() { 64 Text(this.hotSelectListTitle) 65 .fontSize($r('app.integer.citysearch_text_font')) 66 .fontColor($r('app.color.citysearch_text_font_color')) 67 .opacity(CommonConstants.OPACITY) 68 .margin({ 69 left: $r('app.integer.citysearch_txt_margin_left'), 70 bottom: $r('app.integer.citysearch_row_margin_bottom') 71 }) 72 73 Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center, wrap: FlexWrap.Wrap }) { 74 ForEach(this.hotSelectList, (hotCityItem: HotListItemView) => { 75 // 这里规定每行占四个城市 76 Column() { 77 hotCityItem.contentBuilder.builder(hotCityItem.hotListItem) 78 }.onClick(() => { 79 this.hotSelectHandle(hotCityItem.hotListItem); 80 }) 81 }) 82 } 83 .width(CommonConstants.VIEW_FULL) 84 85 List({ 86 space: CommonConstants.LIST_SPACE, 87 initialIndex: CommonConstants.INITIAL_INDEX, 88 scroller: this.scroller 89 }) { 90 ForEach(this.alphabetSelectList, (alphabetListItem: AlphabetListItemView) => { 91 ListItem() { 92 Column() { 93 Text(`${alphabetListItem.alphabetListItem.name}`) 94 .height($r('app.integer.citysearch_list_item_height')) 95 .fontSize($r('app.integer.citysearch_font_size')) 96 .fontColor($r('app.color.citysearch_text_font_color')) 97 .width(CommonConstants.VIEW_FULL) 98 ForEach(alphabetListItem.alphabetListItem.dataList, (item: string) => { 99 Column() { 100 alphabetListItem.contentBuilder.builder(item) 101 }.onClick(() => { 102 this.alphabetSelectHandle(item); 103 }) 104 }) 105 } 106 } 107 }) 108 } 109 .width(CommonConstants.VIEW_FULL) 110 .margin({ 111 left: $r('app.integer.citysearch_txt_margin_left'), 112 bottom: $r('app.integer.citysearch_txt_margin_bottom') 113 }) 114 .layoutWeight(1) 115 .edgeEffect(EdgeEffect.None) 116 .divider({ 117 strokeWidth: $r('app.integer.citysearch_divider_strokeWidth'), 118 color: $r('app.color.citysearch_divider_color'), 119 startMargin: $r('app.integer.citysearch_divider_start'), 120 endMargin: $r('app.integer.citysearch_divider_end') 121 }) 122 .listDirection(Axis.Vertical) 123 .scrollBar(BarState.Off) 124 .onScrollIndex((firstIndex: number, lastIndex: number) => { 125 this.stabIndex = firstIndex; 126 }) 127 } 128 .alignItems(HorizontalAlign.Start) 129 130 /* TODO:知识点:可以与容器组件联动用于按逻辑结构快速定位容器显示区域的组件,arrayValue为字母索引字符串数组,selected为初始选中项索引值。 131 * 1. 当用户滑动List组件,list组件onScrollIndex监听到firstIndex的改变,绑定赋值给AlphabetIndexer的selected属性,从而定位到字母索引。 132 * 2. 当点击AlphabetIndexer的字母索引时,通过scrollToIndex触发list组件滑动并指定firstIndex,从而实现List列表与AlphabetIndexer组件 133 * 首字母联动吸顶展示。 134 */ 135 AlphabetIndexer({ arrayValue: this.alphabetIndexer, selected: this.stabIndex }) 136 .height(CommonConstants.VIEW_FULL) 137 .selectedColor($r('app.color.citysearch_alphabet_select_color'))// 选中项文本颜色 138 .popupColor($r('app.color.citysearch_alphabet_pop_color'))// 弹出框文本颜色 139 .selectedBackgroundColor($r('app.color.citysearch_alphabet_selected_bgc'))// 选中项背景颜色 140 .popupBackground($r('app.color.citysearch_alphabet_pop_bgc'))// 弹出框背景颜色 141 .popupPosition({ 142 x: $r('app.integer.citysearch_pop_position_x'), 143 y: $r('app.integer.citysearch_pop_position_y') 144 }) 145 .usingPopup(true) // 是否显示弹出框 146 .selectedFont({ size: $r('app.integer.citysearch_select_font'), weight: FontWeight.Bolder })// 选中项字体样式 147 .popupFont({ size: $r('app.integer.citysearch_pop_font'), weight: FontWeight.Bolder })// 弹出框内容的字体样式 148 .alignStyle(IndexerAlign.Right)// 弹出框在索引条左侧弹出 149 .itemSize(CommonConstants.ALPHABET_SIZE)// 每一项的尺寸大小 150 .margin({ right: CommonConstants.ALPHABET_MARGIN_RIGHT_SIZE }) 151 .onSelect((tabIndex: number) => { 152 this.scroller.scrollToIndex(tabIndex); 153 }) 154 } 155 .flexShrink(1) 156 .flexGrow(1) 157 .padding({ bottom: $r('app.integer.citysearch_padding_bottom') }) 158 } 159 160 aboutToAppear(): void { 161 if (this.alphabetSelectList.length) { 162 this.alphabetSelectList.forEach((item: AlphabetListItemView) => { 163 this.alphabetIndexer.push(item.alphabetListItem.name); 164 }) 165 } 166 } 167}