hibix's blog

明日の自分への備忘録

【Flutter】キーボードの表示状態を検知するカスタムフックを作ってみた

先日、キーボードの表示状態を検知しなくてはならない状況に遭遇しました。

検知は flutter_keyboard_visibility を用いて簡単に行うことができます。いくつかの実装が用意されていますが、ここでは Direct query and subscription の実装を使用します。

import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'dart:async';

late StreamSubscription<bool> keyboardSubscription;

@override
void initState() {
  super.initState();

  var keyboardVisibilityController = KeyboardVisibilityController();
  // Query
  print('Keyboard visibility direct query: ${keyboardVisibilityController.isVisible}');

  // Subscribe
  keyboardSubscription = keyboardVisibilityController.onChange.listen((bool visible) {
    print('Keyboard visibility update. Is visible: $visible');
  });
}

@override
void dispose() {
  keyboardSubscription.cancel();
  super.dispose();
}

ただ、このサンプルを見て、「これは カスタムフックにできるのでは?」と思い実装してみました。

こちらがそのカスタムフックの実装です。

/// キーボードの表示状態を取得する Hook
bool useKeyboardVisibility() {
  return use(const _KeyboardVisibility());
}

class _KeyboardVisibility extends Hook<bool> {
  const _KeyboardVisibility();

  @override
  _KeyboardVisibilityState createState() => _KeyboardVisibilityState();
}

class _KeyboardVisibilityState extends HookState<bool, _KeyboardVisibility> {
  late final KeyboardVisibilityController _controller;
  late final StreamSubscription<bool> _subscription;

  @override
  void initHook() {
    super.initHook();
    _controller = KeyboardVisibilityController();
    _subscription = _controller.onChange.listen((_) {
      // build を発火させる
      setState(() {});
    });
  }

  @override
  bool build(BuildContext context) {
    return _controller.isVisible;
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

また、これをもっと使いやすく、キーボードを閉じた場合に限定したものも作ってみました。

/// キーボードが非表示になった時にコールバックを呼び出す Hook
void useOnKeyboardHidden(VoidCallback callback) {
  final keyboardVisibility = useKeyboardVisibility();
  useEffect(
    () {
      if (!keyboardVisibility) {
        callback();
      }
      return null;
    },
    [keyboardVisibility],
  );
}

今回は StreamSubscription を用いる形のものからカスタムフックを作成してみました。これまで flutter_hooks 組み込みのフックを組み合わせた関数のカスタムフックは何度か作成したことがありますが、クラスのカスタムフックは初めてだったので最初は戸惑いました。いい具合に作成できた気がします。

もっといい実装あるよ!これじゃあ、〇〇の場合に動かないよ!といったご意見、ご指摘ありましたら、是非ともコメントください。