Flutter 将内容包含到页面中

Flutter include content into a page

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

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

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

我的最终目标是在获得 selected 值后,发出 http 请求,获取列表 return 并显示列表视图。

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

(我是 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

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

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

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

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

我建议您阅读这篇文章以 Navigation Basics

您可以使用 listView 生成器来显示选定的结果。

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

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

状态示例代码

  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

itemCount: 2,

itemCount: selectedPosts?.length ?? 0,

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

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

帖子页面:

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只是为了更好的阅读。你可以使用原来的方法来构建widget)

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());
        }
      }
    );
  }
}