【问题标题】:Flutter include content into a pageFlutter 将内容包含到页面中
【发布时间】:2021-08-08 00:31:15
【问题描述】:

我实际上有一个正在工作的搜索栏(自动完成)。

当我选择一个结果时,displaySnack() 正在工作,它显示一个snackBar,但我想显示 testList() 的内容。

我的目标是了解如何启动另一个小部件,以便能够一次又一次地在页面上添加新小部件。

我的最终目标是一旦我获得了选定的值,发出一个 http 请求,获取一个列表作为返回并显示一个列表视图。

函数已执行(我可以在调试器中看到它)但不显示任何内容..

(我是 Flutter 的新手,所以请尽可能解释您的回答 :)) onSuggestionSelected :是的,我知道它是无效的..

import 'package:drawer/src/share/snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import '../models/post_model.dart';
import '../services/http_service.dart';
// import 'package:http/http.dart' as http;


class PostsPage extends StatelessWidget {

  final String title;
  const PostsPage({Key? key, required this.title}) : super(key: key);
  
  static Future<List<Post>> filterList(String value) async {
    List<Post> list = await HttpService.fetchPosts();
    return list.where(
      (x) => x.title.toLowerCase().contains(value.toLowerCase())).toList();
  }  
  
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: SafeArea(
          child: Container(
            padding: EdgeInsets.all(16),
            child: TypeAheadField<Post?>(
              debounceDuration: Duration(milliseconds: 500),
              hideSuggestionsOnKeyboardHide: false,
              textFieldConfiguration: TextFieldConfiguration(
                decoration: InputDecoration(
                  prefixIcon: Icon(Icons.search),
                  border: OutlineInputBorder(),
                  hintText: 'Select the namespace...',
                ),
              ),
              suggestionsCallback: filterList,
              itemBuilder: (context, Post? suggestion) {
                final user = suggestion!;

                return ListTile(
                  title: Text(user.title),
                );
              },
              noItemsFoundBuilder: (context) => Container(
                height: 100,
                child: Center(
                  child: Text(
                    'No Namespace Found.',
                    style: TextStyle(fontSize: 24),
                  ),
                ),
              ),
              onSuggestionSelected: (Post? suggestion) {
                final user = suggestion!;
                
                displaySnack(context, '  Namespace: '+user.title);
                testList(context);  ################################ HERE
              },
            ),
          ),
        ),
      );
      
}


  Widget testList(BuildContext context) {
    return ListView.separated(
      separatorBuilder: (BuildContext context, int index) => const Divider(),
        itemCount: 2,
        itemBuilder: (context, index) {
          return Card(
              child: ListTile(
                  title: Text("ppp"),
                  subtitle: Text("ppp"),
                  leading: CircleAvatar(
                      backgroundImage: NetworkImage(
                          "https://images.unsplash.com/photo-1547721064-da6cfb341d50"))
                  ));
        });
  }

我需要那个:https://prnt.sc/136njev

【问题讨论】:

    标签: flutter dart widget


    【解决方案1】:

    很明显,您希望小部件重建以显示结果。最直接的方法是使用 StatefulWidget。所以我在你的情况下使用它(你也可以找到很多方法来管理状态List of state management approaches

    1. 将您的 PostsPage 更改为 StatefulWidget 并在用户被选中时重建
    2. 在您的 PostsPage 中添加 Column 并分为 2 部分:TypeAheadField 和 Result
    3. 结果部分可以使用FutureBuilder(可以在数据未准备好时显示加载指示器)

    帖子页面:

    class PostsPage extends StatefulWidget {
      final String title;
    
      const PostsPage({Key? key, required this.title}) : super(key: key);
    
      static Future<List<Post>> filterList(String value) async {
        // skip
      }
    
      @override
      _PostsPageState createState() => _PostsPageState();
    }
    
    class _PostsPageState extends State<PostsPage> {
      Post? user;
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: SafeArea(
            child: Column(
              children: [
                Container(
                  padding: EdgeInsets.all(16),
                  child: TypeAheadField<Post>(
                    // ... 
                    // skip
                    // ...
                    onSuggestionSelected: (Post? suggestion) {
                      setState(() {
                        user = suggestion!;
                        displaySnack(context, '  Namespace: '+user.title);
                      });
                    },
                  ),
                ),
                Expanded(child: MyResult(post: user)),
              ],
            ),
          ),
        );
      }
    }
    

    结果部分: (我把它做成了一个独立的 StatelessWidget 只是为了更好的阅读,你可以使用原来的方法来构建这个小部件)

    class MyResult extends StatelessWidget {
      const MyResult({
        required this.post,
        Key? key,
      }) : super(key: key);
    
      final Post? post;
    
      Future<List<OtherObject>> getOtherObjects(Post? post) async{
        if(post == null){
          return [];
        }else{
          return Future.delayed(Duration(seconds:3),()=>[OtherObject(title: '001'),OtherObject(title: '002'),OtherObject(title: '003')]);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder<List<OtherObject>>(
          future: getOtherObjects(post),
          builder: (context, snapshot) {
            if(snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
              final result = snapshot.data!;
    
              return ListView.separated(
                separatorBuilder: (BuildContext context,
                    int index) => const Divider(),
                itemCount: result.length,
                itemBuilder: (context, index) {
                  return Card(
                    child: ListTile(
                      title: Text(result[index].title),
                      subtitle: Text("ppp"),
                      leading: CircleAvatar(
                        backgroundImage: NetworkImage(
                            "https://images.unsplash.com/photo-1547721064-da6cfb341d50"),
                      ),
                    ),
                  );
                },
              );
            }else {
              return Center(child: CircularProgressIndicator());
            }
          }
        );
      }
    }
    

    【讨论】:

    • 非常感谢,这正是我所要求的,这对我学习有状态和无状态的用法有很大帮助!并感谢您将结果分离到一个新的小部件中。我会尽快给答案!
    【解决方案2】:

    所以你所做的基本上只是用你的 testList() 函数调用创建一个 ListView 并且什么都不做,但是你想做的是让那个小部件出现在屏幕上,对吗?

    如果你创建一个新的,Flutter 不只是显示 Widget,你必须告诉它渲染。想象一下,你正在准备 Widgets(例如 Widgets 中的 Widgets),Flutter 会在你还没完成的情况下立即将它渲染到屏幕上,那不会那么好。

    您需要将该 Widget 推送到 Flutter 为您提供的 Navigator 小部件上。

    onSuggestionSelected: (Post? suggestion) {
      final user = suggestion!;
                
      displaySnack(context, '  Namespace: '+user.title);
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => testList(context)),
      );
    }
    

    我建议你阅读这篇文章到Navigation Basics

    【讨论】:

    • 感谢您的回答,但不,我根本不想要这个,我知道如何创建路由并传递参数。但我想在搜索栏底部显示一个列表:prnt.sc/136njev
    【解决方案3】:

    您可以使用 listView builder 来显示选定的结果。

              onSuggestionSelected: (Post? suggestion) {
                final user = suggestion!;
                
                displaySnack(context, '  Namespace: '+user.title);
                //get results
                var results = fetchResult(suggestion);
                //return a listview of the results
                return ListView.builder(
                physics: const AlwaysScrollableScrollPhysics(),
                shrinkWrap: true,
                scrollDirection: Axis.vertical,
                itemCount: results.length,
                itemBuilder: (_context, index) {
                  Post post = results[index];
                  return Card(
                      elevation: 2,
                      child: InkWell(
                        child: Container(
                            padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(6.0),
                              border: Border.all(color: Colors.black),
                              ),
                          child: DefaultTextStyle(
                            style: TextStyle(
                                fontWeight: FontWeight.bold,
                                fontSize: 12,
                                color: Colors.white),
                            child: Row(children: [
                              Expanded(
                                flex: 2,
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Text(post.data),
                                  ],
                                  ),
                                ),
                            ]),
                          ),
                            ),
                        onTap: () {
                          //do something when user clicks on a result
                        },
                        ));
                }
              },
    

    【讨论】:

    • 无法返回,"onSuggestionSelected" 是无效的
    • 您需要更新显示结果建议的列表。使用 setState((){ 建议列表 = 结果列表; };
    • 不,我不想更新我的建议列表。请阅读我的帖子,我说了我需要什么,我也放了一个 gif 和一个图形。一旦我在搜索栏上选择了一个项目,我就会创建一个 httprequest(theSelectedElement),它返回类似 Future 的东西> 。我在搜索栏之后显示此列表,在同一页面上
    【解决方案4】:

    如果要显示选定项目的列表,则必须在小部件树中添加ListView。还要使用StatefullWidget 而不是StatelessWidget,因为每当您选择一个项目时,所选列表都会因此而改变状态。

    状态示例代码

      List<Post> selectedPosts;
      @override
      void initState() {
        super.initState();
        selectedPosts = [];
      }
    
    
      @override
      Widget build(BuildContext context) => Scaffold(
            appBar: AppBar(
              title: Text(title),
            ),
            body: SafeArea(
              child: Column(
                children: [
                  Container(
                    padding: EdgeInsets.all(16),
                    child: TypeAheadField<Post?>(
                      debounceDuration: Duration(milliseconds: 500),
                      hideSuggestionsOnKeyboardHide: false,
                      textFieldConfiguration: TextFieldConfiguration(
                        decoration: InputDecoration(
                          prefixIcon: Icon(Icons.search),
                          border: OutlineInputBorder(),
                          hintText: 'Select the namespace...',
                        ),
                      ),
                      suggestionsCallback: filterList,
                      itemBuilder: (context, Post? suggestion) {
                        final user = suggestion!;
    
                        return ListTile(
                          title: Text(user.title),
                        );
                      },
                      noItemsFoundBuilder: (context) => Container(
                        height: 100,
                        child: Center(
                          child: Text(
                            'No Namespace Found.',
                            style: TextStyle(fontSize: 24),
                          ),
                        ),
                      ),
                      onSuggestionSelected: (Post? suggestion) {
                        final user = suggestion!;
                        displaySnack(context, '  Namespace: '+user.title);
                      setState(()=>  selectedPosts.add(suggestion));
                   
                      },
                    ),
                  ),
                   testList(context),
                ],
              ),
            ),
          );
    

    并在testList 函数中更改项目计数

    itemCount: 2,
    

    itemCount: selectedPosts?.length ?? 0,
    

    【讨论】:

    • “我的最终目标是一旦我获得了选定的值,就发出一个 http 请求,获取一个列表作为返回并显示一个列表视图。”我录制了一些东西,我选择了一个值,它生成了一个返回列表的 http get,并且通过这个列表,我在搜索栏的底部显示了同一页面中的列表..
    • 您想在搜索栏下方显示哪个列表?选定的项目列表?还是所选项目中有一个列表?
    • 一旦我在搜索栏上选择了一个项目,我会创建一个 httprequest(theSelectedElement) 来返回类似 Future> 的内容。我在搜索栏之后显示此列表,在同一页面上
    猜你喜欢
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 2014-09-30
    • 2013-06-25
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    相关资源
    最近更新 更多