我有一个横跨整个页面长度的容器.虽然我已经成功地在左侧添加了边框,但我现在希望在顶部和底部都包括边框.然而,我对try 一种独特的设计概念很感兴趣;遗憾的是,我不确定实现这一目标的步骤.

我希望我的边框从左边4px的厚度开始,然后沿着容器的长度逐渐减小,直到右边达到0.5px.

我不确定如何继续,这就是我提出这个问题的原因.

我正在与您分享我当前的代码,尽管它不是很广泛.

class InfoContainer extends StatelessWidget {
  final Color color;
  final IconData icon;
  final String text;

  const InfoContainer({
    super.key,
    required this.color,
    required this.icon,
    required this.text
  });

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(5.0),
      child: Container(
        height: 60,
        decoration: BoxDecoration(
          color: color.withOpacity(0.3),
          border: Border(
            left: BorderSide(color: color, width: 4.0),
            top: BorderSide(), // Here
            bottom: BorderSide(), // Here
          )
        ),
      ),
    );
  }
}

推荐答案

由于您的用例超出了Ffltter提供的默认行为(通过Border),因此利用Flight的开放源码特性并判断底层类是很有用的.

通过查看BoxDecoration‘S边界属性,我们可以看到该参数接受BoxBorder.这就是Border实现的内容,因为Border不包括这个用例,所以我们可以创建BoxBorder的自定义实现.

我已经实现了一个名为InclinedBorder的自定义实现,它可以有一对垂直或水平倾斜的边框.创建BoxBorder的自定义实现需要告诉Ffltter如何在paint方法中通过画布绘制边框,这需要一些数学运算.

最终结果

Inclined borders showing vertical and horizonal configuration

InclinedBorder implementation:

class InclinedBorder extends BoxBorder {
  final Axis inclineAxis;
  final double inclinedBorderStartWidth;
  final double inclinedBorderEndWidth;
  final double startBorderConstantWidth;
  final double endBorderConstantWidth;

  // The paint implementation have a minor gap between the border-sides this
  // corrects it.
  final double gapCorrection = 0.5;

  const InclinedBorder({
    required this.inclineAxis,
    required this.inclinedBorderStartWidth,
    required this.inclinedBorderEndWidth,
    required this.startBorderConstantWidth,
    required this.endBorderConstantWidth,
  });

  @override
  void paint(
    Canvas canvas,
    Rect rect, {
    TextDirection? textDirection,
    BoxShape shape = BoxShape.rectangle,
    BorderRadius? borderRadius,
  }) {
    final paint = Paint();

    switch (inclineAxis) {
      case Axis.horizontal:
        paint.strokeWidth = startBorderConstantWidth;
        canvas.drawLine(
            rect.topLeft - Offset(startBorderConstantWidth / 2, gapCorrection),
            rect.bottomLeft -
                Offset(startBorderConstantWidth / 2, -gapCorrection),
            paint);
        paint.strokeWidth = endBorderConstantWidth;
        canvas.drawLine(
            rect.topRight +
                Offset(endBorderConstantWidth / 2, -gapCorrection),
            rect.bottomRight +
                Offset(endBorderConstantWidth / 2, gapCorrection),
            paint);

        paint.style = PaintingStyle.fill;

        Path path = Path();
        path.moveTo(
            rect.topLeft.dx - startBorderConstantWidth, rect.topLeft.dy);
        path.lineTo(rect.topLeft.dx - startBorderConstantWidth,
            rect.topLeft.dy - inclinedBorderStartWidth);
        path.lineTo(rect.topRight.dx + endBorderConstantWidth,
            rect.topRight.dy - inclinedBorderEndWidth);
        path.lineTo(
            rect.topRight.dx + endBorderConstantWidth, rect.topRight.dy);

        path.moveTo(
            rect.bottomLeft.dx - startBorderConstantWidth, rect.bottomLeft.dy);
        path.lineTo(rect.bottomLeft.dx - startBorderConstantWidth,
            rect.bottomLeft.dy + inclinedBorderStartWidth);
        path.lineTo(rect.bottomRight.dx + endBorderConstantWidth,
            rect.bottomRight.dy + inclinedBorderEndWidth);
        path.lineTo(
            rect.bottomRight.dx + endBorderConstantWidth, rect.bottomRight.dy);

        canvas.drawPath(path, paint);
        break;

      case Axis.vertical:
        paint.strokeWidth = startBorderConstantWidth;

        canvas.drawLine(
            rect.topLeft - Offset(gapCorrection, startBorderConstantWidth / 2),
            rect.topRight -
                Offset(-gapCorrection, startBorderConstantWidth / 2),
            paint);
        paint.strokeWidth = endBorderConstantWidth;
        canvas.drawLine(
            rect.bottomLeft +
                Offset(-gapCorrection, endBorderConstantWidth / 2),
            rect.bottomRight +
                Offset(gapCorrection, endBorderConstantWidth / 2),
            paint);

        paint.style = PaintingStyle.fill;
        paint.strokeWidth = 1;

        Path path = Path();
        path.moveTo(
            rect.topLeft.dx, rect.topLeft.dy - startBorderConstantWidth);
        path.lineTo(rect.topLeft.dx - inclinedBorderStartWidth,
            rect.topLeft.dy - startBorderConstantWidth);
        path.lineTo(rect.bottomLeft.dx - inclinedBorderEndWidth,
            rect.bottomLeft.dy + endBorderConstantWidth);
        path.lineTo(
            rect.bottomLeft.dx, rect.bottomLeft.dy + endBorderConstantWidth);

        path.moveTo(
            rect.topRight.dx, rect.topRight.dy - startBorderConstantWidth);
        path.lineTo(rect.topRight.dx + inclinedBorderStartWidth,
            rect.topRight.dy - startBorderConstantWidth);
        path.lineTo(rect.bottomRight.dx + inclinedBorderEndWidth,
            rect.bottomRight.dy + endBorderConstantWidth);
        path.lineTo(
            rect.bottomRight.dx, rect.bottomRight.dy + endBorderConstantWidth);

        canvas.drawPath(path, paint);
        break;
    }
  }

  @override
  BorderSide get top => BorderSide(
        width: inclineAxis == Axis.horizontal
            ? max(inclinedBorderStartWidth, inclinedBorderEndWidth)
            : startBorderConstantWidth,
      );

  @override
  BorderSide get bottom => BorderSide(
        width: inclineAxis == Axis.horizontal
            ? max(inclinedBorderStartWidth, inclinedBorderEndWidth)
            : endBorderConstantWidth,
      );

  @override
  EdgeInsetsGeometry get dimensions {
    switch (inclineAxis) {
      case Axis.horizontal:
        return EdgeInsets.fromLTRB(
          startBorderConstantWidth,
          max(inclinedBorderStartWidth, inclinedBorderEndWidth),
          endBorderConstantWidth,
          max(inclinedBorderStartWidth, inclinedBorderEndWidth),
        );
      case Axis.vertical:
        return EdgeInsets.fromLTRB(
          max(inclinedBorderStartWidth, inclinedBorderEndWidth),
          startBorderConstantWidth,
          max(inclinedBorderStartWidth, inclinedBorderEndWidth),
          endBorderConstantWidth,
        );
    }
  }

  @override
  bool get isUniform => false;

  // TODO: This has not been implemented.
  @override
  ShapeBorder scale(double t) => throw UnimplementedError();
}

图像背后的用法/代码示例

注意Container‘S边距和InclinedBorder/BoxBorder’S尺寸属性的使用,以正确设置边距.

import 'dart:math';

import 'package:flutter/material.dart';

main() => runApp(const MaterialApp(home: BorderTestScreen()));

class BorderTestScreen extends StatelessWidget {
  const BorderTestScreen({super.key});

  @override
  Widget build(BuildContext context) {
    InclinedBorder border1 = const InclinedBorder(
      inclineAxis: Axis.horizontal,
      inclinedBorderStartWidth: 20,
      inclinedBorderEndWidth: 10,
      startBorderConstantWidth: 20,
      endBorderConstantWidth: 20,
    );

    InclinedBorder border2 = const InclinedBorder(
      inclineAxis: Axis.vertical,
      inclinedBorderStartWidth: 20,
      inclinedBorderEndWidth: 10,
      startBorderConstantWidth: 20,
      endBorderConstantWidth: 20,
    );

    return Scaffold(
      body: Center(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Container(
                margin: border1.dimensions,
                decoration: BoxDecoration(
                  color: Colors.green,
                  border: border1,
                ),
                child: const SizedBox(
                  width: 300,
                  height: 100,
                ),
              ),
              const SizedBox(
                height: 8,
              ),
              Container(
                margin: border2.dimensions,
                decoration: BoxDecoration(
                  color: Colors.green,
                  border: border2,
                ),
                child: const SizedBox(
                  width: 300,
                  height: 100,
                ),
              )
            ]),
      ),
    );
  }
}

注意:如果要使用它,请考虑创建一个抽象化维度逻辑的小部件.

希望这个能帮上忙!

Flutter相关问答推荐

如何在Flutter 屏幕中添加箭头形状

Box约束强制无限高:SizedBox. Expand()

文本未设置在集装箱摆动的中心

Android NFC未收到空的NFC标签

我有一个问题:类型';()=>;Null';不是类型转换中类型';(Int)=>;void';的子类型

如何使DropDownMenu宽度等于TextFormfield?

未处理的异常:第1行第5列出现错误:无效的媒体类型:应为/&;.从API获取数据时在Flutter中

在使用 Android 12+ 的真实 Android 设备上,SingleChildScrollView 中最初位于视口之外的无响应 Web 视图

如何在 Flutter (iOS) 中解决这个问题

如何更改 DropDownMenu 的显示方向?

为什么 ref.watch(otherProvider.stream) 在 Riverpod 2.x 中被弃用并且将在 3.x 中被删除?

如何使这种相机叠加在Flutter 中?

你如何在 Flutter 中组合两个数组?

如何在 Flutter 中将列小部件添加到行小部件?

如何在椭圆形图像周围添加边框?Flutter

Flutter :RangeError(索引):无效值:不在包含范围内0..3:4使用IndexedListView.builder

在 Flutter 中单击时切换按钮 colored颜色 没有改变

Flutter:整个判断整个应用生命周期的通用类

检索 api 的值时,我得到_TypeError(类型'Null'不是'String'类型的子类型)

如何从圆角go 除背景 colored颜色