Can anyone please let me know why this code is not working? I have one data model file, One file for page where i have a search text and listview to display the names and main file. If i enter something on the search bar, names should be filtered. Please check the code and let me know what i have done wrong.
import 'package:flutter/widgets.dart';
import 'package:flutter/cupertino.dart';
import './class.dart';`enter code here`
class NameList with ChangeNotifier {
List<NameDetails> names = [
NameDetails('2', 'Mahesh'),
NameDetails('1', 'Ganesh'),
NameDetails('3', 'Suresh'),
NameDetails('4', 'Girish'),
];
List<NameDetails> get getNames {
return names;
}
void filterNames(String fil) {
List<NameDetails> names1;
names1 = names.where((n) => n.name.contains(fil));
names=names1;
notifyListeners();
}
}
import 'package:flutter/material.dart';
import 'package:practice/class.dart';
import 'package:provider/provider.dart';
import './data.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
NameList namesList;
String filterValue;
#override
Widget build(BuildContext context) {
final namesList = Provider.of<NameList>(context);
List<NameDetails> names = namesList.names;
return Scaffold(
appBar: AppBar(
title: TextField(
onChanged: (text) {
namesList.filterNames(text);
},
),
),
body: Column(
children: <Widget>[
Container(
height: 200,
child: Container(
height: 200,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Card(
child: Text('${names[index].name}'),
);
},
itemCount: names.length,
),
),
),
],
));
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './mainScreen.dart';
import './data.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => NameList(),
child: MaterialApp(
title: 'Test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
));
}
}
You can copy paste run full code below
Step 1: You can put filter function in getNames and use List<NameDetails> names = namesList.getNames;
Step 2: filterNames function only update _searchString and do notifyListeners()
code snippet
class NameList with ChangeNotifier {
List<NameDetails> names = ...
String _searchString = "";
UnmodifiableListView<NameDetails> get getNames => _searchString.isEmpty
? UnmodifiableListView(names)
: UnmodifiableListView(
names.where((n) => n.name.contains(_searchString)));
void filterNames(String fil) {
_searchString = fil;
print(_searchString);
notifyListeners();
}
}
...
Widget build(BuildContext context) {
final namesList = Provider.of<NameList>(context);
List<NameDetails> names = namesList.getNames;
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:collection';
class NameDetails {
String id;
String name;
NameDetails(this.id, this.name);
}
class NameList with ChangeNotifier {
List<NameDetails> names = [
NameDetails('2', 'Mahesh'),
NameDetails('1', 'Ganesh'),
NameDetails('3', 'Suresh'),
NameDetails('4', 'Girish'),
];
String _searchString = "";
UnmodifiableListView<NameDetails> get getNames => _searchString.isEmpty
? UnmodifiableListView(names)
: UnmodifiableListView(
names.where((n) => n.name.contains(_searchString)));
void filterNames(String fil) {
_searchString = fil;
print(_searchString);
notifyListeners();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => NameList(),
child: MaterialApp(
title: 'Test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
));
}
}
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
NameList namesList;
String filterValue;
#override
Widget build(BuildContext context) {
final namesList = Provider.of<NameList>(context);
List<NameDetails> names = namesList.getNames;
return Scaffold(
appBar: AppBar(
title: TextField(
onChanged: (text) {
namesList.filterNames(text);
},
),
),
body: Column(
children: <Widget>[
Container(
height: 200,
child: Container(
height: 200,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Card(
child: Text('${names[index].name}'),
);
},
itemCount: names.length,
),
),
),
],
));
}
}
Related
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();
}
}
Here, I have two files dot_indicator.dart and main.dart.
The function which is inside the Dots class "updatePosition()", how can it be accessed inside the onPageChanged of the PageView widget.
import 'package:flutter/material.dart';
import 'package:dots_indicator/dots_indicator.dart';
class Dots extends StatefulWidget {
#override
_DotsState createState() => _DotsState();
}
class _DotsState extends State<Dots> {
final _totalDots = 2;
double currentPosition = 0.0;
double validPosition(double position) {
if (position >= _totalDots) return 0;
if (position < 0) return _totalDots - 1.0;
return position;
}
void updatePosition(double position) {
setState(() => currentPosition = validPosition(position));
}
String getCurrentPositionPretty() {
return (currentPosition + 1.0).toStringAsPrecision(2);
}
#override
Widget build(BuildContext context) {
return DotsIndicator(
dotsCount: _totalDots,
position: currentPosition,
decorator: DotsDecorator(
activeColor: Colors.green,
activeSize: Size.square(30.0),
activeShape: RoundedRectangleBorder(),
),
);
}
}
This widget had the function updatePosition(index), I want to access it in another class.
import 'package:flutter/material.dart';
import 'package:mobile_app/bottom_nav.dart';
import 'package:mobile_app/dot_indicator.dart';
import 'package:mobile_app/first_page.dart';
import 'package:mobile_app/second_page.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(250, 250, 250, 100),
elevation: 0.0,
title: Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Dots(),
),
],
),
),
body: PageSlider(),
bottomNavigationBar: AppBottomNav(),
),
);
}
}
class PageSlider extends StatefulWidget {
const PageSlider({Key? key}) : super(key: key);
#override
_PageSliderState createState() => _PageSliderState();
}
class _PageSliderState extends State<PageSlider> {
Dots _dots = new Dots();
#override
Widget build(BuildContext context) {
PageController controller = PageController(initialPage: 0, keepPage: true);
return PageView(
controller: controller,
onPageChanged: (index) => {
print(index),
//I want the updatePosition(index) here
},
children: <Widget>[
FirstPage(),
SecondPage(),
],
);
}
}
I tried making the instance of the Dots class and tried to use it inside the PageSlider class, it still wont work.
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(),
);
}
}
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.
The Machinemodel instance from the Consumer is always null.
Why?
App
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Provider nested model demo',
theme: ThemeData(
// This is the theme of your application.
primarySwatch: Colors.blue,
),
home: ApplicationPage());
}
}
ApplicationPage
class ApplicationPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var newMachineEntity = new MachineEntity(1, "Power x1000"); //, engines);
return Scaffold(
appBar: AppBar(title: Text("Machine demo"), elevation: 6),
body: ChangeNotifierProvider(create: (context) => new MachineModel(newMachineEntity), child: MachineWidget()));
}
}
Widget
class MachineWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<MachineModel>(builder: (context, machine, child) {
////////////////////// machine instance is null /////////////
return Container(
child: Column(
children: <Widget>[
TextFormField(
initialValue: machine.name,
onChanged: (value) => machine.name = value,
),
],
),
);
});
}
}
Model
class MachineModel extends ChangeNotifier {
MachineEntity machineEntity;
// List<EngineModel> engines;
MachineModel(this.machineEntity) {
// engines = this.machineEntity.engines.map((eng) => new EngineModel(eng)).toList();
}
String get name => machineEntity.name;
set name(String value) {
machineEntity.name = value;
notifyListeners();
}
}
Entity
class MachineEntity {
int id;
String name;
// List<EngineEntity> engines;
MachineEntity(this.id, this.name); //, this.engines);
}