如何创建一个边界线带有clipPath的容器

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

我正在尝试创建这个

design

我能够在交互时实现接近但线条和曲线中的空间

vise visa

我的代码

class SegmentedControl extends StatefulWidget {
  @override
  _SegmentedControlState createState() => _SegmentedControlState();
}

class _SegmentedControlState extends State<SegmentedControl> {
  bool isSpendingSelected = true;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 50,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25),
        border: Border.all(
          color: Colors.grey,
        ),
      ),
      child: Stack(
        children: [
          AnimatedPositioned(
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeInOut,
            left: isSpendingSelected ? 0 : 150,
            child: Container(
              width: 150,
              height: 50,
              decoration: BoxDecoration(
                color: const Color(0xFF22303C), // Dark color for selected tab
                borderRadius: BorderRadius.circular(25),
              ),
            ),
          ),
          Row(
            children: [
              Expanded(
                child: GestureDetector(
                  onTap: () {
                    setState(() {
                      isSpendingSelected = true;
                    });
                  },
                  child: Center(
                    child: Text(
                      'Spending',
                      style: TextStyle(
                        color: isSpendingSelected ? Colors.white : Colors.grey,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ),
              Expanded(
                child: GestureDetector(
                  onTap: () {
                    setState(() {
                      isSpendingSelected = false;
                    });
                  },
                  child: Center(
                    child: Text(
                      'Saving',
                      style: TextStyle(
                        color: isSpendingSelected ? Colors.grey : Colors.grey,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}
flutter
1个回答
0
投票

您可以使用CustomPainter来制作您想要的形状。您可以轻松复制并粘贴代码并在您的应用程序中尝试。

import 'package:flutter/material.dart';

    
class SpendingSavingPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final double cornerRadius = size.height / 2;
    const double gapWidth = 4.0; // Width of the gap between Spending and Saving sections
// Paint for the filled "Spending" section
final paintSpending = Paint()
  ..color = Colors.teal[800]!
  ..style = PaintingStyle.fill;

// Paint for the "Saving" section background
final paintSaving = Paint()
  ..color = Colors.white
  ..style = PaintingStyle.fill;

// Paint for the border
final paintBorder = Paint()
  ..color =  Colors.teal[800]!
  ..style = PaintingStyle.stroke
  ..strokeWidth = 2;

// Draw the entire Saving background
final rRect = RRect.fromLTRBR(
  0,
  0,
  size.width,
  size.height,
  Radius.circular(cornerRadius),
);
canvas.drawRRect(rRect, paintSaving);

// Draw the Spending section
final spendingWidth = (size.width - gapWidth) / 2;
final spendingRect = Rect.fromLTWH(0, 0, spendingWidth, size.height);
final spendingRRect = RRect.fromRectAndCorners(
  spendingRect,
  topLeft: Radius.circular(cornerRadius),
  bottomLeft: Radius.circular(cornerRadius),
  bottomRight: Radius.circular(cornerRadius * 2)
);
canvas.drawRRect(spendingRRect, paintSpending);

// Draw the border with modifications
Path path = Path();

// Start from the top-right corner of the Spending section
path.moveTo(spendingWidth, 1);

// Top side of the Saving section
path.lineTo(size.width - cornerRadius, 1);
path.arcToPoint(
  Offset(size.width, cornerRadius),
  radius: Radius.circular(cornerRadius),
);

// Right side of the Saving section
path.lineTo(size.width, size.height - cornerRadius);

// Bottom side of the Saving section (shortened)
path.arcToPoint(
  Offset(size.width - cornerRadius, size.height - 1),
  radius: Radius.circular(cornerRadius),
);

// *****
// Change the number 10 to control the space
// *****
path.lineTo(spendingWidth + gapWidth + 5, size.height - 1); // Shortened bottom

// Draw the border
canvas.drawPath(path, paintBorder);


 }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

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

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 50,
      child: CustomPaint(
        size: const Size(200, 50), // Adjust the size as needed
        painter: SpendingSavingPainter(),
        child: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              const Padding(
                padding: EdgeInsets.only(left: 20.0),
                child: Text(
                  'Spending',
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                    fontSize: 16,
                  ),
                ),
              ),
              Padding(
                padding: const EdgeInsets.only(right: 20.0),
                child: Text(
                  'Saving',
                  style: TextStyle(
                    color: Colors.teal[400],
                    fontWeight: FontWeight.bold,
                    fontSize: 16,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Padding(
          padding: EdgeInsets.all(16),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              SpendingSavingWidget(),
            ],
          ),
        ),
      ),
    );
  }
}

void main() {
  runApp(const MyApp());
}
© www.soinside.com 2019 - 2024. All rights reserved.