Tap "under" SpriteWidget layer - dart

I would like to combine Flutter SpriteWidget with common app design like this:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
'assets/xyz.jpg',
fit: BoxFit.cover,
),
Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
centerTitle: true,
title: GestureDetector(
onTap: () { print('Tap'); },
child: Text(
'I want to tap this!',
),
),
),
),
assetsLoaded ? SpriteWidget(world) : Container(),
],
),
);
}
But SpriteWidget is overlapping everything and the GestureDetector does'nt work... Is there any solution to tap "under" the SpriteWidget layer? Or any workaround? Thanks!

You can ignore touches from any widget using the IgnorePointer widget.
IgnorePointer(child: SpriteWidget(world),)

Related

changing status bar color works for some pages only

am trying to change the status bar color of my app to dark
i have followed this How to change status bar color in Flutter?
and did this:
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
but for some reason it works only for some pages and the others will still be white!!
for example this page:
#override
Widget build(BuildContext context) {
final theme = Theme.of(context).copyWith(unselectedWidgetColor: Colors.red);
Animation opacityAnimation =
Tween(begin: 0.0, end: 1.0).animate(animationController);
return new Directionality(
textDirection: TextDirection.rtl,
child: new Theme(
data: theme,
child: new Scaffold(
key: scaffoldKey,
drawer: globals.drawer(context),
appBar: new AppBar(
leading: IconButton(
icon: Icon(
CustomFont.burger,
color: Color(0xff474747),
),
onPressed: () {
scaffoldKey.currentState.openDrawer();
},
),
centerTitle: true,
elevation: 0.0,
bottom: PreferredSize(
child: Container(
color: Color(0xff2CB57D),
height: 0.20,
),
preferredSize: Size.fromHeight(0.20)),
backgroundColor: Colors.white,
title: new Image.asset(
'assets/appbar-icon.png',
width: 55.0,
height: 27.0,
),
actions: <Widget>[
IconButton(
icon: Icon(
CustomFont.home,
color: Color(0xff474747),
),
onPressed: () {
globals.goToHome(context);
},
),
],
),
body: ......
),
);
}
the color of this page is always white no matter if i changed or not!
why is this happening? and how to solve it?

Flutter How to set Title to Show Modal Bottom Sheet?

Is there a possibility to set title and perhaps navigation back button on this showModalBottomSheet?
I expect something like this...
Yes it's possible to do something like that in Flutter. You can use Column Widget and make its first child as a title bar or something like that with title and back arrow icon.
Here's the code for that:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
canvasColor: Colors.transparent,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget{
#override
HomePageS createState()=> HomePageS();
}
class HomePageS extends State<MyHomePage>{
#override
Widget build(BuildContext context){
return Scaffold(
body: Container(
color: Colors.white,
child: Center(
child: FlatButton(
child: Text("Show BottomSheet"),
onPressed: () async{
showModalBottomSheet(
context: context,
builder: (BuildContext context){
return ClipRRect(
borderRadius: BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
child: Container(
color: Colors.white,
child: Column(
children: [
ListTile(
leading: Material(
color: Colors.transparent,
child: InkWell(
onTap: (){
Navigator.of(context).pop();
},
child: Icon(Icons.arrow_back) // the arrow back icon
),
),
title: Center(
child: Text("My Title") // Your desired title
)
),
]
)
)
);
}
);
}
)
)
)
);
}
}
Here is the output:
If you don't wanna use the InkWell widget, you can use the IconButton widget like this:
...
ListTile(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.of(context).pop();
}
),
title: Center(
child: Text("My Title")
)
),
...
But if you noticed, the title text is not really centered. In this case, we can replace the ListTile widget to a Stack widget and do something like this:
child: Column(
children: [
Stack(
children: [
Container(
width: double.infinity,
height: 56.0,
child: Center(
child: Text("My Title") // Your desired title
),
),
Positioned(
left: 0.0,
top: 0.0,
child: IconButton(
icon: Icon(Icons.arrow_back), // Your desired icon
onPressed: (){
Navigator.of(context).pop();
}
)
)
]
),
]
)
...
This is the output:
But what would happen if we have a very long text for our title? It would definitely look like this:
Ugly, right? We can see that our Text widget overlaps with our IconButton widget. To avoid this, we can replace our Stack widget with a Row widget.
Here's the code for that:
...
child: Column(
children: [
Row( // A Row widget
mainAxisAlignment: MainAxisAlignment.spaceBetween, // Free space will be equally divided and will be placed between the children.
children: [
IconButton( // A normal IconButton
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.of(context).pop();
}
),
Flexible( // A Flexible widget that will make its child flexible
child: Text(
"My Title is very very very very very very very long", // A very long text
overflow: TextOverflow.ellipsis, // handles overflowing of text
),
),
Opacity( // A Opacity widget
opacity: 0.0, // setting opacity to zero will make its child invisible
child: IconButton(
icon: Icon(Icons.clear), // some random icon
onPressed: null, // making the IconButton disabled
)
),
]
),
]
)
Output would be like this:
And this (if the title is not long):
I guess I have naive solution but this works perfectly for me. You might as well try it.
showModalBottomSheet(
barrierColor: Colors.transparent,
enableDrag: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
context: context,
builder:(context){
return Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0),
child: Stack(children: [
Padding(
padding: const EdgeInsets.only(top: 65),
child: SingleChildScrollView(
child:<<Scrollable Wdgets>>,
),
),
Card(
elevation: 3,
color: Colors.grey[850],
child: ListTile(
leading: Text("YOUR TITLE",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w500)),
trailing: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.close,
color: Colors.white,
size: 20,
),
),
),
),
]),
);}

Make AppBar transparent and show background image which is set to whole screen

I have added AppBar in my flutter application. My screen already have a background image, where i don't want to set appBar color or don't want set separate background image to appBar.
I want show same screen background image to appBar also.
I already tried by setting appBar color as transparent but it shows color like gray.
Example code:
appBar: new AppBar(
centerTitle: true,
// backgroundColor: Color(0xFF0077ED),
elevation: 0.0,
title: new Text(
"DASHBOARD",
style: const TextStyle(
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
fontFamily: "Roboto",
fontStyle: FontStyle.normal,
fontSize: 19.0
)),
)
This is supported by Scaffold now (in stable - v1.12.13+hotfix.5).
Set Scaffold extendBodyBehindAppBar to true,
Set AppBar elevation to 0 to get rid of shadow,
Set AppBar backgroundColor transparency as needed.
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.red,
appBar: AppBar(
// backgroundColor: Colors.transparent,
backgroundColor: Color(0x44000000),
elevation: 0,
title: Text("Title"),
),
body: Center(child: Text("Content")),
);
}
you can use Stack widget to do so. Follow below example.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
title: new Text(
"Hello World",
style: TextStyle(color: Colors.amber),
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: new Container(
color: Colors.red,
),
),
],
),
);
}
}
You can use Scaffold's property "extendBodyBehindAppBar: true"
Don't forget to wrap child with SafeArea
#Override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
extendBodyBehindAppBar: true,
body: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/background/home.png'),
fit: BoxFit.cover,
),
),
child: SafeArea(
child: Center(
child: Container(
width: 300,
height: 300,
decoration: BoxDecoration(
color: Colors.green,
),
child: Center(child: Text('Test')),
),
)),
),
);
}
None of these seem to work for me, mine went something like this:
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(color: Colors.white),
elevation: 0.0,
),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://images.unsplash.com/photo-1517030330234-94c4fb948ebc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1275&q=80'),
fit: BoxFit.cover,
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0),
child:
// Column of widgets here...
),
),
],
),
);
Output:
A lot of answers but nobody explains why extendBodyBehindAppBar works?
It works because when we assigned extendBodyBehindAppBar as true, then the body of the widget takes the height of AppBar, and we see an image covering the AppBar area.
Simple Example:
Size size = MediaQuery.of(context).size;
return Scaffold(
extendBodyBehindAppBar: true,
body: Container(
// height: size.height * 0.3,
child: Image.asset(
'shopping_assets/images/Fruits/pineapple.png',
fit: BoxFit.cover,
height: size.height * 0.4,
width: size.width,
),
),
);
There could be many cases, for example, do you want to keep the AppBar or not, whether or not you want to make the status bar visible, for that, you can wrap Scaffold.body in SafeArea and if you want AppBar to not have any shadow (unlike the red I provided in example 2), you can set its color to Colors.transparent:
Full image (without AppBar)
Scaffold(
extendBodyBehindAppBar: true,
body: SizedBox.expand(
child: Image.network(
'https://wallpaperaccess.com/full/3770388.jpg',
fit: BoxFit.cover,
),
),
)
Full image (with AppBar)
Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.red,
title: Text('MyApp'),
),
body: SizedBox.expand(
child: Image.network(
'https://wallpaperaccess.com/full/3770388.jpg',
fit: BoxFit.cover,
),
),
)
that's what I did and it's working
This is supported by Scaffold now (in stable - v1.12.13+hotfix.5).
Set Scaffold extendBodyBehindAppBar to true,
Set AppBar elevation to 0 to get rid of shadow,
Set AppBar backgroundColor transparency as needed.
Best regards
Scaffold(extendBodyBehindAppBar: true);
In my case I did it as follows:
Additional create an app bar with a custom back button (in this case with a FloatingActionButton). You can still add widgets inside the Stack.
class Home extends StatefulWidget {
#override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _HomeState extends State< Home > {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
this._backgroundImage(), // --> Background Image
Positioned( // --> App Bar
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: Padding( // --> Custom Back Button
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
backgroundColor: Colors.white,
mini: true,
onPressed: this._onBackPressed,
child: Icon(Icons.arrow_back, color: Colors.black),
),
),
),
),
// ------ Other Widgets ------
],
),
);
}
Widget _backgroundImage() {
return Container(
height: 272.0,
width: MediaQuery.of(context).size.width,
child: FadeInImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://images.unsplash.com/photo-1527555197883-98e27ca0c1ea?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80'),
placeholder: AssetImage('assetName'),
),
);
}
void _onBackPressed() {
Navigator.of(context).pop();
}
}
In the following link you can find more information Link
You can Try this This code work for me
#override
Widget build(BuildContext context) {
_buildContext = context;
sw = MediaQuery.of(context).size.width;
sh = MediaQuery.of(context).size.height;
return new Container(
child: new Stack(
children: <Widget>[
new Container(
child: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(image: backgroundImage),
),
],
),
),
new Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
title: new Text(Strings.page_register),
backgroundColor: Colors.transparent,
elevation: 0.0,
centerTitle: true,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20.0),
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: new Form(
key: _formKey,
autovalidate: _autoValidate,
child: FormUI(),
),
),
)
],
),
);
}
backgroundImage
DecorationImage backgroundImage = new DecorationImage(
image: new ExactAssetImage('assets/images/welcome_background.png'),
fit: BoxFit.cover,
);
use stack
set background image
Another Scaffold()
set background color transperant
set custom appbar
use column with singleChildScrollView or ListView
#override Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
backgroundBGContainer(),
Scaffold(
backgroundColor: Colors.transparent,
appBar: appBarWidgetCustomTitle(context: context, titleParam: ""),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
_spaceWdgt(),
Center(
child: Stack(
children: <Widget>[
new Image.asset(
"assets/images/user_icon.png",
width: 117,
height: 97,
),
],
),
),
Widget backgroundBGContainer() {
return Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/ground_bg_image.png"),
fit: BoxFit.cover,
),
color: MyColor().groundBackColor),
);
}
don't forget to set foregroundColor attribite to the desired color in order to make the navigation icon and the title visible
Note that the foregroundColor default value is white.

Fading Edge ListView - Flutter

has anyone come across something like fadingEdgeLength in Android for Flutter so that when you scroll up items start fading into the top of the screen?
Below is my interface built up of the Widgets.
If it helps these are the properties I'm referring to:
android:fadingEdgeLength="10dp"
android:requiresFadingEdge="horizontal">
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CMS Users'),
),
body: ListView.builder(
padding: EdgeInsets.only(top: 20.0, left: 4.0),
itemExtent: 70.0,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 10.0,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new PeopleDetails("Profile Page", profiles[index]),
));
},
child: ListTile(
leading: CircleAvatar(
child: Text(profiles[index].getInitials()),
backgroundColor: Colors.deepPurple,
radius: 30.0,
),
title: Text(
data[index]["firstname"] + "." + data[index]["lastname"]),
subtitle: Text(
data[index]["email"] + "\n" + data[index]["phonenumber"]),
),
),
);
}),
);
}
}
As others have mentioned, you can put the ListView under a ShaderMask, but with minor extra parameterizations you can get much better results - at least if you want to achieve what I wanted.
Optionally you can set the [stops] list for the LinearGradient:
The [stops] list, if specified, must have the same length as [colors]. It specifies fractions of the vector from start to end, between 0.0 and 1.0, for each color.
Plus: There are blend modes, where the color channels of the source are ignored, only the opacity has an effect. BlendMode.dstOut is also such in the example below. As you can see in the screenshot, the purple color is not used concretely, only for the fractions of the vector.
You can play with the different [blendMode] settings, there are quite a few of them.
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: FadingListViewWidget(),
),
),
);
}
class FadingListViewWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 320,
child: ShaderMask(
shaderCallback: (Rect rect) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.purple, Colors.transparent, Colors.transparent, Colors.purple],
stops: [0.0, 0.1, 0.9, 1.0], // 10% purple, 80% transparent, 10% purple
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Colors.orangeAccent,
child: ListTile(
title: Text('test test test test test test'),
),
);
},
),
),
),
);
}
}
You could apply a ShaderMask on top of ListView and use BlendMode to get what you want.
Widget animationsList() {
return Expanded(
child: ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[Colors.transparent,Colors.red],
).createShader(bounds);
},
child: Container(height: 200.0, width: 200.0, color: Colors.blue,),
blendMode: BlendMode.dstATop,
),
);
I had similar request so I created a library for this task.
You can find it here: fading_edge_scrollview
To use it you need to add a ScrollController to your ListView and then pass this ListView as child to FadingEdgeScrollView.fromScrollView constructor
Wrap the Listview with Stack, add the Listview as the first child, the second is Positioned Container with LinearGradient.
Sample from my code:
Stack:
return Stack(
children: <Widget>[
ListView(
scrollDirection: Axis.horizontal,
children: _myListOrderByDate,
),
FadeEndListview(),
],
);
The overlay class:
class FadeEndListview extends StatelessWidget {
const FadeEndListview({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Positioned(
right: 0,
width: 8.0,
height: kYoutubeThumbnailsHeight,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.centerLeft,
stops: [0.0, 1.0],
colors: [
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.0),
],
),
),
),
);
}
}
And it will look something like this:
Try to use
Text(
'This is big text, I am using Flutter and trying to fade text',
overflow: TextOverflow.fade,
maxLines: 1,
),

Flutter Overlapped InkWells Gesture Detection

While working on an application, we have an instance where we want a card to have an inkwell as well as a button on the card (also with an inkwell). However, I have been unable to determine a way to separate the gestures such that only the inkwell directly under the user's tap is invoked. As it is today, it appears that the tap 'bleeds through' to the next inkwell such that both splash effects are invoked. This is undesirable behavior, the application appears to be selecting the card not the invokable item on the card (note: actual application is much different but the same issue is present). I have reproduced this in a simple application to demonstrate the bleed through when the user pressed the button in the bottom right of the card. Is there something I am missing which can prevent this behavior? Thanks
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Card(
color: Colors.blue,
child: InkWell(
onTap: () { },
child: Container(
height: 150.0,
child: Align(
alignment: Alignment.bottomRight,
child: RaisedButton(
color: Colors.red,
onPressed: () { },
),
),
),
),
),
);
}
}
This is the normal expected InkWell behavior as most of the time you want to use it's tap feature for every widget in it's tree. So what you can do is to define a Stack and set the button in the z-axis absolute over the InkWell:
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
child: Card(
color: Colors.blue,
child: Stack(
children: <Widget>[
InkWell(
onTap: () {
print("inkwell");
},
child: Container(
height: 150.0,
),
),
RaisedButton(
color: Colors.red,
onPressed: () {
print("button");
},
),
],
),
),
),
);
}
If you would want to set the button in the bottom right corner again you can set a Row and Colum around it and assign it's alignment:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
child: Container(
height: 150.0,
child: Card(
color: Colors.blue,
child: Stack(
children: <Widget>[
InkWell(
onTap: () {
print("inkwell");
},
child: Container(
height: 150.0,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
RaisedButton(
color: Colors.red,
onPressed: () {
print("button");
},
),
],
),
],
),
],
),
),
),
),
);
}
Upper code would result in seperated widgets:

Resources