(Solved)
I have problem (already solved) that if I select one of the checkbox, all checkbox will selected too. here's the picture
(Not solved)
Can someone that know how to use checkbox in flutter help me here :
Flutter : checkbox sent array data to POST json body parameter
Ok from the code i have added a sample example for you, just copy and run the application to know how things are processing.
Solution Summary:
So you will get list of PetHealthModel and in that we can define a bool variable just for that model so that when that model gets rendered on the screen there will be a default value false and all the checkbox with no tick. and then when you click on the checkbox the specifc model isSelected is made true and only that item will be ticked.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Checkbox Example',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<PetHealthModel> petHealths = [];
#override
void initState() {
super.initState();
getDataHealth();
}
void getDataHealth() async {
// final response = await http.get(
// Uri.parse("http://localhost:8000/api/v1/pet_health"),
// );
// final metadata = PetHealthsMetadata.fromJson(jsonDecode(response.body));
//This above is the same where you get the data
// I have created a sample list
final list = [
PetHealthModel(id: 1, healthStatus: "Dont't no yet"),
PetHealthModel(id: 2, healthStatus: "Wash"),
PetHealthModel(id: 3, healthStatus: "cutting"),
PetHealthModel(id: 4, healthStatus: "styling"),
PetHealthModel(id: 4, healthStatus: "coloring"),
];
// you can use your metadata.data i am using the sample list for demo purpose.
setState(() => petHealths = list);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('heading'),
),
body: Column(
children: [
petHealths.isNotEmpty
? Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: petHealths.map((e) {
return CheckboxListTile(
title: Text(e.healthStatus),
value: e.isSelected,
onChanged: (bool? value) {
setState(() {
e.isSelected = value!;
});
});
}).toList(),
),
)
: Container(),
],
),
);
}
}
class PetHealthModel {
PetHealthModel({
required this.id,
required this.healthStatus,
this.isSelected = false,
// This is where you add the is selected item that means the status of every item can be modified.
});
final int id;
final String healthStatus;
bool isSelected;
// isSelected will not be in the below method because it is not coming from the api and this is just for ui change.
factory PetHealthModel.fromJson(Map<String, dynamic> json) => PetHealthModel(
id: json["id"],
healthStatus: json["health_status"],
);
Map<String, dynamic> toJson() => {
"id": id,
"health_status": healthStatus,
};
}
Let me know if it works for you
Btw, for my second problem already solved.
this is what I add
List<int> customIds=[];
petHealths.isNotEmpty
? Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: petHealths.map((e) {
return CheckboxListTile(
title: Text(e.healthStatus),
value: customIds.contains(e.id),
onChanged: (bool? value) {
if (value == true) {
setState ((){
customIds.add(e.id);
});
} else {
setState((){
customIds.remove(e.id);
});
}
}
);
}).toList(),
),
)
Related
Goal
I use bottomNavigationBar to switch between a few pages. Two of the pages use WebView to show local html files.
Problem
I found that when I switch between these pages, the pages with pure flutter widgets can load perfectly. But the HTML pages will only show the initially loaded page on switching.
For example, If I have two navigator buttons leading to Page1 and Page2, then at runtime, if I tapped Page1 button first, then tapped Page2 button, then the WebView would still show Page1 instead of Page2. This is wrong.
Code
Here is the HTML page code I use
class LocalLoader {
Future<String> loadLocal(String filename) async {
return await rootBundle.loadString('assets/doc/$filename');
}
}
class HtmlPage extends StatelessWidget {
final String htmlFile;
HtmlPage({
#required this.htmlFile
});
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder<String>(
future: LocalLoader().loadLocal(htmlFile),
builder: (context, snapshot) {
if (snapshot.hasData) {
return WebView(
initialUrl: Uri.dataFromString(snapshot.data,
mimeType: 'text/html',
// CAUTION
// - required for non-ascii chars
encoding: Encoding.getByName("UTF-8")
).toString(),
javascriptMode: JavascriptMode.unrestricted,
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
} else {
print('undefined behaviour');
}
return CircularProgressIndicator();
},
),);
}
}
Then with my bottomNavigationBar, I handle the tap event:
class MyFlutterView extends StatefulWidget {
#override
_MyFlutterViewState createState() => _MyFlutterViewState();
}
class _MyFlutterViewState extends State<MyFlutterView> {
final Keys keys = Keys();
int _iSelectedDrawerItem = 3; // self
int _iSelectedNavItem = 0;
static List<Widget> _widgetOptions = <Widget>[
MyFlutterPlaceholder(title: 'Index 0: MyFlutter'),
MyPage(htmlFile: 'page1.html'),
MyPage(htmlFile: 'page2.html'),
];
void _onItemTapped(int index) {
setState(() {
_iSelectedNavItem = index;
});
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
final appBar = AppBar(
backgroundColor: WidgetColors.menubar,
title: Text('MyFlutter'),
);
return Scaffold(
appBar: appBar,
endDrawer: NavDrawer(
keys: keys,
iSelectedDrawerItem: _iSelectedDrawerItem,
),
body: Container(
decoration: BoxDecoration(
gradient: WidgetColors.canvas,
),
child: _widgetOptions.elementAt(_iSelectedNavItem),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex : _iSelectedNavItem,
type: BottomNavigationBarType.fixed,
backgroundColor: WidgetColors.menubar,
fixedColor: WidgetColors.myColor,
// selectedItemColor: WidgetColors.myColor,
unselectedItemColor: Colors.white,
selectedIconTheme: IconThemeData(color: WidgetColors.myColor),
// unselectedIconTheme: IconThemeData(color: Colors.white),
items: [
BottomNavigationBarItem(
label: 'MyFlutter',
icon: Icon(Icons.build)
),
BottomNavigationBarItem(
label: 'Page1-HTML',
icon: Icon(Icons.help,),
),
BottomNavigationBarItem(
label: 'Page2-HTML',
icon: Icon(Icons.info_outline_rounded),
),
],
onTap: _onItemTapped),
);
}
}
I've also tried StatefulWidgets but the problem persists.
Workaround
The only workaround I have right now is to derive from the HtmlPage class for every single page I have, like this:
class Page1 extends HtmlPage {
Page1() : super(htmlFile: 'page1.html');
}
class Page2 extends HtmlPage {
Page2() : super(htmlFile: 'page2.html');
}
After this, the HTML pages will switch and load as expected.
Question
How should I fix this? Should I work on loading the HTML file more explicitly? I thought setState would handle the loading for me automatically and this certainly applies to the pure flutter widget page (MyFlutterPlaceholder class in the code above).
Also, I ensured that the url loading was called every time I switch page through the nav bar.
You can copy paste run full code below
I simulate this case with the full code below
Step 1: Use AutomaticKeepAliveClientMixin
class _WebViewKeepAlive extends State<WebViewKeepAlive>
with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
Step 2: Do not direct put function in future attribute, future: LocalLoader().loadLocal(htmlFile), Please use below way
Future<String> _future;
#override
void initState() {
_future = _getUrl(widget.url);
super.initState();
}
return FutureBuilder(
future: _future,
Step 3: I use PageView in this case
working demo
full code
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyPortalPage(title: 'Flutter Demo Home Page'),
);
}
}
class MyPortalPage extends StatefulWidget {
MyPortalPage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyPortalPageState createState() => _MyPortalPageState();
}
class _MyPortalPageState extends State<MyPortalPage> {
int _currentIndex = 0;
PageController _pageController = PageController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SizedBox.expand(
child: PageView(
controller: _pageController,
children: <Widget>[
Page1(),
WebViewKeepAlive(url: "https://flutter.dev/"),
WebViewKeepAlive(url: "https://stackoverflow.com/"),
Center(child: Text("Settings")),
],
onPageChanged: (int index) {
print("onPageChanged");
setState(() {
_currentIndex = index;
});
},
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
selectedItemColor: Colors.amber[800],
unselectedItemColor: Colors.blue,
onTap: (index) {
print("onItemSelected");
setState(() => _currentIndex = index);
_pageController.jumpToPage(index);
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.apps),
label: 'Challenges',
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
label: 'Users',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: 'Messages',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
}
class Page1 extends StatefulWidget {
const Page1({Key key}) : super(key: key);
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
super.build(context);
return ListView.builder(itemBuilder: (context, index) {
return ListTile(
title: Text('Lorem Ipsum'),
subtitle: Text('$index'),
);
});
}
#override
bool get wantKeepAlive => true;
}
class WebViewKeepAlive extends StatefulWidget {
final String url;
WebViewKeepAlive({Key key, this.url}) : super(key: key);
#override
_WebViewKeepAlive createState() => _WebViewKeepAlive();
}
class _WebViewKeepAlive extends State<WebViewKeepAlive>
with AutomaticKeepAliveClientMixin {
Future<String> _future;
#override
bool get wantKeepAlive => true;
Future<String> _getUrl(String url) async {
await Future.delayed(Duration(seconds: 1), () {});
return Future.value(url);
}
#override
void initState() {
_future = _getUrl(widget.url);
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context);
return FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return WebView(
initialUrl: snapshot.data,
javascriptMode: JavascriptMode.unrestricted,
);
}
}
});
}
}
here is the response
{
"overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground "fight clubs" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
"title": "Fight Club",
}
the model
class Movies {
String title;
String overview;
Movies(
{this.title , this.overview});
factory Movies.fromJson(Map <String, dynamic> parsedJson){
return Movies(title: parsedJson['title'] , overview: parsedJson['overview']);
}
}
and
Future <List<Movies>> fetchMovies () async {
var response = await http.get(url);
var jsonData = jsonDecode(response.body) as List ;
List<Movies> movies = jsonData.map((e) => Movies.fromJson(e)).toList();
print(movies.length);
return movies;
}
I get this error (Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List' in type cast) no matter what i do
You tried to cast jsonData as List but the decoder says it's of type Map (Also your response shows its of type Map)
Future <List<Movies>> fetchMovies () async {
var response = await http.get(url);
var jsonData = jsonDecode(response.body);
if(jsonData is List) //check if it's a List
return List<Movies>.from(jsonData.map(map) => Movies.fromJson(map));
else if(jsonData is Map) //check if it's a Map
return [Movies.fromJson(jsonData)]; //return a List of length 1
}
You can copy paste run full code below
You can use moviesFromJson and display with FutureBuilder
code snippet
List<Movies> moviesFromJson(String str) =>
List<Movies>.from(json.decode(str).map((x) => Movies.fromJson(x)));
if (response.statusCode == 200) {
return moviesFromJson(jsonString);
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
List<Movies> moviesFromJson(String str) =>
List<Movies>.from(json.decode(str).map((x) => Movies.fromJson(x)));
String moviesToJson(List<Movies> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Movies {
Movies({
this.overview,
this.title,
});
String overview;
String title;
factory Movies.fromJson(Map<String, dynamic> json) => Movies(
overview: json["overview"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"overview": overview,
"title": title,
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
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> {
int _counter = 0;
Future<List<Movies>> _future;
Future<List<Movies>> fetchMovies() async {
String jsonString = '''
[{
"overview" : "with underground \\"fight clubs\\" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion",
"title" : "Fight Club"
},
{
"overview" : "test overview",
"title" : "test title"
}
]
''';
var response = http.Response(jsonString, 200);
if (response.statusCode == 200) {
return moviesFromJson(jsonString);
} else {
print(response.statusCode);
}
}
#override
void initState() {
_future = fetchMovies();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<List<Movies>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0,
bottom: 6.0,
left: 8.0,
right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index].title),
Spacer(),
Expanded(
child: Text(
snapshot.data[index].overview,
),
),
],
),
));
});
}
}
}));
}
}
Just check out he answer
[
{
"overview":"A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground \"fight clubs\" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
"title":"Fight Club"
},
{
"overview":"A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground fight clubs forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
"title":"second Club"
}
]
Model
// To parse this JSON data, do
//
// final movies = moviesFromJson(jsonString);
import 'dart:convert';
List<Movies> moviesFromJson(String str) => List<Movies>.from(json.decode(str).map((x) => Movies.fromJson(x)));
String moviesToJson(List<Movies> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Movies {
Movies({
this.overview,
this.title,
});
String overview;
String title;
factory Movies.fromJson(Map<String, dynamic> json) => Movies(
overview: json["overview"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"overview": overview,
"title": title,
};
}
ui page :
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:json_parsing_example/models.dart';
// To parse this JSON data, do
//
// final user = userFromJson(jsonString);
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Users'),
);
}
}
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> {
bool _isLoading = false;
List<Movies> dataList = List();
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
#override
void initState() {
super.initState();
getData();
}
getData() async {
setState(() {
_isLoading = true;
});
String jsonString = await loadFromAssets();
final movies = moviesFromJson(jsonString);
dataList = movies;
setState(() {
_isLoading = false;
});
}
// In your case you just check out this code check out the model class
/* Future <List<Movies>> fetchMovies () async {
var response = await http.get(url);
return moviesFromJson(response.body);
} */
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: _isLoading
? Center(
child: CircularProgressIndicator(),
)
: Container(
child: ListView.builder(
itemCount: dataList.length,
shrinkWrap: true,
itemBuilder: (context, i) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(dataList[i].overview),
));
}),
),
);
}
}
And on thing to tell is the value for the overview has the double quotes which is why there might be some parsing problem just check the code and let me know if it works.
I'm currently hard coding my images inside a list that takes in an imageUrl like this:
final slideList = [
Slide(imageUrl: 'assets/images/dog1.jpeg'),
Slide(imageUrl: 'assets/images/dog2.jpeg'),
Slide(imageUrl: 'assets/images/dog3.jpeg')
];
I have an assets folder with an images folder nested inside, as well as a json file. I'm trying to figure out how to parse the json so I can avoid hard coding every single image I'll have in the future in said list. The json file looks like this:
[
{
"images": [
"assets/images/dog1.jpeg",
"assets/images/dog2.jpeg",
"assets/images/dog3.jpeg"
]
}
]
The images I'm using are located inside of my images folder, therefore I'm not using an api to grab images from the web. I want to be able to parse the json file and store the images in the list in the above code snippet rather than hard coding 100 different imageUrl's.
Any help would be much appreciated!
Assuming you are using json given above your Slide class will look like this
class Slide {
String imageUrl;
Slide(this.imageUrl);
factory Slide.fromJson(dynamic json) {
return Slide(json['Image'] as String);
}
#override
String toString() {
return '{ ${this.imageUrl} }';
}
}
So to parse the json to the slide object you can use following code which will map JSON object to the Slide Object
void main() {
String jsonString = '[{"Image":"assets/images/dog1.jpeg"},{"Image":"assets/images/dog2.jpeg"},{"Image":"assets/images/dog3.jpeg"}]';
var mySlideJson = jsonDecode(jsonString) as List;
List<Slide> slideObjs = mySlideJson.map((slideJson) => Slide.fromJson(slideJson)).toList();
}
Hope this helps to achieve your goal.
You can copy paste run full code below
Step 1: parse with Payload class , you can see full code below
final payload = payloadFromJson(jsonString);
Step 2: use List<Slide>.generate
var slideList = new List<Slide>.generate(3, (i) {
return Slide(
imageUrl: payload[0].images[i],
);
});
output
I/flutter (10200): assets/images/dog1.jpeg
I/flutter (10200): assets/images/dog2.jpeg
I/flutter (10200): assets/images/dog3.jpeg
I/flutter (10200): [Instance of 'Slide', Instance of 'Slide', Instance of 'Slide']
I/flutter (10200): assets/images/dog1.jpeg
I/flutter (10200): assets/images/dog2.jpeg
I/flutter (10200): assets/images/dog3.jpeg
full code
import 'package:flutter/material.dart';
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
List<Payload> payloadFromJson(String str) => List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));
String payloadToJson(List<Payload> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Payload {
List<String> images;
Payload({
this.images,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
images: List<String>.from(json["images"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"images": List<dynamic>.from(images.map((x) => x)),
};
}
class Slide {
final String imageUrl;
Slide({this.imageUrl});
}
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> {
int _counter = 0;
String jsonString = '''
[
{
"images": [
"assets/images/dog1.jpeg",
"assets/images/dog2.jpeg",
"assets/images/dog3.jpeg"
]
}
]
''';
void _incrementCounter() {
final payload = payloadFromJson(jsonString);
print( payload[0].images[0] );
print( payload[0].images[1] );
print( payload[0].images[2] );
var slideList = new List<Slide>.generate(3, (i) {
return Slide(
imageUrl: payload[0].images[i],
);
});
print(slideList.toString());
print(slideList[0].imageUrl);
print(slideList[1].imageUrl);
print(slideList[2].imageUrl);
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I am starting to use flutter and doing the 'Startup Name Generator' tutorial, also modifying the code to do some different things, and have come across an issue I can't solve. I want the AppBar title to show the size of the _suggestions array, but can't get it to work, have tried many different things but to no avail, always getting the exception of trying to use 'setState()' while already in a build.
This is what I currently have:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator',
home: RandomWords(),
);
}
}
class RandomWordsState extends State<RandomWords> {
static final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
ValueNotifier<String> appBarTitleNotifier = ValueNotifier('Startup Name Generator: 0');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(title: ValueListenableBuilder<String>(
valueListenable: appBarTitleNotifier,
builder: (context,value,child) {
return Text(value);
}
)),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
var blder = ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: /*1*/ (context, i) {
if (i.isOdd) return Divider(); /*2*/
final index = i ~/2; /*3*/
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10)); /*4*/
/**** THIS NEXT LINE CAUSES THE ISSUE ****/
appBarTitleNotifier.value = 'Startup Name Generator: ' + _suggestions.length.toString();
}
return _buildRow(_suggestions[index],index);
},
);
return blder;
}
Widget _buildRow(WordPair pair, int i) {
return ListTile(
title: Text(
pair.asPascalCase + ': ' + i.toString(),
style: _biggerFont,
),
);
}
}
class RandomWords extends StatefulWidget {
#override
RandomWordsState createState() => RandomWordsState();
}
I have used a ValueNotifier and listener after doing some research into events, but same exception as when I manually used a setState() call within the ListView itemBuilder (where the issue seems to lie; calling/updating the AppBar title from within the ListView itemBuilder).
I haven't found a solution here so I am asking. Sorry if this has already been answered, but I could not find the solution.
How about using GestureDetector.
onVerticalDragEnd event not executed. but onVerticalDragDown works.
// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Welcome to Flutter'),
toolbarHeight: 100.0,
),
body: const Center(
child: RandomWords(),
),
),
);
}
}
class RandomWords extends StatefulWidget {
const RandomWords({Key? key}) : super(key: key);
#override
State<RandomWords> createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
String title = "Startup Name Generator";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: GestureDetector(
onTap: () {
print('tap');
},
onVerticalDragDown : (details) {
print('onVerticalDragDown');
setState(() {
title = "Startup Name Generator ("+_suggestions.length.toString()+")";
});
},
onVerticalDragEnd : (details) {
print('onVerticalDragEnd ');
setState(() {
title = "Startup Name Generator ("+_suggestions.length.toString()+")";
});
},
child:
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Icon(
// Icons.lightbulb_outline,
// color: Colors.yellow.shade600,
// size: 60,
// ),
// ),
ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
if(i.isOdd) return const Divider();
final index = i ~/ 2;
if(index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10));
}
return ListTile(
title: Text(
// index.toString() + ":" + _suggestions[index].asPascalCase,
_suggestions[index].asPascalCase,
style: _biggerFont,
),
);
},
),
)
);
}
}
Getting below Format exception when I am trying to decode Json response. Please help out.
Unhandled Exception: FormatException: Unexpected character (at character 3)
[{table_no: 1}, {table_no: 2}, {table_no: 3}]
[
{
"table_no": "1"
},
{
"table_no": "2"
},
{
"table_no": "3"
}
]
Future<Response> pos_client_table() async {
String url =
'https://xxxxxx.com/api/v1/table?branch_id=1';
Response response;
Dio dio = new Dio();
dio.options.headers = {'Authorization': prefs.getString('posclient_token')};
try {
response = await dio.get(url);
var jso = json.decode(response.toString());
Fluttertoast.showToast(
msg: "$jso",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} catch (e) {
print(e);
}
return response;
}
void CallTableUrl() async {
Response response = await pos_client_table();
List<Map> _myJson = json.decode(response.toString());
showInSnackBar('$_myJson');
}
Edit add dio parse example and parse picture
Response response;
Dio dio = new Dio();
response = await dio.get("http://yoursite");
print(response);
print(response.data.toString());
List<Payload> payload = payloadFromJson(response.data);
print({payload[0].tableNo});
Assume dio already return correct json string is
String jsonString = '[{"table_no": "1"},{"table_no": "2"},{"table_no": "3"}]';
Step 1: Parse jsonString with payload class
List<Payload> payload = payloadFromJson(jsonString);
payload class
List<Payload> payloadFromJson(String str) =>
List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));
String payloadToJson(List<Payload> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Payload {
String tableNo;
Payload({
this.tableNo,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
tableNo: json["table_no"],
);
Map<String, dynamic> toJson() => {
"table_no": tableNo,
};
}
Step 2: transfer this payload to required map of DropdownMenuItem
for (var i = 0; i < payload.length; i++) {
_myJson.add({'id': payload[i].tableNo, 'name': payload[i].tableNo});
}
Step 3: populate DropdownMenuItem
DropdownButton<String>(
isDense: true,
hint: Text("${payload[0].tableNo}"),
value: _mySelection,
onChanged: (String Value) {
setState(() {
_mySelection = Value;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["id"].toString(),
child: Text(
map["name"],
),
);
}).toList(),
),
full code
import 'package:flutter/material.dart';
import 'dart:convert';
List<Payload> payloadFromJson(String str) =>
List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));
String payloadToJson(List<Payload> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Payload {
String tableNo;
Payload({
this.tableNo,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
tableNo: json["table_no"],
);
Map<String, dynamic> toJson() => {
"table_no": tableNo,
};
}
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
String jsonString = '[{"table_no": "1"},{"table_no": "2"},{"table_no": "3"}]';
List<Payload> payload = payloadFromJson(jsonString);
List<Map> _myJson = [];
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
#override
void initState() {
for (var i = 0; i < payload.length; i++) {
_myJson.add({'id': payload[i].tableNo, 'name': payload[i].tableNo});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Container(
height: 500.0,
child: Center(
child: DropdownButton<String>(
isDense: true,
hint: Text("${payload[0].tableNo}"),
value: _mySelection,
onChanged: (String Value) {
setState(() {
_mySelection = Value;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["id"].toString(),
child: Text(
map["name"],
),
);
}).toList(),
),
),
),
],
),
),
);
}
}