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をコピーしました