Flutter 将内容包含到页面中

问题描述

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

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

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

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

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

(我是新手,所以如果可能的话,请解释你的回答:)) 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,index) {
          return Card(
              child: ListTile(
                  title: Text("ppp"),subtitle: Text("ppp"),leading: CircleAvatar(
                      backgroundImage: NetworkImage(
                          "https://images.unsplash.com/photo-1547721064-da6cfb341d50"))
                  ));
        });
  }

enter image description here

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

解决方法

很明显,您希望小部件重建以显示结果。最直接的方法是使用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());
        }
      }
    );
  }
}

enter image description here

,

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

如果您创建一个新的 Widget,Flutter 不仅会显示 Widget,您还必须告诉它进行渲染。想象一下,你正在准备 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 构建器来显示选定的结果。

int
,

如果您想显示所选项目的列表,则必须在小部件树中添加一个 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,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,