Flutter ListView 搜索并点击

Flutter ListView search and click

所以我目前正在尝试为我的 ListView 实现一些搜索功能,这实际上效果很好。当我输入一些字母时,它会自动显示正确的内容(-> 请参阅 Screenshot_Listview_1.pngScreenshot_Listview_2.png)。

只有一个问题。我希望我的列表视图中的不同文本是可点击的,所以当我点击它们时,应该会出现一个新的 ModalBottomSheet。 例如:我正在搜索“Apple”,当我单击文本“Apple”时,会打开一个 ModalBottomSheet,我可以阅读一些关于苹果的信息。 我尝试了 onTap 方法,到目前为止它仍然有效,但我只能打开相同的 BottomSheet。但是我需要不同的 BottomSheet,具体取决于我点击的内容。

这就是我到目前为止所得到的。你能帮帮我吗?我真的不知道如何解决这个问题。非常感谢!!

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

您可以使用 GestureDetector 包装 Padding 并将操作添加到 onTap 方法中。

return GestureDetector(
  onTap: () {
    // TODO: Add actions onTap
  },
  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: 24, fontFamily: 'Avenir'),
        ),
  );
);

你需要给你的 _testFuction 一些内容取决于你点击让 bottomsheet 知道它应该 show.Just 喜欢什么:

return GestureDetector(
  onTap:(){
    _testFuction(context,glossarListOnSearch[index]);
  }
  ...
) 

void _testFuction(context, someContent) {
  showModalBottomSheet(
    context: context,
    builder: (BuildContext bc) {
      return Scaffold(
        body: Text('This is $someContent bottomsheet'),
      );
    },
  );
}
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}'),
      );
    },
  );
}