Flutter - 禁用一个按钮,而不是所有按钮

Posted

技术标签:

【中文标题】Flutter - 禁用一个按钮,而不是所有按钮【英文标题】:Flutter - Disable a button, not all buttons 【发布时间】:2022-01-06 08:28:28 【问题描述】:

我从 Firebase 获得一份清单。列表按预期加载,但是我有两个问题。

1 - 当列表中的一个项目中的按钮被禁用时,其他项目中的所有按钮也会被禁用。我不希望这种情况发生。我怎样才能通过这个?

2 - 我从 firebase RTDB 获得“positiveCount”和“negativeCount”。我想得到总数(positiveCount +negativeCount),然后计算“positiveCount”的百分比。 (示例:positiveCount = 2,negativeCount = 2,positiveCount 的百分比应为 50%)。问题是,如果只加载一个项目,它可以完美运行。如果加载了多个项目,我会收到错误消息。

例外:

Exception has occurred.
UnsupportedError (Unsupported operation: Infinity or NaN toInt)

我的代码:

import 'package:colour/colour.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:shared_preferences/shared_preferences.dart';

class VaccineCenterList extends StatefulWidget 
  const VaccineCenterList(key) : super(key: key);
  static const String idScreen = "VaccineCenterList";

  @override
  _VaccineCenterListState createState() => _VaccineCenterListState();


class _VaccineCenterListState extends State<VaccineCenterList> 
  final databaseReference = FirebaseDatabase.instance.reference();
  final firestoreInstance = FirebaseFirestore.instance;
  FirebaseAuth auth = FirebaseAuth.instance;
  List<Hospitals> driverList = [];

  late String isTrueOrFalse = "False";

  // // double percentageInt = 0.0;
  int totalVotes = 0;
  // int percentage = 0;

  int positiveCount = 0;
  int negativeCount = 0;

  bool buttonPressed = true;

  TextEditingController hospitalCountyEditingController =
      TextEditingController();

  Future<List<Hospitals>> getHospitalDetails() async 
    try 
      if ((hospitalCountyEditingController.text != "") &&
          (hospitalCountyEditingController.text != " ")) 
        databaseReference
            .child("Hospitals")
            .child(hospitalCountyEditingController.text)
            .onValue
            .listen(
          (event) 
            setState(
              () 
                var value = event.snapshot.value;
                driverList = Map.from(value)
                    .values
                    .map((e) => Hospitals.fromJson(Map.from(e)))
                    .toList();
              ,
            );
          ,
        );
       else 
     catch (e) 
      
    
    return driverList;
  

  calculatePositivePercentage(
      positiveCount, negativeCount) 
    // this method gets the number of "yes" and "no" votes. Then calculates the
    // percentage of people who voted "yes".

    // total = positiveCount + negativeCount;
    // percentage = (positiveCount * 100) ~/ total;

    totalVotes = positiveCount + negativeCount;
    int percentage = positiveCount * 100;
    double votePercentage = percentage / totalVotes;

    
    return votePercentage;
  

  @override
  void initState() 
    super.initState();
    print("I'm in the vaccine list search screen");
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(
        backgroundColor: Colors.grey[100],
        centerTitle: true,
        elevation: 0,
        iconTheme: const IconThemeData(
          color: Colors.black,
        ),
        title: Text(
          "Pamoja",
          style: GoogleFonts.lexendMega(
            fontWeight: FontWeight.bold,
            color: Colors.black,
            fontSize: 35,
          ),
        ),
      ),
      body: GestureDetector(
        onTap: () 
          FocusScope.of(context).requestFocus(FocusNode());
        ,
        child: SingleChildScrollView(
          child: Column(
            children: [
              Container(
                padding: const EdgeInsets.all(8.0),
                child: TextField(
                  controller: hospitalCountyEditingController,
                  keyboardType: TextInputType.text,
                  textCapitalization: TextCapitalization.words,
                  decoration: InputDecoration(
                    border: const OutlineInputBorder(
                      borderSide: BorderSide(
                        color: Colors.black,
                        style: BorderStyle.solid,
                        width: 1,
                      ),
                    ),
                    labelText: "Search County",
                    labelStyle: const TextStyle(
                      fontSize: 14.0,
                      color: Colors.blueGrey,
                    ),
                    hintStyle: GoogleFonts.lexendMega(
                      color: Colors.grey,
                      fontSize: 10,
                    ),
                  ),
                  style: GoogleFonts.lexendMega(
                    fontSize: 14,
                    color: Colors.black,
                  ),
                ),
              ),
              ElevatedButton(
                onPressed: () 
                  buttonPressed = false;
                  setState(() 
                    FocusScope.of(context).requestFocus(
                      FocusNode(),
                    );
                    driverList.clear();
                    if (hospitalCountyEditingController.text == "" ||
                        hospitalCountyEditingController.text == " ") 
                      isTrueOrFalse = "False";
                     else 
                      isTrueOrFalse = "True";
                    
                  );
                  getHospitalDetails();
                ,
                child: Text(
                  "Search",
                  style: GoogleFonts.lexendMega(
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
              SizedBox(
                height: MediaQuery.of(context).size.height,
                // color: Colors.black,
                child: Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: driverList.isEmpty
                      ? Center(
                          // child: CircularProgressIndicator(),
                          child: (isTrueOrFalse == "True")
                              ? const CircularProgressIndicator()
                              : Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text(
                                          "Search for one of the counties below",
                                          style: GoogleFonts.lexendMega()),
                                    ),
                                    Text(
                                      "Nairobi, Baringo, Busia, Bomet, Bungoma, Elgeyo Marakwet, Embu, Garissa, Homa Bay, Isiolo, Kajiado, Kakamega, Kericho, Kiambu, Kilifi, Kirinyaga, Kisii, Kisumu, Kitui, Kwale, Laikipia, Lamu, Machakos, Makueni, Mandera, Marsabit, Meru, Migori, Mombasa, Muranga, Nakuru, Nandi, Narok, Nyamira, Nyandarua, Nyeri, Samburu, Siaya County, Taita Taveta, Tana River County, Tharaka Nithi, Trans Nzoia, Turkana, Uasin Gishu, Vihiga, Wajir, West Pokot",
                                      textAlign: TextAlign.center,
                                      style: GoogleFonts.lexendMega(
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ],
                                ),
                        )
                      : ListView.builder(
                          itemCount: driverList.length,
                          itemBuilder: (context, int index) 
                            final Hospitals hospitals = driverList[index];
                            final String hospitalLocaiton = hospitals.location;
                            final String hospitalPhone = hospitals.phone;
                            // final int totalVotes = hospitals.totalVotes;
                            final String hospitalName = hospitals.name;
                            // final String county = hospitals.county;

                            positiveCount = hospitals.positiveCount;
                            negativeCount = hospitals.negativeCount;

                            // final int percentage = positiveCount * 100;
                            // final double percentageInt =
                            //     percentage / totalVotes;

                            // ignore: unused_local_variable
                            final double setpercentage =
                                calculatePositivePercentage(positiveCount, negativeCount);
                            **final percentageInt = setpercentage.toInt();**

                            return Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Card(
                                elevation: 0,
                                child: ExpansionTile(
                                  title: Text(
                                    hospitalName.toUpperCase(),
                                    style: GoogleFonts.lexendMega(),
                                    textAlign: TextAlign.center,
                                  ),
                                  children: [
                                    Column(
                                      children: [
                                        Container(
                                          child: (hospitalPhone.isNotEmpty)
                                              ? ElevatedButton(
                                                  onPressed: () 
                                                    Clipboard.setData(
                                                      ClipboardData(
                                                        text: hospitalPhone,
                                                      ),
                                                    );
                                                    ScaffoldMessenger.of(
                                                            context)
                                                        .showSnackBar(
                                                      const SnackBar(
                                                        backgroundColor:
                                                            Colors.green,
                                                        content: Text(
                                                          "Number Copied",
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                      ),
                                                    );
                                                  ,
                                                  child: Text(
                                                    hospitalPhone,
                                                    textAlign: TextAlign.center,
                                                    style:
                                                        GoogleFonts.lexendMega(
                                                            fontSize: 13),
                                                  ),
                                                  style:
                                                      ElevatedButton.styleFrom(
                                                    elevation: 0,
                                                  ),
                                                )
                                              : const Text(""),
                                        ),
                                        const SizedBox(
                                          height: 5,
                                        ),
                                        hospitalLocaiton.isNotEmpty
                                            ? Container(
                                                padding:
                                                    const EdgeInsets.all(8),
                                                decoration: BoxDecoration(
                                                  border: Border.all(
                                                    color: Colors.black,
                                                  ),
                                                  borderRadius:
                                                      BorderRadius.circular(10),
                                                ),
                                                child: Text(
                                                  hospitalLocaiton,
                                                  textAlign: TextAlign.center,
                                                  style: GoogleFonts.lexendMega(
                                                    fontSize: 12,
                                                  ),
                                                ),
                                              )
                                            : Text(
                                                hospitalLocaiton,
                                                textAlign: TextAlign.center,
                                                style: GoogleFonts.lexendMega(
                                                  fontSize: 12,
                                                ),
                                              ),
                                        const SizedBox(
                                          height: 10,
                                        ),
                                        Text(
                                          "$percentageInt% (percent) of voters say this hospital administer vaccines.",
                                          textAlign: TextAlign.center,
                                          style: GoogleFonts.lexendMega(
                                            fontWeight: FontWeight.bold,
                                            fontSize: 12,
                                            color: Colors.deepPurple[400],
                                          ),
                                        ),
                                        const SizedBox(
                                          height: 10,
                                        ),
                                        const Divider(
                                          // thickness: 1,
                                          indent: 20,
                                          endIndent: 20,
                                          color: Colors.black87,
                                        ),
                                        const SizedBox(
                                          height: 10,
                                        ),
                                        Text(
                                          "Does this Hospital administer Vaccines?\n(To help the public, please vote only if you know.)",
                                          textAlign: TextAlign.center,
                                          style: GoogleFonts.lexendMega(
                                            fontSize: 12,
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                        // Container(
                                        //   child: (positiveCount == 0)
                                        //       ? Text("Votes: $positiveCount")
                                        //       : Text("Votes: " +
                                        //           positiveCount.toString()),
                                        // ),
                                        Column(
                                          children: [
                                            Row(
                                              mainAxisAlignment:
                                                  MainAxisAlignment.spaceEvenly,
                                              children: [
                                                ElevatedButton(
                                                  onLongPress: buttonPressed
                                                      ? () 
                                                          buttonPressed = false;
                                                          ScaffoldMessenger.of(
                                                                  context)
                                                              .showSnackBar(
                                                            const SnackBar(
                                                              backgroundColor:
                                                                  Colors
                                                                      .purpleAccent,
                                                              content: Text(
                                                                "Vote Removed",
                                                                textAlign:
                                                                    TextAlign
                                                                        .center,
                                                              ),
                                                            ),
                                                          );
                                                          undoPositiveIncrement(
                                                              hospitalName);
                                                        
                                                      : null,
                                                  onPressed: buttonPressed ? () 
                                                    ScaffoldMessenger.of(
                                                            context)
                                                        .showSnackBar(
                                                      const SnackBar(
                                                        backgroundColor:
                                                            Colors.greenAccent,
                                                        content: Text(
                                                          "Voted Yes",
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                      ),
                                                    );
                                                    positiveIncrement(
                                                        hospitalName);
                                                   : null,
                                                  child: Text(
                                                    "Yes - $positiveCount",
                                                    style: GoogleFonts
                                                        .lexendMega(),
                                                  ),
                                                  style:
                                                      ElevatedButton.styleFrom(
                                                    primary: Colour("#87D68D"),
                                                  ),
                                                ),
                                                ElevatedButton(
                                                  onLongPress: buttonPressed ? () 
                                                    ScaffoldMessenger.of(
                                                            context)
                                                        .showSnackBar(
                                                      const SnackBar(
                                                        backgroundColor:
                                                            Colors.purpleAccent,
                                                        content: Text(
                                                          "Vote Removed",
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                      ),
                                                    );
                                                    undoNegativeIncrement(
                                                        hospitalName);
                                                   : null,
                                                  onPressed: buttonPressed ? () 
                                                    ScaffoldMessenger.of(
                                                            context)
                                                        .showSnackBar(
                                                      const SnackBar(
                                                        backgroundColor:
                                                            Colors.redAccent,
                                                        content: Text(
                                                          "Voted",
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                      ),
                                                    );
                                                    negativeIncrement(
                                                        hospitalName);
                                                   : null,
                                                  child: Text(
                                                    "No - $negativeCount",
                                                    style: GoogleFonts
                                                        .lexendMega(),
                                                  ),
                                                  style:
                                                      ElevatedButton.styleFrom(
                                                    primary: Colour("#E3655B"),
                                                  ),
                                                ),
                                              ],
                                            ),
                                            const SizedBox(
                                              height: 10,
                                            ),
                                            Text(
                                              "Total No. of Votes: ",
                                              style: GoogleFonts.lexendMega(
                                                  fontSize: 12),
                                            ),
                                            const SizedBox(
                                              height: 10,
                                            ),
                                            Text(
                                              "1 - To vote, tap once\n2 - To Undo vote, tap and hold",
                                              style: GoogleFonts.lexendMega(
                                                fontSize: 12,
                                              ),
                                              textAlign: TextAlign.start,
                                            ),
                                            const SizedBox(
                                              height: 10,
                                            ),
                                          ],
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            );
                          ,
                        ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  


class Hospitals 
  final String name;
  final String phone;
  final String location;
  // final String county;
  final int positiveCount;
  final int negativeCount;
  // final int intPercentage;
  // final int totalVotes;

  Hospitals(
    required this.name,
    required this.phone,
    required this.location,
    // required this.county,
    required this.positiveCount,
    required this.negativeCount,
    // required this.intPercentage,
    // required this.totalVotes,
  );

  static Hospitals fromJson(Map<String, dynamic> json) 
    return Hospitals(
      name: json['HospitalName'],
      phone: json['HospitalPhone'],
      // county: json['county'],
      location: json['HospitalAddres'],
      positiveCount: json['poitiveCount'],
      negativeCount: json['negativeCount'],
      // intPercentage: json['intPercentage'],
      // totalVotes: json['totalVotes']
    );
  

问题 2 的解决方案:

calculatePositivePercentage(positiveCount, negativeCount) 
    // this method gets the number of "yes" and "no" votes. Then calculates the
    // percentage of people who voted "yes".

    double votePercentage = 0;

    if (positiveCount == 0 && negativeCount == 0) 
      try 
        return votePercentage.toInt();
       catch (e) 
        print(e);
      
     else 
      try 
        totalVotes = positiveCount + negativeCount;
        int percentage = positiveCount * 100;
        votePercentage = percentage / totalVotes;
        return votePercentage.toInt();
       catch (e) 
        print(e);
      
    

  

【问题讨论】:

您能突出显示导致错误的行吗?谢谢 @HelsDying 抱歉,我找不到突出显示它的位置。 " 最终百分比Int = setpercentage.toInt(); " 问题 2,已解决。 【参考方案1】:

为了防止所有按钮被禁用而不是

bool buttonPressed = true;

使用

List<bool> buttonPressed = [true];

您的第二个错误是因为您可能没有从响应尝试中获得 int 值

int.parse();

String 解析为int

【讨论】:

已解决问题 2,您能否向我解释一下如何为问题 1 实施您的解决方案? 如果您知道按钮的数量,那么只需在布尔列表中添加相同数量的 [true,false],然后像 buttonPressed[0] 一样相应地传递它们,并更改相同索引的值 谢谢,这实际上很容易实现。 很高兴为您提供帮助,也请投票。谢谢:) 我赞成你的回答,但我需要 15+ 声望才能反映。

以上是关于Flutter - 禁用一个按钮,而不是所有按钮的主要内容,如果未能解决你的问题,请参考以下文章

如何在文本更改时启用/禁用绑定到 ICommand 的按钮,而不是失去 TextBox 的焦点

Flutter:在浮动操作按钮中使用 appBar 小部件而不是 appBar?

在 TextFormField Flutter 的值更改时禁用 AlertDialog 按钮

Flutter 导航,重新打开页面而不是再次推送

如何禁用 MS Project VBA 中的另存为按钮?

禁用表单按钮,直到所有字段都填写完 rails 5.1