Flutter 解决App登录页面软键盘遮挡住登录按钮或顶起底部控件的问题

本文介绍了在Flutter中如何解决登录页面遇到的软键盘遮挡底部布局的问题,提供了两种解决方案:修改`resizeToAvoidBottomInset`属性和使用可滑动布局。同时,还阐述了当需要在弹出软键盘时滚动布局到指定位置(如登录按钮下方)的方法,包括监听软键盘高度变化和调整ListView中SizeBox高度的实现细节。
摘要由CSDN通过智能技术生成


1 软键盘问题点对比效果图

问题点

在这里插入图片描述

最终效果图

在这里插入图片描述


2 解决软键盘将底部布局顶上去的问题

2.1 方式一:修改resizeToAvoidBottomInset属性

问题点: 当前使用的是Column布局,弹窗软键盘后页面超出范围。

A RenderFlex overflowed by 0.533 pixels on the bottom.

解决方式

Scaffold或者CupertinoPageScaffold中设置resizeToAvoidBottomInset为false

  @override
  Widget build(BuildContext context) {
   
    return Scaffold(
      backgroundColor: Colors.white,
      resizeToAvoidBottomInset:false,
      body: ...,
    );
  }

2.2 方式二:使用可滑动布局

不修改resizeToAvoidBottomInset属性的话,可以使用ListViewSingleChildScrollViewCustomScrollView等布局构建页面。

3 弹出软键盘时滚动布局到指定位置(登录按钮下方)

3.1 问题点描述

在此登录页面布局中使用上述2种方式都会存在问题。

  • 小屏幕手机中,弹出软键盘会将登录按钮挡住
  • 直接使用ListView时,无法将第三方登录布局至于底部

在这里插入图片描述


3.2 实现方式

  1. 在Column布局中使用 ListView + 底部第三方登录
  2. 在ListView中底部加一个可控制高度的SizeBox
  3. 设置resizeToAvoidBottomInset属性为false
  4. 监听软键盘弹出并获取其高度
  5. 改变ListView中底部SizeBox的高度
  6. 滑动ListView到指定位置(使用GlobalKey来确定)

简要代码

class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {
   

  // 软键盘高度
  double _keyboardHeight = 0;

  // 可控制ListView滑动
  final _scrollController = ScrollController();

  // 用于获取目标Widget的位置坐标
  final _targetWidgetKey = GlobalKey();

  @override
  void initState() {
   
    super.initState();
    // 添加监听,didChangeMetrics
    WidgetsBinding.instance.addObserver(this);
  }

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

  // 当应用程序的尺寸发生变化时会调用
  @override
  void didChangeMetrics() {
   
    // 获取页面高度
    var pageHeight = MediaQuery.of(context).size.height;
    if (pageHeight <= 0) {
   
      return;
    }

    // 软键盘顶部  px
    final keyboardTopPixels =
        window.physicalSize.height - window.viewInsets.bottom;
    // 转换为 dp
    final keyboardTopPoints = keyboardTopPixels / window.devicePixelRatio;
    // 软键盘高度
    final keyboardHeight = pageHeight - keyboardTopPoints;

    setState(() {
   
      _keyboardHeight = keyboardHeight;
    });

    if (keyboardHeight <= 0) {
   
      return;
    }
    // 获取目标位置的坐标
    RenderBox? renderBox =
        _targetWidgetKey.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox == null) {
   
      return;
    }
    // 转换为全局坐标
    final bottomOffset =
        renderBox.localToGlobal(Offset(0, renderBox.size.height));
    final targetDy = bottomOffset.dy;
    // 获取要滚动的距离
    // 即被软键盘挡住的那段距离 加上 _scrollController.offset 已经滑动过的距离
    final offsetY =
        keyboardHeight - (pageHeight - targetDy) + _scrollController.offset;
    // 滑动到指定位置
    if (offsetY > 0) {
   
      _scrollController.animateTo(
        offsetY,
        duration: kTabScrollDuration,
        curve: Curves.ease,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
   
    return Scaffold(
      backgroundColor: Colors.white,
      // 避免底部布局被软键盘顶上来
      resizeToAvoidBottomInset: false,
      body: GestureDetector(
        behavior: HitTestBehavior.opaque,
        // 点击空白位置关闭软键盘
        onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
        child: Column(
          children: [
            Expanded(
              child: ListView(
                controller: _scrollController,
                children: [
                  ...
                  // 一系列输入框Widget
                  ...
                  // 弹出的软键盘位于此Widget之下
                  Row(
                    key:<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值