Flutter RichText支持自定义文本溢出效果
extended text 相關文章
- Flutter RichText支持圖片顯示和自定義圖片效果
- Flutter RichText支持自定義文本溢出效果
- Flutter RichText支持自定義文字背景
- Flutter RichText支持特殊文字效果
之前介紹過了Extended text的圖片功能 ,今天要講的還是跟產品設計有關系,老規矩上圖
產品說,那個文本溢出的點點點后面給我加個雞腿,想什么啊,是加個 “全文”字樣,點擊之后跳轉到全文去。
就像下面這種一樣
首先,我看了下Text的源碼,發現這個...是被寫死了的,傳遞給了TextPainter
const String _kEllipsis = '\u2026'; 復制代碼然后再向里面看,就是引擎繪畫的代碼了。。看不到了。。是我太弱了。 在google上搜索了下,發現也有問這個問題26748,上面也是說了。。需要把源碼復制出來,把_kEllipsis改成你想要的,但是。。這個是個字符串啊。。那個比如說藍色怎么弄?比如說點擊怎么弄?
想來想去,一個字就是畫,在Canvas上面盡情畫。
首先,我定義了一個TextSpan 用于用戶自定義文本溢出效果
overFlowTextSpan: OverFlowTextSpan(children: <TextSpan>[TextSpan(text: ' \u2026 '),TextSpan(text: "more detail",style: TextStyle(color: Colors.blue,),recognizer: TapGestureRecognizer()..onTap = () {launch("https://github.com/fluttercandies/extended_text");})], background: Theme.of(context).canvasColor), 復制代碼然后我們直接來到ExtendedRenderParagraph的paint方法
void paint(PaintingContext context, Offset offset) {_paintSpecialText(context, offset);_paint(context, offset);_paintTextOverflow(context, offset);} 復制代碼這個效果肯定需要在畫好字之后,再來魔改
void _paintTextOverflow(PaintingContext context, Offset offset) {if (_hasVisualOverflow && overFlowTextSpan != null) {final Canvas canvas = context.canvas;///we will move the canvas, so rect top left should be (0,0)final Rect rect = Offset(0.0, 0.0) & size;var textPainter = overFlowTextSpan.layout(_textPainter);assert(textPainter.width <= rect.width,);} 復制代碼首先我們需要layout一下我們的overFlowTextSpan,如果你定義的太長,已經超出一行了的話,那么抱歉
老動作,把畫布移動到整個文字的左上角,根據overFlowTextSpanOffset的左上角,計算出最近的TextPosition。
canvas.save();///move to extended textcanvas.translate(offset.dx, offset.dy);final Offset overFlowTextSpanOffset = Offset(rect.width - textPainter.width, rect.height - textPainter.height);///find TextPosition near overflowTextPosition overflowOffset =getPositionForOffset(overFlowTextSpanOffset); 復制代碼再通過這個找出最近文字的top-left,這樣才能保證不會剪切到半個或者不完全的文字。
///find overflow TextPosition that not clip the original textOffset finalOverflowOffset = _findFinalOverflowOffset(rect, rect.width - textPainter.width, overflowOffset.offset);Offset _findFinalOverflowOffset(Rect rect, double x, int endTextOffset) {Offset endOffset = getOffsetForCaret(TextPosition(offset: endTextOffset, affinity: TextAffinity.upstream),rect,);//overflowif (endOffset == null || (endTextOffset != 0 && endOffset == Offset.zero)) {return _findFinalOverflowOffset(rect, x, endTextOffset - 1);}if (endOffset.dx > x) {return _findFinalOverflowOffset(rect, x, endTextOffset - 1);}return endOffset;} 復制代碼這樣子我們就找到我們需要在哪個文字的位置把OverFlowTextSpan繪畫出來,并且想辦法把OverFlowTextSpan下一層的文字給清除或者遮擋住。
首先嘗試是用BlendMode.clear來清除指定區域的文字,失敗,不知道為什么, 我看別人也是這樣子寫的,能清除掉Canvas上面的內容,如果有哪個兄弟知道,請一定要告訴我,感謝萬分。
///why BlendMode.clear not clear the text // canvas.saveLayer(overFlowTextSpanRect, Paint()); // canvas.drawRect( // overFlowTextSpanRect, // Paint() // ..blendMode = BlendMode.clear); // canvas.restore(); 復制代碼那么只能畫一層跟Canvas一樣的顏色來遮住文字了。這里默認使用的是
Theme.of(context).canvasColor 復制代碼然后我們再畫上OverFlowTextSpan
textPainter.paint(canvas, Offset(finalOverflowOffset.dx, overFlowTextSpanOffset.dy)); 復制代碼最后我們要處理一下點擊事件,保存textPainter繪畫的點(相對整個系統坐標的)
overFlowTextSpan.textPainterHelper.saveOffset(Offset(offset.dx + finalOverflowOffset.dx,offset.dy + overFlowTextSpanOffset.dy)); 復制代碼在handleEvent方法中,我們加入以下代碼,如果找到了對應注冊了recognizer的TextSpan,我們就給它觸發,并且return(因為overFlowTextSpan在原來的字的上一層)
if (overFlowTextSpan != null) {final TextPosition position =overFlowTextSpan.textPainterHelper.getPositionForOffset(offset);final TextSpan span =overFlowTextSpan.textPainterHelper.getSpanForPosition(position);if (span?.recognizer != null) {span.recognizer.addPointer(event);return;}} 復制代碼_offset是我們剛才保持的相對整個系統坐標的點,我們需要把傳入的Offset減掉 _offset,這樣這個overFlowTextSpan的相對自己的坐標系才是以(0,0)開始的,最后用這個TextPosition找到對應的TextSpan,大功告成。
///method for [OverFlowTextSpan]///offset int coordinate systemOffset _offset;void saveOffset(Offset offset) {_offset = offset;}///method for [OverFlowTextSpan]TextPosition getPositionForOffset(Offset offset) {return painter.getPositionForOffset(offset - _offset);}///method for [OverFlowTextSpan]TextSpan getSpanForPosition(TextPosition position) {return painter.text.getSpanForPosition(position);} 復制代碼除了清除(覆蓋)文字的那個部分,其他應該都是比較完美的解決方案,期待大家能帶來更多點子,改進 Extended Text
最后放上 Github Extended_Text,如果你有什么不明白的地方,請告訴我,歡迎加入Flutter Candies,一起生產可愛的Flutter 小糖果(QQ群:181398081)
轉載于:https://juejin.im/post/5c8ca608f265da2dd6394001
總結
以上是生活随笔為你收集整理的Flutter RichText支持自定义文本溢出效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建筑论文如何发表
- 下一篇: Python爬虫解析html:lxml的