如何在Flutter中制作倒圆角的容器?

问题描述 投票:0回答:3

这是制作圆角容器的方法:

Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(10),),

但是有没有办法制作如下图所示的倒圆角呢?我在网上找不到任何东西

flutter dart geometry border
3个回答
2
投票

作为一个选项(基于@pskink提示)

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Scaffold(appBar: AppBar(), body: Demo()));
  }
}

class Demo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          Container(
            width: 300,
            height: 200,
            margin: const EdgeInsets.only(top: 24, bottom: 16),
            decoration: ShapeDecoration(shape: WeirdBorder(radius: 32), color: Colors.red),
          ),
          Container(
            width: 200,
            height: 100,
            margin: const EdgeInsets.only(bottom: 16),
            decoration: ShapeDecoration(shape: WeirdBorder(radius: 16, pathWidth: 8), color: Colors.green),
          ),
          Container(
            width: 300,
            height: 200,
            decoration: ShapeDecoration(shape: WeirdBorder(radius: 12, pathWidth: 2), color: Colors.blue),
          ),
        ],
      ),
    );
  }
}

class WeirdBorder extends ShapeBorder {
  final double radius;
  final double pathWidth;

  WeirdBorder({@required this.radius, this.pathWidth = 1});

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection textDirection}) {
    return Path()
      ..fillType = PathFillType.evenOdd
      ..addPath(getOuterPath(rect, textDirection: textDirection), Offset.zero);
  }

  @override
  Path getOuterPath(Rect rect, {TextDirection textDirection}) => _createPath(rect);

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}

  @override
  ShapeBorder scale(double t) => WeirdBorder(radius: radius);

  Path _createPath(Rect rect) {
    final innerRadius = radius + pathWidth;
    final innerRect = Rect.fromLTRB(rect.left + pathWidth, rect.top + pathWidth, rect.right - pathWidth, rect.bottom - pathWidth);

    final outer = Path.combine(PathOperation.difference, Path()..addRect(rect), _createBevels(rect, radius));
    final inner = Path.combine(PathOperation.difference, Path()..addRect(innerRect), _createBevels(rect, innerRadius));
    return Path.combine(PathOperation.difference, outer, inner);
  }

  Path _createBevels(Rect rect, double radius) {
    return Path()
      ..addOval(Rect.fromCircle(center: Offset(rect.left, rect.top), radius: radius))
      ..addOval(Rect.fromCircle(center: Offset(rect.left + rect.width, rect.top), radius: radius))
      ..addOval(Rect.fromCircle(center: Offset(rect.left, rect.top + rect.height), radius: radius))
      ..addOval(Rect.fromCircle(center: Offset(rect.left + rect.width, rect.top + rect.height), radius: radius));
  }
}


0
投票

您也可以使用fw_ticket套餐。


0
投票

如果您想要创建每个角落都可以独立定制的自定义门票。我有东西。

这就是结果:

这是代码。

形状

import 'package:flutter/material.dart';

class SwTicketBorder extends ShapeBorder {
  final double radius;
  final Color? fillColor;
  final double borderWidth;
  final Color? borderColor;
  final bool topLeft;
  final bool topRight;
  final bool bottomLeft;
  final bool bottomRight;

  const SwTicketBorder({
    required this.radius,
    this.fillColor,
    this.borderWidth = 1.0,
    this.borderColor,
    this.topLeft = true,
    this.topRight = true,
    this.bottomLeft = true,
    this.bottomRight = true,
  });

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
    return Path()
      ..fillType = PathFillType.evenOdd
      ..addPath(getOuterPath(rect, textDirection: textDirection), Offset.zero);
  }

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) =>
      _createPath(rect);

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
    if (fillColor == null && borderColor == null) return;

    if (fillColor != null) {
      final fillPaint = Paint()
        ..color = fillColor! // Use the provided fillColor
        ..style = PaintingStyle.fill;
      final fillPath = getInnerPath(rect, textDirection: textDirection);
      canvas.drawPath(fillPath, fillPaint);
    }

    if (borderColor != null) {
      final borderPaint = Paint()
        ..color = borderColor!
        ..style = PaintingStyle.stroke
        ..strokeWidth = borderWidth;
      final borderPath = getOuterPath(rect, textDirection: textDirection);
      canvas.drawPath(borderPath, borderPaint);
    }
  }

  @override
  ShapeBorder scale(double t) => SwTicketBorder(radius: radius);

  Path _createPath(Rect rect) {
    // Inset the rect by the pathWidth so the border is inside the rect.
    Rect insetRect = rect.deflate(borderWidth);

    // The path for the 'ticket' shape
    Path path = Path();

    // The distance from the corner to start the curve for the inverted corners
    double inset = radius;

    // Move to the start point
    path.moveTo(insetRect.left + inset, insetRect.top);

    // Top line and top-right inverted corner
    path.lineTo(insetRect.right - inset, insetRect.top);
    path.arcToPoint(
      Offset(insetRect.right, insetRect.top + inset),
      radius: Radius.circular(inset),
      clockwise: !topRight,
    );

    // Right line and bottom-right inverted corner
    path.lineTo(insetRect.right, insetRect.bottom - inset);
    path.arcToPoint(
      Offset(insetRect.right - inset, insetRect.bottom),
      radius: Radius.circular(inset),
      clockwise: !bottomRight,
    );

    // Bottom line and bottom-left inverted corner
    path.lineTo(insetRect.left + inset, insetRect.bottom);
    path.arcToPoint(
      Offset(insetRect.left, insetRect.bottom - inset),
      radius: Radius.circular(inset),
      clockwise: !bottomLeft,
    );

    // Left line and top-left inverted corner
    path.lineTo(insetRect.left, insetRect.top + inset);
    path.arcToPoint(
      Offset(insetRect.left + inset, insetRect.top),
      radius: Radius.circular(inset),
      clockwise: !topLeft,
    );

    // Close the path
    path.close();

    return path;
  }
}

使用示例

  width: double.infinity,
  decoration: const ShapeDecoration(
    shape: SwTicketBorder(
      radius: 16,
      fillColor: Colors.grey,
      borderColor: Colors.yellow,
      borderWidth: 4,
      bottomLeft: true,
      bottomRight: true,
      topLeft: false,
      topRight: false,
    ),
  ),
  padding: const EdgeInsets.symmetric(
    horizontal: 16,
    vertical: 24,
  ),
  child: const Column(
    children: [
      Text(
        "This is a ticket",
        style: TextStyle(
          fontSize: 24,
          fontWeight: FontWeight.w600,
        ),
      ),
      Text(
        "And this is its description",
        style: TextStyle(
          fontSize: 16,
        ),
      ),
    ],
  ),
)
© www.soinside.com 2019 - 2024. All rights reserved.