Search code examples
flutterif-statementlistviewonclicksearchbar

Flutter ListView search and click


So I'm currently trying to implement some searching functionality to my ListView and this does work great actually. When I type in some letters it automatically shows me the right things (-> See Screenshot_Listview_1.png and Screenshot_Listview_2.png).

There is only one problem. I want the different texts from my listview to be clickable, so when I click on them a new ModalBottomSheet should appear. For example: I'm searching for "Apple" and when I click on the text "Apple" a ModalBottomSheet opens and I can read some facts about apples. I tried the onTap method and it works so far but I only managed to open the same BottomSheet.. But I need different BottomSheets depending on what I have tapped on.

This is what I got so far. Can you please help me out? I really don't know how to solve this problem. Thank you so much!!

import 'package:flutter/material.dart';
import 'dart:ui' as ui;


class GlossarScreen extends StatefulWidget {
  @override
  _GlossarScreenState createState() => _GlossarScreenState();
}

class _GlossarScreenState extends State<GlossarScreen> {
  TextEditingController _textEditingController = TextEditingController();

  List<String> glossarListOnSearch = [];
  List<String> glossarList = [
    'Apple',
    'Orange',
    'Banana',
    'Grapefruit',
    'Mango',
    'Kiwi',
    'Grapes',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Glossar'),
        flexibleSpace: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
                colors: [Color(0xffFBD23E), Color(0xffF6BE03)],
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter),
          ),
        ),
        bottom: PreferredSize(
          preferredSize: Size(0, 60),
          child: Padding(
            padding: const EdgeInsets.fromLTRB(12, 0, 12, 10),
            child: Container(
              //height: 50,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                    colors: [Colors.white60, Colors.white70],
                    begin: Alignment.topCenter,
                    end: Alignment.bottomCenter),
                borderRadius: BorderRadius.circular(50),
              ),
              child: Padding(
                padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
                child: TextField(
                  textAlign: TextAlign.left,
                  onChanged: (value) {
                    setState(() {
                      glossarListOnSearch = glossarList
                          .where((element) => element
                              .toLowerCase()
                              .contains(value.toLowerCase()))
                          .toList();
                    });
                  },
                  controller: _textEditingController,
                  decoration: InputDecoration(
                      border: InputBorder.none,
                      errorBorder: InputBorder.none,
                      enabledBorder: InputBorder.none,
                      contentPadding: EdgeInsets.all(0),
                      hintText: 'Search'),
                ),
              ),
            ),
          ),
        ),
      ),
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
              colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
              begin: Alignment.topLeft,
              end: Alignment.bottomRight),
        ),
        child: _textEditingController.text.isNotEmpty &&
                glossarListOnSearch.isEmpty
            ? Column(
                children: [
                  Align(
                    alignment: Alignment.center,
                    child: Padding(
                      padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
                      child: Text(
                        'No results',
                        style: TextStyle(
                            fontFamily: 'Avenir',
                            fontSize: 22,
                            color: Color(0xff848484)),
                      ),
                    ),
                  )
                ],
              )
            : ListView.builder(
                itemCount: _textEditingController.text.isNotEmpty
                    ? glossarListOnSearch.length
                    : glossarList.length,
                itemBuilder: (context, index) {
                  return GestureDetector(
                    onTap: () {
                      _testFuction(context);
                    },
                    child: Padding(
                      padding: const EdgeInsets.fromLTRB(12, 15, 12, 15),
                      child: Text(
                        _textEditingController.text.isNotEmpty
                            ? glossarListOnSearch[index]
                            : glossarList[index],
                        style: TextStyle(
                            color: Colors.black,
                            fontSize: 20,
                            fontFamily: 'Avenir'),
                      ),
                    ),
                  );
                },
              ),
      ),
    );
  }
}

void _testFuction(context) {
  showModalBottomSheet(
    context: context,
    builder: (BuildContext bc) {
      return Scaffold(
        body: Text('This text should be dependent on what I have tapped on. If I tap on "Apple" a different ModalBottomSheep shall appear then when I press on "Banana".'),
      );
    },
  );
}

Screenshot_ListView_1

Screenshot_ListView_2


Solution

  • import 'package:flutter/material.dart';
    import 'dart:ui' as ui;
    
    import 'package:stack_demo/models/FruitModel.dart';
    
    class GlossarScreen extends StatefulWidget {
      @override
      _GlossarScreenState createState() => _GlossarScreenState();
    }
    
    class _GlossarScreenState extends State<GlossarScreen> {
      TextEditingController _textEditingController = TextEditingController();
    
      List<FruitModel> glossarListOnSearch = [];
      List<FruitModel> glossarList = [];
    
      @override
      void initState() {
        glossarList.add(FruitModel(id: 0, name: 'Apple', facts: 'Good for health'));
        glossarList.add(
            FruitModel(id: 1, name: 'Banana', facts: 'Banana is also for health'));
        glossarList.add(
            FruitModel(id: 2, name: 'Orange', facts: 'Orange good for health'));
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Glossar'),
            flexibleSpace: Container(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                    colors: [Color(0xffFBD23E), Color(0xffF6BE03)],
                    begin: Alignment.topCenter,
                    end: Alignment.bottomCenter),
              ),
            ),
            bottom: PreferredSize(
              preferredSize: Size(0, 60),
              child: Padding(
                padding: const EdgeInsets.fromLTRB(12, 0, 12, 10),
                child: Container(
                  //height: 50,
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                        colors: [Colors.white60, Colors.white70],
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter),
                    borderRadius: BorderRadius.circular(50),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
                    child: TextField(
                      textAlign: TextAlign.left,
                      onChanged: (value) {
                        setState(() {
                          glossarListOnSearch = glossarList
                              .where((element) => element.name!
                                  .toLowerCase()
                                  .contains(value.toLowerCase()))
                              .toList();
                        });
                      },
                      controller: _textEditingController,
                      decoration: InputDecoration(
                          border: InputBorder.none,
                          errorBorder: InputBorder.none,
                          enabledBorder: InputBorder.none,
                          contentPadding: EdgeInsets.all(0),
                          hintText: 'Search'),
                    ),
                  ),
                ),
              ),
            ),
          ),
          body: Container(
            decoration: BoxDecoration(
              gradient: LinearGradient(
                  colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight),
            ),
            child: _textEditingController.text.isNotEmpty &&
                    glossarListOnSearch.isEmpty
                ? Column(
                    children: [
                      Align(
                        alignment: Alignment.center,
                        child: Padding(
                          padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
                          child: Text(
                            'No results',
                            style: TextStyle(
                                fontFamily: 'Avenir',
                                fontSize: 22,
                                color: Color(0xff848484)),
                          ),
                        ),
                      )
                    ],
                  )
                : ListView.builder(
                    itemCount: _textEditingController.text.isNotEmpty
                        ? glossarListOnSearch.length
                        : glossarList.length,
                    itemBuilder: (context, index) {
                      return GestureDetector(
                        onTap: () {
                          _textEditingController.text.isNotEmpty
                              ? _testFuction(context, glossarListOnSearch[index])
                              : _testFuction(context, glossarList[index]);
                        },
                        child: Padding(
                          padding: const EdgeInsets.fromLTRB(12, 15, 12, 15),
                          child: Text(
                            _textEditingController.text.isNotEmpty
                                ? glossarListOnSearch[index].name!
                                : glossarList[index].name!,
                            style: TextStyle(
                                color: Colors.black,
                                fontSize: 20,
                                fontFamily: 'Avenir'),
                          ),
                        ),
                      );
                    },
                  ),
          ),
        );
      }
    }
    
    void _testFuction(context, FruitModel model) {
      showModalBottomSheet(
        context: context,
        builder: (BuildContext bc) {
          return Scaffold(
            body: Text('${model.facts}'),
          );
        },
      );
    }