Flutter dialog(1) - showDialog의 설명

응용 개발에서 많든 적든 탄창이 필요한 문제에 부딪힐 수 있다. 예를 들어 사용자의 확인이 필요하고 정보를 입력해야 하는 등 문제가 있다. 이것은 다이어로그와 관련된 개념을 사용해야 한다.
flutter에서 모든 보이는 것은widget이고 dialog도 예외가 아니다
그러나android나iOS와는 다른 점은Flutter의dialog는 단독 클래스가 아니라 사용자 정의Widget입니다
앞에 쓰다
우선 편의를 위해서, 나는 간단한 방법을 정의하여 버튼을 구축하는 데 사용하였다
  Widget buildButton(
    String text,
    Function onPressed, {
    Color color = Colors.white,
  }) {
    return FlatButton(
      color: color,
      child: Text(text),
      onPressed: onPressed,
    );
  }


showDialog
dialog 방법은 사인이 이렇게 되어 있어요.
이 중 context와builder는 필수 패스입니다
builder에서 Widget을 되돌려야 합니다. 이 Widget은 다이어로그로 페이지에 표시됩니다
예를 들어 제가 간단하게 이 방법을 썼어요.
    showDialog(
      context: context,
      builder: (ctx) {
        return Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              buildButton("  1", () {}),
              buildButton("  2", () {}),
            ],
          ),
        );
      },
    );

내가 이 방법을 호출할 때, 이러한 양식을 얻을 수 있다
이것이 가장 간단한 방법입니다. 그리고 외부를 클릭하면 다이어로그가 사라집니다.
닫을 때의 반환값 추가
이어서 제가 단추에 구체적인 이벤트를 추가할게요.
코드를 다음과 같이 수정합니다
_showDialog() async {
    var result = await showDialog(
      context: context,
      builder: (ctx) {
        return Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              buildButton("  1", () => Navigator.of(context).pop(1)),
              buildButton("  2", () => Navigator.pop(context, 2)),
            ],
          ),
        );
      },
    );

    print("result = $result");
  }

그리고 각각 1, 2와 외부를 눌러서 다이어로그를 사라지게 하면 다음과 같은 결과를 얻을 수 있습니다.
그러나 이것은 다이어로그에 고정된 내용을 표시할 수 있을 뿐이다. 만약에 다이어로그에 내용 변화가 있다면 이 방식을 사용하면 안 된다. setState를 호출해도 변화가 일어나지 않는다. 이것은 외부 State의 상태 변화가 다이어로그의 내용에 영향을 주지 않기 때문이다. 왜냐하면 다이어로그는 앱 뿌리에 부착된 것이지 페이지에 부착된 것이 아니기 때문이다.
StatefulWidget과 함께 사용
그래서 저희 다이어로그에서도 Stateful Widget을 사용할 수 있습니다. 한 페이지처럼 이 페이지가 전체 화면이 아닐 수도 있습니다.
제가 간단한 CounterWidget을 정의했어요.

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  var _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Material(
            child: Container(
              width: 100,
              height: 100,
              child: Text(
                _counter.toString(),
                style: TextStyle(fontSize: 40),
              ),
              alignment: Alignment.center,
            ),
            color: Colors.white,
          ),
          buildButton("+1", () => setState(() => _counter++)),
          buildButton("-1", () => setState(() => _counter--)),
        ],
      ),
    );
  }
}

그리고 호출
showDialog(context: context, builder: (ctx) => CounterWidget());

여기에서 볼 수 있듯이, 상태를 가진 컨트롤러도 다이어로그에 표시될 수 있다
StatefulBuilder 통합
flutter에는 StatefulBuilder라는 클래스가 있습니다.
이 종류의builder 구조에서state를 줍니다. 이state는 방법입니다.void를 되돌려줍니다. 매개 변수를 전달하는 방법은 방법입니다. 듣기에 매우 복잡합니다.
대충 이렇게 써요.
var statefulBuilder = StatefulBuilder(
    builder: (ctx, state) {
        state(() {});
        return Container();
    },
);

setState랑 비슷해 보여요.
여기에서 나는 프로그레스의 변화를 시뮬레이션했지만, 이 진도는 외부에서 전해진 것이다
_showDialogWithStatefulBuilder() {
    var progress = 0.0;
    StateSetter ss;
    Timer.periodic(Duration(milliseconds: 300), (timer) {
      progress += 0.1;
      if (ss != null) {
        ss(() {});
      }
      if (progress >= 1) {
        timer.cancel();
        ss = null;
      }
    });
    var sb = StatefulBuilder(
      builder: (ctx, state) {
        ss = state;
        return Center(
          child: Container(
            height: 40,
            child: LinearProgressIndicator(
              backgroundColor: Colors.white,
              value: progress,
            ),
          ),
        );
      },
    );
    showDialog(context: context, builder: (ctx) => sb);
  }

이것은 단지 간단한 설명일 뿐이다. 실제 응용에서 진도표는 여러 곳에서 복용할 수 있어야 한다. StatefulWidget를 사용하여 복용해야 한다. StatefulBuilder를 쉽게 사용해서 이 일을 하는 것이 아니라 구축할 때stream을 전송하고stream을 감청하는 것이 좋다. 이런 Timer의 형식을 사용해서는 안 된다.
StatefulBuilder는 팝업 레이아웃에 사용해야 합니다. 특이해서 다른 곳에 사용할 수 없는 경우
iOS 스타일 사용
어떤 학우들이 물어볼지도 몰라요. 당신의 이 시연은 모두 MD 스타일이에요. 제가 필요로 하는 것은 애플 스타일인데 어떡해요?
flutter에서 iOS 스타일이 필요하면Cupertino 구성 요소만 사용하면 됩니다
void showCupertinoDialog() {
    var dialog = CupertinoAlertDialog(
      content: Text(
        "  ,          ",
        style: TextStyle(fontSize: 20),
      ),
      actions: <Widget>[
        CupertinoButton(
          child: Text("  "),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
        CupertinoButton(
          child: Text("  "),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ],
    );

    showDialog(context: context, builder: (_) => dialog);
  }

입력 상자가 있는 dialog
 showHasInputDialog() {
    var widget = Center(
      child: Container(
        height: 40,
        width: double.infinity,
        child: Material(
          child: TextField(),
        ),
      ),
    );
    showDialog(context: context, builder: (_) => widget);
  }

소프트 키보드에 따라 자동으로 위치 변경
이전의 입력 상자에 문제가 있습니다. 만약 당신의 탄창이 밑에 있다면, 튀어나온 입력 상자가 가려질 수 있습니다
여기에는 또 다른 방법이 필요하다
import 'package:flutter/material.dart';
import 'dart:ui' as ui;

class InputDialog extends StatefulWidget {
  @override
  _InputDialogState createState() => _InputDialogState();
}

class _InputDialogState extends State<InputDialog> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

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

  @override
  void didChangeMetrics() {
    super.didChangeMetrics();
    if (this.mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    var mediaQueryData = MediaQueryData.fromWindow(ui.window);
    return AnimatedContainer(
      color: Colors.transparent,
      duration: const Duration(milliseconds: 300),
      padding: EdgeInsets.only(bottom: mediaQueryData.viewInsets.bottom),
      child: Material(child: TextField()),
      alignment: Alignment.center,
    );
  }
}

다이어로그 클래스를 정의한 다음 창의 변화를 감청합니다
그리고 변화할 때 동적으로padding을 수정하여 입력상자가 영원히 인터페이스 중심에 있는 목적을 달성한다
후기
전체 코드github
1편에서는 주로 showDialog 방법의 사용 방법과 건의를 다루었다
이상

좋은 웹페이지 즐겨찾기