I want to create a line without any shadow and gradient.
I try to create a simple Container with color, as below:
https://dartpad.dev/?id=72468c06f2cab2d4025c0842828f3907
return Container(
height: 200,
width: 100,
color: Colors.white,
child: Center(
child: Container(
height: 3,
color: Colors.red,
),
),
);
But I got the result as this:
After zooming in, we see that it contains a gradient to the background color:
What should I do to create a completely pure line, without any shadows or gradients?
I've tried the clipBehavior property and all 4 values have the same result.
you can use container's clipBehavior property to achieve this as described in this official documentation.
https://api.flutter.dev/flutter/dart-ui/Clip.html
you can use following properties.
hardEdge, which is a little faster, but with lower fidelity.
antiAliasWithSaveLayer, which is much slower, but can avoid the
bleeding edges if there's no other way.
Paint.isAntiAlias, which is the anti-aliasing switch for general draw operations.
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 200,
width: 100,
color: Colors.white,
child: Center(
child: Container(
clipBehavior: Clip.hardEdge, //<-- this property
height: 3,
decoration: BoxDecoration(
color: Colors.red,
),
),
),
);
}
}
Output:
working: https://ibb.co/PZR1XkF
Related
everyone.
(A)The code below stretches the text as much as possible vertically (and horizontally) within the range of 300*300.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Animated Icons',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(),
body:
Container(
color:Colors.blue,
width:300.0,
height:300.0,
child:
FittedBox(
fit: BoxFit.fill,
child: Text(
'Some Example Text.',
style: TextStyle(
fontSize: 20.0,
),
),
),
),
);
}
}
(B)On the other hand, the code below does not stretch the text.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(),
body:
// Container(
// color:Colors.blue,
// width:300.0,
// height:300.0,
// child:
FittedBox(
fit: BoxFit.fill,
child: Text(
'Some Example Text.',
style: TextStyle(
fontSize: 20.0,
),
),
),
// ),
);
}
}
Why is this?
My understanding at this point is that in code (B), the constraint passed from the parent to the FittedBox is the screen size (minus the size of the AppBar), so I expected the text to be stretched across the entire screen except for the AppBar.
However, the actual result is very different.
Why is that?
Are there any points to consider that I'm missing?
Even if I ask "Why?", I actually got such results, so if I just use the framework, I have no choice but to accept it.
FittedBox scales its child within itself but the Widget itself tries to be as small as possible. You almost get it right except for what the actual constraints are. Scaffold "loosens" the constraints in its body. For better understanding this are the actual constraints in the examples you used.
Case A:
BoxConstraints(
minHeight: 300,
minWidth: 300,
maxHeight: 300,
maxWidth: 300,
);
Case B:
BoxConstraints(
minHeight: 0,
minWidth: 0,
maxHeight: 600,
maxWidth: 340,
);
As you can see, in case B, the minimum size is 0 so the FittedBox does not have a minimum size defined hence it will be the size of its child. BoxFit does not alter the size of the FittedBox, only the size of its content.
You can see the constraints passed down the next Widget using LayoutBuilder like this:
Scaffold(
appBar: AppBar(),
body: LayoutBuilder(
builder: (context, constraints) {
//You can print the constraints like this
debugPrint(constraints.minHeight.toString());
return const FittedBox(
fit: BoxFit.fill,
child: Text('Example'),
);
},
),
);
How to achieve this dual-curved layout on Flutter? double.infinity for height and width. Never mind about the Text and color, any color will do. Thank you :)
You can use a Column with two Flexible widgets, both of them containing a Stack as a child, and two Container widgets in each. This way the containers will be on top of each other, and one of them can have a decoration with rounded corners:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(body: MyWidget()),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(children: [
Flexible(
flex: 1,
child: Stack(children: [
Container(
color: Colors.blue,
),
Container(
decoration: const BoxDecoration(
borderRadius:
BorderRadius.only(bottomRight: Radius.circular(100)),
color: Colors.yellow,
))
])),
Flexible(
flex: 3,
child: Stack(children: [
Container(
color: Colors.yellow,
),
Container(
decoration: const BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(topLeft: Radius.circular(100)),
))
]),
)
]);
}
}
The result will be like this:
Thank you for your answer #Peter Koltai you answered perfectly correct. Thank you
I want to create a widget similar to CircleAvatar, but not rounded.
This is CircleAvatar:
And this is the avatar I want to create:
I want to know if there is a default widget to do this, as CircleAvatar for rounded avatars.
There are so many ways to achieve it but I will only make use one.
Wrap a ClipRRect() widget around a child widget(this could be an image or any other relevant widget like a Container used in my example). Then, pass BorderRadius.circular(20.0) value to borderRadiusproperty of ClipRRect(). That is the active lines of code that create the effect.
Check below for my example:
ClipRRect(
borderRadius: BorderRadius.circular(20.0),//or 15.0
child: Container(
height: 70.0,
width: 70.0,
color: Color(0xffFF0E58),
child: Icon(Icons.volume_up, color: Colors.white, size: 50.0),
),
),
see result here
You can use ClipRRect with specified BorderRadius property like this:
see image here
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10.0)),//add border radius here
child: Image.asset('assets/01.jpg'),//add image location here
),
You can use the combination of ClipRRect and Container Widget to achieve the same, use the above code given.
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 ClipRRect(
borderRadius: BorderRadius.circular(15.0),//or 15.0
child: Container(
height: 70.0,
width: 70.0,
color: const Color(0xffFF0E58),
child: const Icon(Icons.volume_up, color: Colors.white, size: 50.0),
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Listview Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: ListWidget(),
),
);
}
}
class ListWidget extends StatelessWidget {
const ListWidget({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
return ListView(
children: <Widget>[
Container(
width: width,
height: height,
color: Colors.black,
),
Container(
width: width,
height: height,
color: Colors.black,
),
Container(
width: width,
height: height,
color: Colors.black,
),
Container(
width: width,
height: height,
color: Colors.black,
),
],
);
}
}
When I run the above code in emulator, sometimes there is a thin white line appearing between two containers as shown below.
This happens almost always and is much more noticeable when I build the app for the web and runs on chrome.
Even the production build has these lines.
I am unable to figure out what is happening, I even tried replacing ListView with a SingleChildScrollView with child as a Column. But its still the same.
I want to display a "Close keyboard" button above the keyboard when it is visible.
I know that the resizeToAvoidBottomInset can impact how the keyboard interact with the rest of the application, however it doesn't do exactly what I want.
I have a background image and others widgets (not shown in the sample below) which should not be resized and not moved when the keyboards is shown. This is an ok behavior when the resizeToAvoidBottomInset attribute is set to false.
However, I would like to add a button which should appear above the keyboard.
How can I do that? I only want one widget floating above the keyboard, not all the app.
Here is a sample code :
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _getBody() {
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
}
Your Positioned widget has a bottom of 0, replacing with an appropriate value should do the job.
MediaQuery.of(context).viewInsets.bottom will give you the value of the height covered by the system UI(in this case the keyboard).
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _getBody() {
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: MediaQuery.of(context).viewInsets.bottom,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
}
2022 Update
A PR was merged that provides platform-synchronized animations for closing/opening the keyboard. See the PR in effect here.
Detailed Answer
To achieve keyboard-visibility-based animated padding, here are a few modifications over #10101010's great answer:
If you want the bottom change when keyboard changes visibility to be animated AND you want extra padding under your floating child then:
1- Use keyboard_visibility flutter pub
To listen when keyboard is appearing/disappearing, like so:
bool isKeyboardVisible = false;
#override
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
isKeyboardVisible = visible;
},
);
}
Optionally you can write your own native plugins, but it's already there you can check the pub's git repo.
2- Consume visibility flag in your AnimatedPostioned:
For fine-tuned animated padding, like so:
Widget _getBody() {
double bottomPadding = 0;
if (isKeyboardVisible) {
// when keyboard is shown, our floating widget is above the keyboard and its accessories by `16`
bottomPadding = MediaQuery.of(context).viewInsets.bottom + 16;
} else {
// when keyboard is hidden, we should have default spacing
bottomPadding = 48; // MediaQuery.of(context).size.height * 0.15;
}
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
AnimatedPositioned(
duration: Duration(milliseconds: 500),
bottom: bottomPadding,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
3- Keyboard-specific animation curve and duration for synchronized animation
For now this is still an known ongoing issue
You can use the bottomSheet of a Scaffold widget.
Example:
return Scaffold(
appBar: AppBar(
title: const Text("New Game"),
),
bottomSheet: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
color: Colors.blue,
child: const SizedBox(
width: double.infinity,
height: 20,
child: Text("Above Keyboard"),
))
...
)
You can use bottomSheet parameter of the Scaffold, which keep a persistent bottom sheet. See below code.
class InputScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Close')),
bottomSheet: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
color: Colors.black,
child: const SizedBox(width: double.infinity, height: 10)),
body: Column(
children: [
const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter your input here',
),
),
ElevatedButton(
onPressed: () {},
child: const Text('Submit'),
),
],
),
);
}
}
check this package, it can show a dismiss button above the keyboard.