5

I have created a page in which there is search bar and then the listview builder which is building items of List coming from provider class. When I tap on search bar, the keyboard appears ,suddenly disappears and page refreshes. when page is refreshed, first it shows circularprogressIndicator and then regular ListView.builder. Kindly Help. Thank you in advance!

import 'package:carstraders/models/cars.dart';
import 'package:carstraders/providers/cars_provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class SearchPage extends StatefulWidget {
  static const routeName = 'search-page';

  const SearchPage({Key? key}) : super(key: key);

  @override
  _SearchPageState createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  var search = TextEditingController();
  var list = [];
  List<Cars> allItems = [];
  String query = '';

  bool isFirstTime = true;

  @override
  void initState() {
    allItems = Provider.of<CarsProvider>(context, listen: false).list;
    list = allItems;
    // TODO: implement initState
    super.initState();
  }

this is the function which searches the items and updates the list

  void searchItem(String val) {
    final searched = allItems.where((element) {
      final transmission = element.transmission.toLowerCase();
      final model = element.model.toLowerCase();
      final make = element.make.toLowerCase();
      final price = element.price.toString();
      final engine = element.engine.toString();
      final searchedVal = val.toLowerCase();
      if (model.contains(searchedVal) ||
          make.contains(searchedVal) ||
          price.contains(searchedVal) ||
          engine.contains(searchedVal) ||
          transmission.contains(searchedVal)) {
        return true;
      }
      return false;
    }).toList();
    setState(() {
      list = searched;
      query = val;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Search'),
      ),
      body: FutureBuilder(
        future: Provider.of<CarsProvider>(context,listen: false).fetchAndSet(),
        builder: (ctx, snap) => snap.connectionState == ConnectionState.waiting
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Column(children: [
                Row(
                  children: [
                    Expanded(
                      child: Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: TextField(
                          onChanged: searchItem,
                          // style: TextStyle(color: Colors.white),
                          controller: search,
                          key: const Key('search'),
                          keyboardType: TextInputType.emailAddress,
                          decoration: InputDecoration(
                            label: const Text('Search'),
                            suffixIcon: query.isEmpty
                                ? null
                                : GestureDetector(
                                    child: const Icon(Icons.close),
                                    onTap: () {
                                      setState(() {
                                        query = '';
                                        searchItem('');
                                        search.clear();
                                        FocusScope.of(context).unfocus();
                                      });
                                    },
                                  ),
                            prefixIcon: const Icon(Icons.search_sharp),
                            enabledBorder: const OutlineInputBorder(
                              borderSide: BorderSide(
                                color: Colors.grey,
                                width: 0.5,
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
                Expanded(
                  child: ListView.builder(
                    itemBuilder: (ctx, i) => buildItem(list[i], context),
                    itemCount: list.length,
                  ),
                )
              ]),
      ),
    );
  }
}

this widget builds the item of listview.builder

Widget buildItem(Cars item, BuildContext context) {
  return GestureDetector(
    onTap: () =>
        Navigator.of(context).pushNamed('search-item-detail', arguments: item),
    child: Card(
      elevation: 5,
      child: Row(
        // mainAxisAlignment: MainAxisAlignment.start,
        children: [
          SizedBox(
            width: MediaQuery.of(context).size.width * 0.43,
            child: Image.network(item.img),
          ),
          SizedBox(width: MediaQuery.of(context).size.width * 0.02),
          Column(
            children: [
              Text(
                item.year.toString() + ' ' + item.make + ' ' + item.model,
                style: const TextStyle(
                  color: Colors.blueAccent,
                ),
              ),
              SizedBox(
                  width: MediaQuery.of(context).size.width * 0.5,
                  child: const Divider(color: Colors.black)),
              Row(
                children: [
                  Text('${item.mileage} mi'),
                  Container(
                      margin: EdgeInsets.symmetric(
                          horizontal: MediaQuery.of(context).size.width * 0.03),
                      decoration: const BoxDecoration(
                          border: Border(left: BorderSide(color: Colors.grey))),
                      child: const Text('')),
                  Text('£${item.price}')
                ],
              ),
              SizedBox(
                  width: MediaQuery.of(context).size.width * 0.5,
                  child: const Divider(color: Colors.black)),
              Row(
                children: [
                  Text('   ' + item.plateNo),
                  Container(
                    margin: EdgeInsets.symmetric(
                        horizontal: MediaQuery.of(context).size.width * 0.03),
                    child: const Text(''),
                    decoration: const BoxDecoration(
                        border: Border(left: BorderSide(color: Colors.grey))),
                  ),
                  Text(item.transmission)
                ],
              )
            ],
          )
        ],
      ),
    ),
  );
}
Ken White
  • 123,280
  • 14
  • 225
  • 444
Student
  • 341
  • 1
  • 2
  • 12
  • As a side note, you should call super.initState(); at the beginning of initState. – Jahn E. Jan 12 '22 at 10:00
  • Why are you using a futurebuilder? You can simply use a column with your search widget + Expanded(ListView.builder). [Check this video](https://www.youtube.com/watch?v=oFZIwBudIj0)! – Jahn E. Jan 12 '22 at 10:05
  • FutureBuilder to show loading spinner while data is fetched from provider's list. If any improvement is required, please tell me. I will be very thankful to you. – Student Jan 12 '22 at 10:22
  • @FlutterBeginner What does `fetchAndSet` do exactly? Please post that code too. – Rohan Taneja Jan 15 '22 at 21:36
  • The problem is solved. I just removed the futurebuilder – Student Jan 16 '22 at 17:30

1 Answers1

1

future builder trigger on every build. so when you click on searchBox the keyboard changes screen size and Expanded rebuild futureBuilder.


Solution Easy way .

Replace below part of future Builder

Column
  row
  Expanded
    listView.Builder

with

ListView.builder(
   itemBuilder: (ctx, i) {
    if(i==0){
      return row  
    }
    return buildItem(list[i -1], context)

   },
   itemCount: list.length + 1,
),
 

I think your code can write better. if you use bloc pattern or Riverpod pattern(similar to provider and has same author) so please look at this links

Sajjad
  • 2,593
  • 16
  • 26