在Flutter中剪出文字效果

时间:2018-09-03 14:47:57

标签: android ios flutter

我如何将文本切入一个盒子容器中,使内容在其下可见?

这正是我的意思:

如您所见,图片下方显示了图片。我该怎么办?

2 个答案:

答案 0 :(得分:1)

您必须使用CustomPainterTextPainterBlendModesaveLayer

result

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Playground',
      home: TestPage(),
    );
  }
}

class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        image: DecorationImage(image: AssetImage('assets/earth.jpg'), fit: BoxFit.cover),
      ),
      child: Center(
        child: CustomPaint(
          painter: CutOutTextPainter(text: 'YOUR NAME'),
        ),
      ),
    );
  }
}

class CutOutTextPainter extends CustomPainter {
  CutOutTextPainter({this.text}) {
    _textPainter = TextPainter(
      text: TextSpan(
        text: text,
        style: TextStyle(
          fontSize: 40.0,
          fontWeight: FontWeight.w600,
        ),
      ),
      textDirection: TextDirection.ltr,
    );
    _textPainter.layout();
  }

  final String text;
  TextPainter _textPainter;

  @override
  void paint(Canvas canvas, Size size) {
    // Draw the text in the middle of the canvas
    final textOffset = size.center(Offset.zero) - _textPainter.size.center(Offset.zero);
    final textRect = textOffset & _textPainter.size;

    // The box surrounding the text should be 10 pixels larger, with 4 pixels corner radius
    final boxRect = RRect.fromRectAndRadius(textRect.inflate(10.0), Radius.circular(4.0));
    final boxPaint = Paint()..color = Colors.white..blendMode=BlendMode.srcOut;

    canvas.saveLayer(boxRect.outerRect, Paint());

    _textPainter.paint(canvas, textOffset);
    canvas.drawRRect(boxRect, boxPaint);

    canvas.restore();
  }

  @override
  bool shouldRepaint(CutOutTextPainter oldDelegate) {
    return text != oldDelegate.text;
  }
}

答案 1 :(得分:1)

您可以为此使用ShaderMask,这允许您将着色器应用于小部件,并考虑到Blend Mode。混合模式是我们感兴趣的,因此着色器将是一种简单的颜色:

class Cutout extends StatelessWidget {
  const Cutout({
    Key key,
    @required this.color,
    @required this.child,
  }) : super(key: key);

  final Color color;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return ShaderMask(
      blendMode: BlendMode.srcOut,
      shaderCallback: (bounds) => LinearGradient(colors: [color], stops: [0.0]).createShader(bounds),
      child: child,
    );
  }
}

这是渲染示例: Render of the Cutout widget

对于您的确切示例图片,该子项应为Text小部件,并且还应将其包括在ClipRRect中以用于圆角(或者您可以使用{{1 }}如果对BoxDecoration的性能有影响)

此解决方案的优势在于,它可以与任何小部件一起使用,并且是一个可组合的小部件,可以在布局中弹出。