Flutter: Material Widget And SingleChildScrollView Render Conflict Inside Drawer - flutter

This problem only happens inside Drawer
I wanted to shape the ripple effect of my ExpansionTile so I used the Material widget and it works, but when the tile expands, the background color of the tiles below ExpansionTile does not move with them.
When ExpansionTile is collapsed
When ExpansionTile is expanded
I found out that when I remove SingleChildScrollView the problem solves but I need items to scroll. Also when ScrollPhysics has been set to AlwaysScroll, scrolling till the end of the scroll's possible position would rerender items and fix the issue.
Reproducible Example:
void main() {
runApp(
MaterialApp(
title: 'Title',
home: Scaffold(
appBar: AppBar(
title: const Text('Title'),
),
drawer: const MyList(),
body: Container(),
),
),
);
}
class MyList extends StatelessWidget {
const MyList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Drawer(
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
items(),
],
),
),
);
}
Widget items() {
return Wrap(
runSpacing: 12,
children: [
menu(),
const ListTile(title: Text('title'), tileColor: Colors.grey),
const ListTile(title: Text('title')),
]
);
}
Widget menu() {
return Material(
clipBehavior: Clip.antiAlias,
type: MaterialType.transparency,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
),
child: const ExpansionTile(
leading: Icon(Icons.group),
title: Text('title'),
children: [
ListTile(title: Text('title')),
ListTile(title: Text('title')),
],
),
);
}
}

If you want to avoid SingleChildScrollView and still be able to scroll over a list, you can use ListView.builder link: - ListView.builder flutter.dev

Try removing type: MaterialType.transparency,
class MyList extends StatelessWidget {
const MyList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Drawer(
child: SingleChildScrollView(
child: Column(
children: [
for (int i = 0; i < 2; i++) items(),
],
),
),
);
}
Widget items() {
return Wrap(
children: [
menu(),
const ListTile(
title: Text('title'),
tileColor: Colors.grey,
),
const ListTile(title: Text('title')),
],
);
}
Widget menu() {
return Material(
clipBehavior: Clip.antiAlias,
// type: MaterialType.transparency,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: const ExpansionTile(
leading: Icon(Icons.group),
title: Text('title'),
children: [
ListTile(title: Text('title')),
ListTile(title: Text('title')),
],
),
);
}
}

I asked for this problem on flutter's Github repo and I got the answer.
Just need to use ListTileTheme widget instead of Material widget.
Github issue link:
https://github.com/flutter/flutter/issues/112372

Related

Flutter DraggableScrollableSheet with multiple descendant Scrollable widgets

I want to add Routing inside DraggableScrollableSheet widget, so I need a way to add many Scrollable widgets like ListView GridView etc inside DraggalbleScrollable. I was thinking about using NotificationListener to listen all ScrollNotification events of descendants but I dont know what to do with controller.
import 'package:flutter/material.dart';
class NestedDraggableScrollable extends StatelessWidget {
const NestedDraggableScrollable({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Positioned.fill(
child: DraggableScrollableSheet(
initialChildSize: 0.5,
minChildSize: 0.1,
maxChildSize: 1,
builder: (context, controller) =>
NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
///??????
controller.jumpTo(scrollInfo.metrics.pixels);
return true;
///??????
},
child: PageView(
children: [
ListView(
children: const [
ListTile(
key: Key("value1"),
title: Text("One"),
),
ListTile(
key: Key("value2"),
title: Text("Two"),
),
ListTile(
key: Key("value3"),
title: Text("Three"),
),
],
),
ListView(
children: const [
ListTile(
title: Text("One One"),
),
ListTile(
title: Text("Two Two"),
),
ListTile(
title: Text("Three Three"),
),
],
),
],
),
)),
);
}
}

How can I place a button in a scrollable list with ExpansionTiles in Flutter?

I have a scrolableView with x amount of ExpansionTiles, I need to place the 'Test' button on the bottom of the page, only if a number of tiles are fitting the screen or if they expand within the page, else to push the button off the screen.
import 'package:flutter/material.dart';
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
List datas = [1, 2, 3, 4, 5, 6];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: datas.length,
shrinkWrap: true,
itemBuilder: (context, i) {
return ExpansionTile(
title: Text(
datas[i].toString(),
),
children: List.generate(
datas.length,
(index) {
return Text(datas[index].toString());
},
));
},
),
ElevatedButton(onPressed: () {}, child: Text('Test'))
],
),
),
),
);
}
}
The UX is a little tricky. It will be easy and get better performance using CustomScrollView.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate.fixed(
[
...datas
.map((e) => ExpansionTile(
title: Text(
e.toString(),
),
children: List.generate(
datas.length,
(index) {
return Text(datas[index].toString());
},
)))
.toList(),
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: ElevatedButton(
onPressed: () {},
child: const Text('Test'),
),
),
)
],
)),
);
}
The important thing is using SliverFillRemaining with hasScrollBody: false along with Align child.
More about CustomScrollView.

Scrollable Listview issue - Flutter

class StoryUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Stories'),
),
body: Column(
children: [
Text('Georgy'),
Storycard(),
],
),
),
);
}
}
class Storycard extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, int index) {
return GestureDetector(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
child: Column(
children: <Widget>[
ClipRRect(
child: Image.asset(
news[index].image,
),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0)),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(news[index].newsHeadline,
style: GoogleFonts.ubuntu(
fontSize: 17, fontWeight: FontWeight.bold)),
)
],
),
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewsDetails(news: news[index])));
});
},
itemCount: news.length,
);
}
}
I am trying here to have a list of scrollable cards. I want space above the cards to add some text. SO I tried using column and have a text and Listview Bulider as children. But the emulator is showing blank screen.
When the StoryCard() is alone used as the body the output comes with widgets. I can't add anything above the Listview. Can someone help.
enter image description here
Use Expanded class or Flexible class for the ListView.
ListView requires a finite height for it's content.
With your current code, ListView is having infinite height, hence the error. Expanded or Flexible helps you to have the remaining space to be utilized for your child
Solution
class StoryUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Stories'),
),
body: Column(
children: [
Text('Georgy'),
// here is the change
Expanded(
child: Storycard()
)
]
)
)
);
}
}
Using Flexible
class StoryUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Stories'),
),
body: Column(
children: [
Text('Georgy'),
// here is the change
Flexxible(
fit: FlexFit.loose,
child: Storycard()
)
]
)
)
);
}
}

Change AppBar title padding

Due to unavailability of modifying app bar leading property width I'm forced to create my own leading trailing property by using AppBar title property. However I've noticed that title has some default horizontal padding there.
Scaffold(
appBar: AppBar(
centerTitle: true,
title: Container(
height: 36,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(width: 80, child: Text('Cancel')),
Text('Profile'),
Container(width: 80, child: Text('Done'))
],
),
),
),
)
Is there any way to make it smaller?
Use action[] inside the appbar instead of using Row.
appBar: new AppBar(
//title: new Text(Strings.app_name),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: new RaisedButton(onPressed: (){
},
child: new Text('Cancel'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child:
new RaisedButton(onPressed: (){
},child: new Text('done'),)
),
],
//centerTitle:true,
),
You can use the titleSpacing property of the AppBar to control the horizontal spacing for the title.
For example following snippet will remove all the leading spacing from title-
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0.0,
title: const Text('AppBar Demo'),
),
body: const Center(
child: Text(
'This is the home page',
style: TextStyle(fontSize: 24),
),
),
);
}
}
I hope this helps!
Please use titleSpacing: 0.0
appBar: AppBar(
titleSpacing: 0.0,
title: Text('AppBar Example'),
),

Can't get icon & text to appear

I can't seem to get icon button to appear with text next to it. Should look like:
I am following the introduction tutorial in Udacity. Still trying to get my head around all of the correct formatting, widgets, etc
Code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: "Category List",
home: Scaffold(
appBar: AppBar(
title: Text('This is a list item'),
),
body: Category(),
),
),
);
}
class Category extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
child: Container(
child: Padding(
padding: EdgeInsets.all(16.0),
child: InkWell(
onTap: () => {},
child: Row(
children: <Widget>[
Icon(Icons.access_alarms),
Text('Click'),
],
),
),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: "Category List",
home: Scaffold(
appBar: AppBar(
title: Text('This is a list item'),
),
body: Category(),
),
),
);
}
class Category extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
child: Container(
decoration:BoxDecoration(
color:Colors.green.withOpacity(0.4),
border:Border.all(),
),
child: Padding(
padding: EdgeInsets.all(16.0),
child: InkWell(
onTap: () => {},
child: Row(
children: <Widget>[
Icon(Icons.access_alarms),
Text('Click'),
],
),
),
),
),
);
}
}
have you tried to wrap your icons and text using Expanded() widget?