searchfield icon indicating copy to clipboard operation
searchfield copied to clipboard

OverlayEntry is null in a ListView

Open bebaoboy opened this issue 1 year ago • 3 comments

Describe the bug

Exception has occurred.
_AssertionError ('package:flutter/src/widgets/overlay.dart': Failed assertion: line 207 pos 12: '_overlay != null': is not true.)

To Reproduce

Demo video (app froze)

https://github.com/user-attachments/assets/37a495e3-d1c1-4113-8c59-a02a0c671bbd

Steps to reproduce the behavior in the demo video:

  1. Clone the main branch.
  2. Add more searchfields to the example file.
  3. Run the example app like the video below: search on the second field, then scroll back up (the second field is now out of sight), then tap on the first field.
  4. See error

image

Further investigation, it seems that the Overlay Entry was invalidated by the list view due to being scroll off-screen. image

[x] By clicking this checkbox, I confirm I am using the latest version of the package found on pub.dev/searchfield

Code sample

Show code sample Well nothing much, I just put two UserSelect() on the same page. Pretty sure they don't conflict when sharing the same sample data.

image

Raw code of example main.dart
import 'package:example/custom.dart';
import 'package:example/network_sample.dart';
import 'package:example/pagination.dart';
import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter App',
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: SearchFieldSample(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class SearchFieldSample extends StatefulWidget {
  const SearchFieldSample({Key? key}) : super(key: key);

  @override
  State<SearchFieldSample> createState() => _SearchFieldSampleState();
}

class _SearchFieldSampleState extends State<SearchFieldSample> {
  int suggestionsCount = 12;
  final focus = FocusNode();

  @override
  void initState() {
    suggestions = [
      'United States',
      'Germany',
      'Canada',
      'United Kingdom',
      'France',
      'Italy',
      'Spain',
      'Australia',
      'India',
      'China',
      'Japan',
      'Brazil',
      'South Africa',
      'Mexico',
      'Argentina',
      'Russia',
      'Indonesia',
      'Turkey',
      'Saudi Arabia',
      'Nigeria',
      'Egypt',
    ];
    super.initState();
  }

  final TextEditingController searchController = TextEditingController();
  var suggestions = <String>[];
  int counter = 0;
  @override
  Widget build(BuildContext context) {
    Widget searchChild(x) => Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12),
          child: Text(x, style: TextStyle(fontSize: 18, color: Colors.black)),
        );
    return Scaffold(
        appBar: AppBar(title: Text('Searchfield Demo')),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              suggestionsCount++;
              counter++;
              suggestions.add('suggestion $suggestionsCount');
            });
          },
          child: Icon(Icons.add),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListView(
            children: [
              UserSelect(),
              SizedBox(
                height: 550,
              ),
              TextFormField(
                  autovalidateMode: AutovalidateMode.onUserInteraction,
                  decoration: InputDecoration(
                    labelText: 'Flutter TextFormField',
                  ),
                  validator: (value) {
                    if (value == null || value.length < 4) {
                      return 'error';
                    }
                    return null;
                  }),
              SizedBox(
                height: 50,
              ),
              UserSelect(),
              SizedBox(
                height: 50,
              ),
              SearchField(
                hint: 'Basic SearchField',
                initialValue: SearchFieldListItem<String>('ABC'),
                suggestions: ['ABC', 'DEF', 'GHI', 'JKL']
                    .map(SearchFieldListItem<String>.new)
                    .toList(),
                suggestionState: Suggestion.expand,
              ),
              SizedBox(
                height: 50,
              ),
              Pagination(),
              SizedBox(
                height: 50,
              ),
              NetworkSample(),
              SizedBox(
                height: 50,
              ),
              SearchField(
                suggestionDirection: SuggestionDirection.flex,
                onSearchTextChanged: (query) {
                  final filter = suggestions
                      .where((element) =>
                          element.toLowerCase().contains(query.toLowerCase()))
                      .toList();
                  return filter
                      .map((e) =>
                          SearchFieldListItem<String>(e, child: searchChild(e)))
                      .toList();
                },
                initialValue: SearchFieldListItem<String>('United States'),
                controller: searchController,
                autovalidateMode: AutovalidateMode.onUserInteraction,
                validator: (value) {
                  if (value == null || !suggestions.contains(value.trim())) {
                    return 'Enter a valid country name';
                  }
                  return null;
                },
                onSubmit: (x) {},
                autofocus: false,
                key: const Key('searchfield'),
                hint: 'Search by country name',
                itemHeight: 50,
                onTapOutside: (x) {
                  // focus.unfocus();
                },
                scrollbarDecoration: ScrollbarDecoration(
                  thickness: 12,
                  radius: Radius.circular(6),
                  trackColor: Colors.grey,
                  trackBorderColor: Colors.red,
                  thumbColor: Colors.orange,
                ),
                suggestionStyle:
                    const TextStyle(fontSize: 18, color: Colors.black),
                searchStyle: TextStyle(fontSize: 18, color: Colors.black),
                suggestionItemDecoration: BoxDecoration(
                  // color: Colors.grey[100],
                  // borderRadius: BorderRadius.circular(10),
                  border: Border(
                    bottom: BorderSide(
                      color: Colors.grey.shade200,
                      width: 1,
                    ),
                  ),
                ),
                searchInputDecoration: InputDecoration(
                  hintStyle: TextStyle(fontSize: 18, color: Colors.grey),
                  focusedBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(24),
                    borderSide: const BorderSide(
                      width: 1,
                      color: Colors.orange,
                      style: BorderStyle.solid,
                    ),
                  ),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(24),
                    borderSide: const BorderSide(
                      width: 1,
                      color: Colors.black,
                      style: BorderStyle.solid,
                    ),
                  ),
                  contentPadding: const EdgeInsets.symmetric(
                    horizontal: 20,
                  ),
                ),
                suggestionsDecoration: SuggestionDecoration(
                    // border: Border.all(color: Colors.orange),
                    elevation: 8.0,
                    selectionColor: Colors.grey.shade100,
                    hoverColor: Colors.purple.shade100,
                    gradient: LinearGradient(
                      colors: [
                        Color(0xfffc466b),
                        Color.fromARGB(255, 103, 128, 255)
                      ],
                      stops: [0.25, 0.75],
                      begin: Alignment.topLeft,
                      end: Alignment.bottomRight,
                    ),
                    borderRadius: BorderRadius.only(
                      bottomLeft: Radius.circular(10),
                      bottomRight: Radius.circular(10),
                    )),
                suggestions: suggestions
                    .map((e) =>
                        SearchFieldListItem<String>(e, child: searchChild(e)))
                    .toList(),
                focusNode: focus,
                suggestionState: Suggestion.expand,
                onSuggestionTap: (SearchFieldListItem<String> x) {},
              ),
              SizedBox(
                height: 50,
              ),
              SearchField(
                enabled: false,
                hint: 'Disabled SearchField',
                suggestions: ['ABC', 'DEF', 'GHI', 'JKL']
                    .map(SearchFieldListItem<String>.new)
                    .toList(),
                suggestionState: Suggestion.expand,
              ),
              SizedBox(
                height: 50,
              ),
              NetworkSample(),
              Text(
                'Counter: $counter',
                style: Theme.of(context).textTheme.bodyLarge,
              ),
            ],
          ),
        ));
  }
}

bebaoboy avatar Jul 15 '24 05:07 bebaoboy