I am new to coding and to flutter but am attempting to build an app for scanning, creating database, and inventory. I have been attempting to use flutter_barcode_scanner to achieve this along with several others while looking at multiple videos and blogs but have become unsuccessful and am now I'm coming here for help.
Provided is the code that I'm currently attempting to write for it. At this point I've confused myself since I was recently trying to utilize scan_preview also as my goal is to implement the scanner as a stream in half or 1/3rd of the screen and having the rest of the screen as the result that is pulled from the database or to create a new item if no match.
I am looking for some assistance in how to implement the barcode scanner in the fashion where it streams in part of the screen and why I am getting these issues and how to fix them. I have attempted the fixes that androidstudio is providing me but it creates many more issues.
Am I going about this the correct way?
How do I use flutter_barcode_scanner to stream in only a portion of the screen?
Errors from AndroidStudio:
child: ScanMode.BARCODE( Error: The expression doesn't evaluate to a function, so it can't be invoked
Center(child: Text(barcode)) Error: Undefined name 'barcode'
'#ff6666', 'Cancel', true, ScanMode.BARCODE)! Error: This requires the 'non-nullable' language feature to be enabled
return Scaffold(
appBar: AppBar(
title: Text("Barcode Scanner"),
centerTitle: true,
),
body: Column(
children: [
SizedBox(
width: double.infinity,
height: height / 0.6,
child: ScanMode.BARCODE(
onScanResult: (result) {
debugPrint('scan result: $result');
setState(() {
_data = result;
});
},
),
),
SizedBox(height: 20),
Center(child: Text(barcode))
],
));
}
}
class ScannerHelper extends StatefulWidget {
#override
_ScannerHelperState createState() => _ScannerHelperState();
}
class _ScannerHelperState extends State<ScannerHelper> {
String _scanbarcode = 'Unknown';
#override
void initState() {
super.initState();
}
Future<void> startBarcodeScanStream() async {
FlutterBarcodeScanner.getBarcodeStreamReceiver(
'#ff6666', 'Cancel', true, ScanMode.BARCODE)!
.listen((barcode) => print(barcode));
}
//build - to resolve scanner issue
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Barcode scan')),
body: Builder(builder: (BuildContext context) {
return Container(
alignment: Alignment.center,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => startBarcodeScanStream(),
child: Text('Start barcode scan stream')),
Text('Scan result : $_scanbarcode\n',
style: TextStyle(fontSize: 20))
]));
})));
}
Related
In my flutter application, I have to provide an option to change the font size of the application Text contents.
So, normally, I know that for different screen sizes, We can manage but this is not that case.
I have just gone through this plugin:
https://pub.dev/packages/sizer
But, It's not the case which I am looking for.
The case is to choose particular font size option and according to selected option the font height should be change.
How can I achieve this? Thanks.
If you want the user to be able to change fontsize in your application you could do something like this.
class _MyHomePageState extends State<MyHomePage> {
double? _fontSize = 14;
void _changeFontSize(double fontSize) {
setState(() {
_fontSize = fontSize;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'FontSize is now: $_fontSize',
style: TextStyle(fontSize: _fontSize),
),
ElevatedButton(onPressed: () => _changeFontSize(22), child: const Text("22")),
ElevatedButton(onPressed: () => _changeFontSize(24), child: const Text("24")),
ElevatedButton(onPressed: () => _changeFontSize(26), child: const Text("26")),
],
),
),
);}}
I want to create a show dialog box that will act as a disclosure. The one that I've used now gives me a fullscreen dialog, which I don't want. I want it to take the least amount of space that is needed.
This disclosure should pop up immediately as soon as the app opens, therefore, I've added this in the init state. Can someone please tell me how to minimise the size?
The code is as below.`
class LandingScreen extends StatefulWidget {
static const routeName = "/landing_screen";
#override
_LandingScreenState createState() => _LandingScreenState();}
class _LandingScreenState extends State<LandingScreen> {
bool _introDone = false;
#override
void initState() {
// TODO: implement initState
super.initState();
SharedPreferences.getInstance().then((value) {
final introDone = value.getBool("introDone") ?? false;
setState(() {
_introDone = introDone;
});
!_introDone
? showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("DISCLOSURE"),
content: Column(
children: <Widget>[
const Text("This app collects location data to enable location tracking in order to provide location based reminders. This include collecting location data even when the app is running in the background. The data collected will be handled according to the terms of our Privacy notice"),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: () {},
child: const Text("GOT IT")),
],
);
},
):null;
});
#override
Widget build(BuildContext context) {
return Containter();
}
}
Your problem is in the Column widget. You have to changethe mainAxisSize to min.
builder: (BuildContext context) {
return AlertDialog(
title: const Text("DISCLOSURE"),
content: Column(
mainAxisSize: MainAxisSize.min, // <---
children: <Widget>[
const Text("This app collects location data to enable location tracking in order to provide location based reminders. This include collecting location data even when the app is running in the background. The data collected will be handled according to the terms of our Privacy notice"),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: () {},
child: const Text("GOT IT")),
],
);
},
I'm trying to use the simple state management described in the Flutter docs, using a ChangeNotifier, a Consumer, and a ChangeNotifierProvider.
My problem is that I can't get a hold a on valid context to update my model (details below...). I get an error:
Error: Error: Could not find the correct Provider above this CreateOrganizationDialog Widget
This likely happens because you used a BuildContext that does not include the provider of your choice. There are a few common scenarios:
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that CreateOrganizationDialog is under your MultiProvider/Provider.
This usually happen when you are creating a provider and trying to read it immediately.
Here are extracts of my code:
class OrganizationModel extends ChangeNotifier {
final List<Organization> _items = [];
/// An unmodifiable view of the items in the cart.
UnmodifiableListView<Organization> get items => UnmodifiableListView(_items);
void addList(List<Organization> items) {
_items.addAll(items);
notifyListeners();
}
}
This is my model.
class OrganizationBodyLayout extends StatelessWidget {
Future<void> _showCreateOrganizationDialog() async {
return showDialog<void>(
context: navigatorKey.currentState.overlay.context,
barrierDismissible: false,
child: CreateOrganizationDialog());
}
_onCreateOrganizationPressed() {
_showCreateOrganizationDialog();
}
_onDeleteOrganizationPressed() {
//TODO something
}
_onEditOrganizationPressed() {
//TODO something
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(mainAxisSize: MainAxisSize.max, children: [
ButtonBar(
alignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
RaisedButton(
onPressed: _onCreateOrganizationPressed,
child: Text("New Organization"),
),
],
),
Expanded(
child: Container(
color: Colors.pink,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: ChangeNotifierProvider(
create: (context) => OrganizationModel(),
child: OrganizationListView(),
)),
Expanded(child: Container(color: Colors.brown))
]))),
]));
}
}
A stateless widget that contains a ChangeNotifierProvider just on top of the list widget using the model.
On a button click, a modal dialog is shown, then data is fetched from the network. I should then update my model calling the addList operation.
Below is the code for the stateful dialog box.
class CreateOrganizationDialog extends StatefulWidget {
#override
_CreateOrganizationDialogState createState() =>
_CreateOrganizationDialogState();
}
class _CreateOrganizationDialogState extends State<CreateOrganizationDialog> {
TextEditingController _nametextController;
TextEditingController _descriptionTextController;
#override
initState() {
_nametextController = new TextEditingController();
_descriptionTextController = new TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Container(
width: 200,
height: 220,
child: Column(
children: [
Text('New organization',
style: Theme.of(context).textTheme.headline6),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration: new InputDecoration(hintText: "Organization name"),
controller: _nametextController,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration:
new InputDecoration(hintText: "Organization description"),
controller: _descriptionTextController,
),
),
ButtonBar(
children: [
FlatButton(
child: new Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: new Text("Create"),
onPressed: () {
setState(() {
Future<Organization> organization =
backendCreateOrganization(_nametextController.text,
_descriptionTextController.text);
organization.then((value) {
Future<List<Organization>> organizations =
backendReloadOrganizations();
organizations.then((value) {
var model = context.read<OrganizationModel>();
// var model = navigatorKey.currentState.overlay.context.read<OrganizationModel>();
//model.addList(value);
});
});
});
Navigator.of(context).pop();
//context is the one for the create dialog here
},
)
],
)
],
),
));
}
}
My problem happens at the line
var model = context.read<OrganizationModel>();
Thinking of it, the context available here is the modal dialog box context - so it's kind of logical that the Provider is not found in the widget tree.
However, I can't see how to retrieve the proper context (which would be the one for the result list view, where the Provider is located) in order to get the model and then update it.
Any idea is welcome :-)
Solved (kind of).
The only way I've found to solve this is by making my model a global variable:
var globalModel = OrganizationModel();
And referencing this global model in all widgets that consume it. I can't find a way to find the context of a stateless widget from within a callback in another stateful widget.
It works, but it's ugly. Still open to elegant solutions here :-)
Get_it seems to be elegant way of sharing models across the application. Please check the documentation for the different use cases they provide.
You could do something like the following
GetIt getIt = GetIt.instance;
getIt.registerSingleton<AppModel>(AppModelImplementation());
getIt.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());
And in other parts of your code, you could do something like
var myAppModel = getIt.get<AppModel>();
I'm trying to achieve a scrollable List with videos. I'm using the video_player widget and wrapping the player in a Card with a simple button.
Now i noticed that whenever I use ListView.builder with videos in the list, it is extremely lagging, especially when scrolling back up. i'm posting a GiF bellow if you would like to see the behaviour.
I have this problem ONLY when I have Videos in the list.
If I replace the videos with a simple Image widget, the scrolling is smooth and runs as intended. (Also provided a GiF below)
When I scroll through the list I get this message in my Console:
flutter: Another exception was thrown: setState() or markNeedsBuild() called during build.
And I think (but not sure) that this is the cause of the problem, maybe the way I implemented the video_player plugin (?)
class VideoPlayPause extends StatefulWidget {
VideoPlayPause(this.controller);
final VideoPlayerController controller;
#override
_VideoPlayPauseState createState() => _VideoPlayPauseState();
}
class _VideoPlayPauseState extends State<VideoPlayPause> {
//This Part here
_VideoPlayPauseState() {
listener = () {
setState(() {});
};
}
Maybe its setting state every time I scroll ?
I tried flutter run --release but saw no difference at all.
I'm running the app on a physical Iphone X.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MVP_Test1'),
),
body: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: videoUrl.length,
itemBuilder: (context, i) {
return Card(
child: Column(
children: <Widget>[
Column(
children: <Widget>[
const ListTile(
leading: Icon(Icons.live_tv),
title: Text("Nature"),
),
Stack(
alignment: FractionalOffset.bottomRight +
const FractionalOffset(-0.1, -0.1),
children: <Widget>[
// If I replace this with Image.asset("..."), the scrolling is very smooth.
AssetPlayerLifeCycle(
videoUrl[i],
(BuildContext context,
VideoPlayerController controller) =>
AspectRatioVideo(controller)),
]),
],
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('ADD VIDEO'),
onPressed: () {
/* ... */
},
),
],
),
),
],
),
);
},
),
);
}
Result when I run Flutter Analyze
flutter analyze
Analyzing mvp_1...
No issues found! (ran in 1.9s)
You can see how when scrolling back up it looks like the app is skipping frames or something. Here's a video:
https://giphy.com/gifs/u48BNQ13r15Zay5SnN
Here's a video with photos instead of videos:
https://giphy.com/gifs/236RKyA8y1pfecmR1d
I'm working on my first Flutter app (debugging on my Android phone). I have a list with row items. When you long-press the row, it copies the content into the user's clipboard. This is working great!
But I need to let the user know that the content was copied.
I've attempted to follow many tutorials on trying to get the row surrounded by a build method or inside a Scaffold, but I can't get any to work. Is there an alternative method to notifying the user (simply) that something like "Copied!" took place?
Notice the commented out Scaffold.of(... below. It just seems like there must be an easier method to notifying the user other than wrapping everything in a Scaffold. (and when I try, it breaks my layout).
import 'package:flutter/material.dart';
import 'package:my_app/Theme.dart' as MyTheme;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/services.dart';
class RowRule extends StatelessWidget {
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(new Text(ruleGroup['label'],
style: MyTheme.TextStyles.articleContentLabelTextStyle));
}
if (!ruleGroup['details'].isEmpty) {
builder.add(new Text(ruleGroup['details'],
style: MyTheme.TextStyles.articleContentTextStyle));
}
return builder;
}
#override
Widget build(BuildContext context) {
return new GestureDetector(
onLongPress: () {
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
// Scaffold.of(context).showSnackBar(SnackBar
// (content: Text('text copied')));
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 3.0),
child: new FlatButton(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 0.0),
child: new Stack(
children: <Widget>[
new Container(
margin: const EdgeInsets.symmetric(
vertical: MyTheme.Dimens.ruleGroupListRowMarginVertical),
child: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.0, vertical: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildChildren(),
),
)),
)
],
),
),
));
}
}
The goal is to have a page like this (see image), which I have, and it works and scrolls...etc, but I cannot get it to work with a Scaffold, and therefore, haven't been able to use the snackbar. Each "Row" (which this file is for) should show a snackbar on longPress.
You can use GlobalKey to make it work the way you want it.
Since I don't have access to your database stuff, this is how I gave you an idea to do it. Copy and paste this code in your class and make changes accordingly. I also believe there is something wrong in your RowRule class, can you just copy the full code I have given you and run?
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatelessWidget {
final GlobalKey<ScaffoldState> _key = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFFFFFFF).withOpacity(0.9),
key: _key,
body: Column(
children: <Widget>[
Container(
color: Color.fromRGBO(52, 56, 245, 1),
height: 150,
alignment: Alignment.center,
child: Container(width: 56, padding: EdgeInsets.only(top: 12), decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.yellow)),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: 120,
itemBuilder: (context, index) {
return Container(
color: Colors.white,
margin: const EdgeInsets.all(4),
child: ListTile(
title: Text("Row #$index"),
onLongPress: () => _key.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Copied \"Row #$index\""))),
),
);
},
),
),
],
),
);
}
}
These is a simple plugin replacement for the Snackbar named "Flushbar".
You can get the plugin here - https://pub.dartlang.org/packages/flushbar
You don't have to take care of any wrapping of widgets into scaffold also you get a lot of modifications for you like background gradient, adding forms and so on into Snackbar's and all.
Inside your onLongPressed in GestureDetectore you can do this.
onLongPressed:(){
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
Flushbar(
message: "Copied !!",
duration: Duration(seconds: 3),
)..show(context);
}
This will display the snackbar in you app where you would want to see it also you can get a lot of modification available to you so the you can make it look as per your app.
There are couple of things you need to do, like use onPressed property of the FlatButton it is mandatory to allow clicks, wrap your GestureDetector in a Scaffold. I have further modified the code so that it uses GlobalKey to make things easy for you.
Here is the final code (Your way)
class RowRule extends StatelessWidget {
final GlobalKey<ScaffoldState> globalKey = GlobalKey();
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(new Text(ruleGroup['label'], style: MyTheme.TextStyles.articleContentLabelTextStyle));
}
if (!ruleGroup['details'].isEmpty) {
builder.add(new Text(ruleGroup['details'], style: MyTheme.TextStyles.articleContentTextStyle));
}
return builder;
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: globalKey,
body: GestureDetector(
onLongPress: () {
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text('text copied')));
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 3.0),
child: new FlatButton(
onPressed: () => print("Handle button press here"),
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 0.0),
child: new Stack(
children: <Widget>[
new Container(
margin: const EdgeInsets.symmetric(vertical: MyTheme.Dimens.ruleGroupListRowMarginVertical),
child: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.0, vertical: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildChildren(),
),
),
),
)
],
),
),
),
),
);
}
}
I made a dropdown banner package on pub that allows you to easily notify users of errors or confirmation of success. It's a work in progress as I continue to add visually rich features.
I am not sure if your build() method is completed or you are yet to change it, because it consist of many widgets which are just redundant. Like there is no need to have Container in Container and further Padding along with a FlatButton which would make complete screen clickable. Also having Column won't be a good idea because your screen may overflow if you have more data. Use ListView instead.
So, if you were to take my advice, use this simple code that should provide you what you are really looking for. (See the build() method is of just 5 lines.
class RowRule extends StatelessWidget {
final GlobalKey<ScaffoldState> globalKey = GlobalKey();
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(
ListTile(
title: Text(ruleGroup['label'], style: MyTheme.TextStyles.articleContentLabelTextStyle),
onLongPress: () {
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Clicked")));
},
),
);
}
if (!ruleGroup['details'].isEmpty) {
builder.add(
ListTile(
title: Text(ruleGroup['details'], style: MyTheme.TextStyles.articleContentTextStyle),
onLongPress: () {
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Clicked")));
},
),
);
}
return builder;
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: globalKey,
body: ListView(children: _buildChildren()),
);
}
}
I read your comments on all answers and here is my conslusion:
You need ScaffoldState object that is just above the widget in tree to show Snackbar. You can either get it through GlobalKey as many have suggested. Fairly simple if the Scaffold is created inside build of the widget, but if it is outside the widget (in your case) then it becomes complicated. You need to pass that key, wherever you need it through Constructor arguments of child widgets.
Scaffold.of(context) is a very neat way to just do that. Just like an InheritedWidget, Scaffold.of(BuildContext context) gives you access of the closest ScaffoldState object above the tree. Else it could be a nightmare to get that instance (by passing it through as constructor arguments) if your tree was very deep.
Sorry, to disappoint but I don't think there is any better or cleaner method than this, if you want to get the ScaffoldState that is not built inside build of that widget. You can call it in any widget that has Scaffold as a parent.