Home > other >  Flutter: singleChildScrollView into pageView with vertical scrollDirection
Flutter: singleChildScrollView into pageView with vertical scrollDirection

Time:02-15

I would like to use the SingleChildScrollView in a pageView with vertical scrolling, the problem is that scrolls conflict and the pageview stops scrolling and only SingleChildScrollView starts scrolling. I needed to move the registration form above the keyboard.

the blue square is to show what I would like to move with the SingleChildScrollView

this is my app

this is the main page:

    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: PageView(
        controller: loginScreenPageController,
        scrollDirection: Axis.vertical,
        children: [
          const RegisterPage(),
          Column(children: <Widget>[
            ClipRRect(
              child: Container(
                decoration: const BoxDecoration(
                  color: Colors.black,
                ),
                height: MediaQuery.of(context).size.height / 100 * screenHeight,
                width: MediaQuery.of(context).size.width,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text("NON HO UN ACCOUNT",
                        style: GoogleFonts.poppins(
                          color: Colors.white,
                          fontSize: 25,
                        )),
                    const Icon(
                      Icons.arrow_downward,
                      size: 100,
                      color: Colors.white,
                    ),
                    SizedBox(
                      height: downArrowAnimationSize,
                    ),
                  ],
                ),
              ),
            ),
            Expanded(
              child: Container(
                decoration: const BoxDecoration(
                  color: Color.fromARGB(255, 255, 133, 12),
                ),
                height: MediaQuery.of(context).size.height / 2,
                width: MediaQuery.of(context).size.width,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text("HO GIA' UN ACCOUNT",
                        style: GoogleFonts.poppins(
                          color: Colors.white,
                          fontSize: 25,
                        )),
                    const Icon(
                      Icons.arrow_upward,
                      size: 100,
                      color: Colors.white,
                    ),
                    SizedBox(
                      height: downArrowAnimationSize,
                    ),
                  ],
                ),
              ),
            ),
          ]),
          const LoginPage()
        ],
      ),
    );

and this is the form page

  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: SingleChildScrollView(
        child: Container(
          color: const Color.fromARGB(255, 255, 133, 12),
          child: Column(
            children: [
              SizedBox(height: MediaQuery.of(context).size.height / 100 * 10),
              Image(
                  image:
                      const AssetImage("lib/assets/logo_app_palestre_bianco.png"),
                  height: MediaQuery.of(context).size.height / 100 * 20),
              SizedBox(height: MediaQuery.of(context).size.height / 100 * 8),
              Padding(
                padding: EdgeInsets.only(
                    left: MediaQuery.of(context).size.width / 100 * 10,
                    right: MediaQuery.of(context).size.width / 100 * 10),
                child: TextFormField(
                  focusNode: emailFocusNode,
                  onFieldSubmitted: (_) => {passwordFocusNode.requestFocus()},
                  cursorColor: Colors.white,
                  style: GoogleFonts.poppins(color: Colors.white),
                  decoration: const InputDecoration(
                    labelText: "E-Mail",
                    labelStyle: TextStyle(color: Colors.white),
                    focusColor: Colors.white,
                    enabledBorder: UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.white)),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: Colors.white),
                    ),
                  ),
                ),
              ),
              SizedBox(height: MediaQuery.of(context).size.height / 100 * 3),
              Padding(
                padding: EdgeInsets.only(
                    left: MediaQuery.of(context).size.width / 100 * 10,
                    right: MediaQuery.of(context).size.width / 100 * 10),
                child: TextFormField(
                  style: GoogleFonts.poppins(color: Colors.white),
                  obscureText: _isObscure,
                  focusNode: passwordFocusNode,
                  cursorColor: Colors.white,
                  decoration: InputDecoration(
                    labelText: "Password",
                    suffixIcon: IconButton(
                        onPressed: () {
                          //Funzione anonime per alternare lo stato di visibilità e l'icona vicino alla textfromfield che rappresentà lo stato di visibilità
                          setState(() {
                            _isObscure = !_isObscure;
                          });
                        },
                        icon: Icon(
                          _isObscure ? Icons.visibility : Icons.visibility_off,
                          color: Colors.white,
                        )),
                    labelStyle: const TextStyle(color: Colors.white),
                    focusColor: Colors.white,
                    enabledBorder: const UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.white)),
                    focusedBorder: const UnderlineInputBorder(
                      borderSide: BorderSide(color: Colors.white),
                    ),
                  ),
                ),
              ),
              Padding(
                padding: EdgeInsets.only(
                    top: MediaQuery.of(context).size.height / 100 * 2,
                    right: MediaQuery.of(context).size.width / 100 * 10),
                child: Align(
                  alignment: AlignmentDirectional.centerEnd,
                  child: GestureDetector(
                    onTap: () {},
                    child: Text(
                      "Password Dimenticata?",
                      style:
                          GoogleFonts.poppins(color: Colors.white, fontSize: 10),
                    ),
                  ),
                ),
              ),
              SizedBox(
                height: MediaQuery.of(context).size.height / 100 * 3,
              ),
              SizedBox(
                width: MediaQuery.of(context).size.width / 100 * 80,
                child: ElevatedButton(
                    style: ElevatedButton.styleFrom(primary: Colors.white),
                    onPressed: () {
                      _showMyDialog();
                    },
                    child: Text(
                      "Accedi",
                      style: GoogleFonts.poppins(color: Colors.black),
                    )),
              ),
              SizedBox(
                height: MediaQuery.of(context).size.height / 100 * 5,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Flexible(
                    child: Padding(
                      padding: EdgeInsets.only(
                          left: MediaQuery.of(context).size.width / 100 * 10),
                      child: Container(
                        color: Colors.white,
                        width: MediaQuery.of(context).size.width / 100 * 15,
                        height: MediaQuery.of(context).size.height / 100 * 0.2,
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text("Oppure Collegati con",
                        style: GoogleFonts.poppins(color: Colors.white)),
                  ),
                  Flexible(
                    child: Padding(
                      padding: EdgeInsets.only(
                          right: MediaQuery.of(context).size.width / 100 * 10),
                      child: Container(
                        color: Colors.white,
                        width: MediaQuery.of(context).size.width / 100 * 15,
                        height: MediaQuery.of(context).size.height / 100 * 0.2,
                      ),
                    ),
                  ),
                ],
              ),
              SizedBox(
                width: MediaQuery.of(context).size.width / 100 * 80,
                child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                        primary: const Color.fromARGB(255, 66, 103, 178)),
                    //Funzione che sull'onPressed va a mostrate l'allert box di errore
                    onPressed: () => _showMyDialog(),
                    child: Text("Facebook",
                        style: GoogleFonts.poppins(color: Colors.white))),
              )
            ],
          ),
        ),
      ),
    );
  }

CodePudding user response:

to understand if the phone keyboard is open I used this variable that is updated in the build

  Widget build(BuildContext context) {
    bool isKeyboardShowing = MediaQuery.of(context).viewInsets.vertical > 0;

    return SafeArea(
      child: Scaffold(
        body: PageView(
          scrollDirection: Axis.vertical,
          children: [
            Text(isKeyboardShowing ? "si" : "no"),
            WillPopScope(
              onWillPop: () async => false,
              child: SingleChildScrollView(
                physics:
                    isKeyboardShowing ? null : NeverScrollableScrollPhysics(),
                child: Container(
                  color: const Color.fromARGB(255, 255, 133, 12),
                  child: Column(
                    children: [
                      SizedBox(
                          height:
                              MediaQuery.of(context).size.height / 100 * 10),
                      Image(
                          image: const AssetImage(
                              "lib/assets/logo_app_palestre_bianco.png"),
                          height:
                              MediaQuery.of(context).size.height / 100 * 20),
                      SizedBox(
                          height: MediaQuery.of(context).size.height / 100 * 8),
                      Padding(
                        padding: EdgeInsets.only(
                            left: MediaQuery.of(context).size.width / 100 * 10,
                            right:
                                MediaQuery.of(context).size.width / 100 * 10),
                        child: TextFormField(
                          cursorColor: Colors.white,
                          style: GoogleFonts.poppins(color: Colors.white),
                          decoration: const InputDecoration(
                            labelText: "E-Mail",
                            labelStyle: TextStyle(color: Colors.white),
                            focusColor: Colors.white,
                            enabledBorder: UnderlineInputBorder(
                                borderSide: BorderSide(color: Colors.white)),
                            focusedBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.white),
                            ),
                          ),
                        ),
                      ),
                      SizedBox(
                          height: MediaQuery.of(context).size.height / 100 * 3),
                      Padding(
                        padding: EdgeInsets.only(
                            left: MediaQuery.of(context).size.width / 100 * 10,
                            right:
                                MediaQuery.of(context).size.width / 100 * 10),
                        child: TextFormField(
                          style: GoogleFonts.poppins(color: Colors.white),
                          cursorColor: Colors.white,
                          decoration: InputDecoration(
                            labelText: "Password",
                            suffixIcon: IconButton(
                                onPressed: () {
                                  //Funzione anonime per alternare lo stato di visibilità e l'icona vicino alla textfromfield che rappresentà lo stato di visibilità
                                },
                                icon: Icon(
                                  Icons.visibility,
                                  color: Colors.white,
                                )),
                            labelStyle: const TextStyle(color: Colors.white),
                            focusColor: Colors.white,
                            enabledBorder: const UnderlineInputBorder(
                                borderSide: BorderSide(color: Colors.white)),
                            focusedBorder: const UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.white),
                            ),
                          ),
                        ),
                      ),
                      Padding(
                        padding: EdgeInsets.only(
                            top: MediaQuery.of(context).size.height / 100 * 2,
                            right:
                                MediaQuery.of(context).size.width / 100 * 10),
                        child: Align(
                          alignment: AlignmentDirectional.centerEnd,
                          child: GestureDetector(
                            onTap: () {},
                            child: Text(
                              "Password Dimenticata?",
                              style: GoogleFonts.poppins(
                                  color: Colors.white, fontSize: 10),
                            ),
                          ),
                        ),
                      ),
                      SizedBox(
                        height: MediaQuery.of(context).size.height / 100 * 3,
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width / 100 * 80,
                        child: ElevatedButton(
                            style:
                                ElevatedButton.styleFrom(primary: Colors.white),
                            onPressed: () {},
                            child: Text(
                              "Accedi",
                              style: GoogleFonts.poppins(color: Colors.black),
                            )),
                      ),
                      SizedBox(
                        height: MediaQuery.of(context).size.height / 100 * 5,
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Flexible(
                            child: Padding(
                              padding: EdgeInsets.only(
                                  left: MediaQuery.of(context).size.width /
                                      100 *
                                      10),
                              child: Container(
                                color: Colors.white,
                                width: MediaQuery.of(context).size.width /
                                    100 *
                                    15,
                                height: MediaQuery.of(context).size.height /
                                    100 *
                                    0.2,
                              ),
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text("Oppure Collegati con",
                                style:
                                    GoogleFonts.poppins(color: Colors.white)),
                          ),
                          Flexible(
                            child: Padding(
                              padding: EdgeInsets.only(
                                  right: MediaQuery.of(context).size.width /
                                      100 *
                                      10),
                              child: Container(
                                color: Colors.white,
                                width: MediaQuery.of(context).size.width /
                                    100 *
                                    15,
                                height: MediaQuery.of(context).size.height /
                                    100 *
                                    0.2,
                              ),
                            ),
                          ),
                        ],
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width / 100 * 80,
                        child: ElevatedButton(
                            onPressed: () {},
                            style: ElevatedButton.styleFrom(
                                primary:
                                    const Color.fromARGB(255, 66, 103, 178)),
                            //Funzione che sull'onPressed va a mostrate l'allert box di errore

                            child: Text("Facebook",
                                style:
                                    GoogleFonts.poppins(color: Colors.white))),
                      )
                    ],
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );

The safe area is important for not calculate the space for the sistem ui like notch

CodePudding user response:

A solution would be to make the SingleChildScrollView only scrollable if the keyboard is open.

For that, check if bottom padding is larger than 0.

MediaQuery.of(context).viewInsets.bottom > 0

Now change the physics of the SingleChildScrollView depending on it.

SingleChildScrollView(
  physics:  MediaQuery.of(context).viewInsets.bottom > 0 ? null : NeverScrollableScrollPhysics(),
  child: ...
)

But that's a bad practice. ViewInset is not specific to keyboard. I'd suggest to use platform_channel to directly call native API that tells if the keyboard is visible or not.

Here is a package for that. flutter_keyboard_visibility

  • Related