Flutter half circle with multiple fill colors - flutter

I would like to create this in Flutter:
I know you can create a half circle like this.
But how I can get these multiple fill colors?
I know there is way to get this done with LinearGradient. (something like this)
But this might work, but I need to each color-section as a separated part/widget because I want to animate them in the next step.
How could I get this done?

You can do this using Custom Painter but then I understand it would be challenging to animate each color bar. I have been able to create something like you need
I used the ClipRRect widget to cut out the bottomLeft and bottomRight portions of a square -> SemiCircle.
Each Color bar is a Container and since you would like to animate each bar you can easily replace the Container with an AnimatedContainer and proceed from there. You might also need to make the widget stateful for animations.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
// Assuming constraints here.
// Play with width and height values
const double widgetWidth = 100;
const double widgetHeight = 60;
// To get a semicircle
const double bottomRadius = widgetWidth / 2;
//Since we have 5 colors . Each color bars height is 60/5 = 12
const double colorBarHeight = widgetHeight / 5;
return ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(bottomRadius),
bottomRight: Radius.circular(bottomRadius)),
child: SizedBox(
width: widgetWidth,
height: widgetHeight,
child: Column(
children: [
Container(
width: widgetWidth,height: colorBarHeight,color: Colors.green),
Container(
width: widgetWidth,height: colorBarHeight,color: Colors.orange),
Container(
width: widgetWidth,height: colorBarHeight,color: Colors.yellow),
Container(
width: widgetWidth, height: colorBarHeight, color: Colors.red),
Container(
width: widgetWidth, height: colorBarHeight, color: Colors.blue),
])));
}
}

Please try this below code:
class SemiCircle extends StatelessWidget {
const SemiCircle({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(300),
bottomRight: Radius.circular(300),
),
child: Container(
alignment: Alignment.center,
height: 100,
width: 200,
child: Column(
children: [
Container(
height: 10,
color: Colors.red,
),
Container(
height: 10,
color: Colors.yellow,
),
Container(
height: 10,
color: Colors.green,
),
Container(
height: 10,
color: Colors.red,
),
Container(
height: 10,
color: Colors.yellow,
),
Container(
height: 10,
color: Colors.green,
),
Container(
height: 10,
color: Colors.red,
),
Container(
height: 10,
color: Colors.yellow,
),
Container(
height: 10,
color: Colors.green,
),
Container(
height: 10,
color: Colors.red,
),
],
),
),
),
),
],
),
);
}
}
You will get an output like below:

Related

How to add backgroud like this in flutter

I want to add background that has circle like picture below:
And in my Figma, has asset like this:
And my code is like this:
Widget buildArea(int index) => Card(
color: ColorName.brandSecondaryBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: Container(
padding: const EdgeInsets.only(top: 20, bottom: 20),
child: buildAreaItem(),
),
);
Anyone else who know how to add it?
May not be a clean way but try Using a Stack widget and use Positioned widget inside.
Here's a sample for what you are trying to achieve.
Scaffold(
body: Center(
child: Stack(
children: [
Container(
width: 300,
height: 150,
decoration: BoxDecoration(
color: Colors.indigo,
borderRadius: BorderRadius.circular(20)
),
),
Positioned(
left: -50,
top: -35,
child: Stack(
alignment: AlignmentDirectional.center,
children:
[
Container(
width: 150,
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100)
),),
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.indigo,
borderRadius: BorderRadius.circular(100)
),),
]
))
],
),
)
)
Try This Code:
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'dart:ui';
import 'package:google_fonts/google_fonts.dart';
import 'package:myapp/utils.dart';
class circlescreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
double baseWidth = 428;
double fem = MediaQuery.of(context).size.width / baseWidth;
double ffem = fem * 0.97;
return Container(
width: double.infinity,
child: Container(
// iphone13promax1auq (1:2)
width: double.infinity,
decoration: BoxDecoration (
color: Color(0xff3241a0),
borderRadius: BorderRadius.circular(20*fem),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
// ellipse1hmV (1:4)
margin: EdgeInsets.fromLTRB(0*fem, 0*fem, 237*fem, 272*fem),
width: 318*fem,
height: 318*fem,
decoration: BoxDecoration (
borderRadius: BorderRadius.circular(159*fem),
border: Border.all(color: Color(0xff3c4baf)),
),
),
Container(
// ellipse3jCP (1:6)
margin: EdgeInsets.fromLTRB(0*fem, 0*fem, 0*fem, 113*fem),
width: 198*fem,
height: 198*fem,
decoration: BoxDecoration (
borderRadius: BorderRadius.circular(99*fem),
border: Border.all(color: Color(0xff3c4baf)),
),
),
Container(
// ellipse2oi3 (1:5)
margin: EdgeInsets.fromLTRB(0*fem, 0*fem, 205*fem, 0*fem),
width: 318*fem,
height: 318*fem,
decoration: BoxDecoration (
borderRadius: BorderRadius.circular(159*fem),
border: Border.all(color: Color(0xff3c4baf)),
),
),
],
),
),
);
}
}
export your figma component with the just the background( purple with circles).
Then add that in assets and use it in the child of Card. So your widget tree would be :
Card
=>
Container( //with background decoration as image and necessary padding if any
)
=>
buildAreaItem()
You can also crop the image to get just the top corner ring or play with the fit property in DecorationImage widget.

How to set minWidth Container in Expand

I using flutter to build the Web Application,
I have a response problem, I want my window to be as small as 600 dp, and when zoomed horizontally, the middle container will automatically scale, but the smallest is 200 dp.
I tried to write the code as follows, but it doesn't work as I expected. When I shrink to width less than 600, main container keeps automatically shrink and shrink to less than 200 db.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
Expanded(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 20),
constraints: BoxConstraints(minWidth: 300),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(20)),
child: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
return state.widget;
}),
),
),
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
],
),
Have you tried using ConstrainedBox instead of regular Container?
It has properties minHeigth and minWidth / maxHeight and maxWidth.
I found that ConstrainedBox's minWidth is ignored in Row widget.
So I implemented center widget's dynamic width by using 'MediaQuery' like what you want.
But if you decrease width, the overflow issue is happened.
So I changed Row widget to ListView widget to fix overflow issue.
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) {
double centerWidth = MediaQuery.of(context).size.width - 480;
return ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(left: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
Container(
width: centerWidth < 300 ? 300 : centerWidth,
margin: EdgeInsets.symmetric(horizontal: 20),
constraints: BoxConstraints(minWidth: 150, ),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'Hello, World!',
style: Theme.of(context).textTheme.headline4,
),
),
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
],
);
}
}

Designing a Flutter button with image and text

If I just throw together an image and some text in a rounded-corner rectangle, the user will not know that they can "click here". But I don't have to bake my own solution. InkWell covers this scenario, complete with a nice shadow.
I am positioning
a custom clickable icon using the
InkWell
class, itself requiring to be inside an
Ink
instance.
import 'package:flutter/material.dart';
const boat_url = ('https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/'
'Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG/'
'182px-Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG');
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Image',
home: Scaffold(
backgroundColor: Colors.grey,
body: MyImage(),
)));
}
class MyImage extends StatelessWidget {
MyImage({Key key,});
#override
Widget build(BuildContext context) {
Size sz = MediaQuery.of(context).size * 0.4;
double border = 4;
return Stack(children: [
Positioned(
top: 100,
left: 100,
width: sz.width,
height: sz.height,
child: Material(
child: Ink(
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
new BoxShadow(
color: Colors.red,
blurRadius: 10.0,
offset: new Offset(30.0, 20.0),
),
],
border: Border.all(
color: Colors.blue,
width: border,
),
borderRadius: BorderRadius.circular(40),
),
child: InkWell(
onTap: (){/*..*/},
child: Column(
children: [
Container(
height: 4 * (sz.height - 2 * border) / 5,
alignment: Alignment.center,
child: Image.network(boat_url),
),
Container(
height: (sz.height - 2 * border) / 5,
child: FittedBox(
clipBehavior: Clip.antiAlias,
alignment: Alignment.centerLeft,
fit: BoxFit.fitHeight,
child: Text('A long descriptive sentence')),
)
],
)),
),
)),
]);
}
}
1- I'm not actually using Colors.white, and the Scaffold itself has
backgroundColor: Colors.grey. Where is the white background coming from?
2- When we talk of a "shadow", I'm expecting the shadow to be behind
the ink/inkwell object. Why does the shadow appear in front?
Related: 1
That white color is from the Material widget, to remove that you can use type param.
Material(
type: MaterialType.transparency,
child: Container(),
);
Here is code to achieve the custom button
Video link
Scaffold(
backgroundColor: Colors.blueGrey,
body: SafeArea(
child: Container(
decoration: BoxDecoration(
color: Colors.green.shade200,
border: Border.all(color: Colors.green),
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
blurRadius: 5,
spreadRadius: 2,
color: Colors.black26,
)
]),
margin: const EdgeInsets.all(20),
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {},
splashColor: Colors.black26,
child: IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Image.asset(
'assets/images/marked_tyre_base.png',
fit: BoxFit.cover,
width: 80,
height: 80,
),
const SizedBox(
height: 10,
),
Text(
'Tyre 1',
style: TextStyle(color: Colors.white),
)
]),
),
),
),
),
),
),
);
Screenshot:
Create a class, ImageTextButton:
class ImageTextButton extends StatelessWidget {
final VoidCallback onPressed;
final ImageProvider image;
final double imageHeight;
final double radius;
final Widget text;
ImageTextButton({
#required this.onPressed,
#required this.image,
this.imageHeight = 200,
this.radius = 28,
#required this.text,
});
#override
Widget build(BuildContext context) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: onPressed,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Ink.image(
image: image,
height: imageHeight,
fit: BoxFit.cover,
),
SizedBox(height: 6),
text,
SizedBox(height: 6),
],
),
),
);
}
}
Usage:
ImageTextButton(
onPressed: () {},
image: AssetImage('chocolate_image'),
text: Text('Chocolate'),
)

How to clip one container over another in flutter?

I want to build a reusable card widget, it will have an image and text with some custom design layout. I tried everything I could, but wasn't able to achieve the desired result. Any help would be much appreciated.
This is what I want to do
I'm stuck here
This is my code
class ReusabelCard extends StatelessWidget {
ReusabelCard(
{this.cardChild, #required this.assetImagePath, #required this.cardText});
final Widget cardChild;
final String assetImagePath;
final String cardText;
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.35,
width: MediaQuery.of(context).size.width * 0.5,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(MediaQuery.of(context).size.width * 0.5 * 0.28),
),
child: Stack(
children: [
LayoutBuilder(
builder: (context, contraint) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(
Icons.trip_origin,
size: contraint.biggest.width,
color: Colors.grey[300],
),
Container(
height: MediaQuery.of(context).size.height*0.05,
width: MediaQuery.of(context).size.width,
color: Colors.green,
),
],
);
},
),
],
)
);
}
}
Use ClipRRect to do it:
ClipRRect(
borderRadius: BorderRadius.circular(50.0), //clipping the whole widget
child: Container(
height: MediaQuery.of(context).size.height * 0.4, //I adjusted here for responsiveness problems on my device
width: MediaQuery.of(context).size.width * 0.5,
color: Colors.white,
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
children: [
Center(
child: Icon(
Icons.trip_origin,
size: constraint.biggest.width,
color: Colors.grey[300],
),
),
Positioned(
right: 0,
left: 0,
top: 20.0,
child: Icon(
Icons.sports_volleyball_rounded, //just to represent the ball
size: constraint.biggest.width * 0.5,
),
),
Positioned(
bottom: 0.0,
child: Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.1,
width: constraint.biggest.width,
color: Colors.yellow[700],
child: Text(
'Sports',
style: Theme.of(context)
.textTheme
.headline3
.copyWith(color: Colors.white),
),
),
),
],
);
},
),
),
);

Flutter multiple items in Row with Expanded/Flexible

I want to have more(in this example 4) items in Row. I tried use Expanded or Flexible or mainAxisAlignment: MainAxisAlignment.spaceEvenly to fill up all width of screen. But I want to heve items lets say specific width and height 50 pixels, and GestureDetector which is around item to be 1/4 of screen(4 items = full width). So everywhere I tap in the row something will be selected. My problem is that every my solution deforms items(circles) or circle must be very huge to width = height to not be deformed.
I also tried wrapping whole _ratingEmoji in Expanded and giving ratingItem.ratingIndicator constraints to max width but with same result.
Row of items:
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (var ratingItem in editGroceryRatingProvider.foodRatings)
_ratingEmoji(editGroceryRatingProvider, ratingItem, context),
],
),
Item:
Widget _ratingEmoji(EditGroceryRatingProvider editGroceryRatingProvider,
SelectedFoodRating ratingItem, BuildContext context) {
return GestureDetector(
child: ratingItem.selected
? Container(
width: MediaQuery.of(context).size.width / 8,
height: MediaQuery.of(context).size.width / 8,
padding: const EdgeInsets.all(2.0),
decoration: BoxDecoration(
border: Border.all(
color: Color(0xFF312ADB),
width: 3.0,
),
borderRadius: BorderRadius.circular(32.0)),
child: Center(
child: ratingItem.ratingIndicator,
),
)
: ratingItem.ratingIndicator,
onTap: () => editGroceryRatingProvider.updateSelectedRating(ratingItem),
);
}
RatingIndicator which is "circle" item to be on the screen:
Container(
decoration: BoxDecoration(
border: Border.all(
color: color,
width: 1.5,
),
borderRadius: BorderRadius.circular(64.0),
),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 3.0,
),
borderRadius: BorderRadius.circular(64.0),
),
child: ClipOval(
child: Container(
width: width ?? MediaQuery.of(context).size.width / 7,
height: height ?? MediaQuery.of(context).size.width / 7,
color: color,
),
),
),
);
Thanks a lot.
Update:
Items should stay as they are on screenshot, but "whole" row should be clickable(means even if you click between 2 items, one closer to click should be selected)
Check, please solution.
The whole area is clickable. You just need to add your item instead of mine.
#override
Widget build(BuildContext context) {
final colors = [Colors.red, Colors.blue, Colors.brown, Colors.cyan];
return Scaffold(
body: Container(
alignment: Alignment.center,
color: const Color(0xffFAFAFA),
child: Row(
children: List.generate(
colors.length,
(index) => Expanded(
child: GestureDetector(
onTap: () => print('Tapped:$index'),
child: Container(
height: 50,
color: Colors.transparent,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors[index],
),
),
)),
)),
),
),
);