web-dev-qa-db-ja.com

Flutter-複数選択リストビュー

私のアプリにはリストがあります。そのリストに、長押しの選択 このRaouf Rahicheの投稿 を実装しました。選択が有効になっている場合、appbarが異なるIconButtonがあり、選択を無効にする必要があります。しかし、私はそれを行う方法がわかりません。

今までのところ、期待どおりに機能していません。下のビデオに動作が表示されています。 enter image description here

長押し選択は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
              ],
            ),
          ),
        ),
      );
  }
}

私はこのウィジェットを SideHeaderListView 内で次のように呼び出しています:

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;
      }
    });
  }

誰かが私の問題を解決できるといいのですが。前もって感謝します。

9
user9047282

まず最初に、次のように各アイテムにコンストラクタのキーを追加する必要があります。

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

なぜ鍵?キーを使用すると、ウィジェットを正しく識別できます。ドキュメントで参照:

新しいウィジェットは、そのキーが要素に関連付けられている現在のウィジェットのキーと同じである場合にのみ、既存の要素を更新するために使用されます。

GlobalKeyを作成します(GLobalキーがKeyを拡張します)。ウィジェットにアクセスするための各アイテムに対して、グローバルキーを作成します。ドキュメントから:

アプリ全体で一意のキー。グローバルキーは要素を一意に識別します。グローバルキーは、[BuildContext]や[StatefulWidget]の場合は[State]などの要素に関連付けられている他のオブジェクトへのアクセスを提供します。

(SelectableItemで)各項目のグローバルキーの作成をコードに追加します。

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

アイテムは、位置とグローバルキーを保存できるマップです。親からビューを選択する場合は、アイテムのマップからglobalKeyにアクセスし、ウィジェットにアクセスして必要な操作を実行します(更新、チェック解除など)。

編集:例:

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

コードの一部にコメントしました-//isSelected: selectedFlag,このフィールドをウィジェットに追加する必要があると思います

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();
  }
  ....

そして、あなたがアイテムのリストを作成しているとき:

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

これはうまくいくと思います

0