Home > Mobile >  Fluter - how to add a TabBar in the body of scaffold
Fluter - how to add a TabBar in the body of scaffold

Time:06-21

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 -

  • Related