Flutter PRO 팁 #0: 시작할 때 대화 상자 열기

때때로 사용자가 새 화면을 열 때 대화 상자를 표시해야 합니다. 중요한 정보를 표시하기 위해 특정 요구 사항이 충족되거나 응용 프로그램의 일부 관련 사실에 대해 경고해야 할 수 있습니다. 관련성이 있는 경우 사용자가 화면을 열 때만 대화 상자를 표시하도록 결정했을 수 있습니다.

📽 Video version available on YouTube and Odysee





위젯이 StatefulWidget 인 경우 다음과 같이 생각했을 수 있습니다.

class SomeWidget extends StatefulWidget {
  const SomeWidget({Key? key}) : super(key: key);

  @override
  State<SomeWidget> createState() => _SomeWidgetState();
}

class _SomeWidgetState extends State<SomeWidget> {
  @override
  void initState() {
    super.initState();

    // Try to open a dialog in initState()
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        content: const Text('Dialog content'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Accept'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample'),
      ),
      body: const Center(
        child: Text('Body of the Scaffold'),
      ),
    );
  }
}


그러나 다음과 같은 오류가 발생합니다.

======== Exception caught by widgets library =======================================================
The following assertion was thrown building Builder:
dependOnInheritedWidgetOfExactType<_LocalizationsScope>() or dependOnInheritedElement() was called before _PostFrameCallbackSampleState.initState() completed.

When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.

Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.



이런 일이 발생하는 이유는 해당 위젯이 렌더링 단계에 있기 때문에 대화 상자를 표시하려면 해당 단계가 완료될 때까지 기다려야 합니다. 어떻게 할 수 있습니까? 운 좋게도 WidgetsBinding 클래스에는 addPostFrameCallback라는 메서드가 있으며, 이 메서드의 documentation은 다음을 알려줍니다.

Schedule a callback for the end of this frame.



이 방법을 통해 다음과 같이 현재 프레임의 렌더링이 끝날 때 실행되도록 해당 작업을 '예약'할 수 있습니다.

class PostFrameCallbackSample extends StatefulWidget {
  const PostFrameCallbackSample({Key? key}) : super(key: key);

  @override
  State<PostFrameCallbackSample> createState() =>
      _PostFrameCallbackSampleState();
}

class _PostFrameCallbackSampleState extends State<PostFrameCallbackSample> {
  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance?.addPostFrameCallback((_) {
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          content: const Text('Dialog content'),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Accept'),
            ),
          ],
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Post Frame Callback sample'),
      ),
      body: const Center(
        child: Text('Body of the Scaffold'),
      ),
    );
  }
}


이렇게 하면 이 위젯의 ​​수명 주기 시작 시 문제 없이 대화 상자를 표시할 수 있습니다. 실제로 대화 상자를 표시하는 것 외에 UI를 변경해야 하는 다른 작업에도 사용할 수 있습니다.

위젯이 StatelessWidget인 경우 다음과 같이 FutureBuilder로 래핑할 수 있습니다.

class PostFrameCallbackSampleStateless extends StatelessWidget {
  const PostFrameCallbackSampleStateless();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _showDialog(context),
      builder: (context, snapshot) => Scaffold(
        appBar: AppBar(
          title: const Text('Post Frame Callback Stateless'),
        ),
        body: const Center(
          child: Text('Body of the Scaffold'),
        ),
      ),
    );
  }

  Future<void> _showDialog(BuildContext context) async {
    WidgetsBinding.instance?.addPostFrameCallback((_) {
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          content: const Text('Dialog content'),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Accept'),
            ),
          ],
        ),
      );
    });
  }
}


트리에 새 위젯을 추가할 때 대화 상자를 표시하는 것은 다시는 문제가 되지 않습니다. 😀

이 자습서here의 샘플을 찾을 수 있습니다.

즐거운 코딩하세요!

좋은 웹페이지 즐겨찾기