I am trying to use the camera plugin for flutter.
I call availableCameras() in the main function of the app, as I have seen in documentation like this:
List<CameraDescription> cameras;
Future<void> main() async {
try {
cameras = await availableCameras();
} catch (e) {
print("Error: $e");
}
runApp(MyApp());
}
The try statement fails instantly printing
Error: Null check operator used on a null value
I call Home() in MyApp(), which has a tabbed navigator, which calls FaceAScreen() like this:
return Scaffold(
appBar: buildAppBar(),
bottomNavigationBar: BottomNavBar(tabController: _tabController, myTabs: myTabs),
body: TabBarView(
controller: _tabController,
children: <Widget>[Body(), FaceAScreen(cameras: widget.cameras)],
),
);
I want the Camera in the FaceAScreen() page, but it shows, expectedly, "No Camera!" text, since the List cameras is null.
The code build method for FaceAScreen() is:
#override
Widget build(BuildContext context) {
if (!isDetecting) {
return Center(
child: Container(
margin: EdgeInsets.all(10),
child: Text("No cameras!"),
),
);
}
// This is not what causes the no camera to show on the page
if (!controller.value.isInitialized) {
return Container(child: Text("No cameras"));
}
return AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
);
}
I have looked at the null value error relentlessly and have upgraded my flutter package from the terminal many times, including running flutter clean. Flutter doctor shows everything is fine. I also have double checked the settings on my android emulator and have front facing set to webcam0 and back facing as "emulated". I checked opening the camera app in the emulator and that works. All the tutorials seem to write use the availableCameras() method exactly as I did (without the try catch even). Any help would be great, thanks!
Recently I finished a tutorial, which uses camera and works fine. The code below can be of help to you:
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
class CameraPage extends StatefulWidget {
CameraPage({Key key}) : super(key: key);
#override
_CameraPageState createState() => _CameraPageState();
}
/* ============================================================================================= */
class _CameraPageState extends State<CameraPage> {
List<CameraDescription> _cameras;
CameraController _controller;
var _isReady = false;
/* ---------------------------------------------------------------------------- */
#override
void initState() {
super.initState();
_setUpCamera();
}
/* ---------------------------------------------------------------------------- */
void _setUpCamera() async {
try {
// initialize cameras
_cameras = await availableCameras();
// initialize camera controllers
// Current bug for high/medium with Samsung devices
_controller = CameraController(_cameras[0], ResolutionPreset.medium);
await _controller.initialize();
} on CameraException catch (_) {
// do something on error
}
if (mounted) setState(() => _isReady = true);
}
/* ---------------------------------------------------------------------------- */
Widget cameraPreview() {
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: CameraPreview(_controller),
);
}
/* ---------------------------------------------------------------------------- */
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
floatingActionButton: getFooter(),
body: getBody(),
);
}
/* ---------------------------------------------------------------------------- */
Widget getBody() {
final size = MediaQuery.of(context).size;
var flag = !_isReady || _controller == null || !_controller.value.isInitialized;
return Container(
decoration: flag ? BoxDecoration(color: Colors.white) : null,
width: size.width,
height: size.height,
child: flag
? Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(strokeWidth: 3),
),
)
: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
child: cameraPreview(),
),
);
}
.....
}
Obviously your Android device emulator must have enabled cameras and SD Card.
Related
I am using android studio and flutter. I want to build the screen as shown below in the image:screen Image
let's say I have 4 screens. on the first screen, the bar will load up to 25%. the user will move to next screen by clicking on continue, the linearbar will load up to 50% and so on. the user will get back to previous screens by clicking on the back button in the appbar.
I tried stepper but it doesn't serve my purpose.
You can use the widget LinearProgressIndicator(value: 0.25,) for the first screen and with value: 0.5 for the second screen etc.
If you want to change the bar value within a screen, just use StatefullWidget's setState(), or any state management approaches will do.
import 'package:flutter/material.dart';
class ProgressPage extends StatefulWidget {
const ProgressPage({super.key});
#override
State<ProgressPage> createState() => _ProgressPageState();
}
class _ProgressPageState extends State<ProgressPage> {
final _pageController = PageController();
final _pageCount = 3;
int? _currentPage;
double? _screenWidth;
double? _unit;
double? _progress;
#override
void initState() {
super.initState();
_pageController.addListener(() {
_currentPage = _pageController.page?.round();
setState(() {
_progress = (_currentPage! + 1) * _unit!;
});
});
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
_screenWidth = MediaQuery.of(context).size.width;
_unit = _screenWidth! / _pageCount;
_progress ??= _unit;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('HOZEROGOLD')),
body: Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.yellow,
height: 10,
width: _progress,
),
),
Expanded(
child: PageView(
controller: _pageController,
children: _createPage(),
),
),
],
),
);
}
List<Widget> _createPage() {
return List<Widget>.generate(
_pageCount,
(index) => Container(
color: Colors.white,
child: Center(
child: ElevatedButton(
onPressed: () => _moveNextPage(),
child: Text('NEXT $index'),
),
),
),
);
}
void _moveNextPage() {
if (_pageController.page!.round() == _pageCount-1) {
_pageController.jumpToPage(0);
} else {
_pageController.nextPage(
curve: Curves.bounceIn,
duration: const Duration(milliseconds: 100));
}
}
}
HAPPY CODING! I hope it will be of help.
I'm new to flutter and have a memory leak in my program. I was wondering if anyone jumped out to anyone about my code as to why it might be causing a memory leak. I was hoping I made some sort of newbie mistake that someone could call out. I commented out my listviewbuilder row widget and replaced it with simple text, and that seemed to lessen the memory leak. So it seems like it might be row related, but I don't understand how.
I am not scrolling or anything like that I just fire up the memory profiler. It shows that there is an ever-increasing size in the filtered node, but does not say why.
I went back through my changesets and found some code that seemed to be causing the issues. Specifically the memory leak went away when I rmeoveLoadingAnimationWidget:
AnimatedOpacity(
opacity: isUpdating ? 1.0 : 0.0,
duration: isUpdating
? const Duration(milliseconds: 0)
: const Duration(milliseconds:500),
child: Row(
children: [
LoadingAnimationWidget.fourRotatingDots(
color: Colors.black12,
size: 20,
),
SizedBox(
width: 3,
),
Text(
"Saving...",
style: TextStyle(color: Colors.grey.shade600),
),
],
),
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:save_extra_money/main.dart';
import 'package:save_extra_money/shared/loading/LoadingIndicator.dart';
import 'package:save_extra_money/transactions/TransactionUpdaterProvider.dart';
import 'package:save_extra_money/transactions/TransactionsLoadingStates.dart';
import 'package:save_extra_money/transactions/transactionGridRow.dart';
import 'package:http/http.dart' as http;
import '../Shared/ColorContainer.dart';
import '../model/Transaction.dart';
import '../model/webCallInputsAndOutputs/RetrieveTransactionsResults.dart';
import '../shared/globals/GlobalUi.dart';
import 'TransactionsViewModel.dart';
class Transactions extends ConsumerStatefulWidget {
Transactions({Key? key}) : super(key: key);
#override
TransactionsState createState() => TransactionsState();
}
class TransactionsState extends ConsumerState<Transactions> {
ScrollController? controller;
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
if (controller != null) {
controller!.removeListener(_scrollListener);
}
super.dispose();
}
void _scrollListener() {
if (controller == null) {
return;
}
// print(controller.position.extentAfter);
if (controller!.position.extentAfter < 300) {
ref.read(transactionsViewModel.notifier).addMorePagedData();
}
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
var transactionUpdater = ref.watch(transactionUpdaterProvider);
var viewModel = ref.watch(transactionsViewModel);
viewModel.loadInitialData();
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(viewModel.getTitle()),
backgroundColor: GlobalUI.appBar,
centerTitle: true,
),
body: ColorContainer(
size: size,
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child:
getInitialLayout(viewModel, transactionUpdater),
),
),
);
}
Widget getInitialLayout(TransactionsViewModel viewModel,
TransactionUpdaterProvider transactionUpdater){
if(viewModel.state == TransactionsLoadingStates.InitialLoad){
return LoadingIndicator(text: 'Transactions...');
}
else if(viewModel.state == TransactionsLoadingStates.InitialError) {
return Text('Error: ${viewModel.errorText}');
}
else{
return ListView.builder(
controller: controller,
itemCount: viewModel.totalCount,
itemBuilder: (BuildContext context, int index) {
if(index==viewModel.transactions.length){
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5)
),
color: GlobalUI.rowBackground,
),
child: LoadingAnimationWidget.fourRotatingDots(
color: Colors.black12,
size: 60,
),
);
}
if(index>viewModel.transactions.length){
return SizedBox(height: 0,width: 0,);
}
var transaction = viewModel.transactions[index];
return Text(transaction.id);
/*
return TransactionGridRow(
transaction: transaction,
isUpdating: transactionUpdater.isUpdating(transaction.id),
);
*/
});
}
}
}
You should not make api calls in your widget build method
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:save_extra_money/main.dart';
import 'package:save_extra_money/shared/loading/LoadingIndicator.dart';
import 'package:save_extra_money/transactions/TransactionUpdaterProvider.dart';
import 'package:save_extra_money/transactions/TransactionsLoadingStates.dart';
import 'package:save_extra_money/transactions/transactionGridRow.dart';
import 'package:http/http.dart' as http;
import '../Shared/ColorContainer.dart';
import '../model/Transaction.dart';
import '../model/webCallInputsAndOutputs/RetrieveTransactionsResults.dart';
import '../shared/globals/GlobalUi.dart';
import 'TransactionsViewModel.dart';
class Transactions extends ConsumerStatefulWidget {
Transactions({Key? key}) : super(key: key);
#override
TransactionsState createState() => TransactionsState();
}
class TransactionsState extends ConsumerState<Transactions> {
ScrollController? controller;
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(_scrollListener);
viewModel.loadInitialData(); // You can call your async methods in initstate
}
#override
void dispose() {
if (controller != null) {
controller!.removeListener(_scrollListener);
}
super.dispose();
}
void _scrollListener() {
if (controller == null) {
return;
}
// print(controller.position.extentAfter);
if (controller!.position.extentAfter < 300) {
ref.read(transactionsViewModel.notifier).addMorePagedData();
}
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
var transactionUpdater = ref.watch(transactionUpdaterProvider);
var viewModel = ref.watch(transactionsViewModel);
viewModel.loadInitialData(); // Here is the method you should not call here
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(viewModel.getTitle()),
backgroundColor: GlobalUI.appBar,
centerTitle: true,
),
body: ColorContainer(
size: size,
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child:
getInitialLayout(viewModel, transactionUpdater),
),
),
);
}
Widget getInitialLayout(TransactionsViewModel viewModel,
TransactionUpdaterProvider transactionUpdater){
if(viewModel.state == TransactionsLoadingStates.InitialLoad){
return LoadingIndicator(text: 'Transactions...');
}
else if(viewModel.state == TransactionsLoadingStates.InitialError) {
return Text('Error: ${viewModel.errorText}');
}
else{
return ListView.builder(
controller: controller,
itemCount: viewModel.totalCount,
itemBuilder: (BuildContext context, int index) {
if(index==viewModel.transactions.length){
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5)
),
color: GlobalUI.rowBackground,
),
child: LoadingAnimationWidget.fourRotatingDots(
color: Colors.black12,
size: 60,
),
);
}
if(index>viewModel.transactions.length){
return SizedBox(height: 0,width: 0,);
}
var transaction = viewModel.transactions[index];
return Text(transaction.id);
/*
return TransactionGridRow(
transaction: transaction,
isUpdating: transactionUpdater.isUpdating(transaction.id),
);
*/
});
}
}
}
In addition to batuhand, Avoid this:
if(index>viewModel.transactions.length){
return SizedBox(height: 0,width: 0,);
}
Each time index is greater than length it will built a useless SizedBox.
Why do you use "viewModel.totalCount" and "viewModel.transactions.length"? It should be the same.
And if you compare index and length add a minus to length
if(index==viewModel.transactions.length-1)
I have a Home Screen Widget, that plays a fullscreen background video using the video_player package.
This code works fine for me:
class HomeScreen extends StatefulWidget {
HomeScreen({Key key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
VideoPlayerController _controller;
void initState() {
super.initState();
// Pointing the video controller to mylocal asset.
_controller = VideoPlayerController.asset("assets/waterfall.mp4");
_controller.initialize().then((_) {
// Once the video has been loaded we play the video and set looping to true.
_controller.play();
_controller.setLooping(true);
// Ensure the first frame is shown after the video is initialized.
setState(() {});
});
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Stack(
children: <Widget>[
SizedBox.expand(
child: FittedBox(
// If your background video doesn't look right, try changing the BoxFit property.
// BoxFit.fill created the look I was going for.
fit: BoxFit.fill,
child: SizedBox(
width: _controller.value.size?.width ?? 0,
height: _controller.value.size?.height ?? 0,
child: VideoPlayer(_controller),
),
),
),
Container(
child: Center(
child: Text('Hello!'),
),
),
],
),
),
);
}
}
The question is, how can I implement this using flutter Hooks? I understand that I have to use useEffect() to implement the functionality of initState() and dispose(), useFuture() and maybe useMemoized() to handle asynchronous _controller.initialize() call and what possibly else? But, I cannot glue them to get the desired result. Can anyone indicate to me the "using Hooks" implementation of the above code?
I was looking for the answer to how to convert a VideoPlayer demo from StatefulWidget to HookWidget when I came across this question. I've come up with something that works so I'll post it here since there is nothing elsewhere that I could find and some others are hitting this page looking for an answer.
I used a viewmodel. The video controller is a property of the viewmodel. This code will not compile since some of the controls are not included. But it will demonstrate the structure and incorporation of the viewmodel.
Here's the widget file:
import 'package:flutter/foundation.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:video_player/video_player.dart';
import 'intro_viewmodel.dart';
class IntroPage extends HookWidget {
Future<void> saveAndGetStarted(BuildContext context) async {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
await introViewModel.completeIntro();
}
Future<void> onNext(BuildContext context) async {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
await introViewModel.incrementIntro();
}
final List<SliderModel> slides = [
SliderModel(
description: 'A word with you before you get started.\n',
title: 'Why This App?',
localImageSrc: 'media/Screen1-Movingforward-pana.svg',
backgroundColor: Colors.lightGray),
SliderModel(
description: 'This information will help the app be more accurate\n',
title: 'Personal Profile',
localImageSrc: 'media/Screen2-Teaching-cuate.svg',
backgroundColor: Colors.lightGray)
];
#override
Widget build(BuildContext context) {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
children: [
Text(
slides[introViewModel.index].description,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
Expanded(
child: FractionallySizedBox(
widthFactor: .98,
heightFactor: .5,
child: VideoPlayer(introViewModel.videoController),
)),
Align(
alignment: Alignment.bottomCenter,
child: CustomRaisedButton(
onPressed: () {
if (introViewModel.index == slides.length - 1) {
saveAndGetStarted(context);
} else {
onNext(context);
}
},
color: Theme.of(context).accentColor,
borderRadius: 15,
height: 50,
child: Text(
introViewModel.index == 0
? 'Continue'
: 'Save and Get Started',
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.white),
),
),
),
],
),
),
));
}
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IterableProperty<SliderModel>('slides', slides));
}
}
And here is the viewmodel code
import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:video_player/video_player.dart';
import '../top_level_providers.dart';
final introViewModelProvider = ChangeNotifierProvider<IntroViewModel>((ref) {
//this singleton class provides global access to selected variables
final SharedPreferencesService localSharedPreferencesService =
ref.watch(sharedPreferencesService);
return IntroViewModel(localSharedPreferencesService);
});
class IntroViewModel extends ChangeNotifier {
IntroViewModel(this.localSharedPreferencesService) : super() {
state = localSharedPreferencesService?.isIntroComplete();
// Pointing the video controller to my local asset.
videoController = VideoPlayerController.asset('media/test_search.mp4');
videoController.initialize().then((_) {
// Once the video has been loaded we play the video and set looping to true.
// not autoplaying yet
// videoController.play();
// videoController.setLooping(true);
});
}
final SharedPreferencesService localSharedPreferencesService;
VideoPlayerController videoController;
bool state = false;
int index = 0;
Future<void> completeIntro() async {
await localSharedPreferencesService.setIntroComplete();
state = true;
notifyListeners();
}
Future<void> incrementIntro() async {
++index;
notifyListeners();
}
bool get isIntroComplete => state;
}
Here I am working with one project where I need to click an image from the camera and preview it in another screen. so I've done it. but there is some issue here I need to click square image and display also the square image I've tried lots of solutions but it won't work. hope you understand the question. please help me. your little help can make my day.
Here is my code.
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
setState(() {
selectedCameraIdx = 0;
});
_initCameraController(cameras[selectedCameraIdx]).then((void v) {});
} else {
print("No camera available");
}
}).catchError((err) {
print('Error: $err.code\nError Message: $err.message');
});
//---------------------------------------------------------------------
AspectRatio(
aspectRatio: 1,
child: ClipRect(
child: Transform.scale(
scale: 1 / controller.value.aspectRatio,
child: Center(
child: AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
),
),
),
),
)
This is for Display image
Image.file(
File(widget.imagePath),
)
I hope , This is the suitable answer as you wanted.
Plugins: camera, image_cropper
Run this code:
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:path/path.dart' show join;
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;
runApp(
MyApp(firstCamera: firstCamera,)
);
}
class MyApp extends StatelessWidget {
final firstCamera;
// This widget is the root of your application.
MyApp({this.firstCamera});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// routes: routes,
home: TakePictureScreen(
// Pass the appropriate camera to the TakePictureScreen widget.
camera: firstCamera,
),
);
}
}
// A screen that allows users to take a picture using a given camera.
class TakePictureScreen extends StatefulWidget {
final CameraDescription camera;
const TakePictureScreen({
Key key,
#required this.camera,
}) : super(key: key);
#override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
CameraController _controller;
Future<void> _initializeControllerFuture;
#override
void initState() {
super.initState();
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
}
#override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(title: Text('Take a picture')),
// Wait until the controller is initialized before displaying the
// camera preview. Use a FutureBuilder to display a loading spinner
// until the controller has finished initializing.
body: Center(
child: Container(
width: size,
height: size,
child: ClipRect(
child: OverflowBox(
alignment: Alignment.center,
child: FittedBox(
fit: BoxFit.fitWidth,
child: Container(
width: size,
height:size,
child:FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
return CameraPreview(_controller);
} else {
// Otherwise, display a loading indicator.
return Center(child: CircularProgressIndicator());
}
},
),
),
),
),
),
)
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.camera_alt),
// Provide an onPressed callback.
onPressed: () async {
// Take the Picture in a try / catch block. If anything goes wrong,
// catch the error.
try {
await _controller.takePicture().then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(imagePath: value.path),
),
);
});
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},
),
);
}
}
// A widget that displays the picture taken by the user.
class DisplayPictureScreen extends StatefulWidget {
final String imagePath;
const DisplayPictureScreen({Key key, this.imagePath}) : super(key: key);
#override
_DisplayPictureScreenState createState() => _DisplayPictureScreenState();
}
class _DisplayPictureScreenState extends State<DisplayPictureScreen> {
var finalImage ;
#override
void initState() {
super.initState();
croppingImage();
}
croppingImage()async{
File croppedFile = await ImageCropper.cropImage(
sourcePath: File(widget.imagePath).path,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.pink,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
minimumAspectRatio: 1.0,
)
);
if(croppedFile!=null){
setState(() {
finalImage = croppedFile;
});
}else{
setState(() {
finalImage = File(widget.imagePath);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Display the Picture')),
// The image is stored as a file on the device. Use the `Image.file`
// constructor with the given path to display the image.
body: Center(
child:
finalImage !=null ?
Container(
height: MediaQuery.of(context).size.height/2, //400
// width: MediaQuery.of(context).size.width/1.2,//400
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
image: DecorationImage(
image: FileImage(finalImage),
fit: BoxFit.cover
)
),
)
:Container()
)
);
}
}
Modify with your AndroidManifest.xml with this
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="myapp"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-Add Crop Activity -->
<!-Add this line -->
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="#style/Theme.AppCompat.Light.NoActionBar"/>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
Camera View in Square shape:
Cropping captured image before showing:
Captured image in Square view:
You should use image cropper for this feature. when you take image from camera or gallery just crop image through this : https://pub.dev/packages/image_cropper
I need quick access to the CameraPreview data for my new flutter app.
If I take a picture with controller.takePicture(filePath) it takes a few seconds for the file to save to the disk, so that I can access it.
I don't need a high quality image, so getting the same resolution as the phone screen display resolution would be fine. I have tried this method, but it only captures the overlays and widgets that I drew myself, not the Camera preview data.
Here is a minimum working example of the problem when using this method:
https://www.youtube.com/watch?v=CWBLjCwH5c0
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'package:camera/camera.dart';
import 'dart:ui' as ui;
List<CameraDescription> cameras;
Future<Null> main() async {
debugPaintSizeEnabled = false;
debugPaintLayerBordersEnabled = false;
try {
cameras = await availableCameras();
} on CameraException catch (e) {
logError(e.code, e.description);
}
runApp(new MaterialApp(
home: new MyApp(),
));
}
void logError(String code, String message) =>
print('Error: $code\nError Message: $message');
class MyApp extends StatefulWidget {
#override
_State createState() => new _State();
}
class _State extends State<MyApp> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static GlobalKey previewContainer = new GlobalKey();
CameraController controller;
ui.Image image;
Offset blueSquareOffset = new Offset(10.0, 10.0);
#override
void initState() {
super.initState();
controller = new CameraController(cameras[0], ResolutionPreset.low);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
void _getScreenShotImage() async {
_capturePng();
image = await _capturePng();
debugPrint("im height: ${image.height}, im width: ${image.width}");
setState(() {});
}
Future<ui.Image> _capturePng() async {
RenderRepaintBoundary boundary =
previewContainer.currentContext.findRenderObject();
ui.Image image = await boundary.toImage();
return image;
}
/// Display the preview from the camera (or a message if the preview is not available).
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text('Camera is initialising...');
} else {
return Center(
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: RepaintBoundary(
//key: previewContainer,
child: new GestureDetector(
child: new CameraPreview(controller),
),
)),
);
}
}
void _moveBlueSquare(DragUpdateDetails details) {
setState(() {
_getScreenShotImage();
blueSquareOffset = blueSquareOffset + details.delta;
});
}
Widget _blueSquare() {
return new Positioned(
top: blueSquareOffset.dy,
left: blueSquareOffset.dx,
width: 50.0,
height: 50.0,
child: new GestureDetector(
onPanUpdate: _moveBlueSquare,
child: new Container(
color: Color.fromARGB(255, 10, 10, 255),
)));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text('Render Boundry Screenshot Error Example'),
),
body: RepaintBoundary(
key: previewContainer,
child: new Container(
padding: new EdgeInsets.all(0.0),
margin: new EdgeInsets.all(0.0),
child: new RepaintBoundary(
//key: previewContainer,
child: new Stack(
fit: StackFit.expand,
overflow: Overflow.clip,
children: <Widget>[
new Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Expanded(
child: new Stack(children: <Widget>[
new RepaintBoundary(
child: new Container(child: _cameraPreviewWidget()),
),
_blueSquare(),
])),
new Expanded(
child: new Container(
//color: Color.fromARGB(50, 50, 50, 50),
child: new CustomPaint(
painter: new RectanglePainter(image),
)),
)
],
),
],
)))));
}
}
class RectanglePainter extends CustomPainter {
RectanglePainter(this.image);
ui.Image image;
#override
void paint(Canvas canvas, Size size) {
if (image == null) {
canvas.drawRect(
new Rect.fromLTRB(100.0, 50.0, 300.0, 200.0),
new Paint()
..color = Color.fromARGB(255, 50, 50, 255)
..style = PaintingStyle.stroke
..strokeWidth = 6.0);
} else {
canvas.drawImage(image, new Offset(0.0, 0.0), new Paint());
}
}
#override
bool shouldRepaint(RectanglePainter old) {
return true;
}
}
Any help would be greatly appreciated.
Update: July 2020
At the moment, the best way to get a screenshot of the CameraPreview on Flutter, is to use the native_screenshot package.
You can simply use,
Future<void> getScreenshot() async{
String path = await NativeScreenshot.takeScreenshot();
print(path);
}
to save the screenshot. Please refer to package page for additional permissions and settings. Performance-wise, it seems to be a bit slow (500ms-1s on my 2018 Xiaomi A1). I am currently looking at ways to improve the screen capture speed.
There is a way to take snapshot from layouts. try this:
Android get Image of Main Relativelayout from xml layout?
I hope this helps to you.