Я разрабатываю приложение, используя Flutter, и наткнулся на собственную структуру, похожую на кривую, и понятия не имею, как ее создать. Я делюсь скриншотом того же самого.
Я провел небольшое исследование и обнаружил, что это возможно с помощью виджета пути клипа, но опять же, я понятия не имею, как это будет работать. Я также был бы признателен, если бы кто-нибудь объяснил, как это решить.
Возможно, этот код не лучший способ, но проще всего было сделать такой интерфейс.
Scaffold(
backgroundColor: Colors.grey[200],
appBar: CustomAppBar(
backgroundColor: Colors.grey[500],
title: '',
),
body: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.grey[500],
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(56),
),
),
width: MediaQuery.of(context).size.width,
height: 200,
),
Container(
color: Colors.grey[500],
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: const BorderRadius.only(
topRight: Radius.circular(70),
),
),
width: MediaQuery.of(context).size.width,
height: 200,
),
)
],
),
),
Самый простой способ сделать это — использовать ShapeBorder
, поэтому вы можете использовать его в любом контейнере. Как и в случае с виджетом ClipPath
, вы можете определить путь для использования. ShapeBorder
прокладывает вам путь от границы Rect
этого Container
. В приведенном ниже коде я рисую верхнюю дугу над этим прямоугольником, чтобы верхняя граница выравнивалась (и вы также можете разместить другие виджеты прямо над этим контейнером).
import 'package:flutter/material.dart';
class WavyBorder extends ShapeBorder {
const WavyBorder({this.radius = 32});
final double radius;
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
throw UnimplementedError();
}
@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
return Path()
// The top curve is above this container's Rect, keep this in mind with your other Widgets
..moveTo(rect.topLeft.dx, rect.topLeft.dy - radius)
// The 90 degree arc at the top
..relativeArcToPoint(
Offset(radius, radius),
radius: Radius.circular(radius),
clockwise: false,
)
// The horizontal line
..lineTo(rect.topRight.dx - radius, rect.topRight.dy)
// The 90 degree arc at the bottom
..relativeArcToPoint(
Offset(radius, radius),
radius: Radius.circular(radius),
)
// Then just visit the bottom corners normally
..lineTo(rect.bottomRight.dx, rect.bottomRight.dy)
..lineTo(rect.bottomLeft.dx, rect.bottomLeft.dy)
..close();
}
@override
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}
@override
ShapeBorder scale(double t) {
throw UnimplementedError();
}
}
Затем, где бы вы ни захотели его использовать, вы можете добавить его в ShapeDecoration
вашего Container
:
Container(
decoration: ShapeDecoration(
shape: WavyBorder(radius: 32),
...
),
child: ...,
),
Что выглядит так:
Полный код для использования (main.dart
):
import 'package:flutter/material.dart';
import 'wavy_container.dart';
void main() {
runApp(const MaterialApp(
home: HomeScreen(),
debugShowCheckedModeBanner: false,
));
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final TextEditingController controller = TextEditingController();
final FocusNode focusNode = FocusNode();
@override
void initState() {
super.initState();
controller.text = 'Hallo';
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Flex(
direction: Axis.vertical,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Text(
'This text fits neatly above the container. Watch out with the left margin right above it though!',
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
),
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.all(8),
decoration: ShapeDecoration(
shape: const WavyBorder(radius: 32),
color: Theme.of(context).colorScheme.primary,
),
child: Text(
'Look at that pretty wavy border above here!',
style: Theme.of(context)
.textTheme
.headlineLarge
?.copyWith(color: Colors.white),
textAlign: TextAlign.center,
),
),
)
],
),
);
}
}
Предоставьте достаточно кода, чтобы другие могли лучше понять или воспроизвести проблему.