Keyboard not showing properly when text field is placed in sliver

Viewed 1616

I'm trying to create searchbar using Cupertino widgets and slivers. Currently I have following structure:

CupertinoApp
  CupertinoTabScaffold
    CupertinoPageScaffold
      CustomScrollView
        SliverNavigationBar
        SliverPersistentHeader
          _SliverSearchBarDelegate
            CupertinoTextField

SliverPersistentHeader has delegate, which is implemented in the following way:

class _SliverSearchBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverSearchBarDelegate({
    @required this.child,
    this.minHeight = 56.0,
    this.maxHeight = 56.0,
  });

  final Widget child;
  final double minHeight;
  final double maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => maxHeight;

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_SliverSearchBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

And the screen widget looks like this:

class CategoriesScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: CustomScrollView(
        slivers: <Widget>[
          CupertinoSliverNavigationBar( /* ... */ ),
          SliverPersistentHeader(
            delegate: _SliverSearchBarDelegate(
              child: Container(
                /* ... */
                child: CupertinoTextField( /* ... */ ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

The problem is that when I focus in text field, it looks like keyboard is trying to show but then immediately hides. I was thinking that this behavior appears because of scrollview events, but adding ScrollController to CustomScrollView doesn't gave me any results (there was no scroll events while focusing text field).

I was also thinking that the problem appears only in simulator but on real device the behavior is same.

Here's the video demonstration of problem:

video demonstration

UPDATE: Thanks to Raja Jain I figured out that the problem is not in slivers or CategoriesScreen widget itself but in CupertinoTabScaffold in which this widget is wrapped. If I remove CupertinoTabScaffold and set CupertinoApp's home widget to CategoriesScreen widget directly, the problem goes away. Here's my main.dart here, hope it will help, butI don't know how because there's nothing special in it:

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      /* ... */
      // home: CategoriesScreen(),
      home: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          /* ... */
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.all, size: 20.0),
              title: Text('Items'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.categories, size: 20.0),
              title: Text('Categories'),
            )
          ],
        ),
        tabBuilder: (BuildContext tabBuilderContext, int index) {
          return CategoriesScreen();
        },
      ),
    );
  }
}

2 Answers

I copied your code and tried to run.Code is running fine with expected behaviour,Maybe you are rebuilding your widget somewhere while clicking on text field. I'm attaching the code which i tried and working fine.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: CupertinoPageScaffold(
        child: CustomScrollView(
          slivers: <Widget>[
            CupertinoSliverNavigationBar(
              largeTitle: Text("Demo"),
            ),
            SliverPersistentHeader(
              delegate: _SliverSearchBarDelegate(
                child: Container(
                  height: 20.0,
                  width: 20.0,
                  child: CupertinoTextField(/* ... */),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

class _SliverSearchBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverSearchBarDelegate({
    @required this.child,
    this.minHeight = 56.0,
    this.maxHeight = 56.0,
  });

  final Widget child;
  final double minHeight;
  final double maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => maxHeight;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_SliverSearchBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

I just had a similar problem and what solved my issue was to use CupertinoTabView in the CupertinoTabScaffold's tabBuilder, like this:

tabBuilder: (BuildContext tabBuilderContext, int index) {
      return CupertinoTabView(
          builder: (context) => CategoriesScreen(),
      );
    },
Related