When I create a ReordableListView with flutter there are some Icons (in the right) that appear by default :
I would like to remove them because I want to put other Icons at this place and when I do this it renders this (which is obviously not what I want) :
Thanks for helping !
Found the answer, I just needed to add this line in my ReordableListView widget:
buildDefaultDragHandles: false,
Set buildDefaultDragHandles to false and wrap your ListTile using ReorderableDragStartListener to set your item draggable.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final List<int> _items = List<int>.generate(50, (int index) => index);
#override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
final Color oddItemColor = colorScheme.primary.withOpacity(0.05);
final Color evenItemColor = colorScheme.primary.withOpacity(0.15);
return ReorderableListView(
padding: const EdgeInsets.symmetric(horizontal: 40),
// Set this false
buildDefaultDragHandles: false,
children: <Widget>[
for (int index = 0; index < _items.length; index++)
// Wrap using ReorderableDragStartListener
ReorderableDragStartListener(
key: Key('$index'),
index: index,
ListTile(
tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
title: Text('Item ${_items[index]}'),
)
),
],
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final int item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
);
}
}
Related
I am having beacon values with location points. I want to filter this data by two:
According to points
According to beacons' mac addresses'
in order to show filtered results in separate screens.
What I want to do is:
Make same points as one, and when I clicked on the point I wanted to show values according to this point.
This is my current screen I don't want it to be that way
The same for here too, this time according to the mac addresses
This is my current screen I don't want it to be that way
Here is my data models:
class RawBeaconDataModel {
final String name;
final String uuid;
final String macAddress;
final int major;
final int minor;
final double distance;
final String proximity;
final int rssi;
final int txPower;
final String scanTime;
}
class PointModel {
final double lat;
final double long;
}
class LocationBeaconDataModel {
PointModel pointModel;
RawBeaconDataModel rawBeaconDataModel;
}
I am pulling values from this;
List<LocationBeaconDataModel> SCAN_RESULTS = [];
Just in case, my codes:
class ResultsScreen extends StatefulWidget {
const ResultsScreen({Key? key}) : super(key: key);
#override
State<ResultsScreen> createState() => _ResultsScreenState();
}
class _ResultsScreenState extends State<ResultsScreen> {
static const _PAGES = [FilterByPointScreen(), FilterByBeaconsScreen()];
int _selectedPage = 0;
#override
Widget build(BuildContext context) {
//print("${SCAN_RESULTS.toString()}");
return Scaffold(
appBar: AppBar(title: const Text('Results')),
body: _PAGES[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
//elevation: 5,
backgroundColor: Theme.of(context).bottomAppBarColor,
iconSize: 20,
unselectedItemColor: Theme.of(context).hintColor,
selectedItemColor: Theme.of(context).primaryColor,
currentIndex: _selectedPage,
onTap: _selectPage,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.location_on),
label: 'Filter by Points',
),
BottomNavigationBarItem(
icon: Icon(
Icons.bluetooth,
),
label: 'Filter by Beacons')
],
),
);
}
void _selectPage(int index) {
setState(() {
_selectedPage = index;
});
}
}
class FilterByPointScreen extends StatelessWidget {
const FilterByPointScreen({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.only(top: 5, left: 4, right: 4),
itemCount: SCAN_RESULTS.length,
itemBuilder: (ctx, index) {
return ResultItem(
iconData: Icons.location_on,
cardTitle:
"${SCAN_RESULTS[index].pointModel.lat.toStringAsFixed(4)}, ${SCAN_RESULTS[index].pointModel.long.toStringAsFixed(4)}",
locationBeaconDataModel: SCAN_RESULTS[index],
);
});
}
}
class FilterByBeaconsScreen extends StatelessWidget {
const FilterByBeaconsScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.only(top: 5, left: 4, right: 4),
itemCount: SCAN_RESULTS.length,
itemBuilder: (ctx, index) {
return ResultItem(
iconData: Icons.bluetooth,
cardTitle: SCAN_RESULTS[index].rawBeaconDataModel.macAddress,
locationBeaconDataModel: SCAN_RESULTS[index],
);
});
}
}
so i'm working on a Map that has this structure :
Map<String, List<Video>> mapName;
Where Video is just an object that has 3 attributes : String title,String videoURL, bool isDone.
I'm planing on creating a listView that will display all Video titles so i'm just trying to figure out how to get the length of the list that exists into the Map.
I tryed some test and it displayed this :
print(videoList.values.map((list) => list.length));
I/flutter (23887): (9)
Now its true that i have 9 videos in the list, but I cannot use this in my listview itemcount because it requires an int type data.
If your Map have more than one list of videos by the key String of the Map, you can get all lengths using this code:
Map<String, List<Video>> mapName = {
'video1': [Video(),Video()],
'video2': [Video()],
'video3': [Video(),Video(),Video()],
}; //Init
int total = 0;
mapName.keys.forEach((key){
List<Video> video = mapName[key];
int length = video.length;
print('$key: $length');
total += length;
});
print('total: $total');
Flutter Example:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class Video {
final String name;
final String url;
final bool isDone;
Video(this.name, this.url, this.isDone);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Map<String, List<Video>> mapName = {
'video1': [
Video('Bunny', 'http://????', false),
Video('Bunny10', 'http://????', true),
],
'video2': [
Video('Bunny2', 'http://????', false),
],
'video3': [
Video('BunnyX', 'http://????', false),
Video('Bunny12', 'http://????', true),
Video('BunnyZZ', 'http://????', false),
],
}; //Init
List<Video> mVideos = [];
mapName.values.forEach((videos) {
videos.forEach((video) {
mVideos.add(video);
});
});
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: ListView.builder(
itemCount: mVideos.length,
itemBuilder: (context, index) {
Video video = mVideos[index];
String name = video.name;
String url = video.url;
bool isDone = video.isDone;
return ListTile(
tileColor: isDone ? Colors.green : null,
title: Text(name),
subtitle: Text(url),
);
},
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text('Hello, World!', style: Theme.of(context).textTheme.headline4);
}
}
What I've already done
I have a stateful widget that generates a ListView on screen.
class AppListView extends StatefulWidget {
final ValueChanged onChange;
final List<MatchList> matchList;
final ValueChanged finalBetList;
AppListView({this.onChange, this.matchList, this.finalBetList});
#override
_AppListViewState createState() => _AppListViewState();
}
class _AppListViewState extends State<AppListView> {
int counter = 0;
List<MatchList> betList = List<MatchList>();
I have a Home Screen that calls this Stateful Widget. In here I am using a callback function (onChange) to get the counter value from the widget. Everything is working perfect.
Stack(children: [
AppListView(
matchList: matchList,
//callback function brings the counter value from ListView class
onChange: (value) {
setState(() {
counter = value;
});
},
),
Positioned(
child: Padding(
padding: const EdgeInsets.only(top: 280.0, left: 330.0),
child: Container(
width: 60,
height: 60,
child: FloatingActionButton(
onPressed: () {
counter > 0
? Navigator.pushNamed(context, BetScreen.id)
: print('you shall not pass');
},
child: Text(
counter.toString(),
style: kTextStyleAppBarTitle,
),
),
),
),
)
])
What is the problem
But when I am trying to call that widget from another screen with a similar callback function(finalBetList), I got "The method 'call' was called on null. Receiver: null" error. Actually everything that I do is the same as the other example that works fine. I can't find what I'm missing. Is it something about Lists?
class _BetScreenState extends State<BetScreen> {
List<MatchList> betList = List<MatchList>();
int counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
currentBalance: '\u0024' + '200.00',
userLevel: 'Level 30',
userName: 'Mark',
),
body: Container(
child: AppListView(
finalBetList: (value) {
setState(() {
//counter = value;
betList = value;
//print(betList);
});
},
matchList: betList,
),
),
);
}
}
After Edit
I added the cod of AppListView widget
class AppListView extends StatefulWidget {
final ValueChanged onChange;
final List<MatchList> matchList;
final ValueChanged finalBetList;
AppListView({this.onChange, this.matchList, this.finalBetList});
#override
_AppListViewState createState() => _AppListViewState();
}
class _AppListViewState extends State<AppListView> {
int counter = 0;
List<int> betList = List<int>();
#override
Widget build(BuildContext context) {
children: <Widget>[
AppButton.buildAppButton(
context,
AppButtonType.BETSELECTION,
widget.matchList[index].homeOdds,
kCategoryButtonDimensions,
color: widget.matchList[index].homeSelected
? Colors.yellow
: Colors.white,
onPressed: () {
if (widget.matchList[index].drawSelected ||
widget.matchList[index].awaySelected) {
widget.matchList[index].drawSelected =
false;
widget.matchList[index].awaySelected =
false;
counter--;
//betList part
if (betList.length > 0)
betList
.remove(widget.matchList[index].id);
}
widget.matchList[index].homeSelected =
!widget.matchList[index].homeSelected;
if (widget.matchList[index].homeSelected) {
counter++;
betList.add(widget.matchList[index].id);
} else {
counter--;
if (betList.length > 0)
betList.remove(widget.matchList[index]
.id); //if selected, add to betList to send BetScreen
}
widget.onChange(counter);
print(betList);
widget.finalBetList(betList);
setState(() {});
},
),
i have a class that return a widget that create a text field i want call this class in a for loop in other class and every times that call this class text field set different value for my text fields and show text fields in list view how done it and next question about text field is when i set a value to text field and go to next page and back to my page value of text field cleaned and dont show how access to value of it this is my class that create a text field object
import 'package:art_man/components/Utility/Keys.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class InputText extends StatefulWidget {
String _hint, id;
double height;
TextEditingController ctrl;
Color brdercolor;
double brderwidth;
double radius;
double margintop;
TextAlign textAlign;
int maxlines;
Color hintconlor;
double hintsize;
double maxlenght;
TextInputType keyboardtype;
FontWeight fontWeight;
TextEditingController controller;
InputText(this._hint, this.id,
{this.height,
this.brdercolor,
this.brderwidth,
this.margintop,
this.radius,
this.textAlign,
this.maxlines,
this.hintconlor,
this.hintsize,
this.maxlenght,
this.keyboardtype,
this.fontWeight,
this.controller});
#override
myInputText createState() {
myInputText it = new myInputText(id,_hint,
height: height,
brdercolor: brdercolor,
brderwidth: brderwidth,
margintop: margintop,
radius: radius,
maxlines: maxlines,
hintconlor: hintconlor,
alignment: textAlign,
hintsize: hintsize,
maxlenght: maxlenght,
keyboardtype: keyboardtype,
fontwidth : fontWeight,
controller: controller);
return it;
}
}
class myInputText extends State<InputText> {
String _hint;
String id;
double height;
Color brdercolor;
double brderwidth;
double radius;
double margintop;
TextAlign alignment;
int maxlines;
Color hintconlor;
double hintsize;
double maxlenght;
TextInputType keyboardtype;
FontWeight fontwidth;
TextEditingController controller ;
myInputText(this.id,this._hint,
{this.height,
this.brdercolor,
this.brderwidth,
this.margintop,
this.radius,
this.alignment,
this.maxlines,
this.hintsize,
this.hintconlor,
this.maxlenght,
this.keyboardtype,
this.fontwidth,
this.controller});
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
top: margintop == null ? 1.0 : margintop,
),
padding: EdgeInsets.only(right: 3),
height: height == null ? 40.0 : height,
decoration: BoxDecoration(
border: Border.all(
color: brdercolor == null ? Colors.white : brdercolor,
width: brderwidth == null ? 0.0 : brderwidth),
color: brdercolor == null ? Colors.white : brdercolor,
borderRadius: BorderRadius.circular(radius == null ? 25 : radius)),
child: TextField(
controller: controller,
keyboardType: keyboardtype==null?TextInputType.text:keyboardtype,
textInputAction: TextInputAction.next,
inputFormatters: [
new LengthLimitingTextInputFormatter(maxlenght==null?
30:maxlenght.toInt()),
],
onChanged: (value){
Kelid.setter(id, value);
print(Kelid.getter(id));
},
textAlign: alignment == null ? TextAlign.right : alignment,
maxLines: maxlines==null?1:maxlines,
style: TextStyle(
fontSize: hintsize==null?14:hintsize,
),
textDirection: TextDirection.rtl,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: const EdgeInsets.all(0.0),
hintText: _hint,
errorStyle: TextStyle(height: 0),
hintStyle: TextStyle(
fontWeight: fontwidth==null?FontWeight.normal:fontwidth,
color: hintconlor == null ? Colors.grey : hintconlor,
fontSize: hintsize == null ? 13 : hintsize)),
),
);
}
}
From what I understand, you're looking into generating TextField dynamically and be able to store its values. What you can do here is store TextField values using state management available in Flutter. In this approach, I've used the provider package to store the TextField values and are saved on every text change. With the TextField values stored, we can easily restore the values on the TextFields.
Complete sample
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (BuildContext context) => TextFieldDetailsModel(),
child: 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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return _inputText('Hint for index $index', index);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Print all TextField String stored in Provider
// List<String> listText =
// Provider.of<TextFieldDetailsModel>(context, listen: false)
// ._textFieldContent;
// for (int x = 0; x < listText.length; x++) {
// debugPrint('Text: ${listText[x]}, index: $x');
// }
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
child: Icon(Icons.play_arrow),
),
);
}
Widget _inputText(String hint, int index) {
var _textEditingController = TextEditingController();
return Container(
padding: EdgeInsets.all(16.0),
child: Consumer<TextFieldDetailsModel>(builder: (BuildContext context,
TextFieldDetailsModel txtModel, Widget? child) {
// If Provider List contains value, prefill the TextField
if (txtModel._textFieldContent.length > 0 &&
txtModel._textFieldContent.length > index &&
txtModel._textFieldContent[index].trim() != '') {
_textEditingController.text = txtModel._textFieldContent[index];
// set TextField cursor at the end
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
}
return TextField(
controller: _textEditingController,
onChanged: (String str) {
// Only add String if TextField has value
if (str.trim().isEmpty)
txtModel.remove(index);
else
txtModel.add(str, index);
},
decoration: InputDecoration(hintText: hint),
);
}),
);
}
}
// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
class TextFieldDetailsModel extends ChangeNotifier {
final List<String> _textFieldContent = [];
UnmodifiableListView<String> get text =>
UnmodifiableListView(_textFieldContent);
void add(String text, int? index) {
if (index != null)
_textFieldContent.fillAndSet(index, text);
else
_textFieldContent.add(text);
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
}
void remove(int index) {
_textFieldContent.removeAt(index);
notifyListeners();
}
void removeAll() {
_textFieldContent.clear();
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
}
}
// Create filler for skipping ranges
// Source: https://stackoverflow.com/a/65504227/2497859
extension ListFiller<T> on List<String> {
void fillAndSet(int index, String value) {
if (index >= this.length) {
this.addAll(List<String>.filled(index - this.length + 1, ''));
}
this[index] = value;
}
}
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Demo
The values can also be stored only on page change. Create a List<TextEditingController> to be assigned on the TextFields generated.
late List<TextEditingController> _listTextEditingController = [];
...
Widget _inputText(String hint, int index) {
var _textEditingController = TextEditingController();
_listTextEditingController.add(_textEditingController);
...
}
On page change (i.e. button trigger), extract all the List values and store it in the Provider.
for (int x = 0; x < _listTextEditingController.length; x++) {
Provider.of<TextFieldDetailsModel>(context, listen: false).add(_listTextEditingController[x].text, x);
}
I am migrating my application from android to flutter and till now I have used ListView in a flutter. my question is, is there any specialized technique to handle a large amount of data in the flutter? for reference, you can look at android RecyclerView. it handles in-memory views and recycles its runtime. so how to achieve functionality like RecyclerView in Flutter? or it's not necessary for the flutter?
The easiest way is to use a ListView.builder without specifying the itemCount parameter.
Here is the simplest 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 MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Infinite List"),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
);
}
}
Later, you can enhance this by fetching real data. You could show a 'CircularProgressIndicator' in the last item of the list while waiting for the new data.
body: ListView.builder(
itemBuilder: (context, index) {
if (index < data.length) {
// Show your info
return Text("$index");
} else {
getMoreData();
return Center(child: CircularProgressIndicator());
}
},
itemCount: data.length + 1,
),
You can see that we trick the list by adding an index, and calling for more data when displaying that final index.
getMoreData() would include a call to setState() to force a rebuild and to take into account the new data.
Below is a simple infinite list widget based on chemamolins's answer. It accepts an itemBuilder to build the current item and onRequest callback to request more data when the user scrolls to the bottom.
import 'package:flutter/material.dart';
typedef Future<List<T>> RequestFn<T>(int nextIndex);
typedef Widget ItemBuilder<T>(BuildContext context, T item, int index);
class InifiniteList<T> extends StatefulWidget {
final RequestFn<T> onRequest;
final ItemBuilder<T> itemBuilder;
const InifiniteList(
{Key? key, required this.onRequest, required this.itemBuilder})
: super(key: key);
#override
_InifiniteListState<T> createState() => _InifiniteListState<T>();
}
class _InifiniteListState<T> extends State<InifiniteList<T>> {
List<T> items = [];
bool end = false;
_getMoreItems() async {
final moreItems = await widget.onRequest(items.length);
if (!mounted) return;
if (moreItems.isEmpty) {
setState(() => end = true);
return;
}
setState(() => items = [...items, ...moreItems]);
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
if (index < items.length) {
return widget.itemBuilder(context, items[index], index);
} else if (index == items.length && end) {
return const Center(child: Text('End of list'));
} else {
_getMoreItems();
return const SizedBox(
height: 80,
child: Center(child: CircularProgressIndicator()),
);
}
},
itemCount: items.length + 1,
);
}
}
Usage
child: InifiniteList<String>(
onRequest: requestItems,
itemBuilder: (context, item, index) => Container(
padding: const EdgeInsets.all(30),
color: index % 2 == 0 ? Colors.purple.shade100 : Colors.lime.shade100,
child: Text(item, style: Theme.of(context).textTheme.headline6),
),
),
// normally this is the place where you request the next batch of items
// on the network.
Future<List<String>> requestItems(int nextIndex) {
const pageSize = 15;
var result = List<String>.generate(pageSize, (i) => "Item: ${nextIndex + i + 1}");
return Future<List<String>>.delayed(
const Duration(milliseconds: 500),
() => result,
);
}
Live Demo
Displaying lists of data is a fundamental pattern for mobile apps. Flutter includes the ListView widget to make working with lists a breeze.
I have solved the issue by doing the following steps
Use the ListView Widget
There are four constructors of ListView Class
You have to use Builder Constructor (ListView.builder)
Builder Constructor is used when you have to make a list of elements on demand
It is appropriate for list views with a large (or infinite) number of children
HERE you can have Solution Video CLICK HERE