3

In flutter app, when an input field is wrapped inside Scrollable, Opacity, Stack, when keyboard appear, the scrollable view is not correctly placed.

How to make the scrollable view correctly when keyboard appear?

enter image description here

If input field is not wrapped inside Scrollable, the keyboard is not appear at all. It can be test by changing ListView with Column in the following code.

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class SecurePage extends StatelessWidget {
  final int index;

  SecurePage(this.index);

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Secure'),
      ),
      body: new Column(
        children: <Widget>[
          new Text('No $index'),
          new IconButton(
            icon: new Icon(Icons.verified_user),
            onPressed: () {
              Navigator.of(context).push(
                new MaterialPageRoute(
                  builder: (BuildContext context) {
                    return new VerifiedPage(index + 1);
                  },
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

class VerifiedPage extends StatelessWidget {
  final int index;

  VerifiedPage(this.index);

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Verity'),
      ),
      body: new ListView(
        children: <Widget>[
          new Text('No $index'),
          new Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: new TextField(
              autofocus: index % 2 == 1,
              decoration: const InputDecoration(
                hintText: 'Search',
              ),
            ),
          ),
          new IconButton(
            icon: new Icon(Icons.security),
            onPressed: () {
              Navigator.of(context).push(
                new MaterialPageRoute(
                  builder: (BuildContext context) {
                    return new SecurePage(index + 1);
                  },
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  int _page = 0;
  List<Widget> initialWidgets = <Widget>[
    new SecurePage(0),
    new VerifiedPage(0),
  ];

  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Stack(
        children: new List<Widget>.generate(initialWidgets.length, (int index) {
          return new IgnorePointer(
            ignoring: index != _page,
            child: new Opacity(
              opacity: _page == index ? 1.0 : 0.0,
              child: new Navigator(
                onGenerateRoute: (RouteSettings settings) {
                  return new MaterialPageRoute(
                    builder: (_) => initialWidgets[index],
                  );
                },
              ),
            ),
          );
        }),
      ),
      bottomNavigationBar: new BottomNavigationBar(
        currentIndex: _page,
        onTap: (int index) {
          setState(() {
            _page = index;
          });
        },
        items: <BottomNavigationBarItem>[
          new BottomNavigationBarItem(
            icon: new Icon(Icons.security),
            title: new Text('Secure'),
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.verified_user),
            title: new Text('Verified'),
          ),
        ],
      ),
    );
  }
}
Kyaw Tun
  • 10,164
  • 7
  • 44
  • 72

1 Answers1

2

The problem is that you're nesting a Scaffold inside a Scaffold and each scaffold is trying to add padding for the keyboard. You should only ever use one Scaffold at a time. Instead of having an inner Scaffold, consider using Column to position your AppBar at the top of the screen.

screenshot

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class SecurePage extends StatelessWidget {
  final int index;

  SecurePage(this.index);

  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new AppBar(
          title: new Text('Secure'),
        ),
        new Text('No $index'),
        new IconButton(
          icon: new Icon(Icons.verified_user),
          onPressed: () {
            Navigator.of(context).push(
              new MaterialPageRoute(
                builder: (BuildContext context) {
                  return new VerifiedPage(index + 1);
                },
              ),
            );
          },
        ),
      ],
    );
  }
}

class VerifiedPage extends StatelessWidget {
  final int index;

  VerifiedPage(this.index);

  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new AppBar(
          title: new Text('Verity'),
        ),
        new Text('No $index'),
        new Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          child: new TextField(
            autofocus: index % 2 == 1,
            decoration: const InputDecoration(
              hintText: 'Search',
            ),
          ),
        ),
        new IconButton(
          icon: new Icon(Icons.security),
          onPressed: () {
            Navigator.of(context).push(
              new MaterialPageRoute(
                builder: (BuildContext context) {
                  return new SecurePage(index + 1);
                },
              ),
            );
          },
        ),
      ],
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  int _page = 0;
  List<Widget> initialWidgets = <Widget>[
    new SecurePage(0),
    new VerifiedPage(0),
  ];

  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Stack(
        children: new List<Widget>.generate(initialWidgets.length, (int index) {
          return new IgnorePointer(
            ignoring: index != _page,
            child: new Opacity(
              opacity: _page == index ? 1.0 : 0.0,
              child: new Navigator(
                onGenerateRoute: (RouteSettings settings) {
                  return new MaterialPageRoute(
                    builder: (_) => initialWidgets[index],
                  );
                },
              ),
            ),
          );
        }),
      ),
      bottomNavigationBar: new BottomNavigationBar(
        currentIndex: _page,
        onTap: (int index) {
          setState(() {
            _page = index;
          });
        },
        items: <BottomNavigationBarItem>[
          new BottomNavigationBarItem(
            icon: new Icon(Icons.security),
            title: new Text('Secure'),
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.verified_user),
            title: new Text('Verified'),
          ),
        ],
      ),
    );
  }
}
Collin Jackson
  • 80,972
  • 26
  • 188
  • 132
  • Oh, Flutter never end of surprise me on layout. I though AppBar always require to be inside Scaldfold. It has other issue and file [a bug report](https://github.com/flutter/flutter/issues/12339) as I think it is. – Kyaw Tun Sep 30 '17 at 23:50
  • @KyawTun I do not think this is a bug, I am not sure why you are using this complex layout, but Verify is appearing on top of Secure and is invisible for touch events, to see what I mean try to set `ignoring: false` and add a `TextEditingController` to your `TextField` in Verify page, and set `onChanged` property to print the content of the controller, you will find that you are typing in the `TextField` of Verify when you are on Secure page, because it is placed on top of it. – Shady Aziza Oct 02 '17 at 02:55