Home > Net >  Flutter : Pass data from Search textfield to ListView builder on different file
Flutter : Pass data from Search textfield to ListView builder on different file

Time:04-12

I have Text field which searches for book ( Using google book api) and gets the result, I am trying to pass this result to a listview builder which will use Cards to display some data like title, author and so on, both of them are in different dart file. What is the best way to achieve that?

Here is the code,

Search.dart - For testing purposes I am using the cancel/clear button to get the search results. Eventually it will be onChanged. The function is named _getData()

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

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  final _searchController = TextEditingController();
  var _userModel;
  var volumeInfo;
  void _getData() async {
    _userModel = (await GoogleApiService().getBooks(_searchController.text))!;
    setState(() {
      volumeInfo = VolumeDetails.fromJson(_userModel);
      print(volumeInfo);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: const [
            Color.fromRGBO(110, 32, 233, 1),
            Color.fromRGBO(215, 110, 216, 1),
            Color.fromRGBO(248, 248, 250, 1)
          ],
              stops: [
            0.03,
            0.3,
            0.2
          ])),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 330,
                height: 45,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
                  child: TextField(
                    onChanged: ((value) => {}),
                    cursorHeight: 30,
                    cursorColor: Colors.black,
                    textAlign: TextAlign.start,
                    textAlignVertical: TextAlignVertical.bottom,
                    decoration: InputDecoration(
                        suffixIcon: IconButton(
                          icon: Icon(
                            Icons.cancel_rounded,
                            color: Color.fromRGBO(215, 110, 216, 1),
                          ),
                          onPressed: () {
                            _getData(); // Testing for now.
                            //_searchController.clear();
                          },
                        ),
                        filled: true,
                        fillColor: Colors.white,
                        hintText: 'Search for books',
                        hintStyle: TextStyle(color: Colors.grey),
                        border: OutlineInputBorder(
                            borderRadius:
                                const BorderRadius.all(Radius.circular(10)))),
                    controller: _searchController,
                  ),
                ),
              )
            ],
          ),
          Container(
              margin: EdgeInsets.fromLTRB(20, 10, 0, 10),
              child: Row(
                children: [
                  Text(
                    "10 Results for ",
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.white,
                    ),
                  ),
                  Text(
                    '"'   _searchController.text   '"',
                    style: TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                ],
              )),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: double.infinity,
                decoration: BoxDecoration(
                  color: const Color.fromRGBO(248, 248, 250, 1),
                  borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(20),
                    topRight: Radius.circular(20),
                  ),
                ),
                child: SearchList(), // This one has the ListView builder
              ),
            ],
          ),
        ],
      ),
    );
  }

List builder dart

import 'package:flutter/material.dart';

import 'detail_bottom_sheet.dart';

class SearchList extends StatefulWidget {
  @override
  State<SearchList> createState() => _SearchListState();

  SearchList({Key? key}) : super(key: key);
}

class _SearchListState extends State<SearchList> {
  @override
  Widget build(BuildContext context) {
    var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;
    return Container(
      height: 480,
      margin: EdgeInsets.fromLTRB(0, 15, 0, 0),
      child: ListView.builder(
          scrollDirection: Axis.vertical,
          itemCount: 5,
          itemBuilder: (context, index) {
            return Card(
                margin: EdgeInsets.fromLTRB(5, 0, 0, 0),
                color: const Color.fromRGBO(248, 248, 250, 1),
                shadowColor: Colors.transparent,
                child: ListTile(
                  contentPadding:
                      EdgeInsets.symmetric(horizontal: 15, vertical: 0),
                  visualDensity: VisualDensity(vertical: 0, horizontal: 0),
                  dense: false,
                  title: Text('Title Comes here',
                   
                    overflow: TextOverflow.ellipsis,
                    style: TextStyle(fontSize: 15),
                  ),
                  subtitle: Text( 'Author comes here',
                    
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(fontSize: 14)),
                  leading: ClipRRect(
                    borderRadius: BorderRadius.circular(5.0),
                    child: Image.network('image url',
                      // volumeInfo[index].imageLinks?.thumbnail as String,
                      width: 40,
                      fit: BoxFit.fill,
                    ),
                  ),
                  trailing: IconButton(
                    alignment: Alignment.centerRight,
                    onPressed: () {
                      //print("--");
                    },
                    icon: Icon(Icons.add_box_outlined,
                        color: Color.fromRGBO(110, 32, 233, 1)),
                    iconSize: 20,
                  ),
                  onTap: () {
                    showModalBottomSheet(
                        isScrollControlled: true,
                        constraints:
                            BoxConstraints.loose(Size(width, height * 0.85)),
                        context: context,
                        enableDrag: true,
                        backgroundColor: Colors.transparent,
                        builder: (BuildContext context) {
                          return DetailBottomSheet();
                        });
                  },
                  // isThreeLine: true,
                ));
          }),
    );
  }
}

CodePudding user response:

there are many ways to do this. The simplest is to pass data as a parameter

your SearchScreen widget

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

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  final _searchController = TextEditingController();
  var _userModel;
  var volumeInfo;
  bool _loading=false;
  void _getData() async {
    setState(() {
    _loading=true;
    });

    _userModel = (await GoogleApiService().getBooks(_searchController.text))!;
    setState(() {
      volumeInfo = VolumeDetails.fromJson(_userModel);

      // Here it will re-render the page and update the page with the new data
      //I added loading. A loading widget will appear on the screen while searching.
       _loading=false;
      print(volumeInfo);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: const [
            Color.fromRGBO(110, 32, 233, 1),
            Color.fromRGBO(215, 110, 216, 1),
            Color.fromRGBO(248, 248, 250, 1)
          ],
              stops: [
            0.03,
            0.3,
            0.2
          ])),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 330,
                height: 45,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
                  child: TextField(
                    onChanged: ((value) => {}),
                    cursorHeight: 30,
                    cursorColor: Colors.black,
                    textAlign: TextAlign.start,
                    textAlignVertical: TextAlignVertical.bottom,
                    decoration: InputDecoration(
                        suffixIcon: IconButton(
                          icon: Icon(
                            Icons.cancel_rounded,
                            color: Color.fromRGBO(215, 110, 216, 1),
                          ),
                          onPressed: () {
                            _getData(); // Testing for now.
                            //_searchController.clear();
                          },
                        ),
                        filled: true,
                        fillColor: Colors.white,
                        hintText: 'Search for books',
                        hintStyle: TextStyle(color: Colors.grey),
                        border: OutlineInputBorder(
                            borderRadius:
                                const BorderRadius.all(Radius.circular(10)))),
                    controller: _searchController,
                  ),
                ),
              )
            ],
          ),
          Container(
              margin: EdgeInsets.fromLTRB(20, 10, 0, 10),
              child: Row(
                children: [
                  Text(
                    "10 Results for ",
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.white,
                    ),
                  ),
                  Text(
                    '"'   _searchController.text   '"',
                    style: TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                ],
              )),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: double.infinity,
                decoration: BoxDecoration(
                  color: const Color.fromRGBO(248, 248, 250, 1),
                  borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(20),
                    topRight: Radius.circular(20),
                  ),
                ),
                child: _loading ? Center(child: CircularProgressIndicator.adaptive(),)  : SearchList(
                  data:volumeInfo
                ), // This one has the ListView builder
              ),
            ],
          ),
        ],
      ),
    );
  }

your SearchList widget

class SearchList extends StatefulWidget {
  final List<VolumeDetails> data;
  @override
  State<SearchList> createState() => _SearchListState();

  SearchList({Key? key,required this.data}) : super(key: key);
}

class _SearchListState extends State<SearchList> {

  @override
  Widget build(BuildContext context) {
  
    return Container(
      height: 480,
      margin: EdgeInsets.fromLTRB(0, 15, 0, 0),
      child: ListView.builder(
          scrollDirection: Axis.vertical,
          itemCount: widget.data.length,
          itemBuilder: (context, index) {
            return VolumeCard(
              volume:widget.data[index]
            );
          }),
    );
  }
}

your VolumeCard widget

class VolumeCard extends StatelessWidget {
  final VolumeDetails volume;
  const VolumeCard({ Key? key,required this.volume }) : super(key: key);

  @override
  Widget build(BuildContext context) {
      var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;
    return Card(
                margin: EdgeInsets.fromLTRB(5, 0, 0, 0),
                color: const Color.fromRGBO(248, 248, 250, 1),
                shadowColor: Colors.transparent,
                child: ListTile(
                  contentPadding:
                      EdgeInsets.symmetric(horizontal: 15, vertical: 0),
                  visualDensity: VisualDensity(vertical: 0, horizontal: 0),
                  dense: false,
                  title: Text(volume.title ?? "if the title is empty, write here default title",
                   
                    overflow: TextOverflow.ellipsis,
                    style: TextStyle(fontSize: 15),
                  ),
                  subtitle: Text( volume.author ?? "default authoe",
                    
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(fontSize: 14)),
                  leading: ClipRRect(
                    borderRadius: BorderRadius.circular(5.0),
                    child: Image.network(volume.image ?? " out no image url",
                      // volumeInfo[index].imageLinks?.thumbnail as String,
                      width: 40,
                      fit: BoxFit.fill,
                    ),
                  ),
                  trailing: IconButton(
                    alignment: Alignment.centerRight,
                    onPressed: () {
                      //print("--");
                    },
                    icon: Icon(Icons.add_box_outlined,
                        color: Color.fromRGBO(110, 32, 233, 1)),
                    iconSize: 20,
                  ),
                  onTap: () {
                    showModalBottomSheet(
                        isScrollControlled: true,
                        constraints:
                            BoxConstraints.loose(Size(width, height * 0.85)),
                        context: context,
                        enableDrag: true,
                        backgroundColor: Colors.transparent,
                        builder: (BuildContext context) {
                          return DetailBottomSheet(
                            
                          );
                        });
                  },
                  // isThreeLine: true,
                ));
  }
}
  • Related