一洼绿地

Flutter resize widget

·2 min read

前言

flutter 监听键盘弹起,收回是个不好处理的问题, 下面的代码也许能帮到你



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

class KeyboardEventWidget extends StatefulWidget {

  final Widget Function(double bottomMargin)? childBuild;

  final Widget? child;

  final Function(double bottomMargin)? onKbShowBegin;

  final Function(double bottomMargin)? onKbShowEnd;

  final Function(double bottomMargin)? onKbShowing;

  final Function(double bottomMargin)? onKbHideBegin;

  final Function(double bottomMargin)? onKbHideEnd;

  final Function(double bottomMargin)? onKbHiding;

  final Function(double bottomMargin)? onKbSliding;

  const KeyboardEventWidget({
    // build child
    this.childBuild,
    this.child,
    // show
    this.onKbShowBegin,
    this.onKbShowing,
    this.onKbShowEnd,
    // hide
    this.onKbHideBegin,
    this.onKbHiding,
    this.onKbHideEnd,
    // sliding
    this.onKbSliding,
    super.key
  });

  @override
  State<KeyboardEventWidget> createState() => KeyboardEventWidgetState();
}

class KeyboardEventWidgetState extends State<KeyboardEventWidget> with WidgetsBindingObserver {

  double bottomMargin = 0;

  bool isKbHiding = false;

  bool isKbShowing = false;

  bool isKbShowEnd = false;

  final Duration checkEndDelay = const Duration(milliseconds: 200);

  @override
  Widget build(BuildContext context) {
    if (widget.child!=null) {
      return widget.child!;
    }
    else if (widget.childBuild!=null) {
      return widget.childBuild!(bottomMargin);
    }
    return const SizedBox();
  }

  @override
  void initState() {
    super.initState();
    SystemChannels.textInput.invokeMethod('TextInput.hide');
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // 监听
  @override
  void didChangeMetrics() {
    super.didChangeMetrics();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      double newBottomMargin = MediaQuery.of(context).viewInsets.bottom;
      // show begin
      if (newBottomMargin > 0 && bottomMargin == 0) {
        showBegin(newBottomMargin);
      }
      // show end && bottomMargin>200
      else if (newBottomMargin == bottomMargin && isKbShowing && isKbShowEnd) {
        showEnd(newBottomMargin);
      }
      // hide begin // bottomMargin>270
      else if (newBottomMargin < bottomMargin && !isKbHiding) {
        hideBegin(newBottomMargin);
      }
      // hide end
      else if (newBottomMargin == 0 && bottomMargin > 0) {
        hideEnd(newBottomMargin);
      }
      // moving
      if (isKbHiding && bottomMargin > newBottomMargin) {
        if (widget.onKbSliding!=null) {
          widget.onKbSliding!(newBottomMargin>20 ? newBottomMargin-20 : 0);
        }
        if (widget.onKbHiding!=null) {
          widget.onKbHiding!(newBottomMargin>20 ? newBottomMargin-20 : 0);
        }
      }
      else if (isKbShowing && bottomMargin < newBottomMargin) {
        if (widget.onKbShowing!=null) {
          widget.onKbShowing!(newBottomMargin);
        }
        if (widget.onKbSliding!=null) {
          widget.onKbSliding!(newBottomMargin);
        }
      }
      bottomMargin = newBottomMargin;
    });
  }

  void showBegin(double newBottomMargin) {
    isKbShowing = true;
    if (widget.onKbShowBegin!=null) {
      widget.onKbShowBegin!(0);
    }
    Future.delayed(checkEndDelay, (){
        isKbShowEnd = true;
        Future.delayed(const Duration(milliseconds: 100), (){
          if (newBottomMargin == bottomMargin && isKbShowing && isKbShowEnd) {
            showEnd(newBottomMargin);
          }
        });
    });
  }

  void showEnd(double newBottomMargin) {
    isKbShowing = false;
    isKbShowEnd = false;
    if (widget.onKbShowing!=null) {
      widget.onKbShowing!(newBottomMargin);
    }
    if (widget.onKbSliding!=null) {
      widget.onKbSliding!(newBottomMargin);
    }
    if (widget.onKbShowEnd!=null) {
      widget.onKbShowEnd!(newBottomMargin);
    }
  }

  void hideBegin(double newBottomMargin) {
    isKbHiding = true;
    if (widget.onKbHideBegin!=null) {
      widget.onKbHideBegin!(newBottomMargin);
    }
  }

  void hideEnd(double newBottomMargin) {
    isKbHiding = false;
    if (widget.onKbSliding!=null) {
      widget.onKbSliding!(0);
    }
    if (widget.onKbHiding!=null) {
      widget.onKbHiding!(0);
    }
    if (widget.onKbHideEnd!=null) {
      widget.onKbHideEnd!(0);
    }
  }
}