Flutter: Error when displaying single list value - flutter

In Flutter I am reading a file from disk and displaying the list items as a list. Using ListView.builder works fine but with a text widget displaying a single value I get this error. Can someone help?
The error I get is The following RangeError was thrown building MyHomePage(dirty, state: _MyHomePageState#e9932):
RangeError (index): Invalid value: Valid value range is empty: 9
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'dart:async';
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
______________________________
WITH List.View.builder
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _names = [];
Future<List<String>> loadNames() async {
List<String> names = [];
await rootBundle.loadString('assets/Stulkur_A.txt').then((q) => {
for (String i in LineSplitter().convert(q)) {names.add(i)}
});
return names;
}
_setup() async {
List<String> names = await loadNames();
setState(() {
_names = names;
});
}
#override
void initState() {
_setup();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Names'),
),
body: Center(
child: Container(
padding: EdgeInsets.all(15),
child: ListView.builder(
itemCount: _names.length,
itemBuilder: (context, index) {
return Text(_names[index]);
})),
),
);
}
}
_____________________
WITH Text widget
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _names = [];
Future<List<String>> loadNames() async {
List<String> names = [];
await rootBundle.loadString('assets/Stulkur_A.txt').then((q) => {
for (String i in LineSplitter().convert(q)) {names.add(i)}
});
return names;
}
_setup() async {
List<String> names = await loadNames();
setState(() {
_names = names;
});
}
#override
void initState() {
_setup();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Names'),
),
body: Center(
child: Container(
padding: EdgeInsets.all(15),
child: Text(_names[9]),
),
),
);
}
}

Try
body: Center(
child: Container(
padding: EdgeInsets.all(15),
child: _names.isEmpty
? CircularProgressIndicator()
: ListView.builder(
itemCount: _names.length,
itemBuilder: (context, index) {
return Text(_names[index]);
},
),
),
),

You should check if _names.length == 0 show a loader or everything you want otherwise show the ListView widget.

Related

my widget didn't rebuild when remove item from list unless make hot-reload for project

my project about Build music App using flutter-provider and packages name (on_audio_query) so when I get all songs from storage and want to modified them, like remove or add item the widget didn't rebuild automatically the update happened in console only unless press hot-reload to all project and the list has update and can review my code below.
main.dart
import 'package:flutter/material.dart';
import 'package:music_app_v4/test_folder/home_screen.dart';
import 'package:music_app_v4/test_folder/home_model.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MultiProvider(providers: [
ChangeNotifierProvider<HomeModel>(create: (context) => HomeModel()),
],
child: const MyApp(),));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter List Songs'),
);
}
}
HomeScreen.dart
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:music_app_v4/test_folder/home_model.dart';
import 'package:on_audio_query/on_audio_query.dart';
import 'package:provider/provider.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final OnAudioQuery _onAudioQuery = OnAudioQuery();
#override
void initState() {
requestStoragePermission();
super.initState();
}
void requestStoragePermission() async {
try {
if (!kIsWeb) {
bool status = await _onAudioQuery.permissionsStatus();
if (!status) {
await _onAudioQuery.permissionsRequest().then((value) => HomeModel());
}
setState(() {});
}
} catch (e) {
const SocketException.closed();
rethrow;
}
}
#override
Widget build(BuildContext context) {
//var notify = Provider.of<HomeModel>(context,listen: false);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Consumer<HomeModel>(builder: (context,notify,child){
return FutureBuilder<List<SongModel>>(
future: _onAudioQuery.querySongs(ignoreCase: false),
builder: (context,AsyncSnapshot item) {
if (item.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (item.data!.isEmpty) {
return const Center(
child: Text('No found Data'),
);
}
List<SongModel> songs = item.data!;
return ListView.builder(
itemCount: songs.length,
itemBuilder: (context, index) {
return Row(
children: [
Expanded(
child: ListTile(
title: Text(songs[index].title),
),
),
GestureDetector(
onTap: () {
// setState(() {
// _audioEdit.deleteAudio(songs[index].data);
// });
notify.removeAudio(songs[index].data);
print('button pressed');
//_audioEdit.deleteAudio(songs[index].data);
},
child: Icon(Icons.remove_circle))
],
);
},
);
},
);
},),
);
}
}
HomeModel.dart
import 'package:flutter/material.dart';
import 'package:on_audio_edit/on_audio_edit.dart';
import 'package:on_audio_query/on_audio_query.dart';
class HomeModel extends ChangeNotifier{
final OnAudioEdit _audioEdit = OnAudioEdit();
final OnAudioQuery onAudioQuery = OnAudioQuery();
List<SongModel>? songs;
void removeAudio(dynamic data){
_audioEdit.deleteAudio(data);
notifyListeners();
}
}

How to show updated list in shared preferences on UI - Flutter

I am making an app in a flutter in which I can select the contacts from phone book and saving them in shared preferences. No problem in data saving and retrieving but i m struggling with showing the updated list on my UI. It is showing the contacts list but every time I click on Load button it duplicates the list and showing 2 lists , 1 previous and other updated .
how can i show just updated list on UI ?
here is my code:
import 'package:contacts_test/select_contacts.dart';
import 'package:contacts_test/shared_pref.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'contact_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SharedPref sharedPref = SharedPref();
ContactModel modelLoad = ContactModel(displayName: 'saniya' , phoneNumber: '324235 ');
List _list = [];
#override
initState() {
super.initState();
// Add listeners to this clas
// loadSharedPrefs();
}
loadSharedPrefs() async {
try {
print('in load shared pref-- getting keys ');
final prefs = await SharedPreferences.getInstance();
final keys = prefs.getKeys();
print('now load shared pref ');
for (String key in keys) {
ContactModel user = ContactModel.fromJson(await sharedPref.read(key));
_list.add(user);
}
print('done load shared pref ');
}
catch (Excepetion) {
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("contacts "),
),
body: Builder(
builder: (context) {
return Column(children: [
RaisedButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Plugin1()));
},
child: const Text('fluttercontactpicker - plugin1'),
),
RaisedButton(
onPressed: () async {
await loadSharedPrefs();
},
child: Text('Load', style: TextStyle(fontSize: 20)),
),
Expanded(
child: _list.isNotEmpty ?
ListView.builder(
shrinkWrap: true,
itemCount: _list.length,
itemBuilder: (context, position) {
return ListTile(
leading: Icon(Icons.contacts),
title: Text(
_list[position].displayName.toString()
),
trailing: Icon(Icons.delete));
},
) : Center(child: Text('No list items to show')),
),
]);
}
),
);
}
}
Your loadSharedPrefs(); function adds each contact to the list you show. Every time you press the button, the same elements are added again to the list. There are multiple ways to avoid that. You can: empty the list before filling it, you can write a for loop to loop over the length of the incoming contacts and for each to add it to the list by always starting from index 0. In case you use some kind of replacement or removing method, make sure you call setState(()=> { });
Base on the answer, here is a possible solution:
import 'package:contacts_test/select_contacts.dart';
import 'package:contacts_test/shared_pref.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'contact_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SharedPref sharedPref = SharedPref();
ContactModel modelLoad = ContactModel(displayName: 'saniya' , phoneNumber: '324235 ');
List _list = [];
#override
initState() {
super.initState();
// Add listeners to this clas
// loadSharedPrefs();
}
loadSharedPrefs() async {
try {
print('in load shared pref-- getting keys ');
final prefs = await SharedPreferences.getInstance();
final keys = prefs.getKeys();
print('now load shared pref ');
var newList = [];
for (String key in keys) {
ContactModel user = ContactModel.fromJson(await sharedPref.read(key));
newList.add(user);
}
setState(()=> { _list = newList; });
print('done load shared pref ');
}
catch (Excepetion) {
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("contacts "),
),
body: Builder(
builder: (context) {
return Column(children: [
RaisedButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Plugin1()));
},
child: const Text('fluttercontactpicker - plugin1'),
),
RaisedButton(
onPressed: () async {
await loadSharedPrefs();
},
child: Text('Load', style: TextStyle(fontSize: 20)),
),
Expanded(
child: _list.isNotEmpty ?
ListView.builder(
shrinkWrap: true,
itemCount: _list.length,
itemBuilder: (context, position) {
return ListTile(
leading: Icon(Icons.contacts),
title: Text(
_list[position].displayName.toString()
),
trailing: Icon(Icons.delete));
},
) : Center(child: Text('No list items to show')),
),
]);
}
),
);
}
}

Can't add or update a list

So I'm trying to make a list that contains some widgets and then add a new widget to it when I press a button, but it doesn't seem to be working
This is the code:
class MessagesProvider extends ChangeNotifier{
List<dynamic> mesgs = [
new chatBubbleSend(),
new chatBubbleReceiver(),
new chatBubbleReceiver()
];
bool loading = true;
addMesg(){
mesgs.add(chatBubbleSend());
print(mesgs.length);
print(mesgs);
notifyListeners();
}
printMesg(){
print(mesgs.length);
print(mesgs);
}
removeMesg(){
mesgs.removeLast();
print(mesgs.length);
print(mesgs);
notifyListeners();
}
}
and this is what i get when i press the add, remove or print buttons
add,remove,print
and this is the list builder code
ChangeNotifierProvider<MessagesProvider>(
create: (context) => MessagesProvider(),
child: ChatMessages()
),
class ChatMessages extends StatelessWidget {
#override
Widget build(BuildContext context) {
final mesgs = Provider.of<MessagesProvider>(context, listen: false).mesgs;
return ListView.builder(
shrinkWrap: true,
itemCount: mesgs.length,
itemBuilder: (context,index)=> mesgs[index],
);
}
}
I have looking for a solution for over 8 hours now, and still, I couldn't fix it.
I jumped the gun with my first answer sorry.
When trying to recreate I ran into the same frustrating issue - focusing on the the provider being the problem until I realised it's actually the rendering of the updated list that's the issue.
You need to use a list builder to render the updating list in a change notifier consumer in a stateful widget
Full working example below:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class WidgetListProvider with ChangeNotifier {
List<Widget> widgets = [];
int listLength = 0;
void addWidget(){
Widget _widget = Text('Hello');
widgets.add(_widget);
listLength = widgets.length;
print('Added a widget');
notifyListeners();
}
void removeWidget(){
if (widgets.length > 0) {
widgets.removeLast();
listLength = widgets.length;
print('Removed a widget');
notifyListeners();
}
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Widget _appBar (BuildContext context) {
return AppBar(
title: Text('My App'),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(context),
// You need to define widgets that update when a provider changes
// as children of a consumer of that provider
body: Consumer<WidgetListProvider>(builder: (context, widgetProvider, child){
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
child: Text('Add widget'),
onPressed: () {
widgetProvider.addWidget();
},
),
RaisedButton(
child: Text('Remove Widget'),
onPressed: () {
widgetProvider.removeWidget();
},
),
Row(
children: [
Text('Number of Widgets: '),
Text(widgetProvider.listLength.toString()),
],
),
Container(
height: MediaQuery.of(context).size.height*0.6,
child: ListView.builder(itemCount: widgetProvider.widgets.length, itemBuilder: (BuildContext context, int index){
return widgetProvider.widgets[index];
})
)
],
),
);
}
),
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => WidgetListProvider(),
child: MyApp(),
)
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: HomePage(),
);
}
}

Flutter error: type '(String, ItemPriority) => void' is not a subtype of type '(String, [ItemPriority]) => dynamic'

I'm new to Flutter and working on a simple todo list app. For the homepage, I would like to have a list of todo items and a button to add a new todo item. Tapping the 'new' button should pull up a window to type a title for the todo item and add a priority from 1-5 using my custom radio buttons. Clicking the send/submit button on this window should add it to the list of todo items (displayed in a ListView).
I'm getting this error: type '(String, ItemPriority) => void' is not a subtype of type '(String, [ItemPriority]) => dynamic'
It's coming from line 79 "TodoInputWidget(this.newTodoItem)," and I've tried to trace the cause of the error, but I'm not sure I fully understand it. I can't find anywhere that would be producing a list of ItemPrioritys.
I really appreciate any insight on this issue!
Here's the code I have right now:
import 'package:flutter/material.dart';
import 'textInputWidget.dart';
void main() {
runApp(MyApp());
}
enum ItemPriority { low, low_med, med, med_high, high }
extension ItemPriorityExtension on ItemPriority {
RadioModel get radio {
switch (this) {
case ItemPriority.low:
return new RadioModel(true, '1', Colors.green);
case ItemPriority.low_med:
return new RadioModel(true, '2', Colors.lightGreen);
case ItemPriority.med:
return new RadioModel(true, '3', Colors.yellow);
case ItemPriority.med_high:
return new RadioModel(true, '2', Colors.orange);
case ItemPriority.high:
return new RadioModel(true, '2', Colors.red);
default:
return new RadioModel(true, '3', Colors.yellow);
}
}
}
class TodoItem {
String task;
ItemPriority priority;
TodoItem(this.task, this.priority);
}
class RadioModel {
bool isSelected;
String radioNumText;
Color color;
RadioModel(this.isSelected, this.radioNumText, this.color);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Weekly ToDo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<TodoItem> todos = [];
void newTodoItem(String text, ItemPriority priority) {
this.setState(() {
todos.add(new TodoItem(text, priority));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Weekly ToDo')),
body: Column(
children: <Widget>[
Expanded(child: TodoList(this.todos)),
TodoInputWidget(this.newTodoItem),
],
),
);
}
}
class TodoInputWidget extends StatefulWidget {
final Function(String, [ItemPriority]) callback;
TodoInputWidget(this.callback);
#override
_TodoInputWidgetState createState() => _TodoInputWidgetState();
}
class _TodoInputWidgetState extends State<TodoInputWidget> {
String text;
ItemPriority priority;
CustomRadio radio = new CustomRadio(ItemPriority.med);
bool selected = false;
void createTodo(String text) {
this.setState(() {
widget.callback(text, radio.priority);
});
}
createTodoWindow(BuildContext context) {
return showDialog(
context: context,
builder: (context) => SimpleDialog(
title: Text('Create new task'),
children: <Widget>[radio, TextInputWidget(this.createTodo)],
));
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
createTodoWindow(context);
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
),
);
}
}
class TodoList extends StatefulWidget {
final List<TodoItem> todoItems;
TodoList(this.todoItems);
#override
_TodoListState createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: this.widget.todoItems.length,
itemBuilder: (context, index) {
var todoItem = this.widget.todoItems[index];
return ListTile(title: Text(todoItem.task));
},
);
}
}
class RadioItem extends StatelessWidget {
final RadioModel item;
RadioItem(this.item);
#override
Widget build(BuildContext context) {
return Container(
child: Text(item.radioNumText),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: item.color,
),
alignment: Alignment.center,
);
}
}
//ignore: must_be_immutable
class CustomRadio extends StatefulWidget {
ItemPriority priority;
CustomRadio(this.priority);
#override
_CustomRadioState createState() => _CustomRadioState();
}
class _CustomRadioState extends State<CustomRadio> {
List<RadioModel> priorityChoices = new List<RadioModel>();
ItemPriority priority;
#override
void initState() {
super.initState();
widget.priority = priority;
priorityChoices.add(ItemPriority.low.radio);
priorityChoices.add(ItemPriority.low_med.radio);
priorityChoices.add(ItemPriority.med.radio);
priorityChoices.add(ItemPriority.med_high.radio);
priorityChoices.add(ItemPriority.high.radio);
}
#override
Widget build(BuildContext context) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: priorityChoices.length,
itemBuilder: (context, index) {
return IconButton(
onPressed: () {
priorityChoices.forEach((element) {
element.isSelected = false;
});
priorityChoices[index].isSelected = true;
priority = ItemPriority.values[index];
},
icon: RadioItem(priorityChoices[index]),
);
},
);
}
}
Replace function ;
dynamic newTodoItem(String text, [ItemPriority priority]) {
this.setState(() {
todos.add(new TodoItem(text, priority));
});
return some.. or null;
}

How do I add floatingactionbutton in my ListView in Flutter dart

I want to add a floatingactionbutton in my ListPage on the bottom right corner.
I tried adding it but I am getting error or it is becoming a dead code.
An on press will be implemented on that floatingactionbutton to create a user and that will be reflected in the listview page.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() => runApp(new AdminPage());
class AdminPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Admin Dashboard',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Admin Dashboard'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: ListPage(),
);
}
}
class ListPage extends StatefulWidget {
#override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
Future _data;
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore.collection("admins").getDocuments();
return qn.documents;
}
#override
Widget build(BuildContext context) {
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore.collection("admins").getDocuments();
return qn.documents;
}
navigateToDetail(DocumentSnapshot post){
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailPage(post: post,)));
}
#override
void initState(){
super.initState();
_data = getPosts();
}
return Container(
child: FutureBuilder(
future: _data,
builder: (_, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: Text("Loading..."),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index){
return ListTile(
title: Text(snapshot.data[index].data["email"]),
onTap: () => navigateToDetail(snapshot.data[index]),
);
});
}
}),
);
}
}
class DetailPage extends StatefulWidget {
final DocumentSnapshot post;
DetailPage({this.post});
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title : Text(widget.post.data["name"]),
),
body: Container(
child:Card(
child: ListTile(
title:Text(widget.post.data["email"]),
subtitle: Text(widget.post.data["name"]),
),
),
),
);
}
}
Image of the screen can be found below
You can add floatingActionButton argument on Scaffold
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: ListPage(),
floatingActionButton: FloatingActionButton(
onPressed: () =>{},
child: const Icon(Icons.add),
),
);
You can add FAB in listview by wrapping FloatingActionButton inside of Transform.translate:
floatingActionButton:Transform.translate(
offset: const Offset(-10, -70),
child: FloatingActionButton(
onPressed: () =>{},
child: const Icon(Icons.add),
),
),