10. Flutter 수업- Android Studio로 shopapp 만들기(부분 리로딩)

shopapp(부분 리로딩)
홍윤's avatar
Oct 02, 2024
10. Flutter 수업- Android Studio로 shopapp 만들기(부분 리로딩)

위젯 트리에서 부분리로딩이 중요한 이유

💡
성능 최적화개발 효율성 때문에 위젯 트리에서 부분 리로딩이 중요한 이유이다.
  1. 성능 최적화: 위젯 트리 전체를 다시 렌더링하는 대신, 변경된 부분만 리로딩하면 불필요한 연산을 줄여 앱의 성능을 크게 향상시킬 수 있습니다. 이렇게 하면 사용자가 느끼는 UI 반응 속도가 빨라지고, 리소스를 절약할 수 있습니다.
  1. 개발 효율성: 부분 리로딩 덕분에 코드 수정 후 전체 앱을 다시 실행하지 않고, 수정된 부분만 빠르게 확인할 수 있습니다. 이는 개발 속도를 높이고, 실시간으로 변화를 테스트할 수 있게 해줍니다.
따라서, 부분 리로딩성능개발 생산성을 모두 향상시키는 중요한 기능입니다.

1. 전체 페이지 코드

import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: ShopPage(), ); } } class ShopPage extends StatelessWidget { @override Widget build(BuildContext context) { print("ShopPage 그림 그려짐"); return Scaffold( appBar: AppBar(title: Text("쇼핑카트")), body: Column( children: [ // 1. 이미지, 이미지를 사용해서 사이즈를 맞추러면 AspectRatio 무조건 써야한다. Header(), // 2. 동그라미 두 개 _circle(), // 3. 텍스트 필드 (아이콘 포함) _field(), ], ), ); } //사람아이콘을 특정 위치에 넣고 싶을 때 Stack을 쓴다. Stack _field() { return Stack( children: [ TextFormField( maxLines: 3, decoration: InputDecoration( suffixIcon: Icon(Icons.person), enabledBorder: OutlineInputBorder(), ), ), Positioned( left: 200, top: 50, child: Icon(Icons.person), ), ], ); } // 동그란 두 개의 컨테이너를 보여주는 위젯 Container _circle() { return Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.white, // 바깥 컨테이너의 배경색 border: Border.all(), // 바깥 컨테이너의 테두리 borderRadius: BorderRadius.circular(100), ), child: Align( alignment: Alignment(1.0, 0.0), // -1.0~1.0(가로), -1.0~1.0(세로) child: Container( width: 150, height: 150, decoration: BoxDecoration( color: Colors.deepOrange, borderRadius: BorderRadius.circular(75),// 안쪽 컨테이너를 원형으로 만들기 위해 반지름을 75로 설정 ), ), ), ); } } class Header extends StatefulWidget { @override State<Header> createState() => _HeaderState(); } class _HeaderState extends State<Header> { // 객체의 상태! List<String> imageList = [ "https://picsum.photos/id/100/200/200", "https://picsum.photos/id/101/200/200" ]; // 상태 관리 int selectedIndex = 0; @override // build 실행하고 페이지를 다시 그리지 않게 하기 위해 Context를 분리해야 한다. // Context를 분리하려면 위젯을 하나 더 만들면 된다. // Context를 분리하면 부분 리로딩이 가능하다. Widget build(BuildContext context) { print("Header 그림 그려짐"); return Column( children: [ // AspectRatio를 사용해서 이미지를 비율에 맞춰 조절함 AspectRatio( aspectRatio: 3 / 2, child: Image.network( imageList[selectedIndex], fit: BoxFit.cover, ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Container( width: 70, height: 70, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(20), ), child: IconButton( onPressed: () { selectedIndex = 0; print("selectedIndex : $selectedIndex"); setState(() {}); }, icon: Icon(Icons.account_circle_sharp), ), ), Container( width: 70, height: 70, decoration: BoxDecoration( color: Colors.redAccent, borderRadius: BorderRadius.circular(20), ), child: IconButton( onPressed: () { selectedIndex = 1; print("selectedIndex : $selectedIndex"); setState(() {}); }, icon: Icon(Icons.access_alarms_sharp), ), ), ], ), ], ); } }

2. ★Header★(Context 분리, 부분 리로딩)

class ShopPage extends StatelessWidget { @override Widget build(BuildContext context) { print("ShopPage 그림 그려짐"); return Scaffold( appBar: AppBar(title: Text("쇼핑카트")), body: Column( children: [ // 1. 이미지, 이미지를 사용해서 사이즈를 맞추러면 AspectRatio 무조건 써야한다. Header(), //===================================================================== class Header extends StatefulWidget { @override State<Header> createState() => _HeaderState(); } class _HeaderState extends State<Header> { // 객체의 상태! List<String> imageList = [ "https://picsum.photos/id/100/200/200", "https://picsum.photos/id/101/200/200" ]; // 상태 관리 int selectedIndex = 0; @override // build 실행하고 페이지를 다시 그리지 않게 하기 위해 Context를 분리해야 한다. // Context를 분리하려면 위젯을 하나 더 만들면 된다. // Context를 분리하면 부분 리로딩이 가능하다. Widget build(BuildContext context) { print("Header 그림 그려짐"); return Column( children: [ // AspectRatio를 사용해서 이미지를 비율에 맞춰 조절함 AspectRatio( aspectRatio: 3 / 2, child: Image.network( imageList[selectedIndex], fit: BoxFit.cover, ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Container( width: 70, height: 70, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(20), ), child: IconButton( onPressed: () { selectedIndex = 0; print("selectedIndex : $selectedIndex"); setState(() {}); }, icon: Icon(Icons.account_circle_sharp), ), ), Container( width: 70, height: 70, decoration: BoxDecoration( color: Colors.redAccent, borderRadius: BorderRadius.circular(20), ), child: IconButton( onPressed: () { selectedIndex = 1; print("selectedIndex : $selectedIndex"); setState(() {}); }, icon: Icon(Icons.access_alarms_sharp), ), ), ], ), ], ); } }
  • 회색 아이콘을 클릭했을때 페이지 전체가 리로딩 되는 게 아니라 사진만 리로딩 된다.
notion image
notion image
💡

코드설명

주요 개념 설명

1. StatefulWidgetsetState

  • HeaderStatefulWidget을 상속받고 있으며, 이를 통해 화면의 상태를 동적으로 관리할 수 있습니다.
  • setState 메소드를 호출하면 상태가 변경되었음을 Flutter에 알리고, UI가 다시 렌더링됩니다.
  • 여기서는 selectedIndex가 변경될 때마다 UI를 다시 그려서 다른 이미지를 보여줍니다.

2. imageList

  • imageList는 두 개의 이미지 URL을 담고 있는 리스트입니다. 이 리스트는 각각 다른 이미지를 나타내고, 선택된 인덱스에 따라 화면에 표시됩니다.
  • selectedIndex 값에 따라 imageList[selectedIndex]가 변경되고, AspectRatio 위젯에서 해당 이미지가 표시됩니다.

3. AspectRatio

  • AspectRatio는 주어진 비율에 따라 위젯의 크기를 결정하는 데 사용됩니다. 여기서는 3:2 비율로 이미지를 표시하고 있습니다.
  • 이미지는 BoxFit.cover 속성을 사용하여 공간을 가득 채우도록 조정됩니다.

4. 버튼 구성

  • 두 개의 버튼(IconButton)이 있고, 각각 다른 이미지를 선택하는 역할을 합니다.
  • 첫 번째 버튼을 누르면 selectedIndex0으로 설정되고, 두 번째 버튼을 누르면 selectedIndex1로 설정됩니다.
  • selectedIndex가 변경되면 setState()가 호출되어 화면이 다시 그려집니다.

5. setState의 역할

  • setState()는 상태가 변경되었음을 알리고, Flutter가 이 변화를 감지하여 UI를 다시 그립니다.
  • 버튼을 클릭할 때마다 selectedIndex가 변경되고, 이에 맞춰 이미지가 변경됩니다.

6. ContainerBoxDecoration

  • 버튼은 Container로 감싸져 있으며, BoxDecoration을 사용해 배경색과 둥근 모서리를 적용하고 있습니다.
  • 첫 번째 버튼은 회색, 두 번째 버튼은 빨간색(redAccent) 배경을 가지고 있으며, 각각 다른 아이콘을 표시합니다.

동작 흐름

  1. 처음 화면에 selectedIndex 값이 0으로 설정되어 있어 첫 번째 이미지가 표시됩니다.
  1. 첫 번째 버튼을 클릭하면 selectedIndex0으로 변경되며 첫 번째 이미지가 계속 표시됩니다.
  1. 두 번째 버튼을 클릭하면 selectedIndex1로 변경되며, 두 번째 이미지로 변경됩니다.

요약

두 개의 버튼을 사용하여 화면에 표시되는 이미지를 동적으로 변경하는 코드입니다. 각 버튼은 클릭할 때 selectedIndex 값을 변경하고, 이에 따라 이미지가 바뀝니다. 이를 통해 상태 관리와 UI 업데이트 방법을 이해할 수 있습니다.

3. _Circle()

// 동그란 두 개의 컨테이너를 보여주는 위젯 Container _circle() { return Container( //바깥쪽 큰 원 width: 200, height: 200, decoration: BoxDecoration( color: Colors.white,// 바깥 컨테이너의 배경색 border: Border.all(),// 바깥 컨테이너의 테두리 borderRadius: BorderRadius.circular(100), ), child: Align( alignment: Alignment(1.0, 0.0), // -1.0~1.0(가로), -1.0~1.0(세로) child: Container( //안쪽 작은 원 width: 150, height: 150, decoration: BoxDecoration( color: Colors.deepOrange, borderRadius: BorderRadius.circular(75), ), ), ), ); } }
notion image
💡

코드설명

Align 위젯을 사용하여 작은 원 정렬
  • Align 위젯은 자식 위젯(작은 원)을 특정 위치에 배치할 수 있도록 합니다.
  • 여기서 alignment: Alignment(1.0, 0.0)는 작은 원을 바깥쪽 큰 원의 오른쪽 중앙에 배치하는 역할을 합니다.
    • Alignment(1.0, 0.0):
      • 1.0은 가로 방향에서 오른쪽 끝을 의미합니다.
      • 0.0은 세로 방향에서 중앙을 의미합니다.
      • 요약:

        두 개의 원형 컨테이너를 중첩하여 화면에 표시하는 코드입니다. 큰 원 안에 작은 원을 배치하고, 작은 원은 큰 원의 오른쪽 중앙에 배치됩니다. AlignContainer를 적절히 활용하여 원하는 위치에 원하는 모양의 컨테이너를 배치하는 방법을 보여줍니다.

4. _field()

//사람아이콘을 특정 위치에 넣고 싶을 때 Stack을 쓴다. Stack _field() { return Stack( children: [ TextFormField( maxLines: 3, decoration: InputDecoration( suffixIcon: Icon(Icons.person), enabledBorder: OutlineInputBorder(), ), ), Positioned( left: 200, top: 50, child: Icon(Icons.person), ), ], ); }
notion image
💡

코드설명

Stack의 주요 속성

  • Stack은 Flutter에서 여러 위젯을 겹쳐서 배치할 수 있는 위젯입니다.
  • children: Stack 안에 여러 자식 위젯을 배치할 수 있습니다.
  • alignment: 자식 위젯들의 기본 배치를 설정할 수 있습니다. 기본값은 좌상단입니다.
  • fit: Stack의 크기와 자식 위젯들의 크기를 조정할 때 사용됩니다.
이 코드는 Stack을 사용하여 TextFormField 위에 아이콘을 원하는 위치에 정확히 배치하는 방법을 보여줍니다. StackPositioned를 활용하면, 복잡한 레이아웃을 자유롭게 조정할 수 있습니다.

Stack 위젯

  • Stack은 자식 위젯들을 겹치는 방식으로 배치합니다. 각 자식 위젯은 기본적으로 상하로 겹치며, 마지막에 추가된 자식이 위에 그려집니다. Positioned와 함께 사용하면, 자식 위젯을 특정 위치에 배치할 수 있습니다.
  • 사용 목적: Stack은 일반적으로 화면에 여러 요소를 겹치거나, 특정 요소를 배경에 고정하고 다른 요소를 그 위에 띄울 때 사용합니다.

Positioned 위젯

  • *Positioned*는 Stack 내에서 사용되며, 자식 위젯을 특정 위치에 배치할 수 있습니다.
    • 예를 들어, 위의 코드에서는 left: 200top: 50을 통해 아이콘을 텍스트 필드의 위에 좌측에서 200, 상단에서 50 떨어진 위치에 정확히 배치합니다.
 
Share article

Uni