如何修复FocusNode实现后出现的后退导航异常?

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

首先,我的下拉菜单高度没有调整为屏幕弹出键盘占用所留下的空间,这现在在我的旧问题中得到了解决。该解决方案利用

FocusNode
和其他辅助代码来解决我的问题。但由于新代码的实施,可能出现了一个新问题。当用户单击
TextButton
时,我的应用程序允许导航到不同的页面,并且通过单击后退箭头按钮,用户可以返回到上一个主菜单页面。

问题:当用户点击TextButton进入其他页面时,如果不点击

TextField
而是点击后退箭头,不会出现异常,用户可以轻松地前后移动这样。但是当用户点击TextButton,进入下一页,然后点击
TextField
然后按后退箭头时,用户返回到主菜单页面,但同时也会发生异常。发生此异常后,用户无法再选择 TextButton 选项来导航到使用多个 TextButton 实现的任何页面。用户界面冻结。这就是我们如何复制下面所示代码的异常:

以下是我的

main.dart
页面内容:

import 'package:ask__widget_and_app_effective_height/my_home_page.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Screen__Menu(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue,
        title: Text("Demo App"),
      ),
      body: ListView(
        children: [
          TextButton(
            child: const Text("MyHomePage"),
            onPressed: () {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => MyHomePage()));
            },
          ),
        ],
      ),
    );
  }
}

以下是我的

my_home_page.dart
页面内容:

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

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

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @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 = 48;
  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: const Text("Demo App"),
      ),
      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"),
            ],
          ),
        ),
      ),
    );
  }
}

更新:

我还尝试将 Navigator.push 包装在 try-catch 块中,并使用 FloatingActionButton 实现 Navigator.pop。 Navigator.pop 也包含在 try-catch 块中。

Navigator.push:(现在)(遗憾的是,这没有捕获任何异常。)

try {
  Navigator.push(context,
      MaterialPageRoute(builder: (context) => MyHomePage()));
} catch (e) {
  print("########## Caught exception: $e");
} finally {
  print("########## Navigator.push completed!");
}

Navigator.pop:(现在)(这也没有捕获任何异常。但是当尝试前面所说的异常重现方法两次时,似乎会发生异常。)

FloatingActionButton(
  child: Icon(Icons.arrow_back),
  onPressed: () {
    try {
      Navigator.pop(context);
    } catch (e) {
      print("########## Caught exception: $e");
    } finally {
      print("########## Finished Navigator.pop!");
    }
  },
),

我不知道还能尝试什么,代码哪里出了问题?

flutter exception navigation flutter-focus-node
1个回答
0
投票

调试控制台中描述的错误与在不再存在的小部件中设置状态有关。你需要做的就是改变

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

}

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

}

每次设置状态时最好始终检查小部件是否已安装。

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