떨림 응답 쌍기둥 구조

응답 프로그램에서 큰 화면의 다열 레이아웃은 작은 화면에서 서랍이나 팝업 창으로 접는 것이 흔하다.이 강좌에서, 나는 당신에게 그것을 정확하게 만드는 방법을 보여 드리겠습니다.
전체 코드는 github에서 찾을 수 있습니다.

비헤이비어


응답 진동 레이아웃 항목 목록 프레젠테이션
인코딩을 시작하기 전에, 우리가 실현하고자 하는 목표를 정확하게 정의하고, 각 부분을 점차적으로 해결합시다.이것은 우리가 이 임무에 전념하고 전진 중에 우리의 진전을 추적하는 데 도움이 될 것이다.
간단하게 말하면, 창의 화면 크기에 따라 하위 창의 표시 방식을 업데이트하는 작은 위젯이 필요합니다.큰 화면에서 두 개의 창으로 나누어야 한다.작은 화면에는 하나의 창만 표시되고 필요에 따라 두 번째 창의 팝업 창을 열어야 합니다.
  • 유연한 레이아웃
  • 대형 및 작은 화면
  • 팝업 창을 열고 작은 화면
  • 에 두 번째 창 내용을 표시합니다.
  • 창을 시간으로 크게 조정하면pane2의 내용이
  • 이면 팝업 창을 엽니다
  • 작은 크기에서 팝업
  • 방해하지 말고 우리 시작합시다.

    1. 유연한 배치


    응답 전진기둥 배치도
    첫 번째 부분은 Flex 작은 위젯을 Flatter에서 쉽게 사용할 수 있습니다. 다시 사용하기 쉽도록 작은 위젯을 만들 것입니다. 이 위젯은 창의 행동을 수용하고 책임질 수 있습니다.
    class TwoPane extends StatelessWidget {
      final double breakpoint = 800;
      final int paneProportion = 70;
    
      @override
      Widget build(BuildContext context) {
        if (breakpoint < MediaQuery.of(context).size.width) {
          return Flex(
            direction: Axis.horizontal,
            children: [
              Flexible(
                flex: paneProportion,
                child: Pane1(),
              ),
              Flexible(
                flex: 100 - paneProportion,
                child: Pane2(),
              ),
            ],
          );
        }
        return Flex(
          direction: Axis.horizontal,
          children: [
            Flexible(
              flex: 100,
              child: Pane1(),
            ),
          ],
        );
      }
    }
    
    
    Pane1Pane2은 간단한 용기로 텍스트의 하위 등급과 배경을 가지고 있어 구분하기 편리하다.
    class Pane1 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.green[200],
          child: Center(
            child: Text('Pane 1'),
          ),
        );
      }
    }
    
    
    우리의 규범에 따르면 그것들은 Flexible소부품에 봉인되어 있다.Pane1의 신축성은 paneProportion, pane2의 신축성은 100 - paneProportion으로 이 예에서 남은 공간은 각각 70%와 30%이다.
    이런 것들이 있어서 우리는 우리의 첫 번째 목표를 실현했다.장치 화면 너비에 따라 패널 크기를 조절하는 유연한 소부품.일단 폭이 단점보다 작으면, 우리는 첫 번째 창으로만 돌아갑니다.이제 작은 화면의 행동을 추가합니다.

    작은 화면 팝업 페이지


    응답 바이브레이션 2열 레이아웃, 작은 화면에서 단일 열로 접기
    이것은 가장 긴 부분입니다. 주의해야 할 경고가 있기 때문에 인내심을 가지고 제 말을 들어 주십시오.
    다음은 내가 아래에서 분해할 마지막 코드이다.
    
    class TwoPane extends StatefulWidget {
      final Widget pane1;
      final Widget pane2;
    
      /// keeps track of the pane2 open state
      final bool showPane2;
    
      /// Called called when pane2Popup
      final void Function() onClosePane2Popup;
    
      /// the breakpoint for small devices
      final double breakpoint;
    
      /// pane1 has a flex of `paneProportion`. Default = 70
      ///
      /// pane2 `100 - paneProportion`. Default = 30.
      final int paneProportion;
    
      const TwoPane({
        Key? key,
        this.showPane2 = false,
        required this.pane1,
        required this.pane2,
        required this.onClosePane2Popup,
        this.breakpoint = 800,
        this.paneProportion = 70,
      }) : super(key: key);
    
      @override
      _TwoPaneState createState() => _TwoPaneState();
    }
    
    class _TwoPaneState extends State<TwoPane> {
      bool _popupNotOpen = true;
    
      bool get canSplitPanes =>
          widget.breakpoint < MediaQuery.of(context).size.width;
    
      /// Loads and removes the popup page for pane2 on small screens
      void loadPane2Page(BuildContext context) async {
        if (widget.showPane2 && _popupNotOpen) {
          _popupNotOpen = false;
          SchedulerBinding.instance!.addPostFrameCallback((_) async {
            // sets _popupNotOpen to true after popup is closed
            Navigator.of(context)
                .push<Null>(
              new MaterialPageRoute<Null>(
                builder: (BuildContext context) {
                  return new Scaffold(
                    appBar: AppBar(title: Text('hello')),
                    body: widget.pane2,
                  );
                },
                fullscreenDialog: true,
              ),
            )
                .then((_) {
              // less code than wapping in a WillPopScope
              _popupNotOpen = true;
              // preserves value if screen canSplitPanes
              if (!canSplitPanes) widget.onClosePane2Popup();
            });
          });
        }
      }
    
      /// closes popup wind
      void _closePopup() {
        if (!_popupNotOpen) {
          SchedulerBinding.instance!
              .addPostFrameCallback((_) => Navigator.pop(context));
        }
      }
    
      @override
      Widget build(BuildContext context) {
        if (canSplitPanes && widget.showPane2) {
          _closePopup();
          return Flex(
            direction: Axis.horizontal,
            children: [
              Flexible(
                flex: widget.paneProportion,
                child: widget.pane1,
              ),
              Flexible(
                flex: 100 - widget.paneProportion,
                child: widget.pane2,
              ),
            ],
          );
        } else {
          loadPane2Page(context);
          return Flex(
            direction: Axis.horizontal,
            children: [
              Flexible(
                flex: 100,
                child: widget.pane1,
              ),
            ],
          );
        }
      }
    }
    
    
    우선, 구성 요소를 더욱 중용성 있게 하기 위해pane1,pane2와 행위 속성을 매개 변수로 전달합니다.
      final Widget pane1;
      final Widget pane2; 
      final bool showPane2; 
      final void Function() onClosePane2Popup; 
      final double breakpoint;
      final int paneProportion;
    
    onClosePane2Popup 메타데이터를 주의하십시오.작은 화면의 팝업 창을 닫을 때 업데이트 값이 유용합니다.
    그런 다음 팝업 창을 열고 닫는 방법을 추가했습니다.
  • canSplitPanes: 윈도우 크기 및 브레이크 추적
  • loadPane2Page: 작은 화면에pane2 팝업 페이지 불러오기
  • _closePopup: 팝업 창 닫기
  • 팝업 창이 열리는지 여부를 추적하기 위해 _popupNotOpen을 추가했습니다. 화면의 크기를 조정할 때마다 팝업 창이 다시 열리지 않도록 합니다. popupNotOpen은 비최종 필드이기 때문에 애니메이션을 추가할 때 필요한 어셈블리 상태를 설정합니다.
      bool _popupNotOpen = true;
    
      bool get canSplitPanes =>
          widget.breakpoint < MediaQuery.of(context).size.width;
    
      /// Loads the popup page for pane2 on small screens
      void loadPane2Page(BuildContext context) async {
        if (widget.showPane2 && _popupNotOpen) {
          _popupNotOpen = false;
          SchedulerBinding.instance!.addPostFrameCallback((_) async {
            ...
            )
                .then((_) {
              // less code than wapping in a WillPopScope
              _popupNotOpen = true;
              // preserves value if screen canSplitPanes
              if (!canSplitPanes) widget.onClosePane2Popup();
            });
          });
        }
      }
    
      /// closes popup wind
      void _closePopup() {
        if (!_popupNotOpen) {
          SchedulerBinding.instance!
              .addPostFrameCallback((_) => Navigator.pop(context));
        }
      }
    
    
    팝업 창 뒤의 loadPane2Page에서 _popupNotOpentrue10if (!canSplitPanes) widget.onClosePane2Popup();으로 설정하면 사용자가 팝업 창을 닫을 때만 리셋을 실행할 수 있으며, 큰 시간에 리셋을 실행할 수 있도록 조정할 수 없습니다.loadPane2Page_closePopupSchedulerBinding.instance!.addPostFrameCallback()에 포장되어 있으며, 이것은 다른 렌더링 작업을 호출하기 전에 작은 부품을 정확하게 렌더링한 것을 확보하기 위해서입니다.
    증강 구성 요소를 테스트하기 위해서, 간단한 상태 관리를 위한 홈 위젯을 만들었습니다.StatefullWidgetValueNotifier을 사용하여 상태를 업데이트하고 필요에 따라 구성 요소를 재구성하고 있습니다. 단, 선택한 상태 관리를 마음대로 사용하십시오.
    나는 또한 Pane1Pane2을 홈페이지 파일로 옮겼다. 왜냐하면 그들은 사실상 우리의 TwoPane 구성 요소의 일부분이 아니라 하위 구성 요소로만 전달되기 때문이다.
    컨테이너 페이지 코드는 다음과 같습니다.
    // home_page.dart component
    
    import 'package:flutter/material.dart';
    import 'package:two_columns/steps/two_columns1.dart';
    
    class HomePage extends StatefulWidget {
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      ValueNotifier<int?> _selected = ValueNotifier(null);
    
      void _selectValue(int? val) => _selected.value = val;
      void _clearSelected() => _selected.value = null;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text('Home page')),
          body: ValueListenableBuilder(
            builder: (context, _, child) {
              return TwoColumns(
                showPane2: (_selected.value != null) ? true : false,
                onClosePane2Popup: _clearSelected,
                pane1: Pane1(selectValue: _selectValue),
                pane2: Pane2(value: _selected.value),
              );
            },
            valueListenable: _selected,
          ),
        );
      }
    }
    
    class Pane1 extends StatelessWidget {
      final void Function(int?) selectValue;
      const Pane1({required this.selectValue});
    
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.green[200],
          child: Center(
            child: ElevatedButton(
              child: Text('set value'),
              onPressed: () => selectValue(3),
            ),
          ),
        );
      }
    }
    
    class Pane2 extends StatelessWidget {
      final int? value;
    
      const Pane2({Key? key, this.value}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.blue[200],
          child: Center(
            child: Text('Pane2 value is $value'),
          ),
        );
      }
    }
    

    더욱 실제적인 예


    비록 우리가 세운 일은 정상적이지만, 그것은 매우 현실적인 용례가 아니다.더 현실적인 예는 아래의 예다.기본적으로 유일한 변화는 프로젝트 목록을 pane1에 전달하고 세부 정보 카드를 pane2에 전달하는 것이다
    응답 진동 레이아웃 항목 목록 프레젠테이션
    상기 예시된 코드와 모든 절차를 github에서 찾을 수 있습니다.

    한층 더 개선하다.


    나는 그것으로 가방을 만들 것을 고려하고 있기 때문에 가능한 한 코드를 최적화하고 싶다.수직 레이아웃, 더블 스크린 지원, 과도 애니메이션 등 추가 혜택도 추가할 것입니다. 필요에 따라 이 글을 업데이트하겠습니다.
    모티프
    Flatter에서 서랍을 만들 수 있는 작은 위젯이 많지만, 두 창의 화면을 쉽게 확장하고 접을 수 있는 작은 위젯을 찾을 수 없습니다. 그 중 하나는 디테일을 표시하는 데 사용되고, 다른 하나는 주요 내용을 표시하는 데 사용됩니다.그래서 저는 하나를 만들기로 결정했습니다. 저는 여기서 여러분과 공유할 것입니다. 왜냐하면 이것은 매우 유용한 것 같아서 저는 개선하고 여러분에게 배우고 싶습니다.
    그러나 그 전에 개선 방법에 대한 당신들의 의견을 듣고 싶습니다.

    방주


    이것은 제가 프로그래밍에 관한 첫 번째 문장입니다. 여러분께 유용하길 바랍니다.그 밖에 코드뿐만 아니라 쓰기도 포함하는 모든 비판과 건의에 감사 드립니다.

    좋은 웹페이지 즐겨찾기