In my flutter application, I would like to make a circle as a background like that:
The problem is mainly when the screen is in landscape, you can't fit a circle there unless it covers all the screen.
There's another approach with ClipRect, let me know if this doesn't work with you.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final radius = constraints.biggest.width * 1.2;
return SizedBox(
width: radius,
height: radius,
child: FittedBox(
fit: BoxFit.fitHeight,
child: Container(
width: radius,
height: radius ,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
),
),
);
}
);
}
}
Another approach:
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final radius = constraints.biggest.width * 1.2;
return OverflowBox(
maxWidth: radius,
maxHeight: radius,
child: Container(
width: radius,
height: radius ,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
),
);
}
);
}
}
final radius = constraints.biggest.width * 1.2;:
The 1.2 is how much the circle is overlapping, you can change this number.
Related
How would I go about making this design in a ScrollView?
I was thinking about making two containers one with the yellow color & second with the white color and then using clipPath to morph the edges of the white container. But, the problem I would face is that the background image would leave space below the left edge of yellow container which would seem odd so, I would have to absolute position the white container on the Y axis and this entirely would be in a ScrollView which seemed kind of hard to achieve. So, what would be the best suited method to accomplish this?
Thanks.
One way is to use Stack to stack the background image and the column which contains the top textfield and the bottom white container. Then you clip the bottom container
Code example:
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: Builder(
builder: (context) {
return Stack(
alignment: Alignment.topCenter,
children: [
Container(
color: Color.fromRGBO(4, 20, 31, 1),
),
Padding(
padding: const EdgeInsets.only(top: 50.0),
child: Column(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: TextField(
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
)
),
),
),
Expanded(
child: ClipPath(
clipper: MyClipper(radius: 50),
child: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
),
),
)
],
),
)
],
);
}
),
),
);
}
}
class MyClipper extends CustomClipper<Path>{
final double radius;
MyClipper({required this.radius});
#override
Path getClip(Size size) {
return Path()
..lineTo(0, 2*radius)
..arcTo(
Rect.fromCircle(center: Offset(radius, 2*radius), radius: radius),
math.pi,
math.pi/2,
false
)
..lineTo(radius, radius)
..lineTo(size.width-radius, radius)
..arcTo(
Rect.fromCircle(center: Offset(size.width-radius, 0), radius: radius),
math.pi/2,
-math.pi/2,
false
)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close()
;
}
#override
bool shouldReclip(MyClipper oldClipper) {
return false;
}
}
I have a Positioned widget that is draggable, by using Offset and wrapping it inside a Gesture Detector to update its position, and I want to constrain the area that this widget can move, so it cannot go beyond the boundaries. The structure is like this:
Scaffold -> Stack -> Positioned(Circle)
As it is shown below, I want the circle to move only in the are inside the gray lines. Is it possible?
Provide 2x value as limit, I did for touch position purpose.
also, both dx and dy axis can work separately. If you don't want it, you can combine two condition on a single setState.
Result
Widget
class HomeWidget extends StatefulWidget {
#override
_HomeWidgetState createState() => _HomeWidgetState();
}
class _HomeWidgetState extends State<HomeWidget> {
double dx = 0;
double dy = 0;
get limit => 50;
get containerSize => 50;
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: [
Positioned(
left: limit * .5,
child: Container(
height: constraints.maxHeight,
width: 5,
color: Colors.grey,
),
),
Positioned(
bottom: limit * .5,
child: Container(
width: constraints.maxWidth,
height: 5,
color: Colors.grey,
),
),
Positioned(
top: dy - containerSize * .5,
left: dx - containerSize * .5,
child: Container(
height: containerSize,
width: containerSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.deepPurple,
),
),
),
GestureDetector(
onPanUpdate: (details) {
if (details.localPosition.dx > limit)
setState(() {
dx = details.localPosition.dx;
});
if (details.localPosition.dy < constraints.maxHeight - limit)
setState(() {
dy = details.localPosition.dy;
});
print(" $dx, $dy ");
},
),
],
),
),
);
}
}
I want to crop the top right corner a bit more but even on increasing the border radius. It is not exceeding the center point of the container. Can anyone tell how can i obtain design as shown in the pic.
My Code:-
Material(
clipBehavior: Clip.antiAlias,
color: Colors.blue,
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.elliptical(40,90),
),
),
child: Container(
height: 100,
width: 180,
),
),
Expected:-
Current One:-
For custom shapes, you can define CustomClipper (you don't need any packages for that):
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: ClipPath(
clipper: ShapeClipper(),
child: Container(color: Colors.red, width: 300, height: 200),
),
),
),
);
}
}
class ShapeClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
return Path()
..lineTo(0.0, size.height)
..lineTo(size.width, size.height)
..lineTo(size.width - 100, 0.0)
..close();
}
#override
bool shouldReclip(ShapeClipper oldClipper) => false;
}
This should cover your case, just adjust the ShapeClipper with specific values.
In case anyone else wants this, I found a way.
You can use this plugin and modify your code to:-
Diagonal(
clipHeight: 40,
axis: Axis.vertical,
position: DiagonalPosition.BOTTOM_RIGHT,
child: Container(
color: Colors.blue,
height: 100,
width: 180,
),
),
I want to make a container styled as follows:
https://i.stack.imgur.com/ZPS6H.png
Having no idea how to do that I've tried to just incorporate SVG but it takes a different amount of time to render rectangles than to display SVG.
I've tried LinearGradient but even when I define stops it doesn't look right.
Here's what I have now:
Container(
width: width,
height: 0.7 * height,
child: Row(
children: [
Container(
height: 0.7 * height,
width: width * 0.35,
color: yellow,
child: CircularPhoto(),
),
Container(
width: width * 0.15,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/divider#2x.png'),
fit: BoxFit.fill,
),
),
),
Container(
width: width * 0.50,
color: Colors.white,
child: BannerInfo(),
),
],
),
);
This is an example!:
Maybe copy and paste it here to try it!: https://dartpad.github.io/
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height:200,
width:500,
child: Stack(
children:[
Container(
color:Colors.white
),
ClipPath(
child: Container(
width: MediaQuery.of(context).size.width,
color: Colors.yellow,
),
clipper: CustomClipPath(),
)
]
)
)
;
}
}
class CustomClipPath extends CustomClipper<Path> {
var radius=10.0;
#override
Path getClip(Size size) {
Path path = Path();
path.lineTo(0, 200);
path.lineTo(200,200);
path.lineTo(260,0);
path.lineTo(30, 0);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
I have a basic flag widget, with code here:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Flag(),
),
);
}
}
class Flag extends StatelessWidget {
#override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Center(
child: Container(
height: 400,
width: 150,
color: Colors.purple,
),
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}
It looks like this:
If I change scaleFactor to 0.5, it scales as expected:
But if I rotate my emulator to landscape, the proportions are off:
If I make the stripe proportional to the landscape view (e.g. change the stripe width to 250), it gets too big in portrait mode:
How do I ensure the purple stripe takes up the same proportion of space regardless of device size?
The flag is going to get way more complicated so I don't want to use MediaQuery.of(context).size to get the device width and calculate a percentage of that for every single child widget...
Do I need to tell my widget its "canonical" size? Do I need to pass a scaleFactor to every child widget?
Any ideas very appreciated :)
So, I see two ways to solve this, depending on what your eventual goal is. I think the first one is probably what you actually want.
1) Use a Row and an Expanded widget for each part of the flag, with a flex of one. The AspectRatio will keep the aspect ratio fixed, so the proportions should remain the same for the containers. Since the default flex factor is one anyhow, you can also just leave that out. If you need to the white parts to be transparent, just give Colors.transparent as the color.
class Flag extends StatelessWidget {
#override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Row(
children: <Widget>[
Expanded(
flex:1,
child: Container(
color: Colors.white,
),
),
Expanded(
flex:1,
child: Container(
color: Colors.purple,
),
),
Expanded(
flex:1,
child: Container(
color: Colors.white,
),
),
],
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}
2) You could just scale the contents of the center with a Transform widget, but that will squish any content you put inside it, so that's probably not what you want.
class Flag extends StatelessWidget {
#override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Center(
child: Transform(
transform: Matrix4.diagonal3Values(0.33, 1.0, 1.0),
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.purple,
),
),
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}