본문 바로가기
공허의 유산/사상의 도구

[Flutter]. 12. Flutter tutorial on codelab(7)

by 바른생활머시마 2023. 1. 30.
728x90
반응형

예상치 못한 업그레이드가 있기 전까지는 NavigationRail을 추가하여 버튼에 대한 처리를 하였습니다. 또한, Stateless를 Stateful로 Refactoring하는 것도 해보았구요.

https://learn-and-give.tistory.com/52

 

[Flutter]. 10. Flutter tutorial on codelab(6)

지난 번에 Like 버튼을 추가하였습니다. 물론, Like 표시 된 단어들을 보는 기능은 아직 만들지 않았지만, 의도 된 디자인에 맞게 코드를 수정하는 경험을 통해, 주어진 디자인을 바탕으로 어떻게

learn-and-give.tistory.com

 

이제 버튼이 눌려지면 이에 따라 오른쪽 영역에 적절한 뷰가 표시되는 처리를 할 것입니다.

 

버튼 선택에 따른 분기

아래 코드를 Refactoring으로 자동 추가 된 클래스의 build 메쏘드에서 위젯을 리턴 해 주는 앞에 추가 합니다.

Widget page;
switch (selectedIndex) {
  case 0:
    page = GeneratorPage();
    break;
  case 1:
    page = Placeholder();
    break;
  default:
    throw UnimplementedError('no widget for $selectedIndex');
}

처음 이 코드를 보고, GeneratorPage라는 함수를 한참 찾아봤지만, 찾을 수 없었습니다. 그러다가, 처음 시작 할 때 읽었던 Dart의 특징이었던 new없이 instance를 만드는 것이 생각났습니다. 즉, 저 코드를 클래스 instance를 page에 할당하는 것이죠. GeneratorPage라는 클래스는 원래 있던 MyHomePage의 이름을 변경하여 만들어 둔 것이고, Placeholder라는 클래스는 아직 정의하지 않았습니다.

 

 코드 자체는 간단하죠? 버튼 선택에 따라 적절한 instance를 만들어 page에 할당합니다. 이 page를 이전에는 GeneratorPage instance를 직접 넣어주던 곳에 넣어주면 되죠. 완성 된 코드는 아래와 같습니다.

class _MyHomePageState extends State<MyHomePage> {

  var selectedIndex = 0;     // ← Add this property.

  @override
  Widget build(BuildContext context) {

    Widget page;
    switch (selectedIndex) {
      case 0:
        page = GeneratorPage();
        break;
      case 1:
        page = Placeholder();
        break;
      default:
        throw UnimplementedError('no widget for $selectedIndex');
    }
    return Scaffold(
      body: Row(
        children: [
          SafeArea(
            child: NavigationRail(
              extended: false,
              destinations: [
                NavigationRailDestination(
                  icon: Icon(Icons.home),
                  label: Text('Home'),
                ),
                NavigationRailDestination(
                  icon: Icon(Icons.favorite),
                  label: Text('Favorites'),
                ),
              ],
              selectedIndex: selectedIndex,    // ← Change to this.
              onDestinationSelected: (value) {

                // ↓ Replace print with this.
                setState(() {
                  selectedIndex = value;
                });

              },
            ),
          ),
          Expanded(
            child: Container(
              color: Theme.of(context).colorScheme.primaryContainer,
              child: page,
            ),
          ),
        ],
      ),
    );
  }
}

 

너무나 당연하게도 Favorites를 선택하면 뭔가 문제가 생기게 될텐데, Flutter가 UI를 다루기 때문인지 오류도 UI에 딱!!! 눈에 잘 보이도록 표현되네요. 개발 중에 테스트를 하면 눈에 확 잘 보일 것 같습니다.

 

 

 

동적인 UI 제어

지금은 NavigationRail의 버튼 옆에 Label이 보이지 않는데, 이것은 extented : true/false에 의해서 선택 할 수 있다는 것을 앞에서 확인했습니다. 그런데, 늘 보이게 해두면 좁은 화면에서 문제가 될 것이고, 보이지 않게 해두면 버튼을 설명하는 라벨을 넣어도 오른쪽 영역 역시 충분한 경우가 있을 것입니다. 이 경우, 화면의 폭에 따라 라벨을 보이거나 감추는 로직을 적용하면 좋습니다. 이런 처리를 하는 방법을 살펴 볼 예정입니다.

 

 라벨이 보여질 조건이, 화면의 크기가 600픽셀 이상인 경우라고 가정 해 보겠습니다.

 

LayoutBuilder라는 위젯을 써서 구현 해 보겠습니다.

아래 그림과 같이 Scafford를 Builder라는 위젯으로 싸고(Wrap), Builder라는 클래스를 LayoutBuilder라는 클래스로 변경합니다. Refactoring 과정은 아래 그림을 참고 합니다.

 context와 함께 전달 된 constraints라는 인자가 있는데, 여기에 Layout과 관련 된 정보가 들어 있습니다. 이것을 이용하여 조건에 대한 판단을 하고, 거기에 맞게 위젯을 구성하게 됩니다. 최종적으로 아래 코드가 되는데 constraints를 어떻게 사용하는지 잘 살펴봅시다.

class _MyHomePageState extends State<MyHomePage> {
  var selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    Widget page;
    switch (selectedIndex) {
      case 0:
        page = GeneratorPage();
        break;
      case 1:
        page = Placeholder();
        break;
      default:
        throw UnimplementedError('no widget for $selectedIndex');
    }

    return LayoutBuilder(builder: (context, constraints) {
      return Scaffold(
        body: Row(
          children: [
            SafeArea(
              child: NavigationRail(
                extended: constraints.maxWidth >= 600,  // ← Here.
                destinations: [
                  NavigationRailDestination(
                    icon: Icon(Icons.home),
                    label: Text('Home'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.favorite),
                    label: Text('Favorites'),
                  ),
                ],
                selectedIndex: selectedIndex,
                onDestinationSelected: (value) {
                  setState(() {
                    selectedIndex = value;
                  });
                },
              ),
            ),
            Expanded(
              child: Container(
                color: Theme.of(context).colorScheme.primaryContainer,
                child: page,
              ),
            ),
          ],
        ),
      );
    });
  }
}

 

라벨의 표시 여부가 boolean 값으로 되기 때문에, constraints로 전달 받은 화면 폭의 크기를 판별 기준 크기인 600과 비교하여 boolean값을 넘겨주게 하였습니다. 결과를 보면, 창 크기에 따라서 라벨이 보여졌다 사라졌다 합니다. 이 때 눈여겨 볼 특성으로, 라벨이 보여지고 사라지면서 레이아웃의 조정이 그냥 팍팍 되는 것이 아니라 부드럽게 animation 된다는 점입니다. UI를 다루는 툴이기 때문에 이렇게 되도록 만든 것 같네요.

 

 

 

Favorites 뷰 만드는 것을 계속 하지 않고 있는데, 그건 다음 시간에 만들어 보겠습니다.

[Flutter]. 13. Flutter tutorial on codelab(8) (tistory.com)

 

[Flutter]. 13. Flutter tutorial on codelab(8)

앞에서 NavigationRail의 선택에 따라 어떻게 적절한 위젯이 보여지는지 살펴봤습니다. [Flutter]. 12. Flutter tutorial on codelab(7) (tistory.com) [Flutter]. 12. Flutter tutorial on codelab(7) 예상치 못한 업그레이드가 있

learn-and-give.tistory.com

 

 

728x90
반응형

댓글