flutter 基于http响应动态构建卡片

jbose2ul  于 2022-12-19  发布在  Flutter
关注(0)|答案(3)|浏览(178)

我想创建一个基于http响应卡时,一个按钮被点击,我想“搜索项目”和“搜索按钮”留在顶部,而卡列表仍然可以滚动,请帮助。
我尝试使用FutureBuilder小部件,但它在页面第一次加载时加载数据(没有按下按钮)。

class clientRecord {
  final String englishName;
  final String chineseName;

  const clientRecord({
    required this.englishName,
    required this.chineseName,
  });

  factory clientRecord.fromJson(Map<String, dynamic> json) {
    return clientRecord(
      englishName: json['Ename'] as String,
      chineseName: json['Cname'] as String,
    );
  }
}

class homePage extends StatefulWidget {
  @override
  _homePageState createState() => _homePageState();
}

class _homePageState extends State<homePage> {
  final _searchItemController = TextEditingController();

  List<clientRecord> parseJson(String responseBody) {
    final parsed =
        convert.jsonDecode(responseBody).cast<Map<String, dynamic>>();
    return parsed
        .map<clientRecord>((json) => clientRecord.fromJson(json))
        .toList();
  }

  Future<List<clientRecord>> fetchData(http.Client client, _searchItem) async {
    final response = await client
        .get(Uri.parse('test.php'));
    return parseJson(response.body);;
  }

  @override
  void dispose() {
    _searchItemController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Client List')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Padding(
              padding: const EdgeInsets.fromLTRB(0, 30, 0, 20),
              child: Text(
                adminPassword(),
                style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold,
                    color: Colors.orange[800]),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(12.0),
              child: TextField(
                decoration: InputDecoration(
                    border: OutlineInputBorder(), labelText: 'Search Item'),
                controller: _searchItemController,
              ),
            ),
            SizedBox(height: 20),
            Container(
              height: 45,
              width: 250,
              decoration: BoxDecoration(
                  color: Colors.teal, borderRadius: BorderRadius.circular(16)),
              child: TextButton(
                onPressed: () {
                  fetchData(http.Client(), _searchItemController.text);
                },
                child: Text(
                  'Search',
                  style: TextStyle(color: Colors.white, fontSize: 20),
                ),
              ),
            ),
            FutureBuilder<List<clientRecord>>(
              future: fetchData(http.Client(), _searchItemController.text),
              builder: (context, snapshot) {
                if (snapshot.hasError) {
                  return const Center(
                    child: Text('An error has occurred!'),
                  );
                } else if (snapshot.hasData) {
                  return buildBody(dl: snapshot.data!);
                } else {
                  return const Center(
                    child: CircularProgressIndicator(),
                  );
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

class buildBody extends StatelessWidget {
  buildBody({super.key, required this.dl});

  final List<clientRecord> dl;

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        scrollDirection: Axis.vertical,
        controller: _scrollController,
        child: Column(
          children:
          dl.map((dataRecord) => dataCard(dataRecord, context)).toList(),
        ));
  }
}
Widget dataCard(dataRecord, c) {
  return GestureDetector(
    onTap: () {
      // Navigator.push(
      //   c,
      //   MaterialPageRoute(builder: (c) => newdevelopmentdetail(dataRecord.id)),
      // );
    },
    child: Card(
      color: Colors.lightGreen[100],
      child: SizedBox(
        height: 100,
        child: Row(
          children: [
            Text(dataRecord.englishName),
          ],
        ),
      ),
    ),
  );
}
q7solyqu

q7solyqu1#

你有两个不同的问题--关于未来建筑师的使用;并保持搜索项和搜索按钮在顶部。我将尝试回答第一个问题。
你的未来构建器会因为你告诉它:你在FutureBuilder中称之为:

FutureBuilder<List<clientRecord>>(
              future: fetchData(http.Client(), _searchItemController.text),

你可以做的是引入一个单独的Future变量,并根据它是否为空值来创建你的Future构建器。

Future<List<clientRecord>>? myFuture;

...

child: Column(
          children: [
...
  if (myFuture!=null) FutureBuilder<List<clientRecord>>(
              future: myFuture
 ...
else Text('Press button to get list')

您的按钮按下应该执行类似的操作(调用setState以触发重建):

TextButton(
                onPressed: () {
                  myFuture=fetchData(http.Client(), _searchItemController.text);
                  setState((){});
                },
rkue9o1l

rkue9o1l2#

您可以在Future中调用一个API,并像代码片段一样返回Column:

Column(
      children: List.generate(
      // Length of List received in a response
      5,
     (index) {
     // Return a Widget as per requirement
     return Text("data");
              },
            ),
          ),
fruv7luv

fruv7luv3#

通过添加单独的Future List并分配给FutureBuilder的future,http调用后的setState工作正常。
对于没有滚动搜索项的可滚动卡片,使用ListView Package 在Expanded Package 在Column中可以很好地工作。

相关问题