I want to know how to drag the DraggableScrollableSheet widget to go up or down programmatically. For example, based on a timer class.
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('DraggableScrollableSheet'),
),
body: SizedBox.expand(
child: DraggableScrollableSheet(
builder: (BuildContext context, ScrollController scrollController) {
return Container(
color: Colors.blue[100],
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
);
},
),
),
);
}
}
Related
I have noticed if maxChildSize and minChildSize has the same value then swiping up on the contents of DraggableScrollableSheet closes the bottom sheet.
The expected behaviour is to scroll down the ListView provided in the builder argument of the DraggableScrollableSheet.
I believe the expected behaviour should be followed even when both maxChildSize and minChildSize are the same.
Am I missing something?
Here is the minimum reproducible code:
import 'package:flutter/material.dart';
class DraggableBottomSheetTest extends StatelessWidget {
const DraggableBottomSheetTest({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return DraggableScrollableSheet(
maxChildSize: 0.5,
minChildSize: 0.5,
initialChildSize: 0.5,
expand: false,
builder: (context, controller) => ListView.builder(
controller: controller,
itemCount: 50,
itemBuilder: (context, index) => ListTile(
title: Text('Item $index'),
),
),
);
},
);
},
child: Text('Show Modal BottomSheet'),
),
),
);
}
}
import 'package:flutter/material.dart';
class DraggableBottomSheetTest extends StatelessWidget {
const DraggableBottomSheetTest({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true, // set this to true
builder: (context) {
return DraggableScrollableSheet(
maxChildSize: 0.5,
minChildSize: 0.5,
initialChildSize: 0.5,
expand: false,
builder: (context, controller) => ListView.builder(
controller: controller,
itemCount: 50,
itemBuilder: (context, index) => ListTile(
title: Text('Item $index'),
),
),
);
},
);
},
child: Text('Show Modal BottomSheet'),
),
),
);
}
}
I don't have much experience with flutter.
I would like to use the language_tool library (https://pub.dev/packages/language_tool) for Dart and Flutter.
To show the data obtained from the tool() function, I created a FutureBuilder with a ListView.builder inside, which returns a Column.
I would like there to be 2 children inside the column:
1- a Text with mistake.issueDescription as text (for each "mistake")
2- another ListView that returns the elements of the List mistake.replacements for each "mistake"
Anyone know how I can fix it?
Below I put the code I created, which works fine until I put the Listview builder inside the first ListView builder.
import 'package:flutter/material.dart';
import 'package:language_tool/language_tool.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Chat(),
);
}
}
class Chat extends StatefulWidget {
const Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
String text = 'Henlo i am Gabriele';
Future<List<WritingMistake>> tool(String text) async {
var tool = LanguageTool();
var result = tool.check(text);
var correction = await result;
List<WritingMistake> mistakes = [];
for (var m in correction) {
WritingMistake mistake = WritingMistake(
message: m.message,
offset: m.offset,
length: m.length,
issueType: m.issueType,
issueDescription: m.issueDescription,
replacements: m.replacements,
);
mistakes.add(mistake);
}
print(mistakes.length);
print(mistakes);
return mistakes;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Container(
color: Colors.red,
height: 150.0,
width: double.infinity,
child: Center(
child: Text(text, style: const TextStyle(fontSize: 20.0))),
),
FutureBuilder(
future: tool(text),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: Text('Loading...'),
);
} else {
return SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder:
(BuildContext context, int mistakeIdIndex) {
return Column(
children: [
Text(snapshot
.data[mistakeIdIndex].issueDescription),
// this is where the problems begin
ListView.builder(
itemCount: snapshot.data[mistakeIdIndex]
.replacements.length,
scrollDirection: Axis.horizontal,
itemBuilder:
(BuildContext context, int index) {
return Text(snapshot.data[mistakeIdIndex]
.replacements[index]);
}),
],
);
}),
);
}
}),
],
),
),
);
}
}
I hope I was clear and that someone can help me.
Thank you :)
You cannot give a listview-builder as a child for a column try changing the Column widget to a ListView and set its shrinkWrap property to true.
ListView(
children: [
Container(
color: Colors.red,
height: 150.0,
width: double.infinity,
child: Center(
child: Text(text, style: const TextStyle(fontSize: 20.0))),
),
FutureBuilder(
future: tool(text),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: Text('Loading...'),
);
} else {
return SizedBox(
height: 200.0,
child: ListView.builder(
shrinkWrap:true,
itemCount: snapshot.data.length,
itemBuilder:
(BuildContext context, int mistakeIdIndex) {
return ListView(
shrinkWrap:true,
children: [
Text(snapshot
.data[mistakeIdIndex].issueDescription),
// this is where the problems begin
ListView.builder(
shrinkWrap:true,
itemCount: snapshot.data[mistakeIdIndex]
.replacements.length,
scrollDirection: Axis.horizontal,
itemBuilder:
(BuildContext context, int index) {
return Text(snapshot.data[mistakeIdIndex]
.replacements[index]);
}),
],
);
}),
);
}
}),
],
),
),
Here is my code:
#override
Widget build(BuildContext context) {
return FutureBuilder<Categories>(
future: _futureCategories,
builder: (BuildContext context, AsyncSnapshot<Categories> snapshot) {
if (snapshot.hasData) {
final name = snapshot.data?.data;
return DefaultTabController(
length: 1,
child: Scaffold(
body: ListView.builder(
itemCount: name?.length,
itemBuilder: (BuildContext context, int index) {
return Text(
' ${name?[index].name}',
);
},
),
appBar: AppBar(
title: const Text('List User Example'),
bottom: TabBar(
indicatorColor: Colors.lime,
tabs: [
Text(' ${name?[0].name}'.toUpperCase()),
],
isScrollable: true,
labelColor: Colors.black,
),
),
),
);
} else if (snapshot.hasError) {
return NewsError(
errorMessage: '${snapshot.hasError}',
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
);
}
}
This code fetching categories from JSON and uses them on Tabcontroller. The problem is in this current code I cannot access index value.
I am newbie and trying to understand the widget system of Flutter. How can I use Tabcontroller to use int index value on TabController?
return Text(' ${name?[index].name}',);
change
return Text(' ${snapshot.data.name}',);
When I use a ScrollController in a ListView, it blocks the CupertinoSliverNavigationBar largeTitle from transitioning to a smallTitle. However, if I remove the scrollController, the problem goes away. I think it might be a bug in the Cupertino Library
This code demonstrates the issue:
ScrollController scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
CupertinoSliverNavigationBar(
largeTitle: Text('Large Title'),
),
];
},
body: ListView.builder(
controller: scrollController,
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
child: Center(child: Text('Entry ${index}')),
);
}),
),
);
}
Now if I remove the scrollController, the problem is gone:
ScrollController scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
CupertinoSliverNavigationBar(
largeTitle: Text('Large Title'),
),
];
},
body: ListView.builder(
//controller: scrollController,
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
child: Center(child: Text('Entry ${index}')),
);
}),
),
);
}
This is an expected behavior since NestedScrollView is meant to manage the scroll positions of all other child scrolling views:
NestedScrollView class
A scrolling view inside of which can be nested other scrolling views,
with their scroll positions being intrinsically linked.
So, you cannot control the positions of its children views with an individual ScrollController. However, you can provide one for NestedScrollView to manage all at once.
NotificationListener
There is still a way to listen to the scroll events of the inner scroll view besides using ScrollController. You can have your ListView inside of NotificationListener and check the scroll info that it provides.
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
CupertinoSliverNavigationBar(
largeTitle: Text('Large Title'),
),
];
},
body: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (scrollInfo.metrics.pixels ==
scrollInfo.metrics.maxScrollExtent) {
print('Reached the bottom');
}
return;
},
child: ListView.builder(
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
child: Center(child: Material(child: Text('Entry $index'))),
);
},
),
),
),
);
}
I have the following code in one of my screens. I need to add a line of text above the ListView widget. I've tried adding a Column widget above and below the Container that holds the ListView, but I can't seem to get it right.
Can anyone tell me how I do this?
Cheers,
Paul
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(
appBar: rmoAppBar(subText: 'My Jobs'),
drawer: RmoMenu(),
body: isLoading
? Center(child: CircularProgressIndicator())
: Container(
child: ListView.builder(
itemCount: jobs.sjRows.length,
itemBuilder: (BuildContext context, int index) {
return jobCard(jobs.sjRows, index);
},
),
),
),
onWillPop: () => logoutAlert(context: context),
);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(
appBar: rmoAppBar(subText: 'My Jobs'),
drawer: RmoMenu(),
body: isLoading
? Center(child: CircularProgressIndicator())
: Column(
children: [
Text('Your text goes here'),
Expanded(
child: ListView.builder(
itemCount: jobs.sjRows.length,
itemBuilder: (BuildContext context, int index) {
return jobCard(jobs.sjRows, index);
},
),
)
],
),
),
onWillPop: () => logoutAlert(context: context),
);
}