內容高亮并不陌生,特別是在搜索內容頁面,可以說四處可見,就拿掘金這個應用而言,針對某一個關鍵字,我們搜索之后,與關鍵字相同的內容,則會高亮展示,如下圖所示:
如上的效果,在Flutter當中,實現起來可以說是無比的簡單,畢竟原生的組件都給我們提供了,那就是富文本組件RichText。
針對今天的內容,簡單的列一個大綱,主要內容如下:
1、案例簡單效果
2、認識RichText
3、文本的高亮實現邏輯
4、高亮組件源碼
一、案例簡單效果
1、簡單的內容高亮展示
2、列表形式內容展示
二、認識RichText
要實現高亮效果,那么我們必須了解富文本組件RichText,話又說回來,什么是富文本呢?簡單來說,它是一種特殊的文本格式,比普通文本更加豐富多彩,可以包含各種字體、顏色、大小等元素,使文本更加生動、有趣,比如我們常見的閱讀協議等場景,均可采用富文本形式,這是原生的文本無法實現的效果。
初識構造
構造屬性需要注意的是,這里的text,和文本Text中的text是不一樣的,文本Text指的是字符串,這里的text指的是InlineSpan,當然了InlineSpan是抽象基類,一般我們使用TextSpan。
RichText({super.key,required this.text,this.textAlign = TextAlign.start,this.textDirection,this.softWrap = true,this.overflow = TextOverflow.clip,this.textScaleFactor = 1.0,this.maxLines,this.locale,this.strutStyle,this.textWidthBasis = TextWidthBasis.parent,this.textHeightBehavior,this.selectionRegistrar,this.selectionColor,}) : assert(text != null),assert(textAlign != null),assert(softWrap != null),assert(overflow != null),assert(textScaleFactor != null),assert(maxLines == null || maxLines > 0),assert(textWidthBasis != null),assert(selectionRegistrar == null || selectionColor != null),super(children: _extractChildren(text));
常見構造屬性概述:
const TextSpan({this.text,this.children,super.style,this.recognizer,MouseCursor? mouseCursor,this.onEnter,this.onExit,this.semanticsLabel,this.locale,this.spellOut,}) : mouseCursor = mouseCursor ??(recognizer == null ? MouseCursor.defer : SystemMouseCursors.click),assert(!(text == null && semanticsLabel != null));
屬性 | 類型 | 概述 |
textAlign | TextAlign | 文本對齊方式 TextAlign.left |
textDirection | TextDirection | 文本的方向 TextDirection.ltr |
overflow | TextOverflow | 文字溢出的處理方式 |
maxLines | int | 最大行數 |
textWidthBasis | TextWidthBasis | 文本的寬度 TextWidthBasis.parent TextWidthBasis.longestLine |
TextSpan常見屬性
屬性 | 說明 |
text | String類型的文本 |
children | 子組件 |
style | TextStyle類型的文本樣式可以設置文字的大小、顏色、樣式等 |
recognizer | 指定手勢交互 |
簡單案例:
RichText(text: const TextSpan(children: [TextSpan(text: "床前明月光,", style: TextStyle(color: Colors.black)),TextSpan(text: "疑是地上霜。", style: TextStyle(color: Colors.red)),TextSpan(text: "舉頭望明月,", style: TextStyle(color: Colors.blueAccent)),TextSpan(text: "低頭思故鄉。", style: TextStyle(color: Colors.tealAccent))])
效果:
當然了,除了上述寫法之外,也可以使用Text.rich來實現,代碼如下:
const Text.rich(TextSpan(children: [TextSpan(text: "床前明月光,", style: TextStyle(color: Colors.black)),TextSpan(text: "疑是地上霜。", style: TextStyle(color: Colors.red)),TextSpan(text: "舉頭望明月,", style: TextStyle(color: Colors.blueAccent)),TextSpan(text: "低頭思故鄉。", style: TextStyle(color: Colors.tealAccent))]))
三、文本的高亮實現邏輯
RichText可以實現一個富文本展示,那么如何利用這個組件實現某個內容高亮展示呢?首先,我們要明白,高亮的內容是不固定的,一段內容的每個字符都有可能會高亮,所以針對TextSpan,我們就需要動態的創建,然后動態的改變其樣式。
這里的動態也是十分的簡單,無非就是字符串的截取,分別是開頭、結尾、和中間三種情況進行截取,如下圖所示。
當然了,需要注意,有可能要搜索的這個內容,在整個內容中是多處存在的,這個時候,針對以上的邏輯,就需要遍歷循環了,直至找到最后一個搜索的內容。
主要的邏輯如下:
//搜索內容為空if (_searchContent == "") {return Text(_content,style: _ordinaryStyle,);}List<TextSpan> richList = [];int start = 0;int end;//遍歷,進行多處高亮while ((end = _content.indexOf(_searchContent, start)) != -1) {//如果搜索內容在開頭位置,直接高亮,此處不執行if (end != 0) {richList.add(TextSpan(text: _content.substring(start, end), style: _ordinaryStyle));}//高亮內容richList.add(TextSpan(text: _searchContent, style: _highlightStyle));//賦值索引start = end + _searchContent.length;}//搜索內容只有在開頭或者中間位置,才執行if (start != _content.length) {richList.add(TextSpan(text: _content.substring(start, _content.length),style: _ordinaryStyle));}return RichText(text: TextSpan(children: richList),);
四、高亮組件源碼
源碼很簡單,可以結合列表組件或者單獨使用,當然了,有一些特殊需求,文字加大或者改變背景等需求,都可以進行擴展。
class TextHighlight extends StatelessWidget {final TextStyle _ordinaryStyle; //普通的樣式final TextStyle _highlightStyle; //高亮的樣式final String _content; //文本內容final String _searchContent; //搜索的內容const TextHighlight(this._content, this._searchContent, this._ordinaryStyle,this._highlightStyle,{super.key});@overrideWidget build(BuildContext context) {//搜索內容為空if (_searchContent == "") {return Text(_content,style: _ordinaryStyle,);}List<TextSpan> richList = [];int start = 0;int end;//遍歷,進行多處高亮while ((end = _content.indexOf(_searchContent, start)) != -1) {//如果搜索內容在開頭位置,直接高亮,此處不執行if (end != 0) {richList.add(TextSpan(text: _content.substring(start, end), style: _ordinaryStyle));}//高亮內容richList.add(TextSpan(text: _searchContent, style: _highlightStyle));//賦值索引start = end + _searchContent.length;}//搜索內容只有在開頭或者中間位置,才執行if (start != _content.length) {richList.add(TextSpan(text: _content.substring(start, _content.length),style: _ordinaryStyle));}return RichText(text: TextSpan(children: richList),);}
}
案例Demo很是簡單,上邊是搜索框,下面是展示的內容,這里就不貼了,高亮組件已經給大家提供了,大家可以直接復制使用。