예상치 못한 업그레이드가 있기 전까지는 NavigationRail을 추가하여 버튼에 대한 처리를 하였습니다. 또한, Stateless를 Stateful로 Refactoring하는 것도 해보았구요.
https://learn-and-give.tistory.com/52
이제 버튼이 눌려지면 이에 따라 오른쪽 영역에 적절한 뷰가 표시되는 처리를 할 것입니다.
버튼 선택에 따른 분기
아래 코드를 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)
'공허의 유산 > 사상의 도구' 카테고리의 다른 글
Unity3d Input field의 Password 문자열 얻기 (0) | 2023.04.12 |
---|---|
[Flutter]. 13. Flutter tutorial on codelab(8) (0) | 2023.02.01 |
[Flutter]. 11. Flutter upgrade (1) | 2023.01.29 |
[Flutter]. 09. Flutter tutorial on codelab(5) (0) | 2023.01.24 |
[Flutter]. 08. Flutter tutorial on codelab(4) (0) | 2023.01.24 |
댓글