【引言】
本文将介绍一个名为“颜文字搜索器”的开发案例,该应用是基于鸿蒙NEXT平台构建的,旨在帮助用户快速查找和使用各种风格的表情符号。通过本案例的学习,读者可以了解如何在鸿蒙平台上进行数据处理、UI设计以及交互逻辑的实现。
【环境准备】
• 操作系统:Windows 10
• 开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
• 目标设备:华为Mate60 Pro
• 开发语言:ArkTS
• 框架:ArkUI
• API版本:API 12
【Development Ideas】
1. Data model design
In order to represent information about a single emoticon, we define an EmoticonBean class that contains the style, type, the emoticon itself and its meaning. In addition, a boolean property isShown is added to keep track of whether an emoticon should be shown to the user, which helps to dynamically update the list during searches.
2. UI components and layout
The main interface of the application consists of an Index component, which is responsible for the overall layout. The upper part of the interface is a search box that allows the user to enter keywords to filter the list of emoticons. The bottom part is a table that shows all the eligible emoji, with each row consisting of four parts: style, type, emoji and meaning. To enhance the user experience, when the user clicks on an emoji or the highlighted text in its meaning, a corresponding click event is triggered and a log message is output.
3. Data loading and processing
The data for the emoticons comes from a local JSON file () that is read and parsed into an array of EmoticonBean objects before the component is first rendered. Each time the user modifies the content of the search box, the splitAndHighlight method is called to split the meaning of each emoticon and check if there is a matching keyword. If there is, the isShown property is set to true, otherwise it is false, which controls whether the emoticon is displayed in the interface.
4. Searching and highlighting
The splitAndHighlight function is used to split the meaning of an emoticon into multiple segments according to the keyword and return an array of these segments. Segments that contain keywords are highlighted in a different color in the interface to visually point out the matches. Additionally, this function determines whether an emoji is visible or not based on whether or not there is a match, ensuring that only relevant emoji are shown to the user.
5. User interaction
In order to let the user have a better operation experience, we implement the touch event listener on the interface to automatically close the keyboard when the user clicks on a non-input area. This not only ensures a neat interface, but also simplifies the user's operation process.
[complete code]
Data source: src/main/resources/rawfile/
/download/zhongcongxu01/90126325
coding
// Introduce the necessary tool libraries util for text decoding etc. import { util } from '@' // Introduce the BusinessError class for handling business logic errors. import { BusinessError } from '@' // Introduce the inputMethod module to manage input method behavior. import { inputMethod } from '@' // Define a data model that can be observed EmoticonBean represents information about a single emoticon @ObservedV2 class EmoticonBean { // Define the style attribute and initialize it to the empty string style: string = "" // Define the type attribute and initialize to the empty string type: string = "" // Define the emoji itself and initialize it to the empty string emoticon: string = "" // Define the meaning attribute and initialize it to the empty string meaning: string = "" // Constructor that allows the above properties to be set when the object is created constructor(style: string, type: string, emoticon: string, meaning: string) { = style = type = emoticon = meaning } // Define the emoji status tag to be shown or not, defaults to true, use @Trace decorator to make it traceable to changes @Trace isShown: boolean = true } // Use the @Entry and @Component decorators to define the Index component as the application entry point. @Entry @Component struct Index { // Define a state variable, textInput, to store the text content of the search box, which defaults to an empty string. @State private textInput: string = '' // Define a state variable emoticonList to store the list of emoticons, defaults to an empty array. @State private emoticonList: EmoticonBean[] = [] // Define the line color property private lineColor: string = "#e6e6e6" // Define the header background color property private titleBackground: string = "#f8f8f8" // Define the text color attribute private textColor: string = "#333333" // Define the base fill size private basePadding: number = 4 // Define the line width private lineWidth: number = 2 // Define the cell height private cellHeight: number = 50 // Define column weight ratios private weightRatio: number[] = [1, 1, 5, 4] // Define the base font size private baseFontSize: number = 14 // Define a method splitAndHighlight to split and highlight keywords in an emoji's meaning. private splitAndHighlight(item: EmoticonBean, keyword: string): string[] { let text = // Get the text of the meaning of the emoticon if (!keyword) { // If there is no keyword, the entire text is returned directly and the emoji is displayed = true return [text] } let segments: string[] = []; // Used to store split text fragments let lastMatchEnd: number = 0; // Record where the last match ended while (true) { // Loop over keywords to find their position in the text const matchIndex = (keyword, lastMatchEnd); // Find where keywords appear if (matchIndex === -1) { // If no keywords are found, add the remaining text to the segments and exit the loop ((lastMatchEnd)); break; } else { // If keywords are found, add the non-keyword and keyword sections to the segments separately ((lastMatchEnd, matchIndex)); // Non-keyworded section ((matchIndex, matchIndex + )); // Keyword section lastMatchEnd = matchIndex + ; } } // Set emoji to display if a keyword is present = ((keyword) != -1) return segments; } // This method is called when the component is about to appear on the screen and is used to load the emoji data aboutToAppear() { // Read the contents of a local file from Explorer. getContext().("", (err: BusinessError, data) => { if (err) { // If the read fails, print an error message ('getRawFileContent error: ' + (err)) return } // Create a text decoder to convert binary data to strings let textDecoder = ('utf-8', { ignoreBOM: true }) let jsonString = (data, { stream: false }) let jsonObjectArray: object[] = (jsonString) // Parsing a JSON string into an array of objects for (let i = 0; i < ; i++) { // Iterate through the array of objects to fill the emoticonList. let item = jsonObjectArray[i] (new EmoticonBean(item['s'], item['t'], item['e'], item['m'])) } try { // Print the emoticonList to the console for debugging. (`:${(, null, '\u00a0\u00a0')}`) } catch (err) { ('parse error: ' + (err)) } }) } // Define the build method to build the component's UI structure. build() { Column({ space: 0 }) { // Create a column container with no spacing between internal elements // The search box component, bound to the textInput state variable. Search({ value: $$ }) .margin() // Setting the outer margin .fontFeature("\"ss01\" on") // Setting font characteristics // Create a column container for table headers Column() { Row() { // Create a row for the table header // Header text: Style Text('Style') .height('100%') // Set the height to 100% of the parent container .layoutWeight([0]) // Assigning widths based on weights .textAlign() // Center-align text .fontSize() // Setting the font size .fontWeight(600) // Set the font thickness .fontColor() // Set the text color // Split Line Line().height('100%').width().backgroundColor() // Header text: type Text('Type') .height('100%') .layoutWeight([1]) .textAlign() .fontSize() .fontWeight(600) .fontColor() // Split Line Line().height('100%').width().backgroundColor() // Header text: Emoji Text('Expressions') .height('100%') .layoutWeight([2]) .textAlign() .fontSize() .fontWeight(600) .fontColor() // Split Line Line().height('100%').width().backgroundColor() // Header text: meaning Text('Meaning') .height('100%') .layoutWeight([3]) .textAlign() .fontSize() .fontWeight(600) .fontColor() }.height().borderWidth().borderColor() .backgroundColor() // Set the background color }.width(`100%`).padding({ left: , right: }) // Create a scroll container Scroll containing a list of emoji. Scroll() { Column() { // ForEach loop through the emoticonList array, creating one emoticon entry per row. ForEach(, (item: EmoticonBean) => { Row() { // Style of displaying emoticons Text() .height('100%') .layoutWeight([0]) .textAlign() .fontSize() .fontColor() // Split Line Line().height('100%').width().backgroundColor() // Display the type of emoticon Text() .height('100%') .layoutWeight([1]) .textAlign() .fontSize() .fontColor() // Split Line Line().height('100%').width().backgroundColor() // Show emoticons Text() .height('100%') .layoutWeight([2]) .textAlign() .fontSize() .fontColor() .copyOption() // Allow copying to clipboard // Split Line Line().height('100%').width().backgroundColor() // Display the meaning of emoticons, with support for keyword highlighting Text() { ForEach((item, ), (segment: string, index: number) => { ContainerSpan() { Span(segment) .fontColor(segment === ? : ) // Set font color based on whether it's a keyword or not .onClick(() => { // Setting up the click event listener (`Highlighted text clicked: ${segment}`); // Print the text message of the click (`Click index: ${index}`); // Print the index information of the click }); }.textBackgroundStyle({ color: segment === ? : // Set background color based on whether it's a keyword or not }); }); } .height('100%') .layoutWeight([3]) .textAlign() .fontSize() .fontColor() .padding({ left: , right: }) } .height() .borderWidth({ left: , right: , bottom: }) .borderColor() // Visibility of emoticons is determined by their state (whether they are displayed or not) .visibility( ? : ) }) }.width(`100%`).padding({ left: , right: }) }.width('100%').layoutWeight(1).align() // Touch event handling to disable keyboard input when the user clicks on a blank area .onTouch((event) => { if ( == ) { // If it's a press event ().stopInputSession() // Stop the current input session } }) }.width('100%').height('100%').backgroundColor(); // Set the container's width, height and background color } }