0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DrawerやfloatingActionButtonの表示非表示をいい感じに切り替える

Posted at

概要

画面の状態によってdrawerやfloatingActionButtonのアイコンの表示/非表示を切り替えたい&アニメーションをつけたい場合の方法。

drawer_demo2.gif

floatingActionButton

ScaffoldのfloatingActionButtonに渡すウィジェットをFloatingActionButtonウィジェットとnullで切り替えれば良い。
特に他に何も指定しなくても再描画時にいい感じにアニメーションしてくれる。

Scaffold(
      floatingActionButton: editable
          ? FloatingActionButton(
              onPressed: _incrementCounter,
              tooltip: 'Increment',
              child: const Icon(Icons.add),
            )
          : null,
    );

NavigationDrawer(おそらくDrawerも同様)

drawerの場合、floatingActionButtonと同じようにnullを渡すだけだと特にアニメーションがなく、即時に表示非表示が切り替わる。

Scaffold(
      appBar: ...,
      drawer: editable ? const NavigationDrawer(children: []) : null,
      body: ...,
      floatingActionButton: editable
          ? FloatingActionButton(
              onPressed: _incrementCounter,
              tooltip: 'Increment',
              child: const Icon(Icons.add),
            )
          : null,
    );

drawer_demo.gif

NavigationDrawerやDrawerにはアイコンについて指定するプロパティはなく、アイコンの変更等を行う場合はAppBarのleadingをいじる。

drawerの開閉用アイコンを任意のウィジェットにする

drawerの開閉用アイコンはデフォルトでハンバーガーメニューになっている。
ハンバーガーメニューから任意のウィジェットに変更したい場合、AppBarのleadingに、タップしたときにScaffold.of(context).openDrawer()を実行する任意のウィジェットを渡せばよい。

Scaffold(
      appBar: AppBar(
          leading: IconButton(
            icon: drawerIcon,
            onPressed: () => Scaffold.of(context).openDrawer(),
          )),
      drawer: editable ? const NavigationDrawer(children: []) : null,
      body: ...,
      floatingActionButton: ...,
    );

drawerの開閉用アイコンをアニメーションアイコンにする

floationActionButtonと同じようにアニメーションさせるには、先述の任意のウィジェットを、flutter_animateでアニメーションを追加したアイコンボタンとすれば良い。

flutter_animate の導入

flutter pub add flutter_animate

詳しい使い方は公式ドキュメント等を参照。

アニメーションの設定

AppBarのleadingに、表示時はタップでScaffold.of(context).openDrawer()を実行するアイコンボタン(フェードインするアイコン)、非表示時はフェードアウトするアイコンを設定する。

AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: Text(widget.title),
    actions: const [EyeIcon()],
    leading: editable
        ? IconButton(
            onPressed: () {
              Scaffold.of(context).openDrawer();
            },
            icon: drawerIcon // 表示時フェードインつきアイコン
                .animate()
                .fadeIn(duration: const Duration(milliseconds: 200))
                .rotate(
                    begin: 0.5,
                    end: 1,
                    duration: const Duration(milliseconds: 200)))
        : drawerIcon // 非表示時フェードアウトつきアイコン
            .animate()
            .fadeOut(duration: const Duration(milliseconds: 200))
            .rotate(
                begin: 0,
                end: 0.5,
                duration: const Duration(milliseconds: 200))),

サンプルコード(main.dart全体)

editable.dart等を含む全体はGitHubにあります。

サンプルコード
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'eyeicon.dart';
import 'editable.dart';

void main() {
  runApp(const ProviderScope(
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends ConsumerStatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _MyHomePageState();
}

class _MyHomePageState extends ConsumerState<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    final editable = ref.watch(editableProvider);
    const drawerIcon = Icon(Icons.list);

    return Scaffold(
      appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
          actions: const [EyeIcon()],
          leading: editable
              ? IconButton(
                  onPressed: () {
                    Scaffold.of(context).openDrawer();
                  },
                  icon: drawerIcon
                      .animate()
                      .fadeIn(duration: const Duration(milliseconds: 200))
                      .rotate(
                          begin: 0.5,
                          end: 1,
                          duration: const Duration(milliseconds: 200)))
              : drawerIcon
                  .animate()
                  .fadeOut(duration: const Duration(milliseconds: 200))
                  .rotate(
                      begin: 0,
                      end: 0.5,
                      duration: const Duration(milliseconds: 200))),
      drawer: editable ? const NavigationDrawer(children: []) : null,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: editable
          ? FloatingActionButton(
              onPressed: _incrementCounter,
              tooltip: 'Increment',
              child: const Icon(Icons.add),
            )
          : null,
    );
  }
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?