Rutvik Gumasana
Rutvik Gumasana

Reputation: 1620

how to remove widget based on it's index in flutter

I've question about how to close the appropriate widget based on the close button index. here in this image, you can see the output so here I am adding some widget using add button which located inside app bar now i've added close button inside the container when the user pressed the close button it will remove that container.

Here is the image of output :

enter image description here

Here is the code i've tried

class BspUnlicensedSignupPage extends StatefulWidget {
  static const String routeName = "/bspUnlicensedSignup";
  final BspSignupCommonModel bspSignupCommonModel;

  BspUnlicensedSignupPage({
    Key key,
    @required this.bspSignupCommonModel,
  }) : super(key: key);

  @override
  _BspUnlicensedSignupPageState createState() =>
      _BspUnlicensedSignupPageState();
}

class _BspUnlicensedSignupPageState extends State<BspUnlicensedSignupPage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  List<Object> images = List<Object>();
  Future<File> _imageFile;
  bool autovalidate = false;
  bool informationislegitimate = false;
  DateTime expirydate1 = DateTime.now();
  DateTime expirydate2 = DateTime.now();

  final format = DateFormat("yyyy-MM-dd");
  final format2 = DateFormat("yyyy-MM-dd");

  String type2 = 'Passport';
  List<String> _type = <String>[
    '',
    'Passport',
    'Driving License',
    'Voter ID card',
    'Ration Card',
    'Aadhar',
    'Other Id',
  ];
  String type = 'Passport';
  var _myWidgets = List<Widget>();
  int _index = 3;
  final Map<int, String> identification1Values = Map();
  final Map<int, String> documentValues = Map();
  final Map<int, DateTime> expiryDateValues = Map();
  final Map<int, String> issuingAuthority = Map();
  final Map<int, String> identificationPicturesValues = Map();

  final List<TextEditingController> _documentControllers = List();
  final List<TextEditingController> _issuingauthoritytype = List();
  final List<TextEditingController> _expiryDate = List();
  final List<TextEditingController> _issuingauthority = List();
  final List<List<Object>> _identificationpictures = List();

  @override
  void initState() {
    super.initState();
    setState(() {
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
    });
  }

  void _add() {
    int keyValue = _index;
    _myWidgets = List.from(_myWidgets)
      ..add(Column(
        key: Key("$keyValue"),
        children: <Widget>[
          SizedBox(height: 10),
          Container(
            // padding: EdgeInsets.fromLTRB(18,5,18,18),
            padding: EdgeInsets.all(15),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(10),
              boxShadow: [
                BoxShadow(
                  color: Colors.black12,
                  blurRadius: 15,
                ),
              ],
            ),
            child: Column(
              children: <Widget>[
                Stack(
                  children: <Widget>[
                    Align(
                      alignment: Alignment.topRight,
                      child: GestureDetector(
                        child: Icon(Icons.close),
                        onTap: () {
                          print("CLose pressed");
                          _myWidgets.removeAt(_index);
                        },
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    Column(
                      children: <Widget>[
                        SizedBox(
                          height: 20,
                        ),
                        _buildidentificationtype1(keyValue),
                        _builddocumentnumber1(keyValue),
                        _builddate(keyValue),
                        _buildissuingauthority1(keyValue),
                        _buildidentificationpictures(keyValue),
                      ],
                    ),
                  ],
                )
              ],
            ),
          )
        ],
      ));

    setState(() => ++_index);
  }

  bool isClicked = false;

  Widget _buildidentificationtype1(int keyValue) {
    TextEditingController controller = TextEditingController();
    _issuingauthoritytype.add(controller);

    return FormBuilder(
      autovalidate: autovalidate,
      child: FormBuilderCustomField(
          attribute: "Business type",
          validators: [FormBuilderValidators.required()],
          formField: FormField(
            builder: (FormFieldState<dynamic> field) {
              return InputDecorator(
                decoration: InputDecoration(
                  prefixIcon: Icon(Icons.location_on),
                  labelText: "Business type",
                  errorText: field.errorText,
                ),
                isEmpty: type == '',
                child: new DropdownButtonHideUnderline(
                  child: new DropdownButton(
                    value: type,
                    isDense: true,
                    onChanged: (String newValue) {
                      setState(() {
                        type = controller.text = newValue;
                        field.didChange(newValue);
                      });
                    },
                    items: _type.map(
                      (String value) {
                        return new DropdownMenuItem(
                          value: value,
                          child: new Text(value),
                        );
                      },
                    ).toList(),
                  ),
                ),
              );
            },
          )),
    );
  }

  Widget _builddocumentnumber1(int keyValue) {
    TextEditingController controller = TextEditingController();
    _documentControllers.add(controller);
    return new TudoTextWidget(
      controller: controller,
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: "Document Number",
      validator: Validators().validateLicenseno,
      onSaved: (val) {
        setState(() {
          documentValues[keyValue] = val;
        });
        // _licenseno = val;
      },
    );
  }

  Widget _builddate(int keyValue) {
    TextEditingController controller = TextEditingController();
    _expiryDate.add(controller);
    return DateTimeField(
      format: format,
      autocorrect: true,
      autovalidate: autovalidate,
      controller: controller,
      readOnly: true,
      decoration: InputDecoration(
          labelText: "Expiry Date",
          hintText: "Expiry Date",
          prefixIcon: Icon(
            FontAwesomeIcons.calendar,
            size: 24,
          )),
      onShowPicker: (context, currentValue) {
        return showDatePicker(
            context: context,
            firstDate: DateTime(1900),
            initialDate: currentValue ?? DateTime.now(),
            lastDate: DateTime.now());
      },
    );
  }

  Widget _buildissuingauthority1(int keyValue) {
    TextEditingController controller = TextEditingController();
    _issuingauthority.add(controller);
    return new TudoTextWidget(
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: "Issuing Authority",
      validator: (val) => Validators.validateName(val, "Issuing Authority"),
      onSaved: (val) {
        setState(() {
          issuingAuthority[keyValue] = val;
        });
      },
      controller: controller,
    );
  }

  Widget _buildidentificationpictures(int keyValue) {
    return GridView.count(
      physics: NeverScrollableScrollPhysics(),
      shrinkWrap: true,
      crossAxisCount: 5,
      childAspectRatio: 1,
      children: List.generate(images.length, (index) {
        if (images[index] is ImageUploadModel) {
          ImageUploadModel uploadModel = images[index];

          return Card(
            clipBehavior: Clip.antiAlias,
            child: Stack(
              children: <Widget>[
                Image.file(
                  uploadModel.imageFile,
                  width: 300,
                  height: 300,
                ),
                Positioned(
                  right: 5,
                  top: 5,
                  child: InkWell(
                    child: Icon(
                      Icons.remove_circle,
                      size: 20,
                      color: Colors.red,
                    ),
                    onTap: () {
                      setState(() {
                        images.replaceRange(index, index + 1, ['Add Image']);
                      });
                    },
                  ),
                ),
              ],
            ),
          );
        } else {
          return Card(
            child: IconButton(
              icon: Icon(Icons.add),
              onPressed: () {
                _onAddImageClick(index);
              },
            ),
          );
        }
      }),
    );
  }

  @override
  Widget build(BuildContext context) {
    final appBar = AppBar(
      title: Text("BSP Unlicensed Details"),
      leading: IconButton(
        icon: Icon(Icons.arrow_back_ios),
        onPressed: () {
          NavigationHelper.navigatetoBack(context);
        },
      ),
      actions: <Widget>[IconButton(icon: Icon(Icons.add), onPressed: _add)],
      centerTitle: true,
    );
    final bottomNavigationBar = Container(
      color: Colors.transparent,
      height: 56,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          new FlatButton.icon(
            icon: Icon(Icons.close),
            label: Text('Clear'),
            color: Colors.redAccent,
            textColor: Colors.black,
            padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(7),
            ),
            onPressed: () {},
          ),
          new FlatButton.icon(
              icon: Icon(FontAwesomeIcons.arrowCircleRight),
              label: Text('Next'),
              color: colorStyles["primary"],
              padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(7),
              ),
              onPressed: () async {
                setState(() {
                  autovalidate = !autovalidate;
                });
                if (_formKey.currentState.validate()) {
                  BspSignupCommonModel model = widget.bspSignupCommonModel;
                  for (var i = 0; i < _myWidgets.length; i++) {
                    String document = _documentControllers[i].text;
                    String issuingAuthorityType = _issuingauthoritytype[i].text;
                    String expiryDate = _expiryDate[i].text;
                    String issuingAuthority = _issuingauthority[i].text;
                    //  String picture = _identificationpictures[i].text;
                    print('Document: $document');
                    print('IssuingAuthorityType: $issuingAuthorityType');
                    print('ExpiryDate: $expiryDate');
                    print('IssuingAuthority: $issuingAuthority');
                    print('Picture: ${_identificationpictures.length}');
                    print(_myWidgets.length);
                    List<Licensed> listOfLicenses = new List<Licensed>();

                    Licensed licensed = new Licensed(
                        bspLicenseNumber: document,
                        bspAuthority: issuingAuthority,
                        bspExpiryDate: expiryDate,
                        bspIssuing: issuingAuthorityType);

                    licensed.bspLicenseNumber = _documentControllers[i].text;
                    licensed.bspExpiryDate = _expiryDate[i].text;
                    licensed.bspIssuing = _issuingauthoritytype[i].text;
                    licensed.bspAuthority = _issuingauthority[i].text;
                    listOfLicenses.add(licensed);
                    model.unlicensed = listOfLicenses;
                  }

                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => BspLicensedSignupTermsPage(
                              bspSignupCommonModel: model)));
                }
              }),
        ],
      ),
    );
    return new Scaffold(
      appBar: appBar,
      bottomNavigationBar: bottomNavigationBar,
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: Form(
            autovalidate: autovalidate,
            key: _formKey,
            child: Stack(
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Expanded(
                      child: SizedBox(
                        child: ListView(
                          padding: const EdgeInsets.all(18.0),
                          children: _myWidgets,
                        ),
                      ),
                    ),
                  ],
                )
              ],
            )),
      ),
    );
  }
}

Upvotes: 1

Views: 22341

Answers (4)

sr11
sr11

Reputation: 31

I know I'm late to the party but someone else may find this helpful.

I was faced with exactly the same problem. And I'm proud to say that after a good one hour, I found a solution!

To explain it simply:-

  1. Use a Map<String, Widget> instead of a List (as some have rightly suggested already)
  2. Use UniqueKey().toString() to generate a new key as you dynamically build a widget each time and add this <key, value> pair to the Map

Here's the code snippet

Map<String, MyCard> theCards = {
    '0': MyCard(
      isInitialCard: true,
    )
  };

  void removeMyCard(String cIndex) {
    setState(() {
      print(cIndex);
      substrateCards.remove(cIndex);
    });
  }

  void addMyCard() {
    setState(() {
      String id = UniqueKey().toString();
      theCards.putIfAbsent(
          id,
          () => MyCard(
                onClose: () {
                  removeMyCard(id);
                },
              ));
      print(id);
    });
  }

Then, in the ListView.builder, build from the Map, like so:-

ListView.builder(
                shrinkWrap: true,
                itemCount: theCards.length,
                itemBuilder: (BuildContext context, int index) {
                  String key = theCards.keys.elementAt(index);
                  return theCards[key];
                }),

It will work, whether you delete from the middle, end or wherever.

Upvotes: 0

Pablo Barrera
Pablo Barrera

Reputation: 10963

Edit: It seems that you will need to use a Map instead of a List because if you remove an item the indexes could change.

You could do something like this: int keyValue = ++_lastKey;where _lastKey would be a variable that you increment every time you add an item and it will work as unique identifier

Then instead of _myWidgets.removeAt(keyValue); call this _myWidgetsMap.remove(keyValue) inside a setState(), like this:

setState(() {
  _myWidgetsMap.remove(keyValue);
});

And you should call the code inside _add() inside a setState()


But I recommend you to build your widgets according to a list of information, instead of a list of widgets. This way when you change the information, the widgets would adapt correctly.

Upvotes: 3

Hairon Chaviano
Hairon Chaviano

Reputation: 443

class _MyHomePageState extends State<MyHomePage> {
  bool isClosed = false;

  void Closed() {
    setState(() {
      isClosed = true;
    });
    print("CLick");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: !isClosed?Center(
        child: Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.blueAccent,
          ),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              GestureDetector(
                child: Container(
                  child: Icon(Icons.close),
                ),
                onTap: (){
                  Closed();
                },
              ),
              Text(
                'Close Here by Tap',
              ),

            ],
          ),
        ),
      ):Container(), 
    );
  }
}

this code works for me

Upvotes: 2

Hairon Chaviano
Hairon Chaviano

Reputation: 443

Maybe you can try to draw or not draw the widget if the button is tapped or not, you can create a var in the code to handle the state of the widget and when you tap the close button change the value of the var, something like this:

bool isClosed = false;

!isClosed?MyWidget():Container()

and in the onTap() of the close button you need to include this:

setState(() {
      isClosed = true;
    });

I hope this help you

Upvotes: 2

Related Questions