Related
Hello i am learning the state using the getX methods. When the app loads i am adding the categories in the list but the issue is not updating. can anybody look whats my wrong?
Restaurant Ui Button Page:
HomeController con = Get.put(HomeController());
Widget _cardRestoran(BuildContext context, Restaurants restaurant) {
return GestureDetector(
onTap: () {
con.restoranProducts(context, restaurant);
},
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: 15, left: 20, right: 20),
child: ListTile(
title: Text('${restaurant.name ?? ''}' ,),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 5),
Text(
' Şehir: ${restaurant.il ?? ''} - İlçe: ${restaurant.ilce ?? ''}' ,
maxLines: 2,
style: TextStyle(
fontSize: 13
),
),
SizedBox(height: 15),
],
),
trailing: Container(
height: 70,
width: 60,
// padding: EdgeInsets.all(2),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: FadeInImage(
image: restaurant.image != null
? NetworkImage(restaurant.image ?? '')
: AssetImage('assets/img/no-image.png') as ImageProvider,
fit: BoxFit.cover,
fadeInDuration: Duration(milliseconds: 50),
placeholder: AssetImage('assets/img/no-image.png'),
),
),
),
),
),
Divider(height: 1, color: Colors.grey[300], indent: 37, endIndent: 37,)
],
),
);
}
Home Controller
class HomeController extends GetxController{
void restoranProducts(BuildContext context, Restaurants restaurants) async{
await showMaterialModalBottomSheet(
context: context,
useRootNavigator: true,
builder: (context) => RestoranProducts(restaurants: restaurants),
);
}
}
Restaurant Category Controller :
class ClientRestoranProductListController extends GetxController{
String res_id;
List<Category> categories = <Category>[].obs;
ClientRestoranProductListController(#required this.res_id){
getCategories();
}
void getCategories() async {
var result = await categoriesProvider.restaurantCategory("${this.res_id}");
categories.clear();
categories.addAll(result);
}
}
I also tried seperate but it still didnt work.
Restoran Products Category List UI page:
class RestoranProducts extends StatefulWidget {
final Restaurants? restaurants;
const RestoranProducts({Key? key, required this.restaurants}) : super(key: key);
#override
State<RestoranProducts> createState() => _RestoranProductsState();
}
class _RestoranProductsState extends State<RestoranProducts> {
Widget build(BuildContext context) {
String restoranSahibi = "${widget.restaurants?.user_id}";
ClientRestoranProductListController con = Get.put(ClientRestoranProductListController(restoranSahibi));
return Obx(() => DefaultTabController(
length: con.categories.length,
child: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => setState((){
})),
drawer: HomeNavigator(),
appBar: PreferredSize(
preferredSize: Size.fromHeight(110),
child:AppBar(
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors:
[
Colors.amber,
Colors.black,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.0, 0.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp,
)
),
margin: EdgeInsets.only(top: 15),
alignment: Alignment.topCenter,
child: Wrap(
direction: Axis.horizontal,
children: [
_textFieldSearch(context),
_iconShoppingBag()
],
),
),
centerTitle: true,
iconTheme: IconThemeData(color: Colors.white),
bottom: TabBar(
isScrollable: true,
indicatorColor: Colors.white,
labelColor: Colors.black,
unselectedLabelColor: Colors.white,
indicatorSize: TabBarIndicatorSize.tab,
indicator: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
color: Colors.white
),
tabs: List<Widget>.generate(con.categories.length, (index) {
return Tab(
child: Text(con.categories[index].name ?? ''),
);
}),
),
) ,
),
body: TabBarView(
key: Key(Random().nextDouble().toString()),
children: con.categories.map((Category category) {
return FutureBuilder(
future: con.getProducts(category.id ?? '1', con.productName.value),
builder: (context, AsyncSnapshot<List<Product>> snapshot) {
if (snapshot.hasData) {
if (snapshot.data!.length > 0) {
return ListView.builder(
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (_, index) {
return _cardProduct(context, snapshot.data![index]);
}
);
}
else {
return NoDataWidget(text: 'No category');
}
}
else {
return NoDataWidget(text: 'No category');
}
}
);
}).toList(),
)
),
));
}
}
i tried seperate ways but it did not work.
The argument type 'String?' can't be assigned to the parameter type 'String'.dart (argument_type_not_assignable.)
try{
var key = 'email';
await Provider.of<Authentication>(context, listen: false).signUp(
_authData[key],
_authData['password']
);
Navigator.of(context).pushReplacementNamed(HomeScreen.routeName);
} catch(error)
{
var errorMessage = 'Authentication Failed. Please try again later.';
_showErrorDialog(errorMessage);
}
}
try{
await Provider.of<Authentication>(context, listen: false).logIn(
_authData['email'],
_authData['password']
);
Navigator.of(context).pushReplacementNamed(HomeScreen.routeName);
} catch (error)
{
var errorMessage = 'Authentication Failed. Please try again later.';
_showErrorDialog(errorMessage);
}
}
Screenshot
Screenshot
This is a problem of null safety. Basically, your signUp method accepts a String as parameter, but you are passing a String? (the question mark indicated that the valute can be null). In order to solve this situation you have to check if _authData[key] and _authData['password'] (same also for logIn) are not null. Something like this:
try{
var key = 'email';
if(_authData[key] != null && _authData['password'] != null) {
await Provider.of<Authentication>(context, listen: false).signUp(
_authData[key]!,
_authData['password']!,
);
Navigator.of(context).pushReplacementNamed(HomeScreen.routeName);
} else {
throw Exception('Error');
}
} catch(error) {
var errorMessage = 'Authentication Failed. Please try again later.';
_showErrorDialog(errorMessage);
}
Missing concrete implementation of 'State.build'.
Try implementing the missing method, or make the class abstract.dart(non_abstract_class_inherits_abstract_member)
signup_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/authentication.dart';
import 'home_screen.dart';
import 'login_screen.dart';
class SignupScreen extends StatefulWidget {
static const routeName = '/signup';
#override
_SignupScreenState createState() => _SignupScreenState();
}
class _SignupScreenState extends State<SignupScreen> {
final GlobalKey<FormState> _formKey = GlobalKey();
TextEditingController _passwordController = new TextEditingController();
Map<String, String> _authData = {
'email' : '',
'password' : ''
};
void _showErrorDialog(String msg)
{
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An Error Occured'),
content: Text(msg),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: (){
Navigator.of(ctx).pop();
},
)
],
)
);
}
Future<void> _submit() async
{
if(!_formKey.currentState!.validate())
{
return;
}
_formKey.currentState!.save();
try{
var key = 'email';
if(_authData[key] != null && _authData['password'] != null) {
await Provider.of<Authentication>(context, listen: false).signUp(
_authData[key]!,
_authData['password']!,
);
Navigator.of(context).pushReplacementNamed(HomeScreen.routeName);
} else {
throw Exception('Error');
}
} catch(error) {
var errorMessage = 'Authentication Failed. Please try again later.';
_showErrorDialog(errorMessage);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Signup'),
actions: <Widget>[
FlatButton(
child: Row(
children: <Widget>[
Text('Login'),
Icon(Icons.person)
],
),
textColor: Colors.white,
onPressed: (){
Navigator.of(context).pushReplacementNamed(LoginScreen.routeName);
},
)
],
),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.limeAccent,
Colors.redAccent,
]
)
),
),
Center(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
height: 300,
width: 300,
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
//email
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value)
{
if(value!.isEmpty || !value.contains('#'))
{
return 'invalid email';
}
return null;
},
onSaved: (value)
{
_authData['email'] = value!;
},
),
//password
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value)
{
if(value!.isEmpty || value.length<=5)
{
return 'invalid password';
}
return null;
},
onSaved: (value)
{
_authData['password'] = value!;
},
),
//Confirm Password
TextFormField(
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: (value)
{
if(value!.isEmpty || value != _passwordController.text)
{
return 'invalid password';
}
return null;
},
onSaved: (value)
{
},
),
SizedBox(
height: 30,
),
RaisedButton(
child: Text(
'Submit'
),
onPressed: ()
{
_submit();
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
color: Colors.blue,
textColor: Colors.white,
)
],
),
),
),
),
),
)
],
),
);
}
}
}
login_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'signup_screen.dart';
import 'home_screen.dart';
import '../models/authentication.dart';
class LoginScreen extends StatefulWidget {
static const routeName = '/login';
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final GlobalKey<FormState> _formKey = GlobalKey();
Map<String, String> _authData = {
'email' : '',
'password': ''
};
var email;
void _showErrorDialog(String msg)
{
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An Error Occured'),
content: Text(msg),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: (){
Navigator.of(ctx).pop();
},
)
],
)
);
}
Future<void> _submit() async
{
if(!_formKey.currentState!.validate())
{
return;
}
_formKey.currentState!.save();
try{
if(_authData[email] != null && _authData['password'] != null) {
await Provider.of<Authentication>(context, listen: false).logIn(
_authData['email']!,
_authData['password']!,
);
Navigator.of(context).pushReplacementNamed(HomeScreen.routeName);
} else {
throw Exception('Error');
}
} catch(error) {
var errorMessage = 'Authentication Failed. Please try again later.';
_showErrorDialog(errorMessage);
}}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login'),
actions: <Widget>[
FlatButton(
child: Row(
children: <Widget>[
Text('Signup'),
Icon(Icons.person_add)
],
),
textColor: Colors.white,
onPressed: (){
Navigator.of(context).pushReplacementNamed(SignupScreen.routeName);
},
)
],
),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.lightGreenAccent,
Colors.blue,
]
)
),
),
Center(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
height: 260,
width: 300,
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
//email
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value)
{
if(value!.isEmpty || !value.contains('#'))
{
return 'invalid email';
}
return null;
},
onSaved: (value)
{
_authData['email'] = value!;
},
),
//password
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value)
{
if(value!.isEmpty || value.length<=5)
{
return 'invalid password';
}
return null;
},
onSaved: (value)
{
_authData['password'] = value!;
},
),
SizedBox(
height: 30,
),
RaisedButton(
child: Text(
'Submit'
),
onPressed: ()
{
_submit();
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
color: Colors.blue,
textColor: Colors.white,
)
],
),
),
),
),
),
)
],
),
);
}
}
Photo
Problem
I have tried SingleChildListView and ListView widgets but the children end up spanning full width. I need the widgets to not exceed a maxWidth of 850px. Using a container with a width:850 or a BoxContraints(maxWidth:850) does not apply to the children inside the list view.
Desired Outcome
The form should be centered on the page but the scrollbar should be as far right as possible. If the user's mouse is on the form or in the white space to the left/right of the form, the user should retain the ability to scroll up/down.
SFUScaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Container(
constraints:
BoxConstraints(maxWidth: ThemeManager.getTheme().maxWidth),
child: Scrollbar(
isAlwaysShown: true,
controller: _scrollbar,
child: SingleChildScrollView(
controller: _scrollbar,
padding: EdgeInsets.all(15),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SFUSizedBox(height: 5),
Text(
"Secure File Upload Form",
style: ThemeManager.getTheme().formTitleStyle,
),
SFUSizedBox(height: 5),
Text(
"Quickly upload and send documents directly to the ${ThemeManager.getTheme().clientName} team",
style: ThemeManager.getTheme().formSubtitleStyle,
),
SFUSizedBox(height: 5),
Divider(),
SFUSizedBox(height: 5),
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Visibility(
visible: state.hasErrors,
child: FittedBox(
child: Row(
children: [
Icon(
LineIcons.exclamationCircle,
color: ThemeManager.getTheme().errorColor,
size: 30,
),
Text(
"Your form was not sent. Please correct the issues below and try again.",
style: ThemeManager.getTheme().errorStyle,
),
],
),
),
);
}),
Text(
"Tell us who you are",
style: ThemeManager.getTheme().formSectionTitleStyle,
),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
isLargeScreen
? _BuildNameLayout(direction: Axis.horizontal)
: _BuildNameLayout(direction: Axis.vertical),
SFUSizedBox(height: 5),
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Container(
width: isLargeScreen
? ThemeManager.getTheme().px2pt(400)
: ThemeManager.getTheme().px2pt(600),
child: PXFormField(
label: "Member ID:",
optional: true,
initalValue: state.formFields["member_id"] ?? "",
onChanged: (value) {
context
.read<FormCubit>()
.updateFormField('member_id', value);
},
),
);
},
),
SizedBox(height: ThemeManager.getTheme().px2pt(20)),
Divider(),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
Text(
"Share your contact details",
style: ThemeManager.getTheme().formSectionTitleStyle,
),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Container(
width: isLargeScreen
? ThemeManager.getTheme().px2pt(400)
: ThemeManager.getTheme().px2pt(600),
child: PXFormField(
initalValue: state.formFields["email"] ?? "",
label: "Email: *",
optional: false,
onChanged: (value) {
context
.read<FormCubit>()
.updateFormField('email', value);
},
validator: (value) {
if (!FieldValidator.validateEmail(value)) {
return "Please provide a valid email address.";
} else if (state.formErrors
.containsKey("email")) {
return state.formErrors['email'];
}
return null;
}),
);
},
),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Container(
width: isLargeScreen
? ThemeManager.getTheme().px2pt(400)
: ThemeManager.getTheme().px2pt(600),
child: PXFormField(
initalValue:
state.formFields["phone_number"] ?? "",
label: "Phone Number:",
optional: true,
onChanged: (value) {
context
.read<FormCubit>()
.updateFormField('phone_number', value);
},
),
);
},
),
SizedBox(height: ThemeManager.getTheme().px2pt(20)),
Divider(
thickness: 1.0,
),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
Text(
"Select the files that you would like to send",
style: ThemeManager.getTheme().formSectionTitleStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Text(
state.formErrors['files'] != null
? state.formErrors['files'].toString()
: "",
style: ThemeManager.getTheme().errorStyle,
);
},
),
],
),
Text(
"Upload Your Files: *",
style: ThemeManager.getTheme().formLabelStyle,
),
SizedBox(
height: ThemeManager.getTheme().px2pt(15),
),
UploadFilesComponent(),
Container(
child: BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return Column(
children: new List.generate(
state.files.length,
(index) => FileCard(
//Add Progress value here for styling....
file: state.files[index],
fileIndex: index),
),
);
},
),
),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
Divider(),
SizedBox(height: ThemeManager.getTheme().px2pt(10)),
Text(
"Provide any background or instructions for the files you're sending",
style: ThemeManager.getTheme().formSectionTitleStyle),
SFUSizedBox(height: 20),
RichText(
text: TextSpan(
text: "Additional Information:",
style: ThemeManager.getTheme().formLabelStyle,
children: <TextSpan>[
TextSpan(
text: " (optional)",
style: ThemeManager.getTheme()
.formOptionalLabelStyle,
)
]),
),
SFUSizedBox(height: 30),
BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return TextFormField(
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 4,
onChanged: (value) {
context.read<FormCubit>().updateFormField(
'additional_information', value);
},
);
},
),
SFUSizedBox(height: 30),
Center(
child: Container(
width: ThemeManager.getTheme().px2pt(300),
height: ThemeManager.getTheme().px2pt(50),
child: BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return DarkOutlinedButton(
buttonText: "Send Your Files",
onpressed: () {
context.read<FormCubit>().validateForm();
_formKey.currentState!.validate();
if (!state.hasErrors) {
Navigator.pushNamedAndRemoveUntil(context,
"/submission-details", (_) => false);
}
},
);
},
),
),
),
SFUSizedBox(height: 30),
Divider(),
SFUSizedBox(height: 30),
Center(
child: Image.asset("images/powered_by_pensionx.png")),
Center(
child: TextButton(
onPressed: () async {
await showDialog(
context: context,
builder: (_) => ReportProblemModal(),
);
},
child: Text(
"Report a Problem",
style: TextStyle(
color: Theme.of(context).primaryColor),
),
),
)
],
),
),
),
),
),
),
),
);
class SFUSizedBox extends StatelessWidget {
final double height;
const SFUSizedBox({
required this.height,
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(height: ThemeManager.getTheme().px2pt(height));
}
}
class _BuildNameLayout extends StatelessWidget {
final Axis direction;
_BuildNameLayout({required this.direction});
#override
Widget build(BuildContext context) {
List<Widget> content = [
Expanded(
flex: this.direction == Axis.horizontal ? 3 : 0,
child: BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return PXFormField(
initalValue: state.formFields["first_name"] ?? "",
label: "First Name: *",
optional: false,
validator: (value) {
if (state.formErrors.containsKey("first_name")) {
return state.formErrors['first_name'];
}
return null;
},
onChanged: (value) {
context.read<FormCubit>().updateFormField('first_name', value);
},
);
},
),
),
SizedBox(width: 10),
Expanded(
flex: this.direction == Axis.horizontal ? 2 : 0,
child: BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return PXFormField(
initalValue: state.formFields["middle_initial"] ?? "",
label: "Middle Initial:",
optional: false,
onChanged: (value) {
context
.read<FormCubit>()
.updateFormField('middle_initial', value);
},
);
},
),
),
SizedBox(width: 10),
Expanded(
flex: this.direction == Axis.horizontal ? 3 : 0,
child: BlocBuilder<FormCubit, FormCubitState>(
builder: (context, state) {
return PXFormField(
initalValue: state.formFields["last_name"] ?? "",
label: "Last Name: *",
optional: false,
onChanged: (value) {
context.read<FormCubit>().updateFormField('last_name', value);
},
validator: (value) {
if (state.formErrors.containsKey("last_name")) {
return state.formErrors['last_name'];
}
return null;
},
);
},
),
),
];
if (this.direction == Axis.horizontal) {
return Container(
width: ThemeManager.getTheme().maxWidth,
child: Row(children: content));
}
if (this.direction == Axis.vertical) {
return Column(
mainAxisSize: MainAxisSize.min,
children: content,
);
}
// This shoudln't ever happen.
throw new Exception(
'Direction must be set to Axis.horizontal or Axis.vertical');
}
}
The image above has the following problems:
The white space to the left/right doesn't allow the user to scroll
The scroll bar needs to be as far to right as possible.
The form appears to be embedded into the page but I want it to feel like an entire page.
I have the following classes:
AddFormBloc
class AddFormBloc extends FormBloc<String,String>{
// ignore: close_sinks
final trackField = TextFieldBloc(
asyncValidatorDebounceTime: Duration(milliseconds: 500),
);
final latField = TextFieldBloc();
final longField = TextFieldBloc();
AddFormBloc(){
trackField.addAsyncValidators([_isValidTrack]);
addFieldBlocs(fieldBlocs: [
trackField,
latField,
longField
]);
}
...
#override
Stream<FormBlocState<String, String>> onSubmitting() async* {
try{
print(trackField.value);
await Future<void>.delayed(Duration(seconds:2));
yield state.toSuccess();
}catch(e){
yield state.toFailure(
failureResponse: 'Fake error, please continue testing the async validation.'
);
}
}
}
FormAddSong
class FormAddSong extends StatefulWidget {
#override
_FormAddSongState createState() => _FormAddSongState();
}
class _FormAddSongState extends State<FormAddSong> {
AddFormBloc _addFormBloc;
Completer<GoogleMapController> _controller = Completer();
double _lat; //latitud
double _lng; //longitud
Set<Marker> _markers = Set();
#override
void initState() {
super.initState();
_addFormBloc = AddFormBloc();
}
#override
void dispose() {
_addFormBloc.delete();
super.dispose();
}
#override
Widget build(BuildContext context) {
String pattern = "https://open.spotify.com/track/";
String patternIdTrack="4QupQwSViJ7sdZWZOkzZV5";
return Container(
child: FormBlocListener(
formBloc: _addFormBloc,
onSubmitting: (context, state){
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: Center(
child: Card(
child: Container(
width: 80,
height: 80,
padding: EdgeInsets.all(12.0),
child: CircularProgressIndicator(),
),
),
),
),
);
},
onSuccess: (context, state){
Navigator.of(context).pop();
showDialog(context: context, builder: (_) => AlertDialog(
title: Text("se ha agregado correctamente"),
));
},
onFailure: (context, state){
// Hide the progress dialog
Navigator.of(context).pop();
// Show snackbar with the error
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(state.failureResponse),
backgroundColor: Colors.red[300],
),
);
},
child: Column(
children: [
TextFieldBlocBuilder(
maxLength: patternIdTrack.length+pattern.length,
textFieldBloc: _addFormBloc.trackField,
decoration: InputDecoration(
labelText: 'Enlace canción en Spotify',
hintText: 'Enlace canción en Spotify',
prefixIcon: Icon(Icons.music_note),
suffixIcon: IconButton(
icon: Icon(Icons.info_outline),
onPressed: (){
Navigator.push(context,
MaterialPageRoute(builder: (context) => OnBoardingGuideSpotifyLinkPage()));
},
),
),
),
TextFieldBlocBuilder(
isEnabled: false,
textFieldBloc: _addFormBloc.latField,
decoration: InputDecoration(
labelText: 'Latitud (Clic mapa)',
hintText: 'Latitud (Clic mapa)',
prefixIcon: Icon(Icons.edit_location)
),
),
TextFieldBlocBuilder(
readOnly: true,
textFieldBloc: _addFormBloc.longField,
decoration: InputDecoration(
labelText: 'Longitud (Clic mapa)',
hintText: 'Longitud (Clic mapa)',
prefixIcon: Icon(Icons.edit_location)
),
),
SizedBox(height: MediaQuery.of(context).devicePixelRatio*10.0),
FutureBuilder(
future: _initialCameraP(),
builder: (BuildContext context, AsyncSnapshot<Tuple2<Position,Uint8List>>snapshot){
if(snapshot.hasData){
Position ps = snapshot.data.item1;
return GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(ps.latitude,ps.longitude),
zoom: (ps.latitude==0.0 && ps.longitude == 0.0)?2.0:10.0
),
markers: _markers,
onMapCreated: (GoogleMapController controller){
_lat = ps.latitude;
_lng = ps.longitude;
_controller.complete(controller);
},
onTap: (LatLng latLng){
setState(() {
_markers.clear(); //limpiar lista para que solo aparezca sobre donde hemos clicado
//añadir donde hemos clicado
_markers.add(Marker(
markerId: MarkerId(latLng.toString()),
icon: BitmapDescriptor.fromBytes(snapshot.data.item2),
position: latLng,
));
});
},
);
}else{
return CircularProgressIndicator();
}
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: _addFormBloc.submit,
child: Center(child: Text('Enviar')),
),
),
],
),
),
);
}
What I am trying to do is that when a user tap on the GoogleMap, I automatically save the latitude and longitude in some variables and insert those values in the corresponding latitude and longitude textfieldblocbuilder.
Without Bloc, I know how to do it in normal forms, but with Bloc I can't find the way.
I am developing a flutter app, but it show error when I run the app.
I don't understand what is the problem. I think I mix up the logic of how the widget expand in layout.
Please kindly help to solve this issue.
error message:
flutter: The following assertion was thrown during performResize():
flutter: Vertical viewport was given unbounded height.
Viewports expand in the scrolling direction to fill their container.In this case, a vertical
viewport was given an unlimited amount of vertical space in which to expand. This situation
typically happens when a scrollable widget is nested inside another scrollable widget.
Here with my code:
body: Container(
child: Flexible(
child: FirebaseAnimatedList(
query: databaseReference,
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation,
int index) {
return new Card(
color: Colors.black38,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListTile(
leading: IconButton(
icon: Icon(Icons.format_list_bulleted),
color: Colors.blueAccent,
splashColor: Colors.greenAccent,
onPressed: () {
// Perform some action
debugPrint('button ok');
},
),
title: Text(shopList[index].shopName),
subtitle: Text(shopList[index].address),
),
Container(
child: Flexible(
child: Form(
key: formShopKey,
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(
Icons.money_off,
color: Colors.white,
),
title: TextFormField(
maxLength: 100,
initialValue: "",
maxLines: 3,
//onSaved: (val) => booking.seafoodRequest = val,
//validator: (val) => val == "" ? val : null,
decoration: new InputDecoration(
),
),
),
],
),
),
),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: new ButtonBar(
children: <Widget>[
new FlatButton(
child: const Text('BUY TICKETS'),
onPressed: () {
/* ... */
},
),
new FlatButton(
child: const Text('LISTEN'),
onPressed: () {
/* ... */
},
),
],
),
),
],
),
);
},
),
),
);
[1]: https://i.stack.imgur.com/5vAsv.png
[2]: https://i.stack.imgur.com/LuZEl.png
I had to fill in a few gaps but the below should build for you. I also swapped FirebaseAnimatedList with a regular AnimatedList to get it to build. You can compare and adjust the layout.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: AnimatedList(
initialItemCount: 10,
itemBuilder: (BuildContext context, int index,
Animation<double> animation) {
return new Card(
color: Colors.black38,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListTile(
leading: IconButton(
icon: Icon(Icons.format_list_bulleted),
color: Colors.blueAccent,
splashColor: Colors.greenAccent,
onPressed: () {
// Perform some action
debugPrint('button ok');
},
),
title: Text('Name'),
subtitle: Text('Address'),
),
Container(
constraints: BoxConstraints(
minHeight: 100.0,
maxHeight: 200.0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: Form(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(
Icons.money_off,
color: Colors.white,
),
title: TextFormField(
maxLength: 100,
initialValue: "",
maxLines: 3,
//onSaved: (val) => booking.seafoodRequest = val,
//validator: (val) => val == "" ? val : null,
decoration: new InputDecoration(),
),
),
],
),
),
),
],
),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: new ButtonBar(
children: <Widget>[
new FlatButton(
child: const Text('BUY TICKETS'),
onPressed: () {
/* ... */
},
),
new FlatButton(
child: const Text('LISTEN'),
onPressed: () {
/* ... */
},
),
],
),
),
],
),
);
},
),
),
],
),
);
}
}