Flutter | How to click square image from camera and display square image - flutter

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

Related

Flutter Image.memory() loading animation with slow large files

I am fetching an image from the gallery and displaying it in my cropper with Image.memory(). But sometimes (with large files) it takes a few seconds for the image to show. I want to show a loading animation but how do I detect when it is loading or finished? There is no loadingBuilder like for Image.network(). Any ideas?
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
Image.memory(_imageToCrop!)
Like Ankit Kumar Maurya said I studied the frameBuilder documentation and this solved my issue:
Image.memory(
_imageToCrop!,
frameBuilder:
((context, child, frame, wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded) return child;
return AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: frame != null
? child
: SizedBox(
height: 60,
width: 60,
child: CircularProgressIndicator(
strokeWidth: 6),
),
);
}),
),
you can maintain an enum for this,
enum State {idle, loading, done ,error}
now,
State fetchState = State.idle
void fetch()async{
setState((){
fetchState = State.loading;
});
try{
final XFile? image = await _picker.pickImage(source:
ImageSource.gallery);
Image.memory(_imageToCrop!);
setState((){
fetchState = State.done;
});
}catch(e){
setState((){
fetchState = State.error;
});
}
}
Now use this states in your widget tree to show loader when state is loading.
you can use a single boolean variable as said in other answer but with this method you can catch errors at run time. You can use this method for api calls also.
You should once check this documentation provided by flutter frame_builder. You could also use frameBuilder for your requirement.
May be my code will help you:-
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const MaterialApp(
title: 'Temp',
home: const MyApp(),
));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool loading = false;
late Uint8List image;
XFile? file = null;
ImagePicker imagePicker = ImagePicker();
Future<void> pickImage() async {
print('starting');
setState(() {
loading = true;
});
file = await imagePicker.pickImage(source: ImageSource.gallery);
print('file');
if(file != null){
print(file.toString());
image = await file!.readAsBytes();
}
setState(() {
loading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Image Picker'),
),
body: loading
? Container(
child: const Center(child: CircularProgressIndicator()),
)
: file != null?Container(child: Center(child: Image.memory(image),)) : Container(
child: const Center(child: Text('Pick an Image')),
),
floatingActionButton: FloatingActionButton(
child: const Icon(
Icons.image,
),
onPressed: (){
pickImage();
}),
);
}
}
Short Description - my code will fetch an image from the system and then show … I have used a loading widget while the image is fetching and being converted to bytes.
It might be helpful if you share your logic here to figure out the main problem(if missing any thing).

Unable to load cameras from android emulator in flutter

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.

Show download percentage in the Flutter Circular Progress Indicator

I am using Flutter advance_pdf_viewer package to show PDF files that are loaded from the URL. At the first time open, The PDF files are downloaded in the application cache and the next time onwards loaded from the cache. Now I am using CircularProgressIndicator() to show the download progress. I want to add the progress percentage here to give the user better visibility of the progress. How can I do that?
Here is my code:
import 'package:flutter/material.dart';
import 'package:advance_pdf_viewer/advance_pdf_viewer.dart';
#override
_MyBanBook createState() => _MyBanBook();
}
class _MyBanBook extends State<BanBook> {
bool _isLoading = true;
PDFDocument document;
#override
void initState() {
super.initState();
loadDocument();
}
loadDocument() async {
document = await PDFDocument.fromURL('http://www.africau.edu/images/default/sample.pdf');
setState(() => _isLoading = false);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
toolbarHeight: 20,
),
body: Center(
child: _isLoading
? Center(child: CircularProgressIndicator())
: PDFViewer(
document: document,
zoomSteps: 1,
),
),
bottomNavigationBar: BottomAppBar(
child: Container(
height: 85.0,
),
),
),
);
}
}
You can do it by specifying the value property in the CircularProgressIndicator like this :
CircularProgressIndicator(
value: _progress,
//width of the width of the border
strokeWidth: 20,
// color of value
valueColor: Colors.amber
);
u can use flutter_cached_pdfview
and this an example to view a pdf from URL and cache it with placeholder
u can replace placeholder with any widget like CircularProgressIndicator
PDF().cachedFromUrl(
'http://africau.edu/images/default/sample.pdf',
placeholder: (progress) => Center(child: CircularProgressIndicator())
)
take a look https://pub.dev/packages/flutter_cached_pdfview

Using video_player package with Flutter Hooks to play a background fullscreen video

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;
}

How to set text values to change automatically in flutter?

I'm new to flutter and developing an app in which vehicle speed is shown in the floating action button in Scaffold. But I want it to change according to speed automatically so that it doesn't need to refresh/restart manually every time.
Here's my code.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double speedInMps;
double speedInKph;
var geolocator = Geolocator();
var locationOptions = LocationOptions(accuracy: LocationAccuracy.high,
distanceFilter: 10);
Future<void> getVehicleSpeed()async{
try{
geolocator.getPositionStream((locationOptions)).listen((position) async
{
speedInMps = await position.speed;
speedInKph = speedInMps * 1.609344;
print(speedInKph.round());
});
}catch(e){
print(e);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold( floatingActionButton: FloatingActionButton(
onPressed: () {getVehicleSpeed();
},
child: Text(speedInKph.round().toString() +'Km/h'),//Need Improvments
Here
backgroundColor: Colors.green,
),
appBar: AppBar(
title: Text('speed'),
centerTitle: true,
),
body: Center(
child: FlatButton(
onPressed: getVehicleSpeed,
child: Text(
speedInKph.toString(),
style: TextStyle(fontSize: 16.0),
),
color: Color(0xffdd4b39),
textColor: Colors.white,
padding: const EdgeInsets.all(20.0),
),
),
)
);
}
}
I have to hot reload/restart to get updated speed, but I want it to refresh speed automatically.
You need to listen location only once. So put in initState which called when widget is initialized.
#override
void initState() {
super.initState();
getVehicleSpeed();
}
And than call setState method when data is change. It will rebuild the widget.
Future<void> getVehicleSpeed() async {
try {
geolocator.getPositionStream((locationOptions)).listen((position) async {
speedInMps = position.speed;
setState(() {
speedInKph = speedInMps * 1.609344;
});
print(speedInKph.round());
});
} catch (e) {
print(e);
}
}