I would like the camera preview screen to be full-screen, instead of the camera condensed down into a rectangle.
In other words, I would like the camera preview to cover the entire screen, and me build the elements on top of this. Not for the elements to reduce the camera preview.
Is there a specific element of code I need to add?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:camera/camera.dart';
import 'dart:io';
class Camera extends StatefulWidget {
Function setData;
Camera({Key key, this.setData}) : super(key: key);
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<Camera> {
CameraController controller;
List cameras;
int selectedCameraIndex;
String imgPath;
var image;
Future _openGallery() async {
image = await controller.takePicture();
if (widget.setData != null) {
widget.setData(File(image.path));
}
}
#override
void initState() {
super.initState();
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.high);
controller.addListener(() {
if (mounted) {
setState(() {});
}
if (controller.value.hasError) {
print('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {}
if (mounted) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child: _cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 120,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[_cameraControlWidget(context), Spacer()],
),
),
)
],
),
),
),
);
}
/// 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 AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
);
}
/// 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: () {
// getImage();
_openGallery();
Navigator.pop(context);
},
)
],
),
),
);
}
}
The Column widget puts widgets on top of each other vertically. Instead, you should use the Stack widget:
Something like this:
return Scaffold(
body: Container(
child: SafeArea(
child: Stack(
children: [
Expanded(
flex: 1,
child: _cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 120,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[_cameraControlWidget(context), Spacer()],
),
),
)
],
),
),
),
);
Related
I saw in the getx documents that GetxController is business logic class. When i try to seperate business logic in widget, i have an issue about some controllers such as CameraController, QRViewController,MediaPlayer,... Should i put all things in GetxController or keep this in widget?
qr_code.dart
import 'dart:developer';
import 'dart:io';
import 'package:clean_architecture_getx/controller/qr_code/qr_code_controller.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class QrCodeScreen extends StatefulWidget {
const QrCodeScreen({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _QrCodeScreenState();
}
class _QrCodeScreenState extends State<QrCodeScreen> {
final scanQrController = Get.put(ScanQrController());
QRViewController? qrViewController;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
qrViewController!.pauseCamera();
}
qrViewController!.resumeCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(
flex: 1,
child: FittedBox(
fit: BoxFit.contain,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Obx(() {
if (scanQrController.result.value.code != null) {
return Text(
'Barcode Type: ${describeEnum(scanQrController.result
.value.format)} Data: ${scanQrController.result
.value.code}');
} else {
return const Text('Scan a code');
}
}),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: qrViewController?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.flipCamera();
setState(() {});
},
child: FutureBuilder(
future: qrViewController?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(
snapshot.data!)}');
} else {
return const Text('loading');
}
},
)),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.pauseCamera();
},
child: const Text('pause',
style: TextStyle(fontSize: 20)),
),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.resumeCamera();
},
child: const Text('resume',
style: TextStyle(fontSize: 20)),
),
)
],
),
],
),
),
)
],
),
);
}
Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery
.of(context)
.size
.width < 400 ||
MediaQuery
.of(context)
.size
.height < 400)
? 150.0
: 300.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.qrViewController = controller;
});
controller.scannedDataStream.listen((scanData) {
debugPrint('barcode: ${scanData.code}');
scanQrController.updateBarCode(scanData);
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
qrViewController?.dispose();
super.dispose();
}
}
qr_code_controller.dart
import 'package:get/get.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQrController extends GetxController {
final result = Barcode(null, BarcodeFormat.unknown, null).obs;
void onQrViewCreated(QRViewController controller) {}
void updateBarCode(Barcode barcode) {
result.value = barcode;
}
}
Should i put QRViewController to ScanQrController (GetxController) or keep it in widget?
Put the UI in a view, and put the business logic inside a controller. Have a GetX Controller per feature. It would be more helpful if you could provide an example of your code.
My camera preview is distorted. It appears far too zoomed in, and also stretched.
What am I doing wrong? How can I fix?
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(children: <Widget>[
Center(
child: Transform.scale(
scale: controller.value.aspectRatio / deviceRatio,
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller),
),
),
),
]);
}
Note: Should work for iOS and Android.
I am using camera package: camera: ^0.7.0+2
Here full page
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'dart:io';
class Camera extends StatefulWidget {
Function setData;
Camera({Key key, this.setData}) : super(key: key);
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<Camera> {
CameraController controller;
List cameras;
int selectedCameraIndex;
String imgPath;
var image;
Future _openGallery() async {
image = await controller.takePicture();
if (widget.setData != null) {
widget.setData(File(image.path));
}
}
#override
void initState() {
super.initState();
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.high);
controller.addListener(() {
if (mounted) {
setState(() {});
}
if (controller.value.hasError) {
print('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {}
if (mounted) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child: _cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 120,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[_cameraControlWidget(context), Spacer()],
),
),
)
],
),
),
),
);
}
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(children: <Widget>[
Center(
child: Transform.scale(
scale: controller.value.aspectRatio / deviceRatio,
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller),
),
),
),
]);
}
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: () {
_openGallery();
Navigator.pop(context);
},
)
],
),
),
);
}
}
Edit based on answer:
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(children: <Widget>[
Center(
child: Transform.scale(
scale: 16 / 9,
child: Center(
child: AspectRatio(
aspectRatio: 1,
child: Camera(),
),
),
),
),
]);
}
Had the same problem using camerawesome some times ago.
Had to use Transform and an Aspect Ratio:
Transform.scale(
scale: 16 / 9,
child: Center(
child: AspectRatio(
aspectRatio: 1,
child: Camera(),
),
),
),
Use Matrix4.diagonal3Values for scaling, as we can then control the X, Y, Z axis. X is the horizontal, Y is the vertical and Z is for the ones that want to go into other dimensions 🚀.
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
final xScale = cameraController.value.aspectRatio / deviceRatio;
// Modify the yScale if you are in Landscape
final yScale = 1;
return Container(
child: AspectRatio(
aspectRatio: deviceRatio,
child: Transform(
alignment: Alignment.center,
transform: Matrix4.diagonal3Values(xScale, yScale, 1),
child: CameraPreview(cameraController),
),
),
);
If you are working with a camera that rotates and supports Landscape, you will most likely need to scale up the Y axis, and skip the X.
The Lightsnap app is locked in Portrait so we don’t need to re-scale the camera preview when the phone rotates. Just a note that you may need to do this if you are supporting landscape.
Thanks to Lightsnap(More Details here)
I am begginner flutter developer, I want to take a support, I designed welcome page and I put background image to the container, but I want it to scale and re-scale forever while user on welcome page, I just want to learn teory of animation controller and how to use them. How can I implement this to my code. Thank you... Have a nice day.
import 'package:flutter/material.dart';
import 'package:animated_text_kit/animated_text_kit.dart';
import 'file:///C:/Users/yagiz/AndroidStudioProjects/naber/lib/screens/login_screen.dart';
import 'file:///C:/Users/yagiz/AndroidStudioProjects/naber/lib/screens/registration_screen.dart';
import '../widgets.dart';
import 'package:naber/constants.dart';
class WelcomeScreen extends StatefulWidget {
static String id="welcome_screen";
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> with TickerProviderStateMixin {
bool isFinished;
AnimationController controllerForContainerHeight;
AnimationController controllerForContainerWidth;
Animation scaleAnimationForContainerWidth;
Animation scaleAnimationForContainerHeight;
#override
void initState(){
super.initState();
controllerForContainerWidth=AnimationController(duration:(Duration(seconds: 2)),vsync: this);
scaleAnimationForContainerWidth=Tween<double>(begin: 1080, end: 1380).animate(controllerForContainerWidth);
controllerForContainerWidth.forward();
controllerForContainerWidth.addListener(() {
setState(() {
});
});
controllerForContainerWidth.addStatusListener((status) {
if(status==AnimationStatus.completed){
controllerForContainerWidth.reverse();
}
if(status==AnimationStatus.dismissed){
controllerForContainerWidth.forward();
}
});
controllerForContainerHeight=AnimationController(duration:(Duration(seconds: 2)),vsync: this);
scaleAnimationForContainerHeight=Tween<double>(begin: 1920, end: 2220).animate(controllerForContainerHeight);
controllerForContainerHeight.forward();
controllerForContainerHeight.addListener(() {
setState(() {
});
});
controllerForContainerHeight.addStatusListener((status) {
setState(() {
if(status==AnimationStatus.completed){
controllerForContainerHeight.reverse();
}
if(status==AnimationStatus.dismissed){
controllerForContainerHeight.forward();
}
});
});
controllerForContainerHeight.repeat(reverse: true);
}
#override
void dispose(){
controllerForContainerWidth.dispose();
controllerForContainerHeight.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: controllerForContainerHeight,
builder: (BuildContext context,_){
return AnimatedBuilder(
animation: controllerForContainerWidth,
builder: (BuildContext context,_){
return Container(
width: controllerForContainerWidth.value,
height: controllerForContainerHeight.value,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(kWelcomeScreenBackgroundImage),
fit: BoxFit.cover,
),
),
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Hero(
tag: "logo",
child: Container(
child: Image.asset(kLogoImage),
height: 140,
),
),
TypewriterAnimatedTextKit(
speed: Duration(milliseconds:200),
text:[kWelcomePageText],
textStyle: kWelcomePageTextStyle,
),
],
),
SizedBox(
height: 70,
),
WelcomeScreenButtons(text:kLoginText,color1:kLoginButtonColor1,
color2:kLoginButtonColor2,
color3:kLoginButtonColor3,route: LoginScreen.id),
SizedBox(height: 15),
WelcomeScreenButtons(text:kRegistrationText,color1:kRegisterButtonColor1,
color2:kRegisterButtonColor2,
color3:kRegisterButtonColor3,route: RegistrationScreen.id),
],
),
),
);
}
);
}
),
);
}
}
I have a method called handleSignIn. I want to call it inside a class that handles sign in when the screen orientantion is mobile. How can I access the method from one class to another class?
this is my first class
class _SignInState extends State<SignIn> {
#override
void initState() {
super.initState();
MsalMobile.create('assets/auth_config.json', authority).then((client) {
setState(() {
msal = client;
});
refreshSignedInStatus();
});
}
/// Signs a user in
void handleSignIn() async {
await msal.signIn(null, [SCOPE]).then((result) {
// ignore: unnecessary_statements
refreshSignedInStatus();
}).catchError((exception) {
if (exception is MsalMobileException) {
logMsalMobileError(exception);
} else {
final ex = exception as Exception;
print('exception occurred');
print(ex.toString());
}
});
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: Color(0xff392850),
body: Responsive(
mobile: _HomeScreenMobile(
),
// desktop: _HomeScreenDesktop(),
),
),
);
}
}
my _HomeScreenMobile class
class _HomeScreenMobile extends StatelessWidget{
bool isSignedIn = false;
Widget build(BuildContext context) {
ProgressDialog progressDialog = ProgressDialog(context, type:ProgressDialogType.Normal, isDismissible: false, );
progressDialog.style(message: "Signing you in ...");
return Scaffold(
body: Builder(
builder: (context) => Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image.asset('assets/landing.webp',
fit: BoxFit.fill,
color: Color.fromRGBO(255, 255, 255, 0.6),
colorBlendMode: BlendMode.modulate),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 10.0),
Container(
width: 130.0,
child: Align(
alignment: Alignment.center,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Color(0xffffffff),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
FontAwesomeIcons.microsoft,
color: Color(0xFF01A6F0),
),
// Visibility(
// visible: !isSignedIn,
SizedBox(width: 10.0),
Visibility(
visible: !isSignedIn,
child: Text(
'Sign in',
style: TextStyle(
color: Colors.black, fontSize: 18.0),
),
),
],
),
onPressed: () => {
progressDialog.show(),
handleSignIn(),
})),
)
],
),
],
),
),
);
}
}
how can I access handleSign from _HomeScreenMobile without it throwing the error The method 'handleSignIn' isn't defined for the type '_HomeScreenMobile'.. Have tried going through the example shared no luck
HomeScreenMobile could get its reference as a parameter and call it whenever it's necessary.
class _HomeScreenMobile extends StatelessWidget{
bool isSignedIn = false;
_HomeScreenMobile({this.handleSignInReference});
final Future<void> Function() handleSignInReference;
...
onPressed: () => {
progressDialog.show(),
handleSignInReference(),
}
}
Finally, where you call this class:
Responsive(
mobile: _HomeScreenMobile(
handleSignInReference:handleSignIn
),
)
You could create a handle_signin.dart file:
void handleSignIn() async {
await msal.signIn(null, [SCOPE]).then((result) {
refreshSignedInStatus();
}).catchError((exception) {
if (exception is MsalMobileException) {
logMsalMobileError(exception);
} else {
final ex = exception as Exception;
print('exception occurred');
print(ex.toString());
}
});
}
Import it wherever you need it:
import './handle_signin.dart`;
And use it:
#override
Widget build() {
return Scaffold(body: Center(GestureDetector(onTap: () async { await handleSignIn(); })));
}
Important note: while the code above might work for your case, it's highly recommended that you consider more sophisticated approaches to state management and Widget communication, such as BLoC.
My problem is that the CircularProgressIndicator won't stop buffering. My goal is when the video detects a lagging status then the CircularProgressIndicator will show and when it plays again then the CircularProgressIndicator will stop showing.
bool vidBuffering = true;
void buffer() {
setState(() {
vidBuffering = !vidBuffering;
});
}
This is inside a widget where I call the vidBuffering
Widget _buildPlayStack() {
return Stack(
children: [
_buildPlay(),
child: FlatButton(
onPressed: () => setState(() {
_vidController.value.isPlaying ? _vidController.pause() :_vidController.play();
}),
child: Center(
child: (_vidController.value.isPlaying)
? Icon(Icons.pause, color: Colors.green)
: Icon(Icons.play_arrow, color: Colors.green),
),
),
Center(
child: _vidBuffering
? const CircularProgressIndicator()
: null),
],
);
}
Widget _buildPlay() {
return Container(
child: AspectRatio(
aspectRatio: _vidController.value.aspectRatio,
child: VideoPlayer(_controller),
),
);
}
You should be used StreamBuilder for update only Loader
For Example :
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
bool vidBuffering = true;
StreamController streamControllerBuffering = StreamController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildPlayStack(),
RaisedButton(
onPressed: () => buffer(),
child: Text(vidBuffering ? 'Hide' : 'Show'),
)
],
),
),
);
}
void buffer() {
vidBuffering = !vidBuffering;
streamControllerBuffering.sink.add(vidBuffering);
}
Widget _buildPlayStack() {
return Stack(
children: [
_buildPlay(),
FlatButton(
onPressed: () => setState(() {
/*_vidController.value.isPlaying
? _vidController.pause()
: _vidController.play();*/
}),
child: Center(
child: (/*_vidController.value.isPlaying*/ true)
? Icon(Icons.pause, color: Colors.green)
: Icon(Icons.play_arrow, color: Colors.green),
),
),
Center(
child: StreamBuilder(
initialData: true,
stream: streamControllerBuffering.stream,
builder: (builder, snapshot) {
if (snapshot.hasData && snapshot.data) {
return CircularProgressIndicator();
} else {
Offstage();
}
return Offstage();
}),
),
],
);
}
Widget _buildPlay() {
return Container(
height: 200,
width: 200,
color: Colors.amber,
);
}
#override
void dispose() {
streamControllerBuffering.close();
super.dispose();
}
}