Flutter Bluetooth External Barcode Scanner - android

I need to use an external barcode scanner which is connected via Bluetooth to my device (it is recognized as a keyboard). It works well and I can get the content of a barcode inside a TextField.
The problem is that I need to set the focus to the TextField in order to get the content of the barcode... Is there a way for the current screen to listen to the keyboard event that way I could get the data without wasting time selecting the TextField?

Might be too late but you can set the TextField autofocus prop to true.
TextField(
autofocus:true,
)

You can use this example code for RawKeyboardListener:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'RawKeyboardListener';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final FocusNode _focusNode = FocusNode();
String _controller = '';
String? _message;
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
FocusScope.of(context).requestFocus(_focusNode);
final TextTheme textTheme = Theme.of(context).textTheme;
return Container(
color: Colors.white,
alignment: Alignment.center,
child: DefaultTextStyle(
style: textTheme.bodyText1!,
child: RawKeyboardListener(
focusNode: _focusNode,
onKey: (RawKeyEvent event) {
if (event is RawKeyDownEvent) {
if (event.physicalKey == PhysicalKeyboardKey.enter) {
print('ENTER');
setState(() {
_message = _controller;
_controller = '';
});
} else {
print(
'_handleKeyEvent Event data keyLabel ${event.data.keyLabel}');
_controller += event.data.keyLabel;
}
print('controller: $_controller');
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_message ?? 'Press a key',
),
Text(
'${_message?.length}',
),
],
),
),
),
);
}
}
You can use TextEditingController for TextFormField

Related

Flutter setState() not updating the view after Invoking Flutter Code From Native Side

I am trying to implement invoking Flutter Code From Native Side using method channel and working as expected. But having issue with rendering the view after trying to set the state. Can any one help to fix the issue?
Actually the SimSlotInfo is calling from the below widget,
List<Step> getSteps() {
return <Step>[
Step(
state: currentStep > 0 ? StepState.complete : StepState.indexed,
isActive: currentStep >= 0,
title: const Text("Send SMS"),
content: Column(
children: [
SimSlotInfo()
],
),
),
];
}
SimSlotInfo dart class
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutterdemo/model/device_slot.dart';
class SimSlotInfo extends StatefulWidget {
//callback function
final void Function(String) callBackFunction;
const SimSlotInfo(this.callBackFunction, {super.key});
//const SimSlotInfo({Key? key}) : super(key: key);
#override
State<SimSlotInfo> createState() => _SimSlotInfoState();
}
class _SimSlotInfoState extends State<SimSlotInfo> {
final platformMethodChannel = const MethodChannel('common_lib_plugin');
List<SimDetails> simDetailsObj = [];
//execute the below code while page loading
#override
void initState() {
super.initState();
platformMethodChannel.setMethodCallHandler(handleNativeMethodCall);
}
Future<void> handleNativeMethodCall(MethodCall call) async {
// do some processing
switch(call.method) {
case "deviceInfo":
var simData = call.arguments;
var arrayObjsText = '[{"slot":0,"simno":"89911017061","deviceid":"3518920","carrierName":"Vodafone"},{"slot":1,"simno":"89101706","deviceid":"3511643","carrierName":"JIO"}]';
List simObjsJson = jsonDecode(arrayObjsText) as List;
simDetailsObj = simObjsJson.map((tagJson) => SimDetails.fromJson(tagJson)).toList();
setState(() {
simDetailsObj = simDetailsObj;
});
}
}
#override
Widget build(BuildContext context) {
return Column(
children:
simDetailsObj.map((data) => RadioListTile(
dense: true,
contentPadding: EdgeInsets.zero,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${data.carrierName}",
style: const TextStyle(color: Colors.black, fontSize: 18),
),
],
),
groupValue: _selectedSim,
value: data.simno,
onChanged: (val) {
},
)).toList()
);
}
}
First, you are trying to assign List to List so your code is getting brake there. to solve that loop the object with SimDetails object. and that will do the trick
ParentWidget
class _ParentWidgetState extends State<ParentWidget> {
#override
Widget build(BuildContext context) {
return ChildWidget( // <---- child widget
callSetState: (list) { // <--- callback Function
print(list);
setState(() {
// <---
});
},
);
}
}
In Child widget
class ChildWidget extends StatefulWidget {
const ChildWidget({Key? key, required this.callSetState}) : super(key: key);
final Function(List<SimDetails>) callSetState; // <-- declare callback function here
#override
State<ChildWidget> createState() => _ChildWidgetState();
}
and replace your setState with widget.callSetState
Future<void> handleNativeMethodCall(MethodCall methodCall) async {
switch (call.method) {
case 'deviceInfo':
var simData = call.arguments;
var arrayObjsText =
'[{"slot":0,"simno":"89911017061","deviceid":"3518920","carrierName":"Vodafone"},{"slot":1,"simno":"89101706","deviceid":"3511643","carrierName":"JIO"}]';
for (var data in jsonDecode(arrayObjsText)) {
simDetailsObj.add(
SimDetails(
slot: data['slot'],
simno: data['simno'],
deviceid: data['deviceid'],
carrierName: data['carrierName'],
),
);
}
/// setState(() {});
widget.callSetState(simDetailsObj);
break;
default:
}}

Is it possible to update TextFormField using shared state (and without violating good practices)?

I am trying to make test project according to good practices.
Please note that I DON'T want any "hacky" approach. I am willing to learn good way of solving it.
My understanding of "lifting state up" is that any change updates the state, and then view is redrawn (rebuild) using current state. It is great in theory, but it DOES NOT work with TextFormField/TextEditingController.
I want to have a SharedState and bi-directonal TextFormField/TextEditingController, as follows:
case 1 (works):
TextFormField changes -> state is updated -> readonly Text (in WidgetTwo) is updated
case 2 (does not work):
button (in WidgetOne) is clicked -> state is updated -> TextFormField (in WidgetThree) shows new value from state
I have code in 3 different widgets + main file + SharedSate:
main.dart
void main() {
runApp(ChangeNotifierProvider(
create: (_) => sharedState(), child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({Key? key, required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
WidgetOne(),
WidgetTwo(),
WidgetThree(),
]),
),
);
}
}
shared_state.dart
class SharedState extends ChangeNotifier {
int counter = 0;
void setCounter(int c) {
counter = c;
notifyListeners();
}
void incrementCounter() {
counter++;
notifyListeners();
}
void decrementCounter() {
counter--;
notifyListeners();
}
Future fetchCounterFromWeb() async {
// simulate external call
await Future.delayed(Duration(milliseconds: 500));
setCounter(42);
}
}
widget_one.dart
class WidgetOne extends StatelessWidget {
#override
Widget build(BuildContext context) {
var state = Provider.of<SharedState>(context, listen: false);
return Row(
children: [
ElevatedButton(
onPressed: () => state.decrementCounter(),
child: Text('decrement')),
ElevatedButton(
onPressed: () => state.incrementCounter(),
child: Text('increment')),
ElevatedButton(
onPressed: () => state.fetchCounterFromWeb(),
child: Text('fetch counter from web')),
],
);
}
}
widget_two.dart
class WidgetTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
var state = Provider.of<SharedState>(context, listen: true);
return Row(
children: [Text('Value of counter is: ${state.counter}')],
);
}
}
widget_three.dart (problem is here)
class WidgetThree extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return WidgetThreeState();
}
}
class WidgetThreeState extends State<WidgetThree> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late TextEditingController _controller;
#override
void initState() {
super.initState();
var state = Provider.of<SharedState>(context, listen: false);
_controller = TextEditingController(text: state.counter.toString());
}
#override
Widget build(BuildContext context) {
var state = Provider.of<SharedState>(context, listen: true);
// THE ISSUE:
// It is NOT possible to update Controller (or TextEditing field)
// without this hacky line (which is not good practice)
_controller.text = state.counter.toString();
return Form(
key: _formKey,
child: Column(children: [
TextFormField(
controller: _controller,
keyboardType: TextInputType.number,
onChanged: (v) {
state.setCounter(int.parse(v.isEmpty ? '0' : v));
},
)
]),
);
}
}
I know I can possible move TextEditingController to SharedState, but SharedState should be UI agnostic, and TextEditingController is a UI widget.

how can I use flutter_phone_direct_caller packages for real

I run below code but it's not working for real
import 'package:flutter/material.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: RaisedButton(
onPressed: _callNumber,
child: Text('Call Number'),
),
),
));
}
}
_callNumber() async {
const number = '+82)010-7335-7424';
print("hi"); //set the number here
bool? res = await FlutterPhoneDirectCaller.callNumber(number);
}
how can i run for real???
Should I have to build apk and run in real phone..?
I think for call dialer or Direct navigate to the dialer, the best package will be url_launcher. At first please install the package & then try the below code ---
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: _callNumber,
child: Text('Call Number'),
),
),
));
}
}
_callNumber() async {
const number = '+82)010-7335-7424';
print("hi"); //set the number here
if (!await launchUrl(Uri.parse("tel://$number"))) throw 'Could not launch ${Uri.parse("tel://$number")}';
}
Basically, I change the code inside the _callnumber method which is
_callNumber() async {
const number = '+82)010-7335-7424';
print("hi"); //set the number here
if (!await launchUrl(Uri.parse("tel://$number"))) throw 'Could not launch ${Uri.parse("tel://$number")}';
}

connect Flutter code from different sources like for example youtube tutorials

Hello Guys im new to flutter.
To understand Flutter I watched a lot of videos and read blog entries.
But there is always a problem:
Each video is about a specific topic and all of them start with a new Flutter project. As long as I want to continue working on the code I can't change the code.
Below I have added a code by Hanz Müller as an example. Topic NavigationBar.
But now I want to delete the text under the icons and edit the different app pages (body) with text and images.
I can't delete the text under the icons because text can't be ''null''.
And I can't edit the diffrent body pages because I can't find the position.
i only know html and css because it is a hobby and now i search for the place where i find the body container :)
Thanks a lot for your help
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class Destination {
const Destination(this.title, this.icon, this.color);
final String title;
final IconData icon;
final MaterialColor color;
}
const List<Destination> allDestinations = <Destination>[
Destination('Home', Icons.home, Colors.teal),
Destination('Business', Icons.business, Colors.cyan),
Destination('School', Icons.school, Colors.orange),
Destination('Flight', Icons.flight, Colors.blue)
];
class DestinationView extends StatefulWidget {
const DestinationView({ Key key, this.destination }) : super(key: key);
final Destination destination;
#override
_DestinationViewState createState() => _DestinationViewState();
}
class _DestinationViewState extends State<DestinationView> {
TextEditingController _textController;
#override
void initState() {
super.initState();
_textController = TextEditingController(
text: 'sample text: ${widget.destination.title}',
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${widget.destination.title} Text'),
backgroundColor: widget.destination.color,
),
backgroundColor: widget.destination.color[100],
body: Container(
padding: const EdgeInsets.all(32.0),
alignment: Alignment.center,
child: TextField(controller: _textController),
),
);
}
#override
void dispose() {
_textController.dispose();
super.dispose();
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin<HomePage> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: false,
child: IndexedStack(
index: _currentIndex,
children: allDestinations.map<Widget>((Destination destination) {
return DestinationView(destination: destination);
}).toList(),
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (int index) {
setState(() {
_currentIndex = index;
});
},
items: allDestinations.map((Destination destination) {
return BottomNavigationBarItem(
icon: Icon(destination.icon),
backgroundColor: destination.color,
title: Text(destination.title)
);
}).toList(),
),
);
}
}
void main() {
runApp(MaterialApp(home: HomePage(), debugShowCheckedModeBanner: false));
}
If you want to remove the Text under the icon Check the code where the Text widget is place.
So you have the relevant Text widget in BottomNavigationBarItem
title: Text(destination.title)
So if you don't need the Text widget you can simply replace it with Container to display nothing.
title: Text(destination.title)
I would suggest you read the code and understand it will. The better you understand how your widgets are built and rendered it will be easier to modify them.

How to use barcode_scan widget as a child to some other widget?

I am using barcode_scan widget in my flutter app when I call Scan method this widget takes up the whole screen where it show the camera, I want to show that camera view inside another widget.
You can use package https://pub.dev/packages/last_qr_scanner or https://pub.dev/packages/qr_code_scanner
They both use platform view within Flutter
full example code of last_qr_scanner
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:last_qr_scanner/last_qr_scanner.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
const MyApp({
Key key,
}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
var qrText = "";
var controller;
#override
void initState() {
super.initState();
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
final channel = controller.channel;
controller.init(qrKey);
channel.setMethodCallHandler((MethodCall call) async {
switch (call.method) {
case "onRecognizeQR":
dynamic arguments = call.arguments;
setState(() {
qrText = arguments.toString();
});
}
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Barcode Scanner Example'),
),
body: Column(
children: <Widget>[
Expanded(
child: LastQrScannerPreview(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
flex: 4,
),
Expanded(
child: Text("This is the result of scan: $qrText"),
flex: 1,
),
Expanded(
child: RaisedButton(
onPressed: () {
this.controller.toggleTorch();
},
child: Text("Toggle Torch"),
),
flex: 1,
)
],
),
),
);
}
}
Your camera view must be a flutter widget to be embedded in another widget.
You can use this package which outputs the camera preview on a flutter texture and use the Mobile Vision API to detect QR codes and barcodes : https://github.com/rmtmckenzie/flutter_qr_mobile_vision

Categories

Resources