Flutter keyboard issue when wrap under Stack > Opacity > Scrollable

2k Views Asked by At

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'),
          ),
        ],
      ),
    );
  }
}
1

There are 1 best solutions below

2
On

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'),
          ),
        ],
      ),
    );
  }
}