web-dev-qa-db-fra.com

Flutter - Liste de sélection multiple

Dans mon application, j'ai une liste, sur laquelle j'ai mis en place la sélection de presse longue de ce poste de Raouf Rahiche . Lorsque la sélection est activée, j'ai un appbar différent, qui a un IconButton dessus, qui devrait désactiver la sélection. Mais je ne sais pas comment faire ça.

Jusqu'à présent, cela ne fonctionne pas comme il le devrait. Le comportement est affiché dans la vidéo ci-dessous. enter image description here

La sélection longue pression est un StatefulWidget:

class _SelectableItems extends State<SelectableItems> {
  bool isSelected = false;
  GoogleMaterialColors googleMaterialColors = new GoogleMaterialColors();

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
        onLongPress: () {
          setState(() {
            isSelected = !isSelected;
          });
          widget.callback();
        },
        onTap: () {
          setState(() {
            isSelected = !isSelected;
          });
          if (widget.longPressEnabled) {
            widget.callback();
          } else {
            Navigator.Push(
              context, 
              MaterialPageRoute(builder: (context)=>RecipeDetails(widget.name))
            );
          }
        },
        child: ListTile(
          leading: CircleAvatar(
            child: (isSelected
              ? Icon(
                Icons.check,
                color: Colors.white,
              )
              : (widget.image != "no image"
                ? Container(
                  width: 40.0,
                  height: 40.0,
                  decoration: new BoxDecoration(
                    image: new DecorationImage(
                      colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.2), BlendMode.darken),
                      image: AssetImage(widget.image),
                      fit: BoxFit.cover,
                    ),
                    borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
                  ),
                )
                : Text(
                  widget.name[0].toUpperCase(),
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 21.0,
                    fontWeight: FontWeight.w400
                  ),
                )
              )
            ),
            backgroundColor: (isSelected
              ? googleMaterialColors.primaryColor()
              : widget.color.withOpacity(1.00)
            )
          ),
          title: Padding(
            padding: EdgeInsets.only(top: 25.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                widget.title
              ],
            ),
          ),
        ),
      );
  }
}

J'appelle ce widget dans un SideHeaderListView comme ceci:

bool longPressFlag = false;
List<String> indexList = new List();
//other code

                return SideHeaderListView(                  
                    hasSameHeader: (int a, int b){
                      return snapshot.data[a].name[0] == snapshot.data[b].name[0];                  
                    },
                    itemCount: snapshot.data.length,
                    headerBuilder: (BuildContext context, int index){
                      return new Padding(
                        padding: EdgeInsets.only(top: 30.0, left: 20.0, right: 25.0),
                        child: Container(
                          width: 10.0,
                          child: Text(
                            snapshot.data[index].name[0].toUpperCase(),
                            style: TextStyle(
                              color: googleMaterialColors.primaryColor().withGreen(120),                        
                              fontFamily: "Google-Sans",
                              fontSize: 15.0,
                              fontWeight: FontWeight.w600
                            ),
                          ),
                        ),
                      );
                    },
                    itemExtend: 70.0,
                    itemBuilder: (BuildContext context, int index){

                      Color usedColor = convertColor.convertToColor(snapshot.data[index].backgroundColor);                    
                      String image = snapshot.data[index].image;


                      return SelectableItems(
                        color: usedColor,
                        name: snapshot.data[index].name,
                        title: (searchController.text.isEmpty
                          ? Text(snapshot.data[index].name)
                          : recipeName(searchCondition, snapshot.data[index].name)
                        ),
                        index: index,
                        image: image,
                        longPressEnabled: longPressFlag,
                        //isSelected: selectedFlag,
                        callback: () {
                          if (indexList.contains(snapshot.data[index].name)) {
                            indexList.remove(snapshot.data[index].name);
                          } else {
                            indexList.add(snapshot.data[index].name);
                          }
                          longPress();
                        },
                      );
                    },
                  );

void longPress() {
    setState(() {
      if (indexList.length == 0) {
        longPressFlag = false;
      } else {
        longPressFlag = true;
      }
    });
  }

J'espère que quelqu'un pourra résoudre mon problème. Merci d'avance.

9
user9047282

La première chose est que vous devez ajouter à chaque élément une clé dans le constructeur comme ceci:

MyItem({Key key}): super(key: key);

Pourquoi une clé? Une clé vous permet d'identifier correctement votre widget. Voir dans le doc:

Un nouveau widget ne sera utilisé pour mettre à jour un élément existant que si sa clé est la même que la clé du widget actuel associé à l'élément.

Créer une clé globale (une clé globale étend la clé) Pour chaque élément permettant d'accéder au widget, créez une clé globale. Du doc:

Une clé unique sur l'ensemble de l'application. Les clés globales identifient de manière unique les éléments. Les clés globales permettent d'accéder à d'autres objets associés à des éléments, tels que le [BuildContext] et, pour [StatefulWidget], le [State].

Ajoutez dans le code la création d'une clé globale pour chaque élément (dans votre SelectableItem pour vous):

...
var key = new GlobalKey<SelectableItem >();
this.items.put(position, key);
return new SelectableItem(key: key,...);

Les éléments sont une carte où vous pouvez enregistrer la position et la clé globale. Maintenant, lorsque vous souhaitez sélectionner une vue du parent, il suffit d'accéder à la clé globale à partir de la carte des éléments et d'accéder au widget pour faire ce que vous voulez (mettre à jour, décocher, etc ...)

Modifier: exemple:

class SideHeaderListView  {

  Map<int, GlobalKey<_SelectableItems>> map = new Map();

  create() {
    for (int i = 0; i< 10; i++) {
      var key = new GlobalKey<_SelectableItems>();
      var item = new SelectableItems(key: key);
      map.putIfAbsent(i, () => key);
    }
  }

  redrawItem(int i) {
    var widget = this.map[i].currentState;
    widget.redraw();
  }
}

class SelectableItems extends StatefulWidget {

  SelectableItems({key: Key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return new _SelectableItems();
  }
}

class _SelectableItems extends State<SelectableItems> {

  @override
  Widget build(BuildContext context) {
    return new Text("test");
  }

  redraw() {
    setState(() {

    });
  }

 }
0
mcfly

Vous avez commenté une partie du code - //isSelected: selectedFlag, Je pense que vous devez ajouter ce champ à votre widget

class SelectableItems extands StatefulWidget {
    SelectableItems({this.isSelected = false});
    final bool isSelected;
    ...

class _SelectableItems extends State<SelectableItems> {
  bool isSelected;

  @override
  void initState() {
    isSelected = widget.isSelected ?? false;
    super.initState();
  }
  ....

Et lorsque vous créez une liste d'éléments:

return SelectableItems(
  ...
  isSelected: indexList.contains(snapshot.data[index].name)

Je pense que cela pourrait fonctionner

0
Andrey Turkovsky