当我点击TextSpan时,如何使其产生涟漪效果?

9

想象一下,我有一段长篇文字像这样:HELLO THIS IS MY LONG SENTENCE。我希望在点击单词LONG时会产生水波纹(类似墨水飞溅)。

假设我有以下代码:

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'),
    ],
  ),
)

谢谢!

3个回答

14

example

如果你想要一个通用的解决方案来放置小部件在文本的某些部分,可以查看这个代码片段

您可以使用以下代码将涟漪限制在文本的特定部分:

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;
}

所以,诀窍就在于TextSelection偏移量需要与您想要波及的子字符串匹配? - Seth Ladd
@SethLadd 是的,没错,它甚至不必遵循文本跨度。 - Takhion

6
您可以通过调整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(),
          ),
        ),
      ),
    );
  }
}

你可以在拖动时选择文本吗? - satish

6

截至2019年,我们可以使用以下内容:

RichText(
  textAlign: TextAlign.center,
  text: TextSpan(
    style: textTheme.bodyText2,
    text: "HELLO THIS IS MY",
    children: [
      WidgetSpan(
        child: InkWell(
          onTap: () {},
          child: Text(
            "SENTENCE",
            style: TextStyle(color: colorScheme.primary),
          ),
        ),
      ),
    ],
  ),
),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接