Flutterで各種Chipウィジェットの使い方を確認する

「来期アニメ」アプリでアニメのジャンルがわかるようにしたいと思って、Chipウィジェットが使えそうなのでどんな感じか試して見ました。

参考にした記事

Chip Widgets In Flutter
Flutter widgets are built using a modern framework that takes inspiration from React. We have learned before that everything in Flutter is…

Chip

静的なChipです。ラベルのように使えます。

スクリーンショット 2021-06-08 19.10.43
Wrap chipList() {
   return Wrap(
     spacing: 2.0, // Chip間の距離
     //runSpacing: 2.0, // 行間
     children: <Widget>[
       _buildChip('静的な', Colors.orange.shade100),
       _buildChip('な', Colors.orange.shade100),
       _buildChip('チップ。', Colors.orange.shade100),
       _buildChip('フォントサイズで', Colors.orange.shade100),
       _buildChip('チップの大きさが', Colors.orange.shade100),
       _buildChip('変わる', Colors.orange.shade100),
     ],
   );
}

Widget _buildChip(String label, Color color) {
    return Chip(
      //labelPadding: EdgeInsets.all(2.0),
      // avatar: CircleAvatar(
      //   backgroundColor: Colors.white70,
      //   child: Text(label[0].toUpperCase()),
      // ),
      label: Text(
        label,
        style: TextStyle(
          color: Colors.black87,
          fontSize: 10,
        ),
      ),
      backgroundColor: color,
      //elevation: 6.0, // 影の大きさ
      //shadowColor: Colors.grey[60], // 影の色
      //padding: EdgeInsets.all(8.0),
    );
}

FilterChip

複数選択可能なChipです。チェックボックスのように使えます。

スクリーンショット 2021-06-08 19.13.59
Wrap(
  spacing: 4.0,
  runSpacing: 0.0,
  children: filterChip.toList(),
),

Iterable<Widget> get filterChip sync* {
   for (FilterChipItemWidget filterChipItem in _filterChipItems) {
     yield FilterChip(
       //backgroundColor: Colors.tealAccent[200],
       backgroundColor: Colors.grey,
       // avatar: CircleAvatar(
       //   backgroundColor: Colors.cyan,
       //   child: Text(
       //     company.name[0].toUpperCase(),
       //     style: TextStyle(color: Colors.white),
       //   ),
       // ),
       label: Text(
         filterChipItem.name,
       ),
       selected: _filters.contains(filterChipItem.name),
       selectedColor: Colors.orange.shade400,
       onSelected: (bool selected) {
         setState(() {
           if (selected) {
             _filters.add(filterChipItem.name);
           } else {
             _filters.removeWhere((String name) {
               return name == filterChipItem.name;
             });
           }
         });
       },
     );
   }
 }

 _filterChipItems = <FilterChipItemWidget>[
     FilterChipItemWidget('チェック'),
     FilterChipItemWidget('ボックス'),
     FilterChipItemWidget('的'),
     FilterChipItemWidget('な'),
     FilterChipItemWidget('挙動の'),
     FilterChipItemWidget('チップ'),
 ];
   
class FilterChipItemWidget {
 const FilterChipItemWidget(this.name);
 final String name;
}

ActionChip

押すと反応するChipです。ボタンのように使えます。

スクリーンショット 2021-06-08 19.15.46
  Widget _buildActionChips() {
   return ActionChip(
     elevation: 8.0,
     padding: EdgeInsets.all(2.0),
     avatar: CircleAvatar(
       backgroundColor: Colors.redAccent,
       child: Icon(
         Icons.mode_comment,
         color: Colors.white,
         size: 20,
       ),
     ),
     label: Text('押すとメッセージが出るチップ'),
     onPressed: () {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップメッセージです。')),
       );
     },
     backgroundColor: Colors.grey[200],
     shape: StadiumBorder(
         side: BorderSide(
       width: 1,
       color: Colors.redAccent,
     )),
   );
 }

ChoiceChip

選択可能なChipです。セレクトボックスのように使えます。

スクリーンショット 2021-06-08 22.45.42
  Widget _buildChoiceChips() {
   return Container(
     height: MediaQuery.of(context).size.height / 4,
     child: ListView.builder(
       itemCount: _choices.length,
       itemBuilder: (BuildContext context, int index) {
         return ChoiceChip(
           label: Text(_choices[index]),
           selected: _choiceIndex == index,
           selectedColor: Colors.red,
           onSelected: (bool selected) {
             setState(() {
               _choiceIndex = selected ? index : 0;
             });
           },
           backgroundColor: Colors.green,
           labelStyle: TextStyle(color: Colors.white),
         );
       },
     ),
   );
 }
 
 _choices = ["選択", "できる", "チップ"];

InputChip

多機能なChipです。全て?のChipの機能を持っています。
使い所はよくわかりません。

スクリーンショット 2021-06-08 22.46.32
スクリーンショット 2021-06-08 22.46.32
  Widget _buildInputChips() {
   return InputChip(
     padding: EdgeInsets.all(2.0),
     avatar: CircleAvatar(
       backgroundColor: Colors.pink.shade600,
       child: Text('多'),
     ),
     label: Text(
       '多機能なチップ',
       style: TextStyle(color: _isSelected ? Colors.white : Colors.black),
     ),
     selected: _isSelected,
     selectedColor: Colors.blue.shade600,
     // onPressed: () {
     //   ScaffoldMessenger.of(context).showSnackBar(
     //     SnackBar(content: Text('チップを押せます。')),
     //   );
     // },
     onSelected: (bool selected) {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップの選択ができます。')),
       );
       setState(() {
         _isSelected = selected;
       });
     },
     onDeleted: () {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップの削除ができます。')),
       );
     },
   );
 }

まとめ

checkboxだけでなく、label, button, select代わりにも使えるので何かと重宝しそうな予感です。

また、Chipとは関係ないですが、今回の調査でWrapウィジェットを初めて知りました。
結構便利なのでこちらも使い所ありそうです。

とりあえず、「来期アニメ」アプリでは、FilterChipを使ってみました。

‎来期アニメ-「来期のアニメ何観よう」を解決!
‎アニメ改編期ごとに、・来期のアニメ一覧を探す・良さそうなアニメをピックアップ・アニメ録画予約を入れるこれらの作業がいつも面倒で忘れがちなので、同じような悩みを持っている方に向けてアプリ化しました。◆「来期アニメ」一覧画面ホーム画面は、基本的に「来期アニメ」の一覧を表示します。新着順に並べてあるので追加があればすぐにわ...
来期アニメ:「来期のアニメ、何観よっかな」をサポート! - Google Play のアプリ
来期スタートの新作アニメの最新情報をシンプルにお届け

ソース全文

import 'package:flutter/material.dart';

void main() {
 runApp(MyApp());
}

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       primarySwatch: Colors.orange,
     ),
     home: MyHomePage(),
   );
 }
}

class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 late GlobalKey<ScaffoldState> _key;
 late bool _isSelected;
 late List<FilterChipItemWidget> _filterChipItems;
 late List<String> _filters;
 late List<String> _choices;
 late int _choiceIndex;

 @override
 void initState() {
   super.initState();
   _key = GlobalKey<ScaffoldState>();
   _isSelected = false;
   _choiceIndex = 0;
   _filters = <String>['チェック', 'な'];
   _filterChipItems = <FilterChipItemWidget>[
     FilterChipItemWidget('チェック'),
     FilterChipItemWidget('ボックス'),
     FilterChipItemWidget('的'),
     FilterChipItemWidget('な'),
     FilterChipItemWidget('挙動の'),
     FilterChipItemWidget('チップ'),
   ];
   _choices = ["選択", "できる", "チップ"];
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Chip Test'),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           chipList(),
           Container(height: 20),
           Wrap(
             spacing: 4.0, // gap between adjacent chips
             runSpacing: 0.0, // gap between lines
             children: filterChip.toList(),
           ),
           Container(height: 20),
           _buildActionChips(),
           Container(height: 20),
           _buildChoiceChips(),
           Container(height: 20),
           _buildInputChips(),
         ],
       ),
     ),
   );
 }

 Wrap chipList() {
   return Wrap(
     spacing: 2.0,
     //runSpacing: 2.0,
     children: <Widget>[
       _buildChip('静的な', Colors.orange.shade100),
       _buildChip('な', Colors.orange.shade100),
       _buildChip('チップ。', Colors.orange.shade100),
       _buildChip('フォントサイズで', Colors.orange.shade100),
       _buildChip('チップの大きさが', Colors.orange.shade100),
       _buildChip('変わる', Colors.orange.shade100),
     ],
   );
 }

 Widget _buildChip(String label, Color color) {
   return Chip(
     //labelPadding: EdgeInsets.all(2.0),
     // avatar: CircleAvatar(
     //   backgroundColor: Colors.white70,
     //   child: Text(label[0].toUpperCase()),
     // ),
     label: Text(
       label,
       style: TextStyle(
         color: Colors.black87,
         fontSize: 10,
       ),
     ),
     backgroundColor: color,
     //elevation: 6.0, // 影の大きさ
     //shadowColor: Colors.grey[60], // 影の色
     //padding: EdgeInsets.all(8.0),
   );
 }

 Widget _buildActionChips() {
   return ActionChip(
     elevation: 8.0,
     padding: EdgeInsets.all(2.0),
     avatar: CircleAvatar(
       backgroundColor: Colors.redAccent,
       child: Icon(
         Icons.mode_comment,
         color: Colors.white,
         size: 20,
       ),
     ),
     label: Text('押すとメッセージが出るチップ'),
     onPressed: () {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップメッセージです。')),
       );
     },
     backgroundColor: Colors.grey[200],
     shape: StadiumBorder(
         side: BorderSide(
       width: 1,
       color: Colors.redAccent,
     )),
   );
 }

 Widget _buildInputChips() {
   return InputChip(
     padding: EdgeInsets.all(2.0),
     avatar: CircleAvatar(
       backgroundColor: Colors.pink.shade600,
       child: Text('多'),
     ),
     label: Text(
       '多機能なチップ',
       style: TextStyle(color: _isSelected ? Colors.white : Colors.black),
     ),
     selected: _isSelected,
     selectedColor: Colors.blue.shade600,
     // onPressed: () {
     //   ScaffoldMessenger.of(context).showSnackBar(
     //     SnackBar(content: Text('チップを押せます。')),
     //   );
     // },
     onSelected: (bool selected) {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップの選択ができます。')),
       );
       setState(() {
         _isSelected = selected;
       });
     },
     onDeleted: () {
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(content: Text('チップの削除ができます。')),
       );
     },
   );
 }

 Iterable<Widget> get filterChip sync* {
   for (FilterChipItemWidget filterChipItem in _filterChipItems) {
     yield FilterChip(
       //backgroundColor: Colors.tealAccent[200],
       backgroundColor: Colors.grey,
       // avatar: CircleAvatar(
       //   backgroundColor: Colors.cyan,
       //   child: Text(
       //     company.name[0].toUpperCase(),
       //     style: TextStyle(color: Colors.white),
       //   ),
       // ),
       label: Text(
         filterChipItem.name,
       ),
       selected: _filters.contains(filterChipItem.name),
       //selectedColor: Colors.purpleAccent,
       selectedColor: Colors.orange.shade400,
       onSelected: (bool selected) {
         setState(() {
           if (selected) {
             _filters.add(filterChipItem.name);
           } else {
             _filters.removeWhere((String name) {
               return name == filterChipItem.name;
             });
           }
         });
       },
     );
   }
 }

 Widget _buildChoiceChips() {
   return Container(
     height: MediaQuery.of(context).size.height / 4,
     child: ListView.builder(
       itemCount: _choices.length,
       itemBuilder: (BuildContext context, int index) {
         return ChoiceChip(
           label: Text(_choices[index]),
           selected: _choiceIndex == index,
           selectedColor: Colors.red,
           onSelected: (bool selected) {
             setState(() {
               _choiceIndex = selected ? index : 0;
             });
           },
           backgroundColor: Colors.green,
           labelStyle: TextStyle(color: Colors.white),
         );
       },
     ),
   );
 }
}

class FilterChipItemWidget {
 const FilterChipItemWidget(this.name);
 final String name;
}

コメント

  1. […] […]

タイトルとURLをコピーしました