I am new in Dart and Flutter. Now I am having a problem with calling a method from another class.
I have tried to make the method static, but the method contains setState() method so it is not possible.
So I have to call main.dart >>> showDialogWith() from wallet.dart
main.dart
import 'package:flutter/material.dart';
import 'dialog/operation.dart';
import 'pages/wallet.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future showDialogWith(String dialogName) async {
Widget dialog;
switch (dialogName) {
case 'operations':
setState(() {
dialog = OperationsDialog();
});
break;
// another cases and default...
}
await showDialog(
context: context,
child: dialog,
);
}
#override
Widget build(BuildContext context) {
body: WalletContent();
}
}
wallet.dart
class WalletContent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialButton(
onPressed: () {
// here I have to call the 'showDialogWith()' method
},
);
}
}
operation.dart
class OperationsDialog extends StatefulWidget{
OperationsDialog({Key key}) : super(key: key);
#override
_OperationDialogState createState() => new _OperationDialogState();
}
class _OperationDialogState extends State<OperationsDialog> {
#override
Widget build(BuildContext context) {
return new SimpleDialog(
title: new Text('Операции', textAlign: TextAlign.center),
);
}
}
You can pass a function as a parameter.
#override
Widget build(BuildContext context) {
body: WalletContent(showDialogWith);
}
Add a Function field into your WalletContent and assign it to your MaterialButton
class WalletContent extends StatelessWidget {
WalletContent(this.onPressed);
final Function onPressed;
#override
Widget build(BuildContext context) {
return MaterialButton(
onPressed: () => onPressed(...), // Pass your desired string here
);
}
}
Related
I want to draw a line chart catching the data from a JSON file. The JSON is inside the assets folder. But I do not know How to Develop a Line Chart using my JSON Data. Can please somebody help and guide me. Thank you very much.
Here is the JSON
{
"measure": [
{
"count": 8,
"range_array": [20.6, 27.9, 50.6],
"force_array": [116.8, 187.4, 226.6]
}
]
}
Here is the Model
class DataModel {
DataModel({this.measure});
List<DataTitle>? measure;
factory DataModel.fromJson(Map<String, dynamic> json) {
return DataModel(
measure: List<DataTitle>.from(
json['measure'].map((c) => DataTitle.fromJson(c)).toList()),
);
}
}
class DataTitle {
DataTitle(
{required this.number,
required this.firstarray,
required this.secondarray});
int? number;
List<double>? firstarray;
List<double>? secondarray;
DataTitle.fromJson(Map<String, dynamic> json) {
number = json['count'];
firstarray = json['range_array'] == null
? []
: List<double>.from(json['range_array'].map((x) => x.toDouble()));
secondarray = json['force_array'] == null
? []
: List<double>.from(json['force_array'].map((x) => x.toDouble()));
}
#override
String toString() {
return 'DATA TITLE{Count: $number, RangeArray: $firstarray, ForceArray: $secondarray}';
}
}
Here is the where i want to display the Chart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'package:read_local_json/measure_data_model.dart';
import 'dart:async' show Future;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'JSON',
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
Future loadData() async {
final jsonString = await rootBundle.loadString('assets/measurelist.json');
final decodedJson = json.decode(jsonString);
List<DataTitle> dataTileList = (decodedJson['measure'] as List)
.map((jsonElement) => DataTitle.fromJson(jsonElement))
.toList();
print(dataTileList.first);
print(dataTileList.last);
}
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('JSON Chart'),
),
body: const Center(
child: Text('JSON Chart'),
),
);
}
}
The JSON data can be converted to a list with the help of the json.decode function.
import 'dart:convert';
final List<Measure> measures = (json.decode(jsonstring)['measure'] as List).map((i) => Measure.fromJson(i)).toList();
class Measure {
final int count;
final List<double> range_array;
final List<double> force_array;
Measure({this.count, this.range_array, this.force_array});
factory Measure.fromJson(Map<String, dynamic> json) {
return Measure(
count: json['count'],
range_array: json['range_array'],
force_array: json['force_array'],
);
}
}
After that, use a charts package to draw the line chart.
LineChart(
data: LineChartData(
points: measures[0].count.toList().asMap().entries.map((key) => DataPoint(key.key.toDouble(), measures[0].force_array[key.key])).toList(),
),
);
Here is a complete code snippet that should demonstrate the issue that I am bumping into.
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
SystemChrome.setEnabledSystemUIOverlays([]);
runApp(
MaterialApp(
home: MyHomePage(),
),
);
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key,}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
Future<latestVersion> fetchAlbum() async {
final response = await http.get('https://api.jsonbin.io/b/5fd25941bef8b7699e57dce9');
if (response.statusCode == 200) {
print('yay');
return latestVersion.fromJson(jsonDecode(response.body));
} else {
print('nay');
throw Exception('Failed to load version');
}
}
class latestVersion {
final String title;
final String version;
latestVersion({this.version, this.title});
factory latestVersion.fromJson(Map<String, dynamic> json) {
return latestVersion(version: json['version'], title: json['title'],
);
}
}
class _MyHomePageState extends State<MyHomePage> {
static Future<latestVersion> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(''),
Text('CURRENT'),
Text('---------'),
Text('0.37'),
Text(''),
Text('LATEST'),
Text('--------'),
Text(latestVersion.version),
Text(''),
Text(''),
],
),
),
);
}
}
When trying to run this code, I get an error at line 76.
"instance member 'version' cannot be accessed using static access"
How exactly can I access this json-decoded variable? Thank you in advance. I'm new to working with asynchronous functions and Future and would appreciate any help that can be given.
The error means version is not a Static variable. So to access it like this LatestVersion.version either make version a static variable or
Replace
Text(LatestVersion.version),
with
Text(LatestVersion().version),
If everything else is correct in your code the above should work.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
class HomePage extends StatefulWidget {
#override
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
List items;
Future<String> getData() async {
var response = await http.get(
'https://api.torn.com/torn/?selections=items&key=7PnSA9HkVB5B6eAK');
this.setState(() {
Map items = json.decode(response.body);
print(items);
});
}
#override
void initState() {
this.getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Text(items[index]['name']),
);
},
),
);
}
}
As far as i know we can get Json in two forms, first is List and second is a Map.
In my case i received a Map with all data i need but unfortunately i dont know how properly display that.
From print i received data but nothing happen on screen.
You must not re-define items. You need to set it. It will look like this:
setState(() {
items = jsonDecode(response.body);
print(items);
});
Check the setState inside your getData method, you are creating a new items variable instead of assigning the new value to it. Try this one.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
#override
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
Map items = {};
Future<void> getData() async {
http.Response res = await http.get(
"https://api.torn.com/torn/?selections=items&key=7PnSA9HkVB5B6eAK",
);
setState(() => items = jsonDecode(res.body)["items"]);
print(items);
}
#override
void initState() {
getData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
index++;
return Card(
child: Text(items[index.toString()]["name"] ?? "Empty"),
);
},
),
);
}
}
I am trying to use the response.body from a request made in network.dart in main.dart, but it does not seem to work here is my code
import 'package:http/http.dart'as http;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
class Network {
var data;
Future fetchData() async {
Map<String, String> headers = {
HttpHeaders.contentTypeHeader: "application/json",
HttpHeaders.acceptHeader: "application/json",
HttpHeaders.authorizationHeader: "Bearer $token",
};
http.Response response = await http.get (url),
headers: headers,
);
if (response.statusCode == 200) {
data = response.body;
return jsonDecode(data);
} else {
print('this is the ${response.statusCode}');
}
}
}
in the main.dart i am trying to print network.data but its null and when mapping json values i get all nulls what am i missing
Edit below i am assigning a var called body to to the result of the fetchdata in hte network but it does not seem to work when i print i run i get this "Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Future'"
import 'package:flutter/material.dart';
import 'package:foodicsclimamethod/networking.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Network network = Network();
String productName;
int productPrice;
String productData;
void updateUi() async {
Future<dynamic> body = await network.fetchData();
print(body);
}
#override
void initState() {
super.initState();
network.fetchData();
}
It looks like there is an issue with the updateUi method in your code sample. The body variable is typed as Future<dynamic>, however it should be dynamic because you are awaiting the fetchData method. If you wanted to, you could avoid specifying a type altogether and simply use final in order to infer the type. I have included a complete example below showing how this could all fit together:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class Network {
Future fetchData() async {
final headers = <String, String>{
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.acceptHeader: 'application/json',
HttpHeaders.authorizationHeader: 'Bearer $token',
};
final response = await http.get(url, headers: headers);
if (response.statusCode >= 200 && response.statusCode < 300) {
return json.decode(response.body);
} else {
throw Error();
}
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future _future;
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(snapshot.data.toString());
} else {
return CircularProgressIndicator();
}
},
),
);
}
#override
void initState() {
super.initState();
_future = Network().fetchData();
}
}
I have a PageView.builder and 3 GoogleMap-s in it.
I had to create the 3 widgets only the first time, and I do not want to rebuild them again.
Now it is annoying when I just change the page it is flashing once before load. And slow.
Any way to build a FIXED state on that widget?
I tried:
AutomaticKeepAliveClientMixin
and
#override
bool get wantKeepAlive => true;
but not worked.
maybe you forget to call super.build(context); in build method.
Like this:
class TestInnerPage extends StatefulWidget {
#override
_TestInnerPageState createState() => _TestInnerPageState();
}
class _TestInnerPageState extends State<TestInnerPage>
with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
/// Dont't forget this
super.build(context);
return Container();
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
According to the accepted answer, this will be an example using google maps.
class TestInnerPage extends StatefulWidget {
#override
_TestInnerPageState createState() => _TestInnerPageState();
}
class _TestInnerPageState extends State<TestInnerPage>
with AutomaticKeepAliveClientMixin {
//Variables
Completer<GoogleMapController> _controller = Completer();
void onMapCreated(GoogleMapController controller) {
controller.setMapStyle(Utils.mapStyles);
_controller.complete(controller);
}
#override
Widget build(BuildContext context) {
/// Dont't forget this
super.build(context);
return GoogleMap(
myLocationButtonEnabled: false,
compassEnabled: false,
myLocationEnabled: false,
zoomControlsEnabled: false,
// compassEnabled: true,
tiltGesturesEnabled: false,
// markers: _markers,
// polylines: _polylines,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
zoom: CAMERA_ZOOM,
bearing: CAMERA_BEARING,
tilt: CAMERA_TILT,
target: LatLng(
//SOURCE_LOCATION
7.8731,
80.7718),
),
onMapCreated: onMapCreated,
);
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
I had a similar issue working with google map in pageview but after searching online I got a solution that finally worked
All I did was put the google map in a stateful widget, used the with AutomaticKeepAliveClientMixin and #override bool get wantKeepAlive => true; and called in the required widget
This is the stateful widget containing the google map
class GoogleMapWidget extends StatefulWidget{
const GoogleMapWidget({Key? key}) : super(key: key);
#override
_GoogleMapWidgetState createState() => _GoogleMapWidgetState();
}
class _GoogleMapWidgetState extends State<GoogleMapWidget> with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
return Container(
child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)
);
}
}
Then you can call it from your Homepage like so
class Homepage extends StatelessWidget {
#override
build(BuildContext context){
return PageView(
children: <Widget>[
GoogleMapWidget(),
GoogleMapWidget(),
],
);
}
}
I hope this is the answer you're looking for