在Flutter中剪出文字效果

Fab*_*zio 6 android ios flutter

如何将文本切入框形容器中,使内容在其下方可见?

这就是我的意思:

如您所见,图像在文字下方可见。我该怎么办?

bof*_*mer 6

您必须使用CustomPainter, TextPainter,BlendModesaveLayer

结果

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;
  }
}
Run Code Online (Sandbox Code Playgroud)


And*_*onu 5

You could use a ShaderMask for that, which allows you to apply a shader to a widget, taking a Blend Mode into account. The Blend Mode is what we're interested in, so the Shader will be a simple color:

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,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Here is an example render: 抠图小部件的渲染

For your exact example image, the child should be a Text widget and you should also include this in a ClipRRect for the rounded corners (or you can figure out more optimal solutions using BoxDecoration if the performance impact of ClipRRect is an issue)

The advantage of this solution is that it works with any widget as a child and that it's a composable widget that you can pop in your layout.