3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutter GridView の複数選択ですべてを再描画させない方法

Posted at

Flutter の GridView を使って、正方形のサムネイルを表示するアプリを作っています。複数選択することはできたのですが、タップする度にすべて再描画されてしまい画面が点滅してしまいます。
問題を解決することができたので紹介します。

ソースコード

multi_select_gridview.dart
import 'package:flutter/material.dart';

class MultiSelectScreen extends StatefulWidget {
  @override
  _MultiSelectState createState() => _MultiSelectState();
}

class _MultiSelectState extends State<MultiSelectScreen> {
  List<String> list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T'];
  List<bool> selectList = new List.filled(20, false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.extent(
        maxCrossAxisExtent: 150,
        children: List.generate(20, (index) {    
          return MultiSelectItem(
            name: list[index],
            selectList: selectList,
            index:index);   
      })),
    );}
}

/// isSelected で再描画を行い、selectList を親に参照させることで、
/// すべてが再描画されることを防ぎます。
class MultiSelectItem extends StatefulWidget {
  MultiSelectItem({
    @required this.name,
    @required this.selectList,
    @required this.index,
    });
  String name;
  List<bool> selectList;
  int index;
  bool isSelected = false;
  @override
  _MultiSelectItemState createState() => _MultiSelectItemState();
}

class _MultiSelectItemState extends State<MultiSelectItem> {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(2),         
      child: GestureDetector(
        onTap: () {
          setState((){ 
            widget.isSelected = !widget.isSelected;
            widget.selectList[widget.index] = widget.isSelected;
            });
        },
        child: Stack(children: <Widget>[
          Container(color: Colors.grey),
          Center(child: Text(widget.name, style: TextStyle(fontSize: 30,))), 
          Positioned(
            right: 6.0, bottom: 6.0,
            child: CircleAvatar( 
              backgroundColor: widget.isSelected ? Colors.black38 : Color(0x00000000),
              child: Icon( widget.isSelected ? Icons.check : null, 
              size: 36,
              color: Colors.lightBlue
            ))),
          ]),
      ),);}
}

解説

複数選択するために List< bool> を使い setState() を実行します。すると GridView 全体が再描画されて画面が点滅したようになってしまいます。
そこで GridView の個々のアイテムを StatefulWidget にします。アイテムには、自身の isSelected と 親を参照する selectList の2つを持たせるのがポイントです。タップすると自身の isSelected だけが再描画されます。selectList も変更しますが再描画には影響しません。

まとめ

GlidView で選択する度に、画面がすべて再描画されてしまう問題の解決法を紹介しました。Flutter 初心者です。今回の解決法を調べるためにいくつものサンプルを試しました。setState() についてや、StatefulWidget と StatelessWidget の違いなど、急がば回れでかなり勉強になりました。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?