Displaying scrollable list inside Flutter Show Dialog - flutter

I have a dynamic list of names of countries. I want to show this list in a Dialog Box (say when a user clicks a button).
Here is my implementation of the Dialog Box so far:
List<String> countries = [
'India','Japan','China','USA','France','Egypt','Norway','Nigeria','Colombia','Australia','South Korea','Bangladesh','Mozambique','Canada','Germany','Belgium','Vietnam','Bhutan','Israel','Brazil'
];
#override
Widget build(BuildContext context) {
return Dialog(
child: Container(
width: 400,
height: 400,
child: SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
itemCount: countries.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Text('${countries[index]}'),
);
}),
),
));
}
}
The output I am getting is as follows:
Clearly, only 7 countries are visible.
I have tried several other options:
Making height of the Container as double.maxFinite.
Putting another Column inside SingleChildScrollView.
All possible permutations of Column, Container, SingleChildScrollView
However, none of the above methods seem to work (overflow error, limited number of displayed items etc).
What I actually want is to be able to show a list using ListView.builder method inside a ShowDialog.

Solved like this:
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,
),
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> {
List<String> _countries = [
'India',
'Japan',
'China',
'USA',
'France',
'Egypt',
'Norway',
'Nigeria',
'Colombia',
'Australia',
'South Korea',
'Bangladesh',
'Mozambique',
'Canada',
'Germany',
'Belgium',
'Vietnam',
'Bhutan',
'Israel',
'Brazil'
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Push for open list dialog',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _showDialogOnButtonPressing,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_showDialogOnButtonPressing() => showDialog(
context: context,
child: Container(
width: MediaQuery.of(context).size.width - 40,
height: MediaQuery.of(context).size.height - 60,
child: Dialog(
child: ListView.builder(
itemCount: _countries.length,
itemBuilder: (context, index) => ListTile(
title: Text('${index + 1}. ${_countries[index]}'),
),
),
),
),
);
}
The result is in the image, and you can scroll up and down without problems:

Related

Flutter touch events on inidividual letters of a string

I want to be able to detect touch events on individual letters of a string.
For example, if the string is "HELLO", I need to distinguish between tapping on "H" or the "O". The actual strings will be longer than that, around 500 characters.
Naively, I thought about wrapping all characters them into individual Text widgets. Is there a better approach?
Check out this example where I have create a sample example via which you will get an idea for you implementation.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SampleApp(),
debugShowCheckedModeBanner: false,
);
}
}
class SampleApp extends StatefulWidget {
#override
_SampleAppState createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp> {
List<String> sampleStrings = ['H', 'E', 'L', 'L', "O"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your heading'),
),
body: Container(
height: 80,
padding: EdgeInsets.all(15),
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: sampleStrings.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
print('This is the tapped letter : ${sampleStrings[index]}');
},
child: Card(
color: Colors.white,
margin: EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'${sampleStrings[index]}',
style: TextStyle(color: Colors.black),
),
)),
);
},
),
),
);
}
}
Let me know if it works
You can try it with a Gesture Detector. but even with that you may need to use individual letters as separate Gesture Detectors.
https://api.flutter.dev/flutter/widgets/GestureDetector-class.html

SliverAppBar() not collapsing with ListView in Flutter

I'm trying to display tabs for each main tab (Nested Tab Bar) in SliverAppBar(). It's look like this:
See the image
See the GIF
The content of the exam tab it's in Container() widget (That the error in the image came from).
Now, with the Container() widget the SliverAppBar() will collapse when the user scroll the exam tab content (white screen in the image), everything is fine for now.
So, After I replaced the Container() with ListView.builder() to make the tab content scrollable, now I can't collapse SliverAppBar() from the tab content (white screen in the image). but I can from the SliverAppBar().
See this GIF after I added ListView.builder()
So, How I can make the SliverAppBar scrollable (collapsing ) with Listview?
Can anyone help me? please :(
This example (demo):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'SliverAppBar App Demo'),
);
}
}
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
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [
SliverOverlapAbsorber(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
child: SliverSafeArea(
top: false,
sliver: SliverAppBar(
pinned: true,
title: Text(widget.title),
expandedHeight: 500,
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(tabs: [Tab(text: 'Tab A'), Tab(text: 'Tab B')]),
Colors.blue,
),
pinned: false,
),
];
},
body: TabBarView(
children: <Widget>[
NestedTabs('A'),
NestedTabs('B'),
],
),
),
),
),
);
}
}
// This class is to handle the main tabs (Tab A & Tab B)
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar, this._color);
TabBar _tabBar;
final Color _color;
#override
double get minExtent => _tabBar.preferredSize.height;
#override
double get maxExtent => _tabBar.preferredSize.height;
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
color: _color,
alignment: Alignment.center,
child: _tabBar,
);
}
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
class NestedTabs extends StatelessWidget {
final String mainTabName;
NestedTabs(this.mainTabName);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(20),
child: Container(
color: Colors.blue,
alignment: Alignment.bottomCenter,
child: TabBar(
tabs: [
Tab(text: 'Tab $mainTabName-1'),
Tab(text: 'Tab $mainTabName-2')
],
),
),
),
body: TabBarView(
children: [
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 500,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
width: 200,
color: Colors.black45,
child: Center(child: Text('Index ${index}')));
},
),
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 500,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
width: 200,
color: Colors.black45,
child: Center(child: Text('Index ${index}')));
},
)
],
),
);
}
}
Thank you :)
Use SliverList() instead of SliverFillRemaining for ListView

Not able to add arguments based on constructor in my Flutter app

I've created a list of images and I want to display them in cards layout in GridView. Also I created a constructor with properties Color backgroundColor and AssetImage assetImage. This constructor is in a different class Home() so that in my material app I can call it in "home" property. But Home() is asking for 2 arguments and I'm not able to fix this. What should I do? And yeah I'm building an all-in-one websites app so webView is also in the code.
void main() => runApp(
MaterialApp(
routes: {
"/webview": (_) => WebviewScaffold(
withJavascript: true,
withLocalStorage: true,
url: 'https://www.google.com/',
appBar: AppBar(
title: Text('Browser'),
),
),
},
home: Home(),
),
);
class Home extends StatefulWidget {
const Home(this.backgroundColor, this.assetImage);
final Color backgroundColor;
final AssetImage assetImage;
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final webView = FlutterWebviewPlugin();
#override
void initState() {
super.initState();
webView.close();
}
#override
Widget build(BuildContext context) {
var gridView = new GridView.builder(
itemCount: 24,
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return new GestureDetector(
child: Container(
padding: EdgeInsets.all(6),
child: Card(
color: widget.backgroundColor,
child: new InkWell(
onTap: () {},
child: Center(
child: Image(
image: widget.assetImage,
),
),
),
),
),
onTap: () {},
);
});
return Scaffold(
appBar: AppBar(
title: Text('ANytHiNg'),
backgroundColor: Colors.green,
),
body: gridView,
);
}
}
You can may find this helpful.
where you can pass list like this to the constructor,
void main() {
runApp(MyApp(
items: List<String>.generate(10000, (i) => "Item $i"),
));
}
after this get the list by this,
MyApp({Key key, #required this.items}) : super(key: key);

Style clipboard in flutter

I am looking for a way to style the clipboard actions without touching textTheme/button property of the main style theme. Is this even possible?
Seems like the style is directly tied to the theme. Not the best idea but if you really wanted to you would need to create a custom popup and handle all the actions yourself.
This should get you started...
Output:
Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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> {
final _controller = new TextEditingController();
final _textfieldFocusNode = new FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: GestureDetector(
// intercept all pointer calls
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScope.of(context).requestFocus(_textfieldFocusNode);
},
onLongPress: () {
showMenu(
context: context,
// TODO: Position dynamically based on cursor or textfield
position: RelativeRect.fromLTRB(0.0, 300.0, 300.0, 0.0),
items: [
PopupMenuItem(
child: Row(
children: <Widget>[
// TODO: Dynamic items / handle click
PopupMenuItem(
child: Text(
"Paste",
style: Theme.of(context)
.textTheme
.body2
.copyWith(color: Colors.red),
),
),
PopupMenuItem(
child: Text("Select All"),
),
],
),
),
],
);
},
child: IgnorePointer(
// ensures textfield doesn't overrule GestureDetector
child: TextField(
focusNode: _textfieldFocusNode,
controller: _controller,
),
),
),
)
],
),
),
);
}
}

How to implement cycle wheel scroll list widget

Flutter has ListWheelScrollView widget but I want cycle wheel scroll widget. Any ideas how to implement such widget.
How it should work:
For example, I have a list with 10 items and a selected item is 1
The selected element is positioned by center
above this element, you see the last element in the list below the second element
[10]
-> [1] <-
[2]
scroll down
[9]
-> [10] <-
[1]
etc.
Thanks!
You are right considering ListWheelScrollView.
The exact solution is to use ListWheelScrollView.useDelegate with ListWheelChildLoopingListDelegate.
Example:
import 'package:flutter/material.dart';
const String kTitle = 'Loop Wheel Demo';
void main() => runApp(new LoopWheelDemo());
class LoopWheelDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: kTitle,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new HomePage(),
);
}
}
class HomePage extends StatelessWidget {
HomePage({Key key,}) : super(key: key);
#override
Widget build(BuildContext context) {
final _style = Theme.of(context).textTheme.display2;
return new Scaffold(
appBar: new AppBar(
title: new Text(kTitle),
),
body: new Center(
child: new ConstrainedBox(
constraints: BoxConstraints(
// Set height to one line, otherwise the whole vertical space is occupied.
maxHeight: _style.fontSize,
),
child: new ListWheelScrollView.useDelegate(
itemExtent: _style.fontSize,
childDelegate: ListWheelChildLoopingListDelegate(
children: List<Widget>.generate(
10, (index) => Text('${index + 1}', style: _style),
),
),
),
),
),
);
}
}
I've been trying to figure it out how to do that. I've tried lots of options, but the one that made me achieve what I wanted and what you are asking for was using the plugin:
Flutter Swiper (https://pub.dartlang.org/packages/flutter_swiper).
It's pretty customizable e flexible.
Here is the screenshot: https://imgur.com/a/ktxU6Hx
This is how I implemented it:
import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
class Looping extends StatefulWidget {
#override
LoopingState createState() {
return new LoopingState();
}
}
class LoopingState extends State<Looping> {
List<int> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
List<String> options = ['A', 'B', 'C', 'D'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Infinity Loop Items'),),
body: Center(
child: Container(
height: 100.0,
child: Row(
children: <Widget>[
mySwiper(numbers),
mySwiper(options),
],
),
),
),
);
}
Widget mySwiper(List list) {
return Expanded(
child: Swiper(
itemCount: list.length,
scrollDirection: Axis.vertical,
control: SwiperControl(),
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text(
list[index].toString(),
style: TextStyle(fontSize: 20.0),
),
);
}),
);
}
}