I have two scaffold widget in the stack for some purposes .. And every scaffold has its own contents .
the second scaffold has transparent background colors so the first scaffold is visible.
Stack(
children: [
Scaffold(
body: GestureDetector(
onTap: () {},
child: myBody(),
),
),
Scaffold(
backgroundColor: Colors.transparent,
body: ListView.builder(
itemBuilder: (context, index) => ...,
),
)
],
),
the GestureDetector in first Scaffolddoes not work and that's because of the Scaffold stack
Note : I can't wrap the second Scaffold with IgnorePointer because it has clickable ListView.bulder which gonna be ignoring any pointer too
How could I solve this ×_O
You can get callback method from second scaffold list item tap. And create a function on level that will be provided on first scaffold GestureDetector.
void main(List<String> args) {
Widget myBody() {
return Container(
color: Colors.cyanAccent.withOpacity(.3),
);
}
void topLevelGesture() {
debugPrint("got hit on GestureDetector");
}
runApp(
MaterialApp(
home: Stack(
children: [
Scaffold(
body: GestureDetector(
onTap: topLevelGesture,
child: myBody(),
),
),
Scaffold(
backgroundColor: Colors.transparent,
body: ListView.builder(
itemBuilder: (context, index) => ListTile(
title: Text("item $index"),
onTap: () {
topLevelGesture();
print("tapped $index");
},
),
),
),
],
),
),
);
}
You can set Gesture as outside of the stack and with this inner list click also works but when you put the first Scaffold body as a clickable it's not working because the second Scaffold overlay that.
GestureDetector(
onTap(){}
child:Stack(
children[
Scaffold(
body: myBody()
)
Scaffold(
backGroundColor: Colors.transparent
body: ListView.bulder(){....}
)
]
))
You need to add clickable widget at the end in your stack widget as below:
Stack(
children[
firstWidget(),
GestureDetector(
onTap(){},
child: secondWidget()
)
]
)
Related
I've tried a lot to make a list scrollable, but it never worked.
Everytime I wrapped it in a SingleChildScrollView my list just disappeared.
Can someone help pls
Here is my code:
return Scaffold(
body:
SingleChildScrollView(
child: ListView.builder(
itemCount: subjects.length,
itemBuilder: (context, i) {
return singleSubject(
subjects[i],
() => deleteItem(i),
);
},
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: const Color(0xFF383838),
onPressed: newSubject,
child: const Icon(Icons.add),
),
backgroundColor: const Color(0xFFB94844),
);
}
}
You dont need to use SingleChildScrollView while ListView is the only child on body.
Do
body: ListView.builder(
Find more about widgets/scrolling
So I have a drawer and I can open it with the hamburger icon on top-left corner. If I change the screen to another page, this hamburger icon become a back button (<--). How to make this into a hamburger icon again? (So no back button but open the drawer on every screen)
In App Bar of next page put
leading: BurgerIcon(),
The Burger icon is from having a Drawer on your Scaffold.
If your next page/route has a Scaffold with a drawer: specified, you'll get the "burger" icon button again.
Without a drawer: specified on Scaffold Flutter will default to the back arrow to go to the previous route.
Here's an example:
import 'package:flutter/material.dart';
class DrawerDirectoryPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Drawer Directories'),
),
body: Center(
child: InkWell(
child: Text('Page One. Click to go to Page Two.'),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (context) => PageTwo())
),
),
),
drawer: MyDrawerDirectory(),
);
}
}
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Burger Time!'),
),
body: Center(
child: Text('Page TWO /flex'),
),
drawer: MyDrawerDirectory(), // ← Drawer Directory a.k.a. burger icon
);
}
}
class MyDrawerDirectory extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
ListTile(title: Text('Page One'), onTap: () => _navPush(context, DrawerDirectoryPage())),
ListTile(title: Text('Page Two'), onTap: () => _navPush(context, PageTwo()))
],
),
);
}
Future<dynamic> _navPush(BuildContext context, Widget page) {
return Navigator.push(context, MaterialPageRoute(
builder: (context) => page,
));
}
}
In the AppBar widget, you can specify a leading widget. After you specify a leading widget (in your case, an Icon Button), you should set AppBar's automaticallyImplyLeading = false.
If you use the methods Navigator.of(context).push or Navigator.of(context).pushNamed you will also experience this issue.
You can use other method to navigate between screens so it doesn't show the hamburger button
Put automaticallyImplyLeading: false in appBar of next page then set leading icon like this:
automaticallyImplyLeading: false,
leading: Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {
if (scaffoldKey.currentState.isDrawerOpen) {
Navigator.of(context).pop();
} else {
scaffoldKey.currentState.openDrawer();
}
},
child: Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Icon(
Icons.menu,
size: 30,
color: appColor,
),
),
),
),
I have a problem when I want to fill a TextView and the keyboard shows up, the scaffold is squeezing to the left.
Anybody have a clue about that ?
This is my code:
#override
Widget build(BuildContext context) {
final authentCubit = context.watch<AuthentificationCubit>();
final UserRepository user = UserRepository();
print(user.getUserName());
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: Column(
children: <Widget>[
ElevatedButton(
child: Text('Deconnexion'),
onPressed: () {
authentCubit.signOut();
},
),
ElevatedButton(
child: Text('Formulaire contact'),
onPressed: () {
showDialog(context: context,builder: (context)=> ContactForm());
},
),
TextField(),
],
),
),
);
}
}
This is a screen of my problem
Thank you
Had two scaffold in my tree, this is why "resizeToAvoidBottomPadding: false," wasn't working.
Is there a way to show widgets (for example a SliverToBoxAdapter or a normal Container) underneath a SliverChildBuilderDelegate? I have a condition that turns on the SliverList and there can only be one parent widget for a condition, what would I need to wrap it in?
Code currently looks like:
lass Testaaa extends StatelessWidget {
final bool hasData;
const Testaaa({Key key, this.hasData}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: DrawerSettings(),
body: Container(
child: CustomScrollView(
slivers: <Widget>[
AppBarSliver(),
hasData
? SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
return ListTile(
title: Text('cool'),
);
},
),
) // I would like to put another Container here that
// scrolls with the bottom, underneath the SliverList
: Container(
child: Text('no data'),
),
],
),
),
);
}
seems like a work for the spread operator
CustomScrollView(
slivers: <Widget>[
AppBarSliver(),
...hasData
? <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
return ListTile(
title: Text('cool'),
);
},
),
),
const SliverToBoxAdapter(
child: SizedBox(
child: Text('End of the list'),
),
),
]
: <Widget>[
const SliverToBoxAdapter(
child: SizedBox(
child: Text('no data'),
),
)
]
],
)
This way you're telling if hasData is true add all this widgets in the brackets (SliverList and SliverToBoxAdapter with Text 'End of the list') if false add all this other widgets (which is only a SliverToBoxAdapter)
I have a Scaffold with a simple Drawer in which I show a menu where a user can press a button. When this button is pressed I want to display a SnackBar, but the SnackBar is always displayed behind the Drawer. Is there some way to show it in front of the Drawer?
The drawer's code looks like:
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.lock_open),
title: Text('Click Me'),
onTap: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
'Test.',
)));
},
),
],
),
);
}
}
and it is used directly in the Scaffold:
return Scaffold(
drawer: MyDrawer(),
[...]
They said Drawer must be on the top of UI under MaterialDesign rules. But if you wanna such behaviour too much you can write own SnackBar.
static void showSnackBarAsBottomSheet(BuildContext context, String message)
{
showModalBottomSheet<void>(
context: context,
barrierColor: const Color.fromRGBO(0, 0, 0, 0),
builder: (BuildContext context) {
Future.delayed(const Duration(seconds: 5), () {
try {
Navigator.pop(context);
} on Exception {}
});
return Container(
color: Colors.grey.shade800,
padding: const EdgeInsets.all(12),
child: Wrap(children: [
Text(
message,
style:
GoogleFonts.robotoCondensed().copyWith(color: Colors.white),
)
]));
},
);
}
I've solved it by adding one more Scaffold inside Drawer and making its background transparent:
return Scaffold(
drawer: Scaffold(
backgroundColor: Colors.transparent,
body: MyDrawer(),
[...]