I want to add a Tabbar in the body of the scaffold which decide the signUp method i.e, whether using phone number or email. I added a TabBar followed by TabBarView in a column in the body of scaffold. But it gives me the following exception
'The following assertion was thrown during performResize(): Horizontal viewport was given unbounded height. Viewports expand in the cross axis to fill their container and constrain their children to match their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of vertical space in which to expand.'
The same code works independantly when there were no TabBar. Here is my code,
class _SignUpState extends State<SignUp> with SingleTickerProviderStateMixin {
final emailController = TextEditingController();
final phoneController = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool isLoading = true;
late TabController tabController;
@override
void dispose(){
emailController.dispose();
phoneController.dispose();
super.dispose();
}
@override
void initState() {
// TODO: implement initState
super.initState();
tabController = TabController(length: 2, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold
body: SafeArea(
child: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
height: MediaQuery.of(context).size.height,
width: double.infinity,
child: Form(
key: _formKey,
child: ListView(
scrollDirection: Axis.vertical,
children: [
const SizedBox(height: 50,),
const Center(
child: Text(
'MyApp',
style: TextStyle(
color: Colors.red,
fontSize: 75,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 40),
const Center(
child: Text(
'Welcome to My App',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
),
),
),
SizedBox(height: 10,),
const Center(
child: Text(
'Sign up to continue',
style: TextStyle(
color: Color.fromARGB(255, 127, 125, 125),
fontSize: 16,
fontWeight: FontWeight.normal
),
),
),
const SizedBox(height: 50),
TabBar(
controller: tabController,
tabs: [
Tab(text: 'EMAIL ADDRESS',),
Tab(text: 'PHONE NUMBER',),
]
),
Container(
child: TabBarView(
controller: tabController,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 6),
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autofillHints: [AutofillHints.email],
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) {
if (emailController.text == '') {
return 'This is a required field';
}
EmailValidator.validate(value!)
? null
: "Please enter a valid email";
},
cursorColor: Colors.blue,
decoration: InputDecoration(
prefixIcon: Icon(Icons.email),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(
color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Email',
style: TextStyle(
color:
Color.fromARGB(254, 57, 40, 71),
fontSize: 20),
),
Text(
' *',
style: TextStyle(
color: Colors.red, fontSize: 20),
),
]),
hintText: '[email protected]',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 158, 156, 156),
fontSize: 20),
),
),
),
const SizedBox(
height: 50,
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState!.validate() ==
true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 6),
child: TextFormField(
controller: phoneController,
textInputAction: TextInputAction.next,
cursorColor: Colors.blue,
keyboardType: TextInputType.number,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) {
if (value!.length != 10 && value.isNotEmpty) {
return 'phone number must contain 10 numbers';
}
},
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(
color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Phone',
style: TextStyle(
color:
Color.fromARGB(254, 57, 40, 71),
fontSize: 20),
),
]),
prefixIcon: const Icon(Icons.phone),
hintText: 'Your phone number',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 158, 156, 156),
fontSize: 20),
),
),
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState!.validate() ==
true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Already have an account..? ", style: TextStyle(fontSize: 16),),
RichText(
text: TextSpan(
children: [
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = widget.onClickedSignIn,
text:'Log In',
style: TextStyle(
decoration: TextDecoration.underline,
color: Theme.of(context).colorScheme.secondary,
fontSize: 17
)
)
],
),
),
],
),
const SizedBox(height: 100,)
],
),
),
),
),
),
);
}
Future signUp() {
}
}
Can someone help with a solution ?
CodePudding user response:
Instead of double.infinity use MediaQuery.of(context).size.width
CodePudding user response:
You got this Horizontal viewport was given unbounded height.
error. It means you need to add a specific height
TabBar(
controller: tabController,
tabs: [
Tab(text: 'EMAIL ADDRESS',),
Tab(text: 'PHONE NUMBER',),
]
),
Container(
height: 500, // add height here
child: TabBarView(
controller: tabController,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 6),
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autofillHints: [AutofillHints.email],
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) {
},
cursorColor: Colors.blue,
decoration: InputDecoration(
prefixIcon: Icon(Icons.email),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(
color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Email',
style: TextStyle(
color:
Color.fromARGB(254, 57, 40, 71),
fontSize: 20),
),
Text(
' *',
style: TextStyle(
color: Colors.red, fontSize: 20),
),
]),
hintText: '[email protected]',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 158, 156, 156),
fontSize: 20),
),
),
),
const SizedBox(
height: 50,
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState.validate() ==
true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 6),
child: TextFormField(
controller: phoneController,
textInputAction: TextInputAction.next,
cursorColor: Colors.blue,
keyboardType: TextInputType.number,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) {
if (value.length != 10 && value.isNotEmpty) {
return 'phone number must contain 10 numbers';
}
},
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(
color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Phone',
style: TextStyle(
color:
Color.fromARGB(254, 57, 40, 71),
fontSize: 20),
),
]),
prefixIcon: const Icon(Icons.phone),
hintText: 'Your phone number',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 158, 156, 156),
fontSize: 20),
),
),
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState.validate() ==
true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
],
),
),
Container(
height: 500, //add height here
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Already have an account..? ", style: TextStyle(fontSize: 16),),
RichText(
text: TextSpan(
children: [
TextSpan(
recognizer: TapGestureRecognizer(),
text:'Log In',
style: TextStyle(
decoration: TextDecoration.underline,
color: Theme.of(context).colorScheme.secondary,
fontSize: 17
)
)
],
),
),
],
),
),
CodePudding user response:
Change ListView in to Column and TabBarView parent Expanded instead of Container
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class SignUp extends StatefulWidget {
const SignUp({Key? key}) : super(key: key);
@override
State<SignUp> createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> with SingleTickerProviderStateMixin {
final emailController = TextEditingController();
final phoneController = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool isLoading = true;
late TabController tabController;
@override
void dispose() {
emailController.dispose();
phoneController.dispose();
super.dispose();
}
@override
void initState() {
// TODO: implement initState
super.initState();
tabController = TabController(length: 2, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
height: MediaQuery.of(context).size.height,
width: double.infinity,
child: Form(
key: _formKey,
child: Column(
children: [
const SizedBox(
height: 50,
),
const Center(
child: Text(
'MyApp',
style: TextStyle(
color: Colors.red,
fontSize: 75,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 40),
const Center(
child: Text(
'Welcome to My App',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
height: 10,
),
const Center(
child: Text(
'Sign up to continue',
style: TextStyle(color: Color.fromARGB(255, 127, 125, 125), fontSize: 16, fontWeight: FontWeight.normal),
),
),
const SizedBox(height: 50),
TabBar(
controller: tabController,
tabs: [
Tab(
text: 'EMAIL ADDRESS',
),
Tab(
text: 'PHONE NUMBER',
),
],
labelColor: Colors.black,
),
Expanded(
child: TabBarView(
controller: tabController,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 6),
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autofillHints: [AutofillHints.email],
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (emailController.text == '') {
return 'This is a required field';
}
/* EmailValidator.validate(value!)
? null
: "Please enter a valid email";*/
},
cursorColor: Colors.blue,
decoration: InputDecoration(
prefixIcon: Icon(Icons.email),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Email',
style: TextStyle(color: Color.fromARGB(254, 57, 40, 71), fontSize: 20),
),
Text(
' *',
style: TextStyle(color: Colors.red, fontSize: 20),
),
]),
hintText: '[email protected]',
hintStyle: const TextStyle(color: Color.fromARGB(255, 158, 156, 156), fontSize: 20),
),
),
),
const SizedBox(
height: 50,
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState!.validate() == true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 6),
child: TextFormField(
controller: phoneController,
textInputAction: TextInputAction.next,
cursorColor: Colors.blue,
keyboardType: TextInputType.number,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (value!.length != 10 && value.isNotEmpty) {
return 'phone number must contain 10 numbers';
}
},
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.blue, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(color: Color.fromARGB(254, 57, 40, 71)),
),
label: Row(children: const [
Text(
'Phone',
style: TextStyle(color: Color.fromARGB(254, 57, 40, 71), fontSize: 20),
),
]),
prefixIcon: const Icon(Icons.phone),
hintText: 'Your phone number',
hintStyle: const TextStyle(color: Color.fromARGB(255, 158, 156, 156), fontSize: 20),
),
),
),
Center(
child: MaterialButton(
minWidth: double.infinity,
height: 60,
color: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (_formKey.currentState!.validate() == true) {
signUp();
}
},
child: const Text(
'SIGN UP',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 20),
],
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Already have an account..? ",
style: TextStyle(fontSize: 16),
),
RichText(
text: TextSpan(
children: [
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () {
print('login');
},
text: 'Log In',
style: TextStyle(
decoration: TextDecoration.underline,
color: Theme.of(context).colorScheme.secondary,
fontSize: 17))
],
),
),
],
),
const SizedBox(
height: 100,
)
],
),
),
),
),
),
);
}
Future signUp() async {}
}
It will look something like this -