如何根据屏幕键盘高度调整Flutter DropdownMenu高度?

问题描述 投票:0回答:1

在下面的代码中,我打算根据屏幕键盘的存在/不存在来设置

DropdownMenu
的高度。在计算下拉菜单的适当高度时,我还考虑了
AppBar
TextField
等其他元素的高度(具体请参阅代码)。我无法在代码中正确更新键盘
heightKeyboard
变量的高度,以便
heightDropdownMenu
的计算可以使用它。 heightKeyboard 保持未更新,因此下拉菜单的高度不适应屏幕键盘的存在,并且它的某些部分隐藏在键盘下方,使得用户无法访问它们。

我尝试过的:为了修复它,我尝试在

InkWell
周围实现
TextField
并在其
onTap
属性中尝试更新键盘高度,然后更新下拉高度,但这并没有'似乎工作正常,而且我也没有看到其中的 print() 函数也工作,因此无法判断值是否正在更新。

希望有人能帮助我。谢谢你。

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

void main() {
  runApp(const 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'),
    );
  }
}

const List<String> list = <String>[
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
];

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey? _key01 = GlobalKey();
  final GlobalKey? _key02 = GlobalKey();

  late final TextEditingController firstController;

  late Size screenSize;
  double screenWidth = 0;
  double screenHeight = 0;

  double heightAppBar = 0;
  double heightTextField = 0;
  double heightKeyboard = 0;
  double heightOthersCummulative = 0;
  double heightAdjustment = 60;
  double heightDropdownMenu = 0;

  void setDropdownMenuHeight(
      double heightAppBar, double heightTextField, double heightKeyboard) {
    if (heightAppBar > 0 && heightTextField > 0) {
      heightDropdownMenu = screenHeight -
          heightAppBar -
          heightTextField -
          heightKeyboard -
          heightOthersCummulative -
          heightAdjustment;
      // return heightDropdownMenu;
    } else {
      heightDropdownMenu = 150;
      // return heightDropdownMenu;
    }
  }

  late String dropdownValue = list.first;

  String result = "";
  String effective_available_screen_height = "";
  String dimensions = "";

  FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first;

  late Size size;
  double width = 0;
  double height = 0;
  double height01 = 0;

  @override
  void initState() {
    super.initState();
    firstController = TextEditingController();

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      setState(() {
        heightAppBar = _key01?.currentContext?.size?.height ?? -1;
        heightTextField = _key02?.currentContext?.size?.height ?? -1;
        heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
        setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
        dimensions =
            "KeyboardHeight=${heightKeyboard}\nDropdownMenuHeight=${heightDropdownMenu}\nAppBarHeight=${_key01?.currentContext?.size?.height}\nTextFieldHeight=${_key02?.currentContext?.size?.height}";
      });
    });
  }

  @override
  void dispose() {
    firstController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    screenSize = MediaQuery.of(context).size;
    screenWidth = screenSize.width;
    screenHeight = screenSize.height;

    Size ph_size = view.physicalSize;
    double ph_height = ph_size.height;

    size = MediaQuery.of(context).size;
    width = size.width;
    height = size.height;

    final padding = MediaQuery.of(context).viewPadding;
    height01 = height - padding.top - padding.bottom;

    effective_available_screen_height = "$height01";

    // Height of Keyboard when onscreen (ohterwise zero):
    double keyboard_height = MediaQuery.of(context).viewInsets.bottom;

    return Scaffold(
      appBar: AppBar(
        key: _key01,
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Container(
        padding: const EdgeInsets.all(5.0),
        child: Column(
          children: [
            Container(
              child: Row(
                children: [
                  Expanded(
                    flex: 5,
                    child: Container(
                      padding: const EdgeInsets.all(5.0),
                      child: InkWell(
                        onTap: () {
                          setState(() {
                            heightKeyboard =
                                MediaQuery.of(context).viewInsets.bottom;
                            setDropdownMenuHeight(
                                heightAppBar, heightTextField, heightKeyboard);
                            // THESE PRINT DOES NOT SEEM TO PRINT ONTAP:
                            print("==========[InkWell]$heightDropdownMenu");
                            print("========[InkWell](kbdHt=)$heightKeyboard");
                          });
                        },
                        child: TextField(
                          key: _key02,
                          style: const TextStyle(
                            fontSize: 16,
                          ),
                          controller: firstController,
                          keyboardType: TextInputType.number,
                          onChanged: (value) {
                            setState(() {
                              result = value;
                              /*
                              // The following gave error:
                              dimensions =
                                  "${_key01?.currentContext.size.height}";
                              */
                              dimensions =
                                  "${_key01?.currentContext?.size?.height}";
                            });
                          },
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    flex: 5,
                    child: Container(
                      padding: const EdgeInsets.all(5.0),
                      child: DropdownMenu<String>(
                        menuHeight: heightDropdownMenu,
                        // menuHeight: 300,
                        textStyle: const TextStyle(
                          fontSize: 16.0,
                        ),
                        initialSelection: dropdownValue,
                        onSelected: (String? value) {
                          print("==========[DropdownMenu]$heightDropdownMenu");
                          print(
                              "========[DropdownMenu](kbdHt=)$heightKeyboard");
                          setState(() {
                            // codes here
                          });
                        },
                        dropdownMenuEntries:
                            list.map<DropdownMenuEntry<String>>((String value) {
                          return DropdownMenuEntry<String>(
                              value: value, label: value);
                        }).toList(),
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Text("Result = $result"),
            Text("Total physical height = $ph_height"),
            Text("Total logical height = $height"),
            Text("Onscreen Keyboard height = $keyboard_height"),
            Text(
                "Working Height Available (logical) = $effective_available_screen_height"),
            Text("Dimensions: $dimensions"),
          ],
        ),
      ),
    );
  }
}
flutter dynamic layout drop-down-menu on-screen-keyboard
1个回答
0
投票

你不能使用

InkWell
,因为
TextField
会拦截手势,你可以做的是使用
FocusNode
,将其设置为
TextField
en 监听焦点变化,然后等待几毫秒键盘出现并重新计算尺寸。

结果:

代码:

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey _key01 = GlobalKey();
  final GlobalKey _key02 = GlobalKey();

  late final TextEditingController firstController;

  late Size screenSize;
  double screenWidth = 0;
  double screenHeight = 0;

  double heightAppBar = 0;
  double heightTextField = 0;
  double heightKeyboard = 0;
  double heightOthersCummulative = 0;
  double heightAdjustment = 60;
  double heightDropdownMenu = 0;

  void setDropdownMenuHeight(
      double heightAppBar, double heightTextField, double heightKeyboard) {
    if (heightAppBar > 0 && heightTextField > 0) {
      heightDropdownMenu = screenHeight -
          heightAppBar -
          heightTextField -
          heightKeyboard -
          heightOthersCummulative -
          heightAdjustment;
      // return heightDropdownMenu;
    } else {
      heightDropdownMenu = 150;
      // return heightDropdownMenu;
    }
  }

  late String dropdownValue = list.first;

  String result = "";
  String effective_available_screen_height = "";
  String dimensions = "";

  FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first;

  late Size size;
  double width = 0;
  double height = 0;
  double height01 = 0;
  final FocusNode _focusNode = FocusNode();

  @override
  void initState() {
    super.initState();
    firstController = TextEditingController();
    _focusNode.addListener(_onFocusChange);

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      setState(() {
        heightAppBar = _key01.currentContext?.size?.height ?? -1;
        heightTextField = _key02.currentContext?.size?.height ?? -1;
        heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
        setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
        dimensions =
            "KeyboardHeight=$heightKeyboard\nDropdownMenuHeight=$heightDropdownMenu\nAppBarHeight=${_key01.currentContext?.size?.height}\nTextFieldHeight=${_key02.currentContext?.size?.height}";
      });
    });
  }

  void _onFocusChange() {
    Future.delayed(const Duration(milliseconds: 500), () {
      setState(() {
        heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
        setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
      });
    });
  }

  @override
  void dispose() {
    _focusNode.removeListener(_onFocusChange);
    _focusNode.dispose();
    firstController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    screenSize = MediaQuery.of(context).size;
    screenWidth = screenSize.width;
    screenHeight = screenSize.height;

    Size phSize = view.physicalSize;
    double phHeight = phSize.height;

    size = MediaQuery.of(context).size;
    width = size.width;
    height = size.height;

    final padding = MediaQuery.of(context).viewPadding;
    height01 = height - padding.top - padding.bottom;

    effective_available_screen_height = "$height01";

    // Height of Keyboard when onscreen (ohterwise zero):
    double keyboardHeight = MediaQuery.of(context).viewInsets.bottom;

    return Scaffold(
      appBar: AppBar(
        key: _key01,
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: GestureDetector(
        onTap: () {
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Container(
          padding: const EdgeInsets.all(5.0),
          child: Column(
            children: [
              Container(
                child: Row(
                  children: [
                    Expanded(
                      flex: 5,
                      child: Container(
                        padding: const EdgeInsets.all(5.0),
                        child: TextField(
                          key: _key02,
                          style: const TextStyle(
                            fontSize: 16,
                          ),
                          controller: firstController,
                          keyboardType: TextInputType.number,
                          focusNode: _focusNode,
                          onChanged: (value) {
                            setState(() {
                              result = value;
                              /*
                              // The following gave error:
                              dimensions =
                                  "${_key01?.currentContext.size.height}";
                              */
                              dimensions =
                                  "${_key01.currentContext?.size?.height}";
                            });
                          },
                        ),
                      ),
                    ),
                    Expanded(
                      flex: 5,
                      child: Container(
                        padding: const EdgeInsets.all(5.0),
                        child: DropdownMenu<String>(
                          menuHeight: heightDropdownMenu,
                          // menuHeight: 300,
                          textStyle: const TextStyle(
                            fontSize: 16.0,
                          ),
                          initialSelection: dropdownValue,
                          onSelected: (String? value) {
                            print(
                                "==========[DropdownMenu]$heightDropdownMenu");
                            print(
                                "========[DropdownMenu](kbdHt=)$heightKeyboard");
                            setState(() {
                              // codes here
                            });
                          },
                          dropdownMenuEntries: list
                              .map<DropdownMenuEntry<String>>((String value) {
                            return DropdownMenuEntry<String>(
                                value: value, label: value);
                          }).toList(),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              Text("Result = $result"),
              Text("Total physical height = $phHeight"),
              Text("Total logical height = $height"),
              Text("Onscreen Keyboard height = $keyboardHeight"),
              Text(
                  "Working Height Available (logical) = $effective_available_screen_height"),
              Text("Dimensions: $dimensions"),
            ],
          ),
        ),
      ),
    );
  }
}


© www.soinside.com 2019 - 2024. All rights reserved.