Flutter Radio Buttons validation - validation

I am implementing a custom radio button with validation and values are passed in those buttons. There is a run time error which i am not able to figure out. I am getting the following error
The following assertion was thrown during performLayout():
I/flutter (10799): An InputDecorator, which is typically created by a TextField, cannot have an unbounded width.
I/flutter (10799): This happens when the parent widget does not provide a finite width constraint. For example, if the
I/flutter (10799): InputDecorator is contained by a Row, then its width must be constrained. An Expanded widget or a
I/flutter (10799): SizedBox can be used to constrain the width of the InputDecorator or the TextField that contains it.
I/flutter (10799): 'package:flutter/src/material/input_decorator.dart':
I/flutter (10799): Failed assertion: line 945 pos 7: 'layoutConstraints.maxWidth < double.infinity'
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter FormBuilder Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: Colors.purple),
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
MyHomePageState createState() {
return MyHomePageState();
}
}
class MyHomePageState extends State<MyHomePage> {
var data;
bool autoValidate = true;
bool readOnly = false;
bool showSegmentedControl = true;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
final GlobalKey<FormFieldState> _specifyTextFieldKey =
GlobalKey<FormFieldState>();
ValueChanged _onChanged = (val) => print(val);
// var genderOptions = ['Male', 'Female', 'Other'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FormBuilder Example"),
),
body: Padding(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Row(
children: <Widget>[
FormBuilder(
// context,
key: _fbKey,
autovalidate: true,
//initialValue: {
// 'movie_rating': 5,
// },
readOnly: false,
child: Row(
children: <Widget>[
FormBuilderRadio(
decoration:
InputDecoration(labelText: 'My chosen language'),
attribute: "best_language",
leadingInput: true,
onChanged: _onChanged,
validators: [FormBuilderValidators.required()],
options:
["Delete", "Approve", "Revert"]
.map((lang) => FormBuilderFieldOption(
value: lang,
child: Text('$lang'),
))
.toList(growable: false),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Submit",
style: TextStyle(color: Colors.white),
),
onPressed: () {
if (_fbKey.currentState.saveAndValidate()) {
print(_fbKey.currentState.value);
} else {
print(_fbKey.currentState.value);
print("validation failed");
}
},
),
),
SizedBox(
width: 20,
),
Expanded(
child: MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_fbKey.currentState.reset();
},
),
),
],
),
],
),
),
),
);
}
}
void changeIndex() {
setState(() {
selectedIndex = 1;
print("Value passed is delete");
});
}
void changeIndex1() {
setState(() {
selectedIndex = 1;
print("Value passed is a");
});
}
void changeIndex2() {
setState(() {
selectedIndex = 1;
print("Value passed is r");
});
}
Widget customRadio1() => OutlineButton(
onPressed: () => changeIndex(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
borderSide: BorderSide(
color: selectedIndex == 0 ? Colors.red : Colors.grey),
child: Text(lst[0], style: TextStyle(
color: selectedIndex == 0 ? Colors.red : Colors.grey),),
);
Widget customRadio2() => OutlineButton(
onPressed: () => changeIndex1(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
borderSide: BorderSide(
color: selectedIndex == 1 ? Colors.green : Colors.grey),
child: Text(lst[1], style: TextStyle(
color: selectedIndex == 1 ? Colors.green : Colors.grey),),
);
Widget customRadio3() {
return OutlineButton(
onPressed: () => changeIndex2(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
borderSide: BorderSide(
color: selectedIndex == 2 ? Colors.cyan : Colors.grey),
child: Text(lst[2], style: TextStyle(
color: selectedIndex == 2 ? Colors.cyan : Colors.grey),),
);
}
}

An InputDecorator cannot have an unbounded width as mentioned in the logs. The cause of this is that the InputDecorator is in a Scrollable Row and has an undefined width. To solve this issue, you can wrap the child widgets in the Row with a Container with a width configured.

Related

upload image using multipart in flutter

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?

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.

Why isn't the image changing using the Provider Package?

I'm working with the Provider Package on Flutter but can't work out why it's not changing the background image when I call mymodel.image. It should access the MyModal class and change the existing image: Image.asset('images/background_image.jpeg', fit: BoxFit.fill) with the one in the SmallImage screen.
mymodel.image = Image.asset('images/hello_image.png', fit: BoxFit.fill);
Which replaces the background image on the HomePage.
HomePage Screen
import 'package:flutter/material.dart';
import 'package:flutter_app_background/small_images.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyModel>(
create: (context) => MyModel(),
child: MaterialApp(
title: 'Title',
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
#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: Consumer<MyModel>(
builder: (context, myModel, child) {
return myModel.image = Image.asset('images/background_image.jpeg', fit: BoxFit.fill);
},
),
),
),
],
),
);
}
}
class MyModel extends ChangeNotifier {
Image _image;
set image(Image value) {
_image = value;
notifyListeners();
}
Image get image => _image;
}
SmallImage Screen
import 'package:flutter/material.dart';
import 'package:flutter_app_background/main.dart';
import 'package:provider/provider.dart';
class SmallImages extends StatefulWidget {
static int tappedGestureDetector = 1;
#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) {
final mymodel = Provider.of<MyModel>(context,listen:false); //default for listen is `true`
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: () {
// return myValue;
setState(() {
SmallImages.tappedGestureDetector = 1;
});
return mymodel.image = Image.asset('images/hello_image.png', fit: BoxFit.fill);
print('hi');
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 1
? Border.all(
color: Color(0xff2244C7), width: 1.0)
: Border
.all(color: Colors.transparent,),),
child: Image.asset(
'images/nightsky_image.png',
),
),
),
Consumer<MyModel>(
builder: (context, myModel, child) {
return 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/own_image.png',
),
),
);
},
),
Consumer<MyModel>(
builder: (context, myModel, child) {
return 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/iceland_image.png',
),
),
);
},
),
].toList(),
),
],
);
}),
),
),
);
}
}
You have to call notifyListeners in your model when the image has changed otherwise the changenotifierprovider will not know that it needs to rebuild.
One way of doing the would be to wrap the image field with a getter and setter and call notifyListeners in the setter after updating the underlying field.
var Image _image;
set image(Image value) {
_image = value;
notifyListeners();
}
Image get image => _image;

how to custom Tab Bar ? Flutter

I would like to customize my TabBar.
Right now I have this TabBar (stock UI) :
and I would like to have this UI :
I already coded the personalized tab but I don't know how to implement it.
There is my current code about my HomePage :
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController =
TabController(length: 6, vsync: this); // initialise it here
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: _tabController,
isScrollable: true,
tabs: [
Tab(text: "NewPay1.1"),
Tab(text: "NewMall 1.0"),
Tab(text: "海报"),
Tab(text: "企业版"),
Tab(text: "个版"),
Tab(text: "poa"),
],
),
title: Text('tabBar'),
),
body: TabBarView(
controller: _tabController,
children: [
// these are your pages
TaskListPage(),
TestPage(),
],
),
bottomNavigationBar: BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(),
child: Row(
children: <Widget>[
IconButton(
onPressed: () => _tabController.animateTo(0),
icon: Icon(Icons.home),
),
SizedBox(),
IconButton(
onPressed: () => _tabController.animateTo(1),
icon: Icon(Icons.more))
],
mainAxisAlignment: MainAxisAlignment.spaceAround,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
return TestPage().createState();
},
child: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
),
);
}
}
then my CustomTab class :
class CustomTab extends StatefulWidget {
final Function(int) tabSelected;
final List<String> items;
const CustomTab({Key key, this.tabSelected, this.items}) : super(key: key);
#override
_CustomTabState createState() => _CustomTabState();
}
class _CustomTabState extends State<CustomTab> {
var categorySelected = 0;
#override
Widget build(BuildContext context) {
return _getListCategory();
}
Widget _getListCategory(){
ListView listCategory = new ListView.builder(
itemCount: widget.items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index){
return _buildCategoryItem(index);
}
);
return new Container(
height: 50.0,
child: listCategory,
color: Colors.grey[200].withAlpha(200),
);
}
Widget _buildCategoryItem(index){
return new InkWell(
onTap: (){
setSelectedItem(index);
print("click");
},
child: new Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.only(left: 10.0),
child: new Material(
elevation: 2.0,
color: categorySelected == index ? Colors.black : Colors.grey,
borderRadius: const BorderRadius.all(const Radius.circular(25.0)),
child: new Container(
padding: new EdgeInsets.only(left: 12.0,top: 7.0,bottom: 7.0,right: 12.0),
child: new Text(widget.items[index],
style: new TextStyle(
color: categorySelected == index ? Colors.white : Colors.black),
),
),
),
)
],
),
);
}
void setSelectedItem(index) {
if(index != categorySelected) {
widget.tabSelected(index);
setState(() {
categorySelected = index;
});
}
}
}
There is already a plugin for this styled tabbar.
https://pub.dartlang.org/packages/bubble_tab_indicator
I hope this is what you are looking for :)
Yours Glup3
Try this code it is very simple
first initialize this
var radius = Radius.circular(150);
Then
class _Class_Name extends State<ClassName> {
var radius = Radius.circular(150);
#override
Widget build(BuildContext context) {
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
centerTitle: true,
leading: // if you need
),
title:
// if you need
// Scrollable rounded Tab bar
body: TabBar(
isScrollable: true,
labelColor: Colors.black,
tabs: <Widget>[
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
],
indicator: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(radius)),
color: HexColor('#005866')),
),
Container(
height: 80,
child: TabBarView(
children: <Widget>[
Container(
child: Center(
child: Text("Hello"),
),
),
Container(
child: Center(
child: Text("Hi"),
),
),
),
],
),
),
);
}

Flutter: hide and display app bar in scrolling detected

I'm having trouble with app bar animation, I'm using SilverAppBar, in my app. So, the problem is when I'm in the middle of my list and I scroll up, the app bar does not appear, but it appears just when scrolling reaches the top of the items list. I already tested the snap parameter and give it true, but not the result I expect. I have ideas about creating a custom animation for this, but I'm not too experienced in Flutter, and also if there is a way to add parameters, or another widget that will work for my situation, it would be great.
The actual code of the demo I'm using:
Widget _search() => Container(
color: Colors.grey[400],
child: SafeArea(
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
enabled: false,
style: TextStyle(fontSize: 16, color: Colors.white),
decoration: InputDecoration(
prefix: SizedBox(width: 12),
hintText: "Search",
contentPadding:
EdgeInsets.symmetric(horizontal: 32.0, vertical: 14.0),
border: InputBorder.none,
),
),
),
)),
);
Container _buildBody() {
return Container(
child: new GridView.count(
crossAxisCount: 2,
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline,
),
);
}),
));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
resizeToAvoidBottomPadding: false,
body: new NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
new SliverAppBar(
title: Text("Demo",
style: TextStyle(
color: Colors.white,
)),
pinned: false,
floating: true,
forceElevated: innerBoxIsScrolled,
),
];
},
body: new Column(children: <Widget>[
_search(),
new Expanded(child: _buildBody())
])));
}
The result I have now:
Image 1
The result I got after giving true to the snap parameter:
Image 2
Plenty of applications like WhatsApp, Facebook, LinkedIn ... have this animating app bar. To explain more what exactly I expect with this animating app bar, I added an example of Google Play Store, showing the wanted animation: Play Store example
I had a similar issue with CustomScrollView and SliverAppbar using refresh indicator i ended up creating my own custom appbar.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeView extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<HomeView> with SingleTickerProviderStateMixin {
bool _isAppbar = true;
ScrollController _scrollController = new ScrollController();
#override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
appBarStatus(false);
}
if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
appBarStatus(true);
}
});
}
void appBarStatus(bool status) {
setState(() {
_isAppbar = status;
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: AnimatedContainer(
height: _isAppbar ? 55.0 : 0.0,
duration: Duration(milliseconds: 200),
child: CustomAppBar(),
),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return container();
},
),
),
);
}
}
Widget container() {
return Container(
height: 80.0,
color: Colors.pink,
margin: EdgeInsets.all(8.0),
width: 100,
child: Center(
child: Text(
'Container',
style: TextStyle(
fontSize: 18.0,
),
)),
);
}
class CustomAppBar extends StatefulWidget {
#override
AppBarView createState() => new AppBarView();
}
class AppBarView extends State<CustomAppBar> {
#override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
leading: InkWell(
onTap: () => {},
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
backgroundColor: Colors.white,
child: ClipOval(
child: Image.network(
'https://images.squarespace-cdn.com/content/5aee389b3c3a531e6245ae76/1530965251082-9L40PL9QH6PATNQ93LUK/linkedinPortraits_DwayneBrown08.jpg?format=1000w&content-type=image%2Fjpeg'),
),
),
),
),
actions: <Widget>[
IconButton(
alignment: Alignment.centerLeft,
icon: Icon(
Icons.search,
color: Colors.black,
),
onPressed: () {},
),
],
title: Container(
alignment: Alignment.centerLeft,
child: Text("Custom Appbar", style: TextStyle(color: Colors.black),)
),
);
}
}
To get this functionality to work, you will need to use the CustomScrollView widget instead of NestedScrollView. Google Documentation
Here is a working example:
class MyHomeState extends State<MyHome> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
pinned: false,
snap: false,
floating: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 50,
),
),
],
)
);
}
}
Example of this running here
I was able to make the floating Appbar with Tabbar similar to that of WhatsApp by using SliverAppbar with NestedScrollView. Do remember to add floatHeaderSlivers: true, in NestedScrollView. Link to sample code
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CustomSliverAppbar(),
);
}
}
class CustomSliverAppbar extends StatefulWidget {
#override
_CustomSliverAppbarState createState() => _CustomSliverAppbarState();
}
class _CustomSliverAppbarState extends State<CustomSliverAppbar>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(
initialIndex: 0,
length: 2,
vsync: this,
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text(
"WhatsApp type sliver appbar",
),
centerTitle: true,
pinned: true,
floating: true,
bottom: TabBar(
indicatorColor: Colors.black,
labelPadding: const EdgeInsets.only(
bottom: 16,
),
controller: _tabController,
tabs: [
Text("TAB A"),
Text("TAB B"),
]),
),
];
},
body: TabBarView(
controller: _tabController,
children: [
TabA(),
const Center(
child: Text('Display Tab 2',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
],
),
),
);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
}
class TabA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scrollbar(
child: ListView.separated(
separatorBuilder: (context, child) => Divider(
height: 1,
),
padding: EdgeInsets.all(0.0),
itemCount: 30,
itemBuilder: (context, i) {
return Container(
height: 100,
width: double.infinity,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
},
),
);
}
}

Resources