How to draw container outside screen width in flutter? - flutter

How can I create a container with rounded corners as shown below?
I tried using container with width more than the screen width. But that constraints it inside the screen. I tried using an OverFlow box, but couldn't get the same result as well. I don't want to use clipRect to make this as I want to apply animation on the corners.
Edit: Added container snippet with the resulting outcome to clear doubts
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 500,
decoration: BoxDecoration(
color: Colors.green, borderRadius: BorderRadius.circular(500)),
),
),
);
}

I have managed to get similar to what I want by using scale transformation. Would like to see a different approach though.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Align(
alignment: Alignment.bottomCenter,
child: Transform.scale(
scale: 1.7,
child: Container(
height: 400,
decoration: BoxDecoration(
color: Colors.green, borderRadius: BorderRadius.circular(200)),
),
),
),
);
}

I have done this using clippath. If you change size of Container then Clippath size automatically change as per Container size.
You can modify Path for different shape as per your requirement so this is very useful.
Here, I just use ClipPath widget and I create MyCustomShape class for modify shape of child Container widget
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black87,
body: ClipPath(
clipper: MyCustomShape(),
child: Container(
color: Colors.green[800],
height: double.infinity,
),
),
);
}
}
class MyCustomShape extends CustomClipper<Path> {
#override
Path getClip(Size size) {
Path path = new Path(); // use for shape your container
path.lineTo(0.0, 100);
path.quadraticBezierTo(size.width * 0.5, 0.0, size.width, 100);
path.lineTo(size.width, size.height);
path.lineTo(0.0, size.height);
path.close();
return path;
}

after reading your questions and comments many time i hope this what you are looking for
class dummy2 extends StatefulWidget {
#override
_dummy2State createState() => _dummy2State();
}
class _dummy2State extends State<dummy2> with TickerProviderStateMixin {
AnimationController controller;
Animation<double> animaton;
#override
initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
animaton = Tween<double>(begin: 1, end: 2.5).animate(
CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn));
animaton.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
onPressed: () {
controller.forward();
},
child: Text('forward')),
FlatButton(
onPressed: () {
controller.reverse();
},
child: Text('reverse'))
],
),
body: Transform.scale(
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurple, shape: BoxShape.circle),
),
scale: animaton.value,
)));
}
}

I believe you should use SafeArea within a container to fill it. Like this:
Container(
color: Colors.blue,
child: SafeArea(child: ### // you nav or functions),
),
See: https://api.flutter.dev/flutter/widgets/SafeArea-class.html

Related

How to go about creating this clippath design with a background?

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;
}
}

Flutter - Container with ring progress indicator border

I am trying to achieve a container that will have a progress indicator border, like in this image:
I've tried to achieve it using a container inside another container (1 container for the outside white border, and one container for the inside blue background with the icon), but I can't achieve the progress indicator effect.
Does anyone know how can I achieve this?
Thank you
If you don't want to use a CustomPainter you can try to achieve that with a Stack widget
You can see this example in DartPad
Use the value property on the second CircularProgressIndicator to update the value with setState or any other State Management technique you like
import 'package:flutter/material.dart';
const 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 Stack(
children: const [
CircleAvatar(
backgroundColor: Colors.white,
radius: 24,
child: Icon(Icons.check),
),
SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
color: Colors.grey,
value: 1,
),
),
SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
color: Colors.blue,
value: .3, // Change this value to update the progress
),
),
],
);
}
}
There is a widget called CircularProgressIndicator that seems to be exactly what you're after.
How to use it:
CircularProgressIndicator(
backgroundColor: Colors.white,
color: Colors.purple.withAlpha(100),
strokeWidth: 5,
value: value, //
),
backgroundColor: for the white background
color: for the purple overlay
strokeWidth: for the thickness that you want
value: the actual progress of the indicator
And to have the arrow on top just use a round white Container (use a BoxDecoration with shape: BoxShape.circle to make it a circle), and put the arrow on top of it using the Stack widget.
Hope this helps!
class ProgressPainter extends CustomPainter {
final double value;
double deg2rad(double deg) => deg * pi / 180;
ProgressPainter({
required this.value,
});
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..color = Colors.blueGrey;
final rect = Rect.fromCenter(
center: Offset(size.height / 2, size.width / 2),
width: size.width,
height: size.height);
canvas.drawArc(
rect,
deg2rad(-90),
deg2rad(
(value * 360) / 100, // % to degree
),
true,
paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
And use
CustomPaint(
painter: ProgressPainter(value: sliderVal),
child: const SizedBox(
height: 100,
width: 100,
child: Icon( // your inner widget
Icons.ac_unit,
size: 100,
),
),
),
Tested widget:
class _MyHomePageState extends State<MyHomePage> {
double sliderVal = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: Column(
children: [
CustomPaint(
painter: ProgressPainter(value: sliderVal),
child: const SizedBox(
height: 100,
width: 100,
child: Icon(
Icons.ac_unit,
size: 100,
),
),
),
Slider(
value: sliderVal,
min: 0,
max: 100,
onChanged: (value) {
setState(() {
sliderVal = value;
});
},
)
],
),
),
);
}
}

how to increase the border radius limit in flutter?

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,
),
),

Flutter Transform.scale for child widgets not scaling proportionately, why?

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,
);
}
}

Flutter: How manage transition with MediaQuery's values on animatedTransition Widget

first at all, i apologize for my english.
And second i have a trouble manage values for animateTransition. As you can see i have a card widget with a position at the right of the screen and MaterialButton in the center of the screen.
The positioned widget's values are give by MediaQuery Class and after save in the position variable, but when i try change the position's value and call setSate function, the build method redo and initialize the variables and again the new value is the same always because of that (i think that), and for that never will see a transition.
i show the code.
class _DashboardState extends State<Dashboard> {
final double blur = 30;
final double offset = 20;
final double top = 25;
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
double position = -(size.width) * 0.8;
return WillPopScope(
onWillPop: () async =>
SystemChannels.platform.invokeMethod('SystemNavigator.pop'),
child: MaterialApp(
home: Scaffold(
body: SafeArea(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
right: position,
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.decelerate,
child: Card(
elevation: 8,
color: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Container(
width: size.width * 0.9,
height: size.height * 0.8,
),
),
),
),
Center(
child: MaterialButton(
color: Colors.black,
child: Text("mover"),
onPressed: () {
setState(() {
position = 0;
});
},
),
)
],
),
),
),
),
);
}
}
when i try to take out the variables i can't because de context dependency in mediaQuery and i can't initialize the request variables to get size of device, and put in the initial state. any advice for manage this type of problem.
Thanks for your attention