Flutter shadow over other widgets - android

My base widget is a Column. The first element is a Container which has a BoxShadow. The second element is a ListView which builds several Card, depending on the context. If the scroll is 0 the shadow gets displayed. However when start scrolling, the card is "over" the shadow (higher z-index) and hides it.
unscrolled
scrolled
The shadow should stay always on top, over the Cards. How is this done?

EDIT
if you don't want container shadow to disappear on scroll remove the ScrollNotification and NotificationListener
There is a widget for that 😉
You can use ScrollNotification with NotificationListener. Try this;
Happy coding! 🤓
class TestPage extends StatefulWidget {
const TestPage({Key key}) : super(key: key);
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
double blurRadius = 10.0;
double spreadRadius = 1.0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
title: Text('Title'),
),
body: Container(
width: Get.width,
height: Get.height,
child: Stack(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0).copyWith(
top: 62.0,
),
child: NotificationListener<ScrollNotification>(
// ignore: missing_return
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification) {
setState(() {
blurRadius = 0.0;
spreadRadius = 0.0;
});
} else if (scrollNotification is ScrollEndNotification) {
setState(() {
blurRadius = 10.0;
spreadRadius = 1.0;
});
}
},
child: ListView.builder(
// controller: _controller,
itemCount: 10,
itemBuilder: (context, index) {
return Card(
child: Container(
width: Get.width * .8,
height: 100.0,
child: Center(
child: Text('child # index : $index'),
)),
);
},
),
),
),
Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
width: Get.width,
height: 60.0,
margin: EdgeInsets.only(),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20.0),
bottomRight: Radius.circular(20.0),
),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: blurRadius,
spreadRadius: spreadRadius,
),
],
),
child: Center(
child: Text('TOP CONTAINER'),
),
),
),
],
),
),
);
}
}

According to your question, here is the concept of what is going wrong here.
The 1st child of Column is a Container with shadow. Shadow renders outside of the defined size. If you don't provide any spaces after this Container we won't be able to see the shadow. This space can be done by Container margin , SizedBox or wrapping our list with Padding. But now our main question is how we get shadow while index=0. I believe it is coming from ListChildren`. They contain upper spaces, that's why we can see only the 1st time.
On Ui render priority starts from bottom to Top.
How to solve this problem:
We can provide space at the bottom of our container or assign margin(not padding), or use a SizedBox after the container providing the same amount of height as shadow.
providing bottom margin on the container.
adding a SizedBox with height of shadow.
wrapping our list with Padding and providing top:.
In this image,
our shadow: white, background:amber.
Demo code:
import 'package:flutter/material.dart';
class ColumnWithContainerShadow extends StatelessWidget {
const ColumnWithContainerShadow({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber,
body: Column(
children: [
Container(
height: 50,
width: double.infinity,
////* we dont need margin if we have padding on ListView
// margin: EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.green,
boxShadow: [
BoxShadow(
offset: Offset(0, 12),
color: Colors.white,
)
],
),
child: Center(child: Text("Container A")),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 12),
child: ListView(
children: [
...List.generate(
333,
(index) => Container(
/// enable this margine and remove other spaces to see 1st child shadow.(shadow depend on children position)
// margin: EdgeInsets.only(top: 12),
height: 60,
color: Colors.deepPurple,
child: Text("$index"),
),
)
],
),
),
),
Container(
height: 50,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.green,
boxShadow: [
BoxShadow(
offset: Offset(0, 12),
color: Colors.white,
)
],
),
child: Text("Bottom Container"),
),
// Comment to close shadow
SizedBox(
height: 20,
)
],
),
);
}
}

Wrap this upper box in Material widget and provide an elevation.

Related

FLUTTER - A RenderFlex overflowed by 126 pixels on the right

please help me, i have a errpr in my code like this , "A RenderFlex overflowed by 126 pixels on the right". and this is my code.
I've searched the internet that most solutions use flexible, but I'm still confused where to place it. I want when the text increases, the height of the box also increases
ListView.builder(
itemCount: 5,
padding: EdgeInsets.only(left: 16, right: 16),
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
height: 76,
margin: EdgeInsets.only(bottom: 13),
padding:
EdgeInsets.only(left: 24, top: 12, bottom: 12, right: 22),
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 50,
color: kPrimaryColor.withOpacity(0.23))
]),
child: Row(
children: <Widget>[
Row(
children: <Widget>[
Container(
height: 57,
width: 57,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage(
"assets/images/image_1.png"))),
),
SizedBox(
width: 13,
),
Text(
"testing123451 testing123451 testing123451 testing123451",
),
],
)
],
),
);
})
please give me the solution, thank you
At first remove row's parent Row widget and wrap Text widget with Expanded.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return ListView.builder(
itemCount: 5,
padding: EdgeInsets.only(left: 16, right: 16),
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
// height: 76,
margin: EdgeInsets.only(bottom: 13),
padding: EdgeInsets.only(left: 24, top: 12, bottom: 12, right: 22),
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 50,
color: Colors.blue.withOpacity(0.23))
]),
child: Row(
children: <Widget>[
Container(
height: 57,
width: 57,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage("assets/images/image_1.png"))),
),
SizedBox(
width: 13,
),
Expanded(
child: Text(
"testing123451 testing123451 testing123451 testing123451",
),
),
],
),
);
});
}
}
You could use the Expanded widget and wrap it around the Text widget, like this:
Expanded(
child: Text(
"testing123451 testing123451 testing123451 testing123451"
)
),

Change color of cupertino scrollbar in flutter

I need to change color of cupertino scrollbar, but I can't do that via normal constructor. Is there any way to make scrollbar white?
CupertinoScrollbar(
thickness: 5,
controller: scrollController,
thicknessWhileDragging: 8,
//color not exist
)
The CupertinoScrollBar is hardcoded so on iOS you can't change the color, but you can use highlightColor for the ThemeData. The Color will then displayed on Android only.
MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
//main color
primaryColor: const Color(0xffFFC600),
//main font
fontFamily: 'Roboto-Medium',
//swatch stretching
primarySwatch: goldenThemeColor,
visualDensity: VisualDensity.adaptivePlatformDensity,
splashColor: const Color(0xffFFC600),
//color for scrollbar
highlightColor: Color(0xffffc600)
),
import 'package:flutter/material.dart';
class LandingPage extends StatefulWidget {
LandingPage({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _LandingPageState();
}
}
class _LandingPageState extends State<LandingPage> {
ScrollController _controller;
double _offset = 0;
#override
void initState() {
_controller = ScrollController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Container(
child: SingleChildScrollView(
controller: _controller,
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.black,
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.red,
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.green,
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.blue,
),
],
),
),
),
//Scroll bar
Container(
alignment: Alignment.centerRight,
height: MediaQuery.of(context).size.height,
width: 20.0,
margin: EdgeInsets.only(left: MediaQuery.of(context).size.width - 20.0),
decoration: BoxDecoration(color: Colors.black12),
child: Container(
alignment: Alignment.topCenter,
child: GestureDetector(
child: Container(
height: 40.0,
width: 15.0,
margin:
EdgeInsets.only(left: 5.0, right: 5.0, top: _offset),
decoration: BoxDecoration(
color: Colors.grey, //Change Color here
borderRadius: BorderRadius.all(Radius.circular(3.0))),
),
onVerticalDragUpdate: (dragUpdate) {
_controller.position.moveTo(dragUpdate.globalPosition.dy * 3.5);
setState(() {
if(dragUpdate.globalPosition.dy >= 0) {
_offset = dragUpdate.globalPosition.dy;
}
print("View offset ${_controller.offset} scroll-bar offset ${_offset}");
});
},
),
)
),
],
),
);
}
}

How to make a transparent container stand out from the background?

I'm trying to make my containers transparent and still want them to easily standout from the background color, just like below image. (this is PSD image)
Desired Layout
I tried wrapping Container inside a Material widget like this:
class customBar extends StatelessWidget {
const customBar({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
elevation: 2,
borderRadius: BorderRadius.circular(10),
child: Container(
width: double.infinity,
height: 65,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
//color: Color(0xff0a4873),
),
child: Text(
'',
textAlign: TextAlign.left,
),
),
);
}
}
but it gives it too much elevation
also tried using a solid color but that doesn't give me what is required either,
Expanded(
flex: 4,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
customBar(),
Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xff0a4873),
),
child: Text(
'',
textAlign: TextAlign.left,
),
),
],
),
),
),
here is the output:
Output
Material is not necessary. If you want to adjust color transparency either use Colors.YOUR_COLOR.withOpacity(0.0 .. to .. 1.0) or Color.fromRGBO(RED, BLUE, GREEN, 0.0 .. to .. 1.0)
Examples:
Colors.blue.withOpacity(0.3);
// OR
Color.fromRGBO(50, 45, 220, 0.3);
Edit
You can simplify your layout like this.
HomePage
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomContainer(
child: Column(
children: [
// other widgets and your containers here
],
),
),
);
}
}
Your CustomContainer Widget
class CustomContainer extends StatelessWidget {
final Widget child;
CustomContainer({this.child});
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomLeft,
colors: [
Color(0xFF1187be),
Color(0xff061465),
],
),
),
child: child,
);
}
}

Flutter - Adding Container (widget) in GridView when click a button?

I wanted to add a container widget in the GridView when a button is clicked. I was able to do this with the column widget but could not do it with GridView.
import 'package:flutter/material.dart';
List<Widget> gridChild = [
Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
),
Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
),
Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
),
Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
),
Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
),
];
class Grid extends StatefulWidget {
#override
_GridState createState() => _GridState();
}
class _GridState extends State<Grid> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
child: Icon(Icons.add),
onPressed: () {
setState(() {
gridChild.add(Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
));
print(gridChild.length);
});
},
),
body: Container(
child: GridView.count(
crossAxisCount: 2,
children: gridChild,
),
),
);
}
}
What I did was that I added a container in the widget list. The length of the list increases as I click the botton but the container was not added on the screen. It didn't work even though I put the function inside the setState().
I would really appreciate your help.
This works...
class Grid extends StatefulWidget {
#override
_GridState createState() => _GridState();
}
class _GridState extends State<Grid> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
child: Icon(Icons.add),
onPressed: () {
setState(() {
gridChild.add(Container(
margin: EdgeInsets.all(8.0),
width: 30.0,
height: 50.0,
color: Colors.green,
));
});
},
),
body: Container(
child: GridView.count(
crossAxisCount: 2,
children: List.generate(gridChild.length, (index) => gridChild[index]),
),
),
);
}
}
Output:
Use GridView.builder in the body. It should fix your problem. I don't really know why, but I know it works. Hopefully someone can update this answer and provide an explanation.
GridView.builder(
itemCount: gridChild.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemBuilder: (BuildContext context, int index){
return gridChild[index];
},
),
You can do it by calling the setstate method.
while clicking on the button just add a widget to the list and use the setstate after adding to the list. Basically setstate will rebuild the screen.

Remove extra part after clipping in Flutter

Clipping allows me to draw only the part which I want to show. How do I remove the extra part which is not drawn but still takes up space?
The code
import 'package:flutter/material.dart';
class ClipTut extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children: <Widget>[
ClipRect(
clipper: CustomRect(),
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 4, color: Colors.black),
color: Colors.blue,
),
width: 200.0,
height: 200.0,
),
),
Container(
height: 200,
width: 100,
decoration: BoxDecoration(
border: Border.all(width: 4, color: Colors.black),
color: Colors.green,
),
)
],
),
),
);
}
}
class CustomRect extends CustomClipper<Rect> {
#override
Rect getClip(Size size) => Rect.fromLTRB(0, 0.0, size.width/2, size.height);
#override
bool shouldReclip(CustomRect oldClipper) => true;
}
My Solution
I had a similar problem recently (I needed to clip the image in half) and found this sample code on the flutter api site (use the other alignment points to change slicing behaviors) - no extra space left over:
ClipRect(
child: Align(
alignment: Alignment.topCenter,
heightFactor: 0.5,
child: Image.network(userAvatarUrl),
),
)

Categories

Resources