Related
I am facing [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: setState() called after dispose(): _AddToCardWidgetState#c0593(lifecycle state: defunct, not mounted)
And the error is printed as :
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (26736): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (26736): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (26736): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1085:9)
E/flutter (26736): #1 State.setState (package:flutter/src/widgets/framework.dart:1120:6)
E/flutter (26736): #2 _AddToCardWidgetState.build.<anonymous closure>.<anonymous closure> (package:multi_vending_grocery_app/widgets/products/add_to_cart_widget.dart:57:11)
E/flutter (26736): #3 List.forEach (dart:core-patch/growable_array.dart:433:8)
E/flutter (26736): #4 _AddToCardWidgetState.build.<anonymous closure> (package:multi_vending_grocery_app/widgets/products/add_to_cart_widget.dart:55:26)
E/flutter (26736): #5 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (26736): <asynchronous suspension>
Request fellow flutter, and dart developers to help me fix the issue. When I change the product quantity value from AddToCardWidget and navigate back to ProductListWidget the quantity value does not get updated there instead the error explained above displays in my android studio console. Help me fix it, I am new to flutter so can't solve it alone.
CODE FOR AddToCardWidget
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:multi_vending_grocery_app/services/cart_services.dart';
import 'package:multi_vending_grocery_app/widgets/cart/counter_widget.dart';
class AddToCardWidget extends StatefulWidget {
const AddToCardWidget({Key? key, this.documentSnapshot}) : super(key: key);
final DocumentSnapshot? documentSnapshot;
#override
State<AddToCardWidget> createState() => _AddToCardWidgetState();
}
class _AddToCardWidgetState extends State<AddToCardWidget> {
final CartServices _cartServices = CartServices();
User? user = FirebaseAuth.instance.currentUser;
bool isLoading = true;
bool exists = false;
int _qty = 1;
String? _docId;
#override
void initState() {
getCartData();
super.initState();
}
getCartData() async {
final snapshot =
await _cartServices.cart.doc(user?.uid).collection('products').get();
if (snapshot.docs.isEmpty) {
setState(() {
isLoading = false;
});
} else {
setState(() {
isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
//If Product exist in car , we need to get qty details
FirebaseFirestore.instance
.collection('cart')
.doc(user?.uid)
.collection('products')
.where('productId', isEqualTo: widget.documentSnapshot?['productId'])
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
if (doc['productId'] == widget.documentSnapshot?['productId']) {
setState(() {
exists = true;
_qty = doc['qty'];
_docId = doc.id;
});
}
});
});
return isLoading
? Container(
height: 56,
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).primaryColor),
),
),
)
: exists
? CounterWidget(
documentSnapshot: widget.documentSnapshot,
qty: _qty,
docId: _docId.toString(),
)
: InkWell(
onTap: () {
EasyLoading.show(status: "Adding Product To Cart");
_cartServices
.addToCart(widget.documentSnapshot)
.then((value) {
setState(() {
exists = true;
});
EasyLoading.showSuccess("Added to Cart");
});
},
child: Container(
height: 56,
color: Colors.red[400],
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
CupertinoIcons.shopping_cart,
color: Colors.white,
),
SizedBox(
width: 10,
),
Text(
"Add to Basket",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
)),
),
),
);
}
}
CODE FOR ProductListWidget
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:multi_vending_grocery_app/providers/store_provider.dart';
import 'package:multi_vending_grocery_app/services/product_services.dart';
import 'package:multi_vending_grocery_app/widgets/products/product_card_widget.dart';
import 'package:provider/provider.dart';
class ProductListWidget extends StatelessWidget {
const ProductListWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
ProductServices _services = ProductServices();
var _storeProvider = Provider.of<StoreProvider>(context);
return FutureBuilder<QuerySnapshot>(
future: _services.products
.where('published', isEqualTo: true)
.where('categoryName.mainCategory',
isEqualTo: _storeProvider.selectedProductCategory)
.where('categoryName.subCategory', isEqualTo: _storeProvider.selectedSubCategory)
.where('seller.sellerUid',
isEqualTo: _storeProvider.storeDetails?['uid'])
.get(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return const Text("Something Went Wrong");
}
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Column(
children: [
Material(
elevation: 4,
borderRadius: BorderRadius.circular(4),
child: Container(
width: MediaQuery.of(context).size.width,
child: Center(
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
"${snapshot.data.docs.length} Items",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey[600],
fontSize: 18),
),
)
],
),
),
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(4)),
height: 56,
),
),
ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children:
snapshot.data.docs.map<Widget>((DocumentSnapshot document) {
return ProductCard(documentSnapshot: document);
}).toList(),
)
],
);
},
);
}
}
Move the code block
FirebaseFirestore.instance
.collection('cart')
.doc(user?.uid)
.collection('products')
.where('productId', isEqualTo: widget.documentSnapshot?['productId'])
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
if (doc['productId'] == widget.documentSnapshot?['productId']) {
setState(() {
exists = true;
_qty = doc['qty'];
_docId = doc.id;
});
}
});
});
to initState instead of the build, this happens because you are settingState inside the build method, this might happen during the "building frame" process which will cause the issue you have
Moving the code block to initState will probably solve your issue
Whenever I try to clear the TextField by clicking on the IconButton I get an Unhandled Exception warning in the debug console although my TextField is cleared.
Also when I try to add a new value to the TextField my previous value is automatically displayed in the TextField.
Here's my code for the Search_location UI
import 'package:flutter/material.dart';
import 'package:geoflutterfire/geoflutterfire.dart';
import 'package:geolocator/geolocator.dart';
import 'package:maps_app/models/place.dart';
import 'package:maps_app/services/location_api.dart';
import 'package:provider/provider.dart';
class SearchView extends StatefulWidget {
#override
_SearchViewState createState() => _SearchViewState();
}
class _SearchViewState extends State<SearchView> {
final _scrollController = ScrollController();
var latitude, longitude;
var con_width = 0.0;
var list_height = 0.0;
GeoFirePoint point;
Geoflutterfire geo = Geoflutterfire();
bool serviceEnabled;
LocationPermission permission;
#override
void initState() {
super.initState();
getCurrentLocation();
}
getCurrentLocation() async {
try {
final pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
setState(() {
latitude = pos.latitude;
longitude = pos.longitude;
});
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SearchInjector(
child: SafeArea(
child: Consumer<LocationApi>(
builder: (_, api, child) => SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
child: TextField(
onTap: () {
setState(() {
list_height = 56;
});
},
controller: api.addressController,
decoration: InputDecoration(
prefixIcon: IconButton(
icon: Icon(Icons.my_location),
onPressed: () {
// getCurrentLocation();
}),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
setState(() {
api.addressController.clear();
con_width = 0.0;
list_height = 0.0;
});
}),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
borderRadius: BorderRadius.circular(50.0),
),
labelText: 'Search Location',
fillColor: Colors.grey[20],
filled: true),
onChanged: (value) {
setState(() {
con_width = 300.0;
});
api.places.clear();
api.handleSearch(value);
},
),
),
AnimatedContainer(
duration: Duration(milliseconds: 20),
height: list_height,
color: Colors.blue[100].withOpacity(.3),
width: MediaQuery.of(context).size.width,
child: Column(
children: List.generate(1, (i) {
return ListTile(
onTap: () {
setState(() {
api.addressController.text = 'Your Location';
list_height = 0.0;
con_width = 0.0;
});
},
title: Row(
children: [
Icon(Icons.my_location),
SizedBox(
width: 5,
),
Text(
'Your Location',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
],
),
);
}))),
AnimatedContainer(
duration: Duration(milliseconds: 20),
color: Colors.blue[100].withOpacity(.3),
width: MediaQuery.of(context).size.width,
height: con_width,
child: StreamBuilder<List<Place>>(
stream: api.controllerOut,
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(
child: Text('No data address found'));
}
final data = snapshot.data;
return Scrollbar(
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Container(
child: Builder(builder: (context) {
return Column(
children: [
Column(
children: List.generate(data.length,
(index) {
final place = data[index];
return ListTile(
leading: Icon(Icons.home),
onTap: () {
point = geo.point(
latitude: place.latitude,
longitude: place.longitude);
setState(() {
api.addressController.text =
'${place.name}, ${place.subLocality}, ${place.country}, ${place.postalCode}';
con_width = 0.0;
list_height = 0.0;
});
},
title: Text(
'${place.name}, ${place.subLocality}, ${place.locality}, ${place.postalCode} '),
subtitle: Text(
'${place.adminArea}, ${place.country}'),
);
})),
],
);
}),
),
),
);
}),
)
],
),
),
),
),
),
),
);
}
}
class SearchInjector extends StatelessWidget {
final Widget child;
const SearchInjector({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => LocationApi(),
child: child,
);
}
}
This is the Exception I am getting in the debug Console
Restarted application in 1,268ms.
E/MethodChannel#flutter/textinput(29061): Failed to handle method call
E/MethodChannel#flutter/textinput(29061): java.lang.IndexOutOfBoundsException: invalid selection start: 13
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.<init>(TextInputChannel.java:724)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.fromJson(TextInputChannel.java:680)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$1.onMethodCall(TextInputChannel.java:91)
E/MethodChannel#flutter/textinput(29061): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/MethodChannel#flutter/textinput(29061): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#flutter/textinput(29061): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#flutter/textinput(29061): at android.os.Looper.loop(Looper.java:174)
E/MethodChannel#flutter/textinput(29061): at android.app.ActivityThread.main(ActivityThread.java:7697)
E/MethodChannel#flutter/textinput(29061): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#flutter/textinput(29061): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
E/MethodChannel#flutter/textinput(29061): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
E/flutter (29061): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(error, invalid selection start: 13, null, java.lang.IndexOutOfBoundsException: invalid selection start: 13
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.<init>(TextInputChannel.java:724)
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.fromJson(TextInputChannel.java:680)
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$1.onMethodCall(TextInputChannel.java:91)
E/flutter (29061): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (29061): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/flutter (29061): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/flutter (29061): at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (29061): at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (29061): at android.os.Looper.loop(Looper.java:174)
E/flutter (29061): at android.app.ActivityThread.main(ActivityThread.java:7697)
E/flutter (29061): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (29061): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
E/flutter (29061): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
E/flutter (29061): )
[38;5;244mE/flutter (29061): #0 JSONMethodCodec.decodeEnvelope[39;49m
[38;5;244mE/flutter (29061): #1 MethodChannel._invokeMethod[39;49m
E/flutter (29061): <asynchronous suspension>
E/flutter (29061):
The problem is the clearing of the controller.
Instead of
api.addressController.clear();
try:
WidgetsBinding.instance.addPostFrameCallback((_) => api.addressController.clear());
I think you are trying to access index which does not exists, please try to check your list size.
I tried to make a compass for a flutter app.
This idea was to put an image of the compass on the camera preview.
The result seems to be ok:
First, the user has a camera preview with the compass :
The name of the room can be added.
When the user takes a picture, it makes a screenshot that can be shared:
Even it seems to work fine, I have the following error message on Android Studio:
E/flutter (29454): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: setState() called after dispose(): _CompassState#46249(lifecycle state: defunct, not mounted)
E/flutter (29454): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (29454): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (29454): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (29454): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1204:9)
E/flutter (29454): #1 State.setState (package:flutter/src/widgets/framework.dart:1239:6)
E/flutter (29454): #2 _CompassState._onData (package:franck_ehrhart/seller/compass.dart:28:29)
E/flutter (29454): #3 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter (29454): #4 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (29454): #5 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (29454): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:357:11)
E/flutter (29454): #7 _DelayedData.perform (dart:async/stream_impl.dart:611:14)
E/flutter (29454): #8 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:730:11)
E/flutter (29454): #9 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:687:7)
E/flutter (29454): #10 _rootRun (dart:async/zone.dart:1182:47)
E/flutter (29454): #11 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (29454): #12 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (29454): #13 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
E/flutter (29454): #14 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (29454): #15 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (29454): #16 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (29454): #17 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
E/flutter (29454): #18 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (29454): #19 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
E/flutter (29454):
Here is the source code for the compass:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_compass/flutter_compass.dart';
class Compass extends StatefulWidget {
Compass({Key key}) : super(key: key);
#override
_CompassState createState() => _CompassState();
}
class _CompassState extends State<Compass> {
double _heading = 0;
String get _readout => _heading.toStringAsFixed(0) + '°';
#override
void initState() {
super.initState();
FlutterCompass.events.listen(_onData);
}
void _onData(double x) => setState(() { _heading = x; });
final TextStyle _style = TextStyle(
color: Colors.red,
fontSize: 32,
fontWeight: FontWeight.bold,
backgroundColor: Colors.white.withOpacity(0.5) ,
);
#override
Widget build(BuildContext context) {
return CustomPaint(
foregroundPainter: CompassPainter(angle: _heading),
child: Center(child: Text(_readout, style: _style))
);
}
}
class CompassPainter extends CustomPainter {
CompassPainter({ #required this.angle }) : super();
final double angle;
double get rotation => -2 * pi * (angle / 360);
Paint get _brush => new Paint()
..style = PaintingStyle.stroke
..strokeWidth = 4.0;
#override
void paint(Canvas canvas, Size size) {
Paint circle = _brush
..color = Colors.blue.shade800.withOpacity(0.6);
Paint needle = _brush
..color = Colors.lightBlueAccent;
double radius = min(size.width / 2.2, size.height / 2.2);
Offset center = Offset(size.width / 2, size.height / 2);
Offset start = Offset.lerp(Offset(center.dx, radius), center, .4);
Offset end = Offset.lerp(Offset(center.dx, radius), center, -2);
canvas.translate(center.dx, center.dy);
canvas.rotate(rotation);
canvas.translate(-center.dx, -center.dy);
canvas.drawLine(start, end, needle);
canvas.drawCircle(center, radius, circle);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Here is the code for the page displaying both camera preview and compass:
import 'package:camera/camera.dart';
import 'package:flutter/cupertino.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import'package:franck_ehrhart/camera/preview_compass.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:image_picker_saver/image_picker_saver.dart';
import 'package:flutter/services.dart';
class CompassTool extends StatefulWidget {
// Screenshot
CompassTool({Key key}) : super(key: key);
#override
_CompassToolState createState() => _CompassToolState();
}
class _CompassToolState extends State<CompassTool> {
// Screenshot
static GlobalKey screen = new GlobalKey();
// Camera
CameraController controller;
List cameras;
int selectedCameraIndex;
String imgPath;
String compassPath;
// Textinput name of room
TextEditingController nameController = TextEditingController();
String roomName = '';
#override
void initState() {
super.initState();
// Camera
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
_initCameraController(cameras[selectedCameraIndex]).then((void v) {});
} else {
print('No camera available');
}
}).catchError((err) {
print('Error :${err.code}Error message : ${err.message}');
});
}
Future _initCameraController(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = CameraController(cameraDescription, ResolutionPreset.medium);
controller.addListener(() {
if (mounted) {
setState(() {});
}
if (controller.value.hasError) {
print('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueAccent,
appBar: AppBar(
title: Text("ORIENTATION PIECES"),
centerTitle: true,
backgroundColor: Colors.blueAccent.shade700,
),
// body: Compass()
body:
Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child:
_cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 80,
width: double.infinity,
padding: EdgeInsets.all(15),
color: Colors.blueAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_cameraToggleRowWidget(),
_cameraControlWidget(context),
Spacer()
],
),
),
),
Card(
margin: EdgeInsets.symmetric( horizontal: 10.0, vertical :5.0),
child: TextField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Nom de la pièce',
border: OutlineInputBorder(),
labelText: 'Nom de la pièce',
),
onChanged: (text) {
setState(() {
roomName = text;
//you can access nameController in its scope to get
// the value of text entered as shown below
//fullName = nameController.text;
}
);
},
),
),
]
),
),
),
);
}
/// Display the control bar with buttons to take pictures
Widget _cameraControlWidget(context) {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FloatingActionButton(
child: Icon(
Icons.camera,
color: Colors.black,
),
backgroundColor: Colors.white,
onPressed: () {
_onCapturePressed(context);
},
),
],
),
),
);
}
/// Display Camera preview.
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
return
//screenshot
RepaintBoundary(
key: screen,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
new Positioned.fill(
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller)),
),
new Positioned.fill(
child: Compass(
)
),
],
),
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraToggleRowWidget() {
if (cameras == null || cameras.isEmpty) {
return Spacer();
}
CameraDescription selectedCamera = cameras[selectedCameraIndex];
CameraLensDirection lensDirection = selectedCamera.lensDirection;
return Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FlatButton.icon(
onPressed: _onSwitchCamera,
icon: Icon(
_getCameraLensIcon(lensDirection),
color: Colors.white,
size: 24,
),
label: Text(
'${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1).toUpperCase()}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500
),),
),
),
);
}
// Camera
IconData _getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return CupertinoIcons.switch_camera;
case CameraLensDirection.front:
return CupertinoIcons.switch_camera_solid;
case CameraLensDirection.external:
return Icons.camera;
default:
return Icons.device_unknown;
}
}
void _showCameraException(CameraException e) {
String errorText = 'Error:${e.code}\nError message : ${e.description}';
print(errorText);
}
void _onCapturePressed(context) async {
try {
// Compass
RenderRepaintBoundary boundary = screen.currentContext.findRenderObject();
ui.Image image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final compassPath =
await ImagePickerSaver.saveFile(
fileData:byteData.buffer.asUint8List() );
// Camera
final path =
join((await getTemporaryDirectory()).path, '${DateTime.now()}.png');
await controller.takePicture(path);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewCompass(
imgPath: path,
compassPath: compassPath,
roomName: roomName,
)
),
);
} catch (e) {
_showCameraException(e);
}
}
void _onSwitchCamera() {
selectedCameraIndex =
selectedCameraIndex < cameras.length - 1 ? selectedCameraIndex + 1 : 0;
CameraDescription selectedCamera = cameras[selectedCameraIndex];
_initCameraController(selectedCamera);
}
}
And here is the code for the page displaying the screenshot of the previous screen:
import 'dart:io';
import 'dart:typed_data';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
// packages screenshot
import 'package:flutter/rendering.dart';
import 'package:screenshot/screenshot.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_icons/flutter_icons.dart';
// Compass
class PreviewCompass extends StatefulWidget{
final String imgPath;
final String compassPath;
final String roomName;
const PreviewCompass({Key key, this.imgPath, this.compassPath, this.roomName}) : super(key: key);
//PreviewCompass({this.imgPath,this.roomName});
#override
_PreviewCompassState createState() => _PreviewCompassState();
}
class _PreviewCompassState extends State<PreviewCompass>{
// Screenshot
File _imageFile;
ScreenshotController screenshotController = ScreenshotController();
#override
Widget build(BuildContext context) {
return Screenshot(
controller: screenshotController,
child:
Scaffold(
backgroundColor: Colors.blueAccent,
appBar: AppBar(
automaticallyImplyLeading: true,
title: Text("ORIENTATION PIECE"),
centerTitle: true,
backgroundColor: Colors.blueAccent.shade700,
),
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 2,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
new Positioned.fill(child:
Image.file(File(widget.imgPath),fit: BoxFit.fill,),),
new Positioned.fill(child:
Image.file(File(widget.compassPath),fit: BoxFit.fill,),),
/*
Expanded(
// flex: 1,
child:
Image.file(File(widget.imgPath),fit: BoxFit.fill,),
),
Align(
// alignment: Alignment.bottomCenter,
child: Image.file(File(widget.compassPath),fit: BoxFit.fill,),
),*/
],
),
),
Card(
margin: EdgeInsets.symmetric( horizontal: 10.0, vertical :5.0),
child: ListTile (
leading: Icon(
FontAwesome.compass,
color: Colors.blue.shade900,
),
title: (
Text (widget?.roomName,
style: TextStyle(
fontSize: 15.0,
fontFamily: 'Source Sans Pro',
color: Colors.blue.shade900,
)
)
),
)
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.black,
child: Center(
child: IconButton(
icon: Icon(Icons.share,color: Colors.white,),
onPressed: () async {
_takeScreenshotandShare();
},
),
),
),
),
],
),
),
),
);
}
// Screenshot
_takeScreenshotandShare() async {
_imageFile = null;
screenshotController
.capture(delay: Duration(milliseconds: 10), pixelRatio: 2.0)
.then((File image) async {
setState(() {
_imageFile = image;
});
final directory = (await getApplicationDocumentsDirectory()).path;
Uint8List pngBytes = _imageFile.readAsBytesSync();
File imgFile = new File('$directory/screenshot.png');
imgFile.writeAsBytes(pngBytes);
print("File Saved to Gallery");
await Share.file('Screenshot', 'screenshot.png', pngBytes, 'image/png');
})
.catchError((onError) {
print(onError);
});
}
}
Can you please help me with this error ?
Many thanks.
Your error comes from here:
FlutterCompass.events.listen(_onData);
You should store that stream subscription in a variable and cancel it in the dispose method:
StreamSubscription<double> stream;
#override
void initState() {
super.initState();
stream = FlutterCompass.events.listen(_onData);
}
#override
void dispose() {
stream.cancel();
super.dispose();
}
I am trying to make a slider to enlarge and reduce the font but I am facing this error.
E/flutter (11441): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)]
Unhandled Exception: NoSuchMethodError: The method 'setString' was
called on null.
E/flutter (11441): Receiver: null
E/flutter (11441): Tried calling: setString("fontSizeArabic",
"23.99652777777778")
E/flutter (11441): #0 Object.noSuchMethod
(dart:core-patch/object_patch.dart:53:5)
E/flutter (11441): #1 SettingsHelpers.fontSizeArabic
(package:alquranalkareem/helper/settings_helpers.dart:20:17)
E/flutter (11441): #2 _QuranShowState._showTafseer..
(package:alquranalkareem/module/quran/show.dart:881:32)
E/flutter (11441): #3 _SliderState._handleChanged
(package:flutter/src/material/slider.dart:453:14)
E/flutter (11441): #4 _RenderSlider._startInteraction
(package:flutter/src/material/slider.dart:982:7)
E/flutter (11441): #5 _RenderSlider._handleTapDown
(package:flutter/src/material/slider.dart:1031:50)
E/flutter (11441): #6
TapGestureRecognizer.handleTapDown.
(package:flutter/src/gestures/tap.dart:463:51)
E/flutter (11441): #7 GestureRecognizer.invokeCallback
(package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (11441): #8 TapGestureRecognizer.handleTapDown
(package:flutter/src/gestures/tap.dart:463:11)
E/flutter (11441): #9 BaseTapGestureRecognizer._checkDown
(package:flutter/src/gestures/tap.dart:256:5)
E/flutter (11441): #10 BaseTapGestureRecognizer.didExceedDeadline
(package:flutter/src/gestures/tap.dart:227:5)
E/flutter (11441): #11
PrimaryPointerGestureRecognizer.didExceedDeadlineWithEvent
(package:flutter/src/gestures/recognizer.dart:496:5)
E/flutter (11441): #12
PrimaryPointerGestureRecognizer.addAllowedPointer.
(package:flutter/src/gestures/recognizer.dart:449:40)
E/flutter (11441): #13 _rootRun (dart:async/zone.dart:1122:38)
E/flutter (11441): #14 _CustomZone.run
(dart:async/zone.dart:1023:19)
E/flutter (11441): #15 _CustomZone.runGuarded
(dart:async/zone.dart:925:7)
E/flutter (11441): #16 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:965:23)
E/flutter (11441): #17 _rootRun (dart:async/zone.dart:1126:13)
E/flutter (11441): #18 _CustomZone.run
(dart:async/zone.dart:1023:19)
E/flutter (11441): #19 _CustomZone.bindCallback. (dart:async/zone.dart:949:23)
E/flutter (11441): #20 Timer._createTimer.
(dart:async-patch/timer_patch.dart:23:15)
E/flutter (11441): #21 _Timer._runTimers
(dart:isolate-patch/timer_impl.dart:384:19)
E/flutter (11441): #22 _Timer._handleMessage
(dart:isolate-patch/timer_impl.dart:418:5)
E/flutter (11441): #23 _RawReceivePortImpl._handleMessage
(dart:isolate-patch/isolate_patch.dart:174:12)
Do you have a solution to the problem?
settings_helpers
import 'dart:convert';
import 'dart:ui';
import 'package:quiver/strings.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SettingsHelpers {
static SettingsHelpers _instance;
static SettingsHelpers get instance {
if (_instance == null) {
_instance = SettingsHelpers();
}
return _instance;
}
SharedPreferences prefs;
Future fontSizeArabic(double fontSize) async {
await prefs.setString('fontSizeArabic', fontSize.toString());
}
static const double minFontSizeArabic = 22;
double get getFontSizeArabic {
String fontSizeString = prefs.getString('fontSizeArabic');
return double.tryParse(fontSizeString ?? minFontSizeArabic.toString());
}
Future setLocale(Locale locale) async {
var map = {
'languageCode': locale.languageCode,
};
var json = jsonEncode(map);
await prefs.setString('locale', json);
}
Locale getLocale() {
var json = prefs.getString('locale');
if (isBlank(json)) {
return Locale('en');
}
var mapJson = jsonDecode(json);
var locale = Locale(mapJson["languageCode"]);
return locale;
}
Future init() async {
prefs = await SharedPreferences.getInstance();
}
}
_showTafseer
Widget _showTafseer(int pageNum) {
TafseerRepository tafseerRepository = new TafseerRepository();
return FutureBuilder<List<Ayat>>(
future: tafseerRepository.getPageTafseer(pageNum),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
List<Ayat> ayat = snapshot.data;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: <Widget>[
Container(
color: Theme.of(context).primaryColorLight,
child: Row(
children: <Widget>[
Slider(
min: SettingsHelpers.minFontSizeArabic,
max: maxFontSizeArabic,
value: fontSizeArabic,
activeColor: Theme.of(context).hoverColor,
inactiveColor: Theme.of(context).primaryColorDark,
onChanged: (double value) async {
await SettingsHelpers.instance
.fontSizeArabic(value);
setState(
() {
fontSizeArabic = value;
},
);
_myEventBus.eventBus.fire(
FontSizeEvent()
..arabicFontSize = value
);
},
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).hoverColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
)
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text('${fontSizeArabic.toInt()}',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).primaryColorLight)),
),
),
],
),
),
Container(
// width: 300.0,
height: 500.0,
child: ListView.builder(
itemCount: ayat.length,
itemBuilder: (context, position) {
Ayat aya = ayat[position];
List<String> tafseer = aya.tafsser.split("))");
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0)
)
),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
"﴿${tafseer.first}﴾",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Uthmanic",
fontWeight: FontWeight.w500,
fontSize: fontSizeArabic
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
child: Text(
"${tafseer.last.trim()}",
textAlign: TextAlign.justify,
style: TextStyle(
color: Theme.of(context).hoverColor,
fontFamily: 'naskh',
fontWeight: FontWeight.w100,
fontSize: fontSizeArabic
),
),
),
Divider()
],
);
}),
),
],
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
I think the issue is with prefs not being properly initialized. Just try making your initialization simpler as below
I have used the factory design pattern. See this article to learn more about it.
Note that I used a simple floating button to trigger the action rather than the slider
class SettingsHelpers {
SharedPreferences prefs;
static final SettingsHelpers _instance = SettingsHelpers._internal();
SettingsHelpers._internal(){
_init();
}
factory SettingsHelpers() => _instance;
void _init() async {
prefs = await SharedPreferences.getInstance();
}
void fontSizeArabic(double fontSize) async {
prefs.setString('fontSizeArabic', fontSize.toString());
}
static const double minFontSizeArabic = 22;
double get getFontSizeArabic {
String fontSizeString = prefs.getString('fontSizeArabic');
return double.tryParse(fontSizeString ?? minFontSizeArabic.toString());
}
Future setLocale(Locale locale) async {
var map = {
'languageCode': locale.languageCode,
};
var json = jsonEncode(map);
await prefs.setString('locale', json);
}
Locale getLocale() {
var json = prefs.getString('locale');
if (isBlank(json)) {
return Locale('en');
}
var mapJson = jsonDecode(json);
var locale = Locale(mapJson["languageCode"]);
return locale;
}
}
class SampleTest extends StatefulWidget {
#override
_SampleTestState createState() => _SampleTestState();
}
class _SampleTestState extends State<SampleTest> {
double fontSizeArabic;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: _onPressed),
);
}
void _onPressed() async {
double value = 18.0;
SettingsHelpers().fontSizeArabic(value);
}
}
I'm getting a "Closure call with mismatched arguments"-error when I try to submit a form in my Flutter app, and I don't have a single clue why it's happening. It seems to have issues with my handleInputSave-function, however I'm only calling it once and I've confirmed multiple times that the arguments are correct.
The complete error:
I/flutter ( 6655): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 6655): The following NoSuchMethodError was thrown while handling a gesture:
I/flutter ( 6655): Closure call with mismatched arguments: function '_MetricState.build.<anonymous closure>'
I/flutter ( 6655): Receiver: Closure: (dynamic) => bool
I/flutter ( 6655): Tried calling: _MetricState.build.<anonymous closure>()
I/flutter ( 6655): Found: _MetricState.build.<anonymous closure>(dynamic) => bool
I/flutter ( 6655):
I/flutter ( 6655): When the exception was thrown, this was the stack:
I/flutter ( 6655): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
I/flutter ( 6655): #1 NumberInputState.build.<anonymous closure> (package:greeklibrary/components/Select/Metric/numberinput.dart:60:26)
I/flutter ( 6655): #2 FormFieldState._validate (package:flutter/src/widgets/form.dart)
I/flutter ( 6655): #3 FormFieldState.validate.<anonymous closure> (package:flutter/src/widgets/form.dart:364:7)
I/flutter ( 6655): #4 State.setState (package:flutter/src/widgets/framework.dart:1141:30)
I/flutter ( 6655): #5 FormFieldState.validate (package:flutter/src/widgets/form.dart:363:5)
I/flutter ( 6655): #6 FormState._validate (package:flutter/src/widgets/form.dart:203:25)
I/flutter ( 6655): #7 FormState.validate (package:flutter/src/widgets/form.dart:197:12)
I/flutter ( 6655): #8 _MetricState.build.<anonymous closure> (package:greeklibrary/components/Select/Metric/metric.dart:48:51)
I/flutter ( 6655): #9 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:654:14)
I/flutter ( 6655): #10 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:729:32)
I/flutter ( 6655): #11 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
I/flutter ( 6655): #12 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
I/flutter ( 6655): #13 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
I/flutter ( 6655): #14 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
I/flutter ( 6655): #15 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:75:13)
I/flutter ( 6655): #16 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:102:11)
I/flutter ( 6655): #17 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
I/flutter ( 6655): #18 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
I/flutter ( 6655): #19 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter ( 6655): #20 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
I/flutter ( 6655): #21 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
I/flutter ( 6655): #25 _invoke1 (dart:ui/hooks.dart:263:10)
I/flutter ( 6655): #26 _dispatchPointerDataPacket (dart:ui/hooks.dart:172:5)
I/flutter ( 6655): (elided 3 frames from package dart:async)
I/flutter ( 6655):
I/flutter ( 6655): Handler: "onTap"
I/flutter ( 6655): Recognizer:
I/flutter ( 6655): TapGestureRecognizer#8abdf
I/flutter ( 6655): ════════════════════════════════════════════════════════════════════════════════════════════════════
The Metric (parent) widget:
import "package:flutter/material.dart";
import 'package:greeklibrary/styles/variables.dart';
import "./numberinput.dart";
class Metric extends StatefulWidget {
#override
_MetricState createState() => _MetricState();
}
class _MetricState extends State<Metric> {
final _formKey = GlobalKey<FormState>();
var _formData = {};
void handleInputSave(String name, String value) {
print("called");
setState(() => _formData[name] = value);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: colorPrimary,
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Center(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NumberInput(
name: "book",
defaultValue: "1",
validator: (value) =>
!RegExp(r"^[0-9]$").hasMatch(value) &&
!RegExp(r"^[1-2][0-4]$").hasMatch(value),
onSaved: (String name, String value) =>
handleInputSave(name, value),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text("Ἀγε!"),
onPressed: () {
print(_formKey.currentState.validate());
if (_formKey.currentState.validate()) {
// _formKey.currentState.save();
print("succeeded");
// Navigator.of(context).pushNamed("/loading");
}
})
],
),
),
),
),
);
}
}
The NumberInput (child) widget:
import "package:flutter/material.dart";
class NumberInput extends StatefulWidget {
final String name;
final String defaultValue;
final Function validator;
final Function onSaved;
NumberInput({this.name, this.defaultValue, this.validator, this.onSaved});
#override
NumberInputState createState() => NumberInputState();
}
class NumberInputState extends State<NumberInput> {
String value;
#override
void initState() {
super.initState();
setState(() => value = widget.defaultValue);
print(widget.onSaved);
}
Widget build(BuildContext context) {
return Row(
children: <Widget>[
ButtonTheme(
minWidth: 14.0,
buttonColor: Color.fromRGBO(0, 0, 0, 0.0),
child: RaisedButton(
child: Text(
"-",
style: TextStyle(fontSize: 32.0),
),
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
onPressed: () {
setState(() {
if (int.parse(value) > 1) {
value = (int.parse(value) - 1).toString();
}
});
},
),
),
SizedBox(
width: 16.0,
),
Flexible(
child: TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: "Vul een boeknummer in",
),
controller: TextEditingController(text: value),
validator: (value) {
if (widget.validator()) {
return "Vul alstublieft een (geldig) booknummer in.";
}
return null;
},
onSaved: (value) {
widget.onSaved(widget.name, value);
},
),
),
SizedBox(
width: 16.0,
),
ButtonTheme(
minWidth: 14.0,
buttonColor: Color.fromRGBO(0, 0, 0, 0.0),
child: RaisedButton(
child: Text(
"+",
style: TextStyle(fontSize: 32.0),
),
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
onPressed: () {
setState(() => value = (int.parse(value) + 1).toString());
},
),
),
],
);
}
}
You forgot to put value as parameter for your validator
You can copy paste run full code below
code snippet
if (widget.validator(value)) {
return "Vul alstublieft een (geldig) booknummer in.";
}
demo
full code
import 'package:flutter/material.dart';
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();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(flex:1, child: Metric()),
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),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Metric extends StatefulWidget {
#override
_MetricState createState() => _MetricState();
}
class _MetricState extends State<Metric> {
final _formKey = GlobalKey<FormState>();
var _formData = {};
void handleInputSave(String name, String value) {
print("called");
setState(() => _formData[name] = value);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,//colorPrimary,
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Center(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NumberInput(
name: "book",
defaultValue: "1",
validator: (value) =>
!RegExp(r"^[0-9]$").hasMatch(value) &&
!RegExp(r"^[1-2][0-4]$").hasMatch(value),
onSaved: (String name, String value) =>
handleInputSave(name, value),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text("Ἀγε!"),
onPressed: () {
print(_formKey.currentState.validate());
if (_formKey.currentState.validate()) {
// _formKey.currentState.save();
print("succeeded");
// Navigator.of(context).pushNamed("/loading");
}
})
],
),
),
),
),
);
}
}
class NumberInput extends StatefulWidget {
final String name;
final String defaultValue;
final Function validator;
final Function onSaved;
NumberInput({this.name, this.defaultValue, this.validator, this.onSaved});
#override
NumberInputState createState() => NumberInputState();
}
class NumberInputState extends State<NumberInput> {
String value;
#override
void initState() {
super.initState();
setState(() => value = widget.defaultValue);
print(widget.onSaved);
}
Widget build(BuildContext context) {
return Row(
children: <Widget>[
ButtonTheme(
minWidth: 14.0,
buttonColor: Color.fromRGBO(0, 0, 0, 0.0),
child: RaisedButton(
child: Text(
"-",
style: TextStyle(fontSize: 32.0),
),
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
onPressed: () {
setState(() {
if (int.parse(value) > 1) {
value = (int.parse(value) - 1).toString();
}
});
},
),
),
SizedBox(
width: 16.0,
),
Flexible(
child: TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: "Vul een boeknummer in",
),
controller: TextEditingController(text: value),
validator: (value) {
if (widget.validator(value)) {
return "Vul alstublieft een (geldig) booknummer in.";
}
return null;
},
onSaved: (value) {
widget.onSaved(widget.name, value);
},
),
),
SizedBox(
width: 16.0,
),
ButtonTheme(
minWidth: 14.0,
buttonColor: Color.fromRGBO(0, 0, 0, 0.0),
child: RaisedButton(
child: Text(
"+",
style: TextStyle(fontSize: 32.0),
),
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
onPressed: () {
setState(() => value = (int.parse(value) + 1).toString());
},
),
),
],
);
}
}