简体   繁体   English

Flutter ListTile 条件和时间小部件渲染

[英]Flutter ListTile conditional and temporal widget rendering

I have searched around for a while now but can't seem to find a solution to show a widget (in my case a CircularProgressIndicator ) temporarily, in the trailing of a ListTile .我已经搜索了一段时间,但似乎找不到在ListTile的尾随中临时显示小部件(在我的情况下为CircularProgressIndicator )的解决方案。

I have this “page”:我有这个“页面”:

import 'dart:convert';
import 'dart:io';

import 'package:excelerate/model/user_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import '../../app_config.dart';
import '../../model/skill_model.dart';
import '../../providers/app_colors.dart';
import '../../providers/skill_order.dart';
import '../../providers/user_secure_storage.dart';
import '../../providers/utils.dart';
import '../../widgets/excelerate_bottom_bar.dart';

class EditStudentSkills extends StatefulWidget {
  final UserModel student;

  const EditStudentSkills({Key? key, required this.student})
      : super(key: key);

  @override
  State<EditStudentSkills> createState() =>
      _EditStudentSkillsState();
}

class _EditStudentSkillsState extends State<EditStudentSkills> {
  late Future<List<SkillModel>> skills;

  @override
  void initState() {
    super.initState();
    skills = fetchSkills();
  }

  @override
  EditStudentSkills get widget => super.widget;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        backgroundColor: ColorConsts.excelerateBlue,
        title: Text(
          'Rijvaardigheden ${widget.student.firstName}',
          textAlign: TextAlign.start,
        ),
      ),
      body: SafeArea(
        child: FutureBuilder<List<SkillModel>>(
          future: skills,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              List<SkillModel> skillList =
                  snapshot.data as List<SkillModel>;
              return ListView.separated(
                itemCount: skillList.length,
                scrollDirection: Axis.vertical,
                itemBuilder: (BuildContext context, int index) {
                  var skill = skillList[index];
                  return ListTile(
                    contentPadding: const EdgeInsets.only(left: 20, right: 20),
                    leading: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text('${skill.number}.', textAlign: TextAlign.center),
                      ],
                    ),
                    title: Text(skill.name),
                    trailing: CupertinoSwitch(
                      value: skill.completed,
                      onChanged: (value) async {
                        setState(() {
                          skill.completed = value;
                        });

                        updateSkill(skill.number, value);

                        setState(() {});
                      },
                    ),
                  );
                },
                separatorBuilder: (BuildContext context, int index) {
                  return const Divider();
                },
              );
            } else if (snapshot.hasError) {
              return Text(snapshot.error.toString());
            }
            // By default, show a loading spinner.
            return const Center(child: CircularProgressIndicator());
          },
        ),
      ),
      bottomNavigationBar: ExcelerateBottomBar(
        currentIndex: 1,
        onTap: navigate,
      ),
    );
  }

  void navigate(int index) {
    Navigator.of(context).pushReplacement(MaterialPageRoute(
        builder: (context) => Utils.getInstructorScreen(index)));
  }

  Future<List<SkillModel>> fetchSkills() async {
    var bearer = await UserSecureStorage.getBearerToken();
    var headers = {
      'Accept': 'application/json',
      HttpHeaders.authorizationHeader: bearer.toString()
    };

    var infoUrl = Uri.parse(
        "${AppConfig.of(context).apiURL}/api/skill/all-with-status/${widget.student.uid}");
    var response = await http.get(infoUrl, headers: headers);

    var skillMap = await json.decode(response.body);
    var skillList = <SkillModel>[];

    for (int i = 0; i < skillMap.keys.length; i++) {
      var skillName = SkillOrder.order[i];
      skillList.add(SkillModel.fromMap(skillMap[skillName]));
    }

    return skillList;
  }

  void updateSkill(String skillNumber, bool value) async {
    var updateUrl = Uri.parse(
        "${AppConfig.of(context).apiURL}/api/driving-skill/update/${widget.student.uid}");

    var headers = {
      'Content-type': 'application/json',
      'Accept': 'application/json',
    };

    var requestBody =
        json.encode({"skillNumber": skillNumber, "value": value});

    await http.patch(updateUrl,
        headers: headers,
        body: requestBody,
        encoding: Encoding.getByName("utf8"));
  }
}

UserModel and SkillModel are 2 DTO's. UserModel 和 SkillModel 是 2 个 DTO。 SkillOrder is a simple enum that has the order of skills so that it doesn't matter in which order it's coming in. SkillOrder 是一个简单的枚举,它具有技能的顺序,因此它以什么顺序进入并不重要。

When a switch its value changes, an api call will be made to update that item its value in the backend.当 switch 的值发生变化时,将进行 api 调用以在后端更新该项目的值。 In the meantime (between when the switch' value is changed and when the app has received an HttpStatus 200 from the server), I want to show a CircularProgressIndicator next to the switch.同时(在更改开关值和应用程序从服务器接收到 HttpStatus 200 之间),我想在开关旁边显示一个CircularProgressIndicator

I want to go from:我想从:

Normal state, just a switch with a value正常状态,只是一个带值的开关

To:至:

CircularProgressIndicator next to switch that just changed value (hardcoded in picture) CircularProgressIndicator 旁边的开关刚刚更改的值(在图片中硬编码)

So you have to create a bool variable that changes when the value of Switch changes ,for example:因此,您必须创建一个 bool 变量,该变量会在 Switch 的值发生变化时发生变化,例如:

bool? isLoading; 

initState(){
isLoading = false;
setState((){});
}

in the onChanged(){} method of Switch:在 Switch 的 onChanged(){} 方法中:

onChanged(v)async{

v? isLoading = v:null;
setState((){});
await updateSkill(skill.number,value);
} 

in updateSkill function:在 updateSkill 函数中:

Future updateSkill()async{
final response = await http.get("some api");
isLoading = false;
setState((){});
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM