Related
i want to upload a image which has come from signature pad which is in the form of unit8list and i want to upload that image using multipart in flutter.
my signature pad code is:-
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_app/Screens/next.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:signature/signature.dart';
class signature_pad extends StatefulWidget {
#override
_signature_padState createState() => _signature_padState();
}
class _signature_padState extends State<signature_pad> {
var file;
String bytes2;
GlobalKey _globalKey = GlobalKey();
final SignatureController _controller = SignatureController(
penStrokeWidth: 5,
penColor: Colors.black,
exportBackgroundColor: Colors.white,
);
setsignePref(var sign) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
setState(() {
sharedPreferences.setString("sign", sign);
});
}
#override
void initState() {
super.initState();
_controller.addListener(() => print('Value changed'));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Builder(
builder: (BuildContext context) => Scaffold(
body: ListView(
children: <Widget>[ // SIGNATURE CANVAS
Signature(
controller: _controller,
height: MediaQuery.of(context).size.height/1.12,
backgroundColor: Colors.white,
),
//OK AND CLEAR BUTTONS
Container(
decoration: const BoxDecoration(color: Colors.black),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
//SHOW EXPORTED IMAGE IN NEW ROUTE
IconButton(
icon: const Icon(Icons.check),
color: Colors.blue,
onPressed: () async {
if (_controller.isNotEmpty) {
final Uint8List data = await _controller.toPngBytes();
await Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Center(
child: Container(
color: Colors.grey[300],
child: Image.memory(data),
),
),
Padding(
padding: const EdgeInsets.all(20),
child: new RaisedButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context)=> next(image : data)));
},
child: new Text('Submit'),
),
), ],
),
);
},
),
);
}
},
),
//CLEAR CANVAS
IconButton(
icon: const Icon(Icons.clear),
color: Colors.blue,
onPressed: () {
setState(() => _controller.clear());
},
),
],
),
),
],
),
),
),
);
}
}
and my upload page is:-
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/Screens/navidrawer.dart';
import 'package:flutter_app/Screens/signature_pad.dart';
import 'package:flutter_app/Url.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
class next extends StatefulWidget {
final String CompanyCode;
final Uint8List image;
final String docketno;
next({Key key,this.CompanyCode,this.image,this.docketno}) : super(key: key);
#override
_nextState createState() => _nextState();
}
class _nextState extends State<next> {
List<OriginModel> OriginModelList = [];
String selectedOrigin;
// final networkHandler = NetworkHandler();
bool circular = false;
final _globalkey = GlobalKey<FormState>();
final ImagePicker _picker = ImagePicker();
PickedFile _imageFile;
bool _obscuredText = true;
var okData;
var user_id;
var responseResult;
var loading = false;
var count = 0;
var myData;
final _formKey = GlobalKey<FormState>();
var bytes;
Future<String> getUserIdPref() async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
setState(() {
user_id = sharedPreferences.getString("user_id");
});
return user_id;
}
void UploadImage() async {
var request = http.MultipartRequest('POST', Uri.parse(URLs.image));
request.fields['CompanyCode']= "${widget.CompanyCode}";
request.fields['empCode'] = "$user_id";
request.fields['documentType']= "POD";
if (_imageFile != null && widget.image == null) {
print('AddingUserProfilePic ${_imageFile.path}and $user_id');
request.files
.add(await http.MultipartFile.fromPath('file', _imageFile.path));
}
else if(widget.image !=null && _imageFile == null){
bytes = (await rootBundle.load(Image.memory(widget.image).toString())).buffer.asUint8List();
request.files.add(http.MultipartFile.fromBytes('file', bytes));
}
var response = await request.send();
var responseBody = await http.Response.fromStream(response);
myData = json.decode(responseBody.body);
print('Status code is : ${response.statusCode} && ${response}');
if (response.statusCode == 200) {
Fluttertoast.showToast(msg: 'Uploaded Successfully');
Navigator.popUntil(context, (route) {
return count++ == 2;
});
} else {
Fluttertoast.showToast(msg: 'Upload Failed');
}
}
#override
void initState() {
super.initState();
this .getUserIdPref();
}
List<Widget> _buildForm(BuildContext context) {
var l = List<Widget>();
// Image img = Image.memory(widget.image);
Container container = Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
alignment: AlignmentDirectional.topCenter,
child:Form(
key: _formKey,
child: SingleChildScrollView(
child: Container(
child:Column(
children: [
SizedBox(height: MediaQuery.of(context).size.height/20 ),
Container(
margin: EdgeInsets.only(top: 15),
child:
_imageFile == null && widget.image == null ? CircleAvatar(
radius: 80.0,
backgroundImage: NetworkImage(
"https://img.freepik.com/free-vector/illustration-document-icon_53876-37007.jpg?size=626&ext=jpg&ga=GA1.2.1768032709.1573116529")
) :
_imageFile != null && widget.image == null ?
CircleAvatar(
radius: 80.0,
backgroundImage: FileImage(File(_imageFile.path)),)
: Container(
color: Colors.grey[300],
child: Image.memory(widget.image),
),
),
SizedBox(height: MediaQuery.of(context).size.height/30 ),
Column(
crossAxisAlignment : CrossAxisAlignment.start,
children: [
Container( margin: EdgeInsets.only(left: 10,right: 10),
child: Text(
'DOCUMENT TYPE'.toUpperCase(),
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold),
),
),
SizedBox(height: MediaQuery.of(context).size.height/40 ),
Container(margin: EdgeInsets.only(left: 10,right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.cyan,
border: Border.all()),
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(10.0),
child: DropdownButtonHideUnderline(
child: Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.cyan,
),
child: new DropdownButton<String>(
hint: new Text("Select Document Type",style: TextStyle(color: Colors.white) ,),
value: selectedOrigin,
isDense: true,
onChanged: (String newValue) {
setState(() {
selectedOrigin = newValue;
});
print(selectedOrigin);
},
items: OriginModelList.map((OriginModel map) {
return new DropdownMenuItem<String>(
value: map.id,
child: new Text(map.name,
style: new TextStyle(color: Colors.white)),
);
}
).toList(),
),
),
),
),
],
),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=> signature_pad()));
},
child: Container(
margin: EdgeInsets.only(left: 10,right: 10,top: 30),
width: MediaQuery.of(context).size.width,
height: 70,
color: Colors.cyan,
child: Row(
children: [
Container(
child: Image.asset(
"assets/register.png"
),
height: 60,
margin: EdgeInsets.only(left: 5),
),
Container(margin:EdgeInsets.only(left: 10),child: Text("Signature",style: TextStyle(color: Colors.white))),
],
),
),
),
GestureDetector(
onTap: (){
_showAlertDialog();
},
child: Container(
margin: EdgeInsets.only(left: 10,right: 10,top: 20),
width: MediaQuery.of(context).size.width,
height: 70,
color: Colors.cyan,
child: Row(
children: [
Container(
child: Image.asset(
"assets/upload.png"
),
height: 60,
margin: EdgeInsets.only(left: 5),
),
Container(margin:EdgeInsets.only(left: 10),child: Text("Image",style: TextStyle(color: Colors.white))),
],
),
),
),
SizedBox(height: MediaQuery.of(context).size.height/30 ),
Padding(
padding: const EdgeInsets.all(30.0),
child: GestureDetector(
onTap: (){
if (_formKey.currentState.validate()) {
setState(() {
loading = true;
});
UploadImage();
}
},
child: Container(
height: 55.0,
width: 600.0,
child: Text(
'SAVE',
style: TextStyle(
color: Colors.white,
letterSpacing: 0.2,
fontFamily: "Sans",
fontSize: 18.0,
fontWeight: FontWeight.w800),
),
alignment: FractionalOffset.center,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(color: Colors.black38, blurRadius: 15.0)
],
borderRadius: BorderRadius.circular(30.0),
gradient: LinearGradient(colors: <Color>[
Colors.cyan[300],
Colors.cyan[600],
])),
),
),
),
],
),
),
),
),
);
l.add(container);
if (loading) {
var modal = Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Opacity(
opacity: 0.3,
child: const ModalBarrier(dismissible: false, color: Colors.grey),
),
Center(
child: new CircularProgressIndicator(),
),
],
),
);
l.add(modal);
}
return l;
}
#override
Widget build(BuildContext context) {
OriginModelList = [
OriginModel('1', "POD"),
OriginModel('2', "SIGNATURE"),
];
return Scaffold(
appBar: AppBar(
title: Text(
'OPERATIONS',
style: TextStyle(color: Colors.white, fontSize: 16),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.chat,
size: 26.0,
),
)
),
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.call,
),
)
),
],
elevation: 0,
backgroundColor:Colors.cyan,
brightness: Brightness.light,
),
body: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: _buildForm(context),
),
drawer: NaviDrawer(),
);
}
void _showAlertDialog()
{
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context)
{
return AlertDialog(
title: new Text('Make your choice!'),
content: Container(
height: 80,
child: Column(
children: [
GestureDetector(
onTap: (){
takePhoto(ImageSource.camera);
},
child: Row(
children: [
Icon(Icons.camera),
Container(
margin: EdgeInsets.only(left: 5),
child: new Text('Camera')),
],
),
),
GestureDetector(
onTap: (){
takePhoto(ImageSource.gallery);
},
child: Container(
margin: EdgeInsets.only(top: 10),
child: Row(
children: [
Icon(Icons.image),
Container( margin: EdgeInsets.only(left: 5),
child: new Text('Gallery')),
],
),
),
),
],
),
),
);
}
);
}
void takePhoto(ImageSource source) async {
final pickedFile = await _picker.getImage(
source: source,
);
setState(() {
_imageFile = pickedFile;
});
}
}
class OriginModel {
String id;
String name;
#override
String toString() {
return '$id $name';
}
OriginModel(this.id, this.name);
}
and the image type like Image.memory(widget.image) is uploading because it is a iamge type and like widget.image is also not uploading because it is unit8list type.
so how can i upload that?
thank you in advance.....
Is there a way to merge dynamically loaded image file to one image file in flutter?
I have added the image.
I needed to merge the loaded image to one image the code I have used is given below
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as immg;
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:merge_images/merge_images.dart';
class SingleImageUpload extends StatefulWidget {
#override
_SingleImageUploadState createState() {
return _SingleImageUploadState();
}
}
class _SingleImageUploadState extends State<SingleImageUpload> {
List<Object> images = List<Object>();
List<File> imgList = List<File>();
List<Image> listimg = List<Image>();
File _selectedFile;
bool _inProcess = false;
Map data = {};
Readerservice _readerservice;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: Padding(
padding: EdgeInsets.only(left: 12),
child: IconButton(
icon: Icon(Icons.arrow_back_ios,
color: Colors.black,
size: 30,),
onPressed: () {
Navigator.pushNamed(context, '/Mainpage');
},
),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
Text('Basic AppBar'),
]
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_vert,
color: Colors.black,
size: 30,),
onPressed: () {
print('Click start');
},
),
],
),
body:
SizedBox(height: 40),
Expanded(
child: buildGridView(),
),
RaisedButton(
textColor: Colors.white,
color: Colors.orange,
child: Text("Finish",
style: TextStyle(fontSize: 15),),
onPressed: () {
pasimage();
},
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(8.0),
),
),
],
),
),
);
}
Widget buildGridView() {
return GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1,
children: List.generate(images.length, (index) {
if (images[index] is ImageUploadModel) {
ImageUploadModel uploadModel = images[index];
return Card(
clipBehavior: Clip.antiAlias,
child: Stack(
children: <Widget>[
Image.file(
uploadModel.imageFile,
width: 300,
height: 300,
),
Positioned(
right: 5,
top: 5,
child: InkWell(
child: Icon(
Icons.remove_circle,
size: 20,
color: Colors.red,
),
onTap: () {
setState(() {
images.replaceRange(index, index + 1, ['Add Image']);
});
},
),
),
],
),
);
} else {
return Card(
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
//popup
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
elevation: 16,
child: Container(
height: 180.0,
width: 330.0,
child: ListView(
children: <Widget>[
SizedBox(height: 20),
//Center(
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Text(
"Add a Receipt",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 24,
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
// ),
SizedBox(height: 20),
FlatButton(
child: Text(
'Take a photo..',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 20),
),
onPressed: () {
_onAddImageClick(index,ImageSource.camera);
Navigator.of(context).pop();
// picker.getImage(ImageSource.camera);
},
textColor: Colors.black,
),
FlatButton(
child: Text(
'Choose from Library..',
style: TextStyle(fontSize: 20),
textAlign: TextAlign.left,
),
onPressed: () {
_onAddImageClick(index,ImageSource.gallery);
Navigator.of(context).pop();
},
textColor: Colors.black,
),
],
),
),
);
},
);
//pop ends
//_onAddImageClick(index);
},
),
);
}
}),
);
}
Future _onAddImageClick(int index, ImageSource source ) async {
setState(() {
_inProcess = true;
});
File image = await ImagePicker.pickImage(source: source);
if(image != null){
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
maxWidth: 1080,
maxHeight: 1080,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: Colors.black,
toolbarWidgetColor: Colors.white,
//toolbarTitle: "RPS Cropper",
statusBarColor: Colors.deepOrange.shade900,
backgroundColor: Colors.black,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false
),
iosUiSettings: IOSUiSettings(
minimumAspectRatio: 1.0,
)
);
this.setState((){
_selectedFile = cropped ;
_inProcess = false;
});
} else {
this.setState((){
_inProcess = false;
});
}
getFileImage(index);
}
void getFileImage(int index) async {
// var dir = await path_provider.getTemporaryDirectory();
setState(() {
ImageUploadModel imageUpload = new ImageUploadModel();
imageUpload.isUploaded = false;
imageUpload.uploading = false;
imageUpload.imageFile = _selectedFile ;
imageUpload.imageUrl = '';
imgList.add(imageUpload.imageFile);
images.replaceRange(index, index + 1, [imageUpload]);
print(imgList);
});
}
void pasimage(){
for(var i=0;i<imgList.length;i++){
final imaes = immg.decodeImage(imgList[i].readAsBytesSync()) as Image;
listimg.add(imaes);
}
Navigator.pushReplacementNamed(context, '/crop',arguments: {
'imageList':ImagesMerge(
listimg,///required,images list
direction: Axis.vertical,///direction
backgroundColor: Colors.black26,///background color
fit: false,///scale image to fit others
//controller: captureController,///controller to get screen shot
),
});
}
}
class ImageUploadModel {
bool isUploaded;
bool uploading;
File imageFile;
String imageUrl;
ImageUploadModel({
this.isUploaded,
this.uploading,
this.imageFile,
this.imageUrl,
});
}
I have used image merge package from pub.dev I have implemented it in pasimage() function but I got the error.
** The argument type 'List (where Image is defined in C:\src\flutter\packages\flutter\lib\src\widgets\image.dart)' can't be assigned to the parameter type 'List (where Image is defined in C:\src\flutter\bin\cache\pkg\sky_engine\lib\ui\painting.dart)'. **
the error image is attached
import 'dart:ui' as ui;
List<ui.Image> listimg = List<ui.Image>();
...
void pasimage(){
for(var i=0;i<imgList.length;i++){
final imaes = await ImagesMergeHelper.loadImageFromFile(imgList[i]) as ui.Image;
listimg.add(imaes);
}
Navigator.pushReplacementNamed(context, '/crop',arguments: {
'imageList':ImagesMerge(
listimg,///required,images list
direction: Axis.vertical,///direction
backgroundColor: Colors.black26,///background color
fit: false,///scale image to fit others
//controller: captureController,///controller to get screen shot
),
});
}
Try this code.
Problem:
I have a GridView of small images, when the user taps on them it needs to change the background image on a different screen.
Here is the Homepage screen with the background image:
class HomePage extends StatelessWidget {
Image defaultImage;
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
title: Text('Background Image', style: TextStyle(
color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold),
),
iconTheme: IconThemeData(color: Colors.white),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings, color: Colors.black,),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SmallImages()),
);
},
),
],
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Stack(
children: <Widget>
[
Positioned.fill(
child: GestureDetector(
child: defaultImage = Image.asset('images/background_image.jpeg', fit: BoxFit.fill),
),
),
],
),
);
}
}
Here is the SmallImage screen where the user can click on a small image and it would change the background image on the HomePage. The background image would then have a different image for example 'defaultImage = Image.asset('images/background_image25.jpeg', fit: BoxFit.fill)'
class SmallImages extends StatefulWidget {
static int tappedGestureDetector = 0;
#override
_SmallImagesState createState() => _SmallImagesState();
}
class _SmallImagesState extends State<SmallImages> {
List<bool> isSelected;
void initState() {
isSelected = [true, false, false, false, false, false, false, false, false];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Small Image', style: TextStyle(
color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold),
),
iconTheme: IconThemeData(color: Colors.white),
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_left, color: Colors.black,),
onPressed: () {
Navigator.pop(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
},
),
],
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Material(
child: GestureDetector(
child: MaterialApp(
builder: (context, snapshot) {
return GridView.count(
crossAxisCount: 1,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
children: [
GridView(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,
childAspectRatio: MediaQuery
.of(context)
.size
.width /
(MediaQuery
.of(context)
.size
.height / 2),
),
children: [
GestureDetector(
onTap: () {
setState(() {
SmallImages.tappedGestureDetector = 2;
}); // <-- replaced 'tapped' and 'other'
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 2 ? Border.all(
color: Color(0xff2244C7), width: 1.0) : Border
.all(color: Colors.transparent,),),
child: Image.asset('images/smallImage1.png',
),
),
),
GestureDetector(
onTap: () {
setState(() {
SmallImages.tappedGestureDetector = 3;
}); // <-- replaced 'tapped' and 'other'
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 3 ? Border.all(
color: Color(0xff2244C7), width: 1.0) : Border
.all(color: Colors.transparent,),),
child: Image.asset('images/smallImage2.png',
),
),
),
GestureDetector(
onTap: () {
setState(() {
SmallImages.tappedGestureDetector = 4;
}); // <-- replaced 'tapped' and 'other'
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 4 ? Border.all(
color: Color(0xff2244C7), width: 1.0) : Border
.all(color: Colors.transparent,),),
child: Image.asset('images/smallImage3.png',
),
),
),
].toList(),
),
],
);
}),
),
),
);
}
}
I am trying to implement swipe down on stack of cards and making them zoom out.
I have tried many basic animations together but nothing worked.
Here is one of my code that i have tried:
class _HomePageState extends State<HomePage> {
final HomeController _controller;
double _scaley = 1;
double skewY = 0;
double rotateZ = 0;
double radius = 15.0;
_HomePageState(this._controller);
#override
void initState() {
super.initState();
refreshView();
}
refreshView() {
_controller.init((result) {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return _controller.isLoading
? Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_controller.data.defaultCard == null
? Container()
: Container(
height: MediaQuery.of(context).size.height / 2.4,
child: new GestureDetector(
onVerticalDragDown: (DragDownDetails details) {
skewY = 0.3;
rotateZ = -3.14 / 18.0;
_scaley = 1.1;
radius = 20.0;
setState(() {});
},
child: Stack(
alignment: FractionalOffset.topRight,
children: <Widget>[
Positioned(
top: 20,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
Positioned(
top: 70,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
Positioned(
top: 120,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
],
),
),
),
],
),
);
}
}
I need animation like Apple pay:
Its showing single card and I need to show 3 cards as stack:
and by dragging them down will zoom them out(like gif)
So the idea of my program is to generate random numbers with operators and then make a non-for-user result of this operation. And it works, but my app refreshes the data every time I make any action like opening TextField or submitting the result to compare user input with an actual answer.
I guess the problem is because of bad State managment but I cant figure out how to fix it myself.
(I have my own Mathematics class with functions for program but where is no need to worry about)
The code what`s required:
class _GameplayPageState extends State<GameplayPage> {
#override
Widget build(BuildContext context) {
var mathManager = Mathematics();
var firstNum = mathManager.getNumber();
var secondNum = mathManager.getNumber();
var mathOperator = mathManager.getOperator();
var calResult = mathManager.calculate(firstNum, mathOperator, secondNum);
Positioned(
top: 120,
child: Container(
width: screenWidth,
height: 230,
// decoration: BoxDecoration(color: Colors.orange),
child: Align(
alignment: Alignment.center,
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: 10,
),
// >>>> LOOK HERE
Text(
firstNum.toString(),
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
Text(
mathOperator,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 70,
color: Color(0xff52de97),
),
),
Text(
secondNum.toString(),
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5,
),
),
SizedBox(
width: 10,
),
],
),
),
),
),
),
child: TextField(
onSubmitted: (String value) async {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: (value == calResult ? Text('Right') : Text('Wrong!')),
);
});
},
FlatButton(
onPressed: () {
setState(() {
});
},
Sorry for bad formatting ;(
I am not sure with what you are trying to achieve but here's simple code you can try which don't generate new number after checking if the input correct or not and also has new generate number button
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Pageone(),
),
);
}
}
class Pageone extends StatefulWidget {
#override
_PageoneState createState() => _PageoneState();
}
class _PageoneState extends State<Pageone> {
TextEditingController controller = TextEditingController();
int a = Random().nextInt(10);
int b = Random().nextInt(10);
int c;
String result;
#override
void initState() {
plus();
super.initState();
}
void plus() {
c = a + b;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: 10,
),
Text(
'$a',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
Text(
'$b',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
),
),
Text(
'$c',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5,
),
),
SizedBox(
width: 10,
),
],
),
Form(
child: Column(
children: <Widget>[
Container(
width: 300,
child: TextFormField(
controller: controller,
onFieldSubmitted: (String value) {
setState(() =>
result = int.parse(value) == c ? 'true' : 'false');
},
),
),
],
),
),
Text(
result == null ? '' : '$result',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
MaterialButton(
child: Text('Generate new'),
onPressed: () {
setState(() {
a = Random().nextInt(10);
b = Random().nextInt(10);
plus();
});
},
),
],
),
);
}
}
You can try creating a separate stateful widget to contain the part of code where the setstate() is called and convert the original widget to a stateless one.
In your code, the GameplayPage widget rebuilds itself whenever any value is updated. This is because the setstate() causes the widget to rebuild. So you should separate the things that don't change and those that change into different widgets.
For example, you can create the FlatButton as a custom widget and sent the necessary details as parameters.
So I solved this problem via making my mathematics object into several functions and then doing the hardest work before Widget build. The code:
var b = (Random().nextInt(99) + 1);
var operate = getOperator();
var result;
#override
void initState(){
result = calculate(a,operate,b);
super.initState();
}
Thanks everyone for contributing!