2017-09-14 37 views
2

想象一下,我有這樣一段文字:HELLO THIS IS MY LONG SENTENCE。當我點擊它時,我希望字LONG漣漪(墨水飛濺)。當我點擊它時,如何產生TextSpan漣漪?

比方說,我有這樣的代碼:

new RichText(
    text: new TextSpan(
    text: 'HELLO THIS IS MY ', 
    style: DefaultTextStyle.of(context).style, 
    children: <TextSpan>[ 
     new TextSpan(text: 'LONG', style: new TextStyle(fontWeight: FontWeight.bold)), 
     new TextSpan(text: ' SENTENCE'), 
    ], 
), 
) 

謝謝!

回答

1

example

如果你想有一個通用的解決方案來放置小部件對文本,see this gist的部分。

您可以使用下面的代碼有限制的文本的特定部分的紋波:

import 'package:flutter/material.dart'; 
import 'package:flutter/rendering.dart'; 

import 'dart:ui' show TextBox; 
import 'dart:math'; 

void main() { 
    runApp(new MaterialApp(
    home: new Material(
     child: new Center(
     child: new Demo(), 
    ), 
    ), 
)); 
} 

class Demo extends StatelessWidget { 
    final TextSelection textSelection = 
     const TextSelection(baseOffset: 17, extentOffset: 21); 

    final GlobalKey _textKey = new GlobalKey(); 

    @override 
    Widget build(context) => new Stack(
     children: <Widget>[ 
      new RichText(
      key: _textKey, 
      text: new TextSpan(
       text: 'HELLO THIS IS MY ', 
       style: DefaultTextStyle.of(context).style, 
       children: <TextSpan>[ 
       new TextSpan(
        text: 'LONG', 
        style: new TextStyle(fontWeight: FontWeight.bold)), 
       new TextSpan(text: ' SENTENCE'), 
       ], 
      ), 
     ), 
      new Positioned.fill(
      child: new LayoutBuilder(
       builder: (context, _) => new Stack(
        children: <Widget>[ 
         new Positioned.fromRect(
         rect: _getSelectionRect(), 
         child: new InkWell(
          onTap:() => {}, // needed to show the ripple 
         ), 
        ), 
        ], 
       ), 
      ), 
     ), 
     ], 
    ); 

    Rect _getSelectionRect() => 
     (_textKey.currentContext.findRenderObject() as RenderParagraph) 
      .getBoxesForSelection(textSelection) 
      .fold(
      null, 
      (Rect previous, TextBox textBox) => new Rect.fromLTRB(
        min(previous?.left ?? textBox.left, textBox.left), 
        min(previous?.top ?? textBox.top, textBox.top), 
        max(previous?.right ?? textBox.right, textBox.right), 
        max(previous?.bottom ?? textBox.bottom, textBox.bottom), 
       ), 
     ) ?? 
     Rect.zero; 
} 
+0

所以,關鍵是TextSelection偏移量需要匹配要皺子的帽子? –

+0

@SethLadd是的,它甚至不必遵循文本跨度 – Takhion

2

您可以通過在ink_well.dart適應的代碼實現這種效果。

在此示例中,我將rectCallback配置爲擴展到包含卡,但您可以提供一個更小的矩形,其中的水滴以水龍頭爲中心。

video

import 'package:flutter/material.dart'; 
import 'package:flutter/gestures.dart'; 
import 'dart:collection'; 

void main() { 
    runApp(new MaterialApp(home: new DemoApp())); 
} 

class DemoText extends StatefulWidget { 
    @override 
    DemoTextState createState() => new DemoTextState(); 
} 

class DemoTextState<T extends InkResponse> extends State<T> 
    with AutomaticKeepAliveClientMixin { 
    Set<InkSplash> _splashes; 
    InkSplash _currentSplash; 

    @override 
    bool get wantKeepAlive => (_splashes != null && _splashes.isNotEmpty); 

    void _handleTapDown(TapDownDetails details) { 
    final RenderBox referenceBox = context.findRenderObject(); 
    InkSplash splash; 
    splash = new InkSplash(
     controller: Material.of(context), 
     referenceBox: referenceBox, 
     containedInkWell: true, 
     rectCallback:() => referenceBox.paintBounds, 
     position: referenceBox.globalToLocal(details.globalPosition), 
     color: Theme.of(context).splashColor, 
     onRemoved:() { 
      if (_splashes != null) { 
      assert(_splashes.contains(splash)); 
      _splashes.remove(splash); 
      if (_currentSplash == splash) _currentSplash = null; 
      updateKeepAlive(); 
      } // else we're probably in deactivate() 
     }); 
    _splashes ??= new HashSet<InkSplash>(); 
    _splashes.add(splash); 
    _currentSplash = splash; 
    updateKeepAlive(); 
    } 

    void _handleTap(BuildContext context) { 
    _currentSplash?.confirm(); 
    _currentSplash = null; 
    Feedback.forTap(context); 
    } 

    void _handleTapCancel() { 
    _currentSplash?.cancel(); 
    _currentSplash = null; 
    } 

    @override 
    void deactivate() { 
    if (_splashes != null) { 
     final Set<InkSplash> splashes = _splashes; 
     _splashes = null; 
     for (InkSplash splash in splashes) splash.dispose(); 
     _currentSplash = null; 
    } 
    assert(_currentSplash == null); 
    super.deactivate(); 
    } 

    Widget build(BuildContext context) { 
    return new Padding(
     padding: new EdgeInsets.all(20.0), 
     child: new RichText(
     text: new TextSpan(
      text: 'HELLO THIS IS MY ', 
      style: DefaultTextStyle.of(context).style, 
      children: <TextSpan>[ 
      new TextSpan(
       recognizer: new TapGestureRecognizer() 
       ..onTapCancel = _handleTapCancel 
       ..onTapDown = _handleTapDown 
       ..onTap =() => _handleTap(context), 
       text: 'LONG', 
       style: new TextStyle(fontWeight: FontWeight.bold), 
      ), 
      new TextSpan(text: ' SENTENCE'), 
      ], 
     ), 
    ), 
    ); 
    } 
} 

class DemoApp extends StatelessWidget { 
    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     body: new Center(
     child: new Container(
      height: 150.0, 
      width: 150.0, 
      child: new Card(
      child: new DemoText(), 
     ), 
     ), 
    ), 
    ); 
    } 
}