Dn-a / flutter_tags

With flutter tags you can create selectable or input tags that automatically adapt to the screen width
https://pub.dartlang.org/packages/flutter_tags
MIT License
507 stars 127 forks source link

How to force rebuild of Tags when active state has changed? #28

Closed barees63 closed 5 years ago

barees63 commented 5 years ago

I have 3 Tags widgets on a page and the active state of the items in each widget is controlled by a _selectedTags list in the stateful parent widget state.

If I update this list using setState (via OnPressed) the only widget that updates is one that is pulling its content directly from _selectedTags (ie. the length of this list has changed which seems to force a rebuild), the other two widgets are not updating even though the value that controls "active" for the tag items has changed.

Is there anyway to force the other Tags widgets to rebuild to show the new active states?

Hope this makes sense!

Dn-a commented 5 years ago

@barees63 setState should work ... could you post your code?

barees63 commented 5 years ago

Here is a simple example, if you select an item from the second widget it gets added to the list of selected items, however if you remove an item from the first widget, selectedItems updates as expected but the "Active" state of the corresponding item in the second widget is not refreshed.. (this absolutely could be me not properly understanding the way stateful widgets work so I apologize in advance if that's the case!)

import 'package:flutter/material.dart';
import 'package:flutter_tags/tag.dart';

class DummyPage extends StatefulWidget {
  @override
  _DummyPageState createState() => _DummyPageState();
}

class _DummyPageState extends State<DummyPage> {
  final List<String> _allTags = ['Breakfast', 'Lunch', 'Dinner', 'Coffee'];
  final List<String> _selectedTags = ['Lunch'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        backgroundColor: Colors.white,
        body: Column(
          children: <Widget>[
            SizedBox(
              height: 30,
            ),
            Tags(
              itemCount: _selectedTags.length,
              itemBuilder: (index) => _buildTagItem(_selectedTags, index),
            ),
            SizedBox(
              height: 30,
            ),
            Tags(
              itemCount: _allTags.length,
              itemBuilder: (index) => _buildTagItem(_allTags, index),
            ),
          ],
        ));
  }

  ItemTags _buildTagItem(tags, index) {
    final item = tags[index];

    return ItemTags(
      key: Key(index.toString()),
      index: index,
      elevation: 0,
      border: Border.all(
        width: 0,
        color: Colors.white,
      ),
      title: item,
      active: _selectedTags.contains(item),
      textColor: Colors.grey,
      textActiveColor: Colors.white,
      customData: item,
      color: Colors.white,
      activeColor: Colors.purple,
      padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      textStyle: TextStyle(
        fontSize: 12,
      ),
      pressEnabled: true,
      onPressed: (_item) {
        setState(() {
          if (_item.active) {
            _selectedTags.add(_item.customData);
          } else {
            _selectedTags.remove(_item.customData);
          }
        });
      },
    );
  }
}
Dn-a commented 5 years ago

@barees63 I currently have no way to test the code. Anyway, try to comment on this //active: _selectedTags.contains(item)

barees63 commented 5 years ago

well the issue is we have a lot of tags that are separated into groups (individual Tags widgets) and we need to be able to "select" tags in any group and have them added into the _selectedTags array (works) plus have this state change update the active flag of any duplicate tags in other groups (doesn't work).

I guess I'll fork this lib for now and see if I can find a way to make it work for me.. thanks!

barees63 commented 5 years ago

FWIW this issue resolved for me when I moved selectedTags into global state. I think it was just my own confusion about how stateful widgets get rebuilt. Thanks for the great package!

Chris-CWZ commented 4 years ago

hey @barees63, may i know what you mean by moving selectedTags into global state? I'm currently facing an issue where i'm using the tags as filters for a search request, so when a person clicks on "reset filters" I need to change the 'active' attribute of each ItemTag to be false. However this does not seem doable no matter how I use setState(). Hoping you could enlighten me!

Chris-CWZ commented 4 years ago

also, i've tried using the key of the tags to get all of the items under the tag, and if they were 'active', try to change the 'active' to false. however, trying to set active to false throws me an error as it states that 'active can't be used as a setter because it is final'. Would appreciate any help on how else to change the 'active' attribute of each item manually, thanks! Below is my code to try to change the 'active' attribute of the items to false if they were already active.

resetTags() async { List<Item> selectedCountry = _tagCountryKey.currentState?.getAllItem;

if (selectedCountry != null) {
  selectedCountry.where((a) => a.active == true).forEach(
      (a) => a.active = false);
}`
NICKmop commented 1 year ago

if (selectedCountry != null) { selectedCountry.where((a) => a.active == true).forEach( (a) => a.active = false); }`

thk for your reply but i can 't this source code { a.active } active is a final variable

do you have any other plans?