[Flutter] TickerProvider 상태변경

merci·2023년 3월 30일
0

Flutter

목록 보기
2/24
post-thumbnail
post-custom-banner

stateful 위젯의 상태변경

상태를 변경하기 위해서 페이지를 하나 만들어서 테스트

class HelloPage extends StatefulWidget {

   HelloPage({Key? key}) : super(key: key);

  
  State<HelloPage> createState() => _HelloPageState(); // 자동완성으로 만들어짐
}

class _HelloPageState extends State<HelloPage> {
  int num = 1;
  
  
  Widget build(BuildContext context) {
    print("또 실행됨");
    return Scaffold(
      appBar: AppBar(),
      body: Align( // 기본이 가운데 정렬
        // alignment: Alignment.topCenter, // 디폴트값
        child: Column(
          children: [
            Text("Hello ${num}", style: TextStyle(fontSize: 50),),
            ElevatedButton(
              onPressed: (){
              setState(() {
                num++; 
              });
              print("num : ${num}"); 
            }, child: Text("변경", style: TextStyle(fontSize: 20)))
          ],
        ),
      ),
    );
  }
}

상태가 변하는 위젯을 만들기 위해서는 StatefulWidget으로 만든다.
StatelessWidget는 상태가 변경되었을때 변경감지를 하지못해 rebuild를 하지 못한다.

StatefulWidgetsetState() 메소드를 가지고 있는데 필드에 지정한 int num = 1; 의 값을 변경하고 있다.
여기서 numText("Hello ${num}"에서 사용되어 아래처럼 숫자를 화면에 출력한다.

일반적으로 클래스의 필드는 상태를 의미한다.
setState()의 내부에서 상태를 변경한다면 (num증가) setState()는 상태변경을 감지하게 되고 해당 상태를 포함하는 위젯을 rebuild하게 된다.

따라서 변경 버튼을 클릭하게 되면 ElevatedButtononPressed가 실행되어 setState()에 의해 상태가 변하게 되는데 콘솔에도 다음과 같이 출력이 되면서 화면의 그림도 rebuild되어 값이 변하게 된다.

클릭하게 되면 num의 값이 변경되고 rebuild되어서 '또 실행됨'이 출력되고 화면이 변한다.


TabBar / TabBarView 상태변경

아래처럼 자동차와 지하철 이미지를 클릭했을때 아래 정보를 변경하고 싶다면 Stateful위젯을 이용한다.

TabBar는 일반적으로 앱의 다른 화면으로 전환할 수 있는 여러 개의 탭으로 구성된 위젯이다.
탭을 선택했을때 선택된 탭으로 전환하기 위해 TabBarView, TabController와 함께 사용하는데 TabController는 상태를 추적하고 업데이트해주는 기능을 가진다.

class ProfileTap extends StatefulWidget {
  const ProfileTap({Key? key}) : super(key: key);

  
  State<ProfileTap> createState() => _ProfileTapState();
}

class _ProfileTapState extends State<ProfileTap>
    with SingleTickerProviderStateMixin {

  TabController? _tabController;

  
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
    								// requied vsync -> TickerProvider
  }

initState()로 상태를 빌드한다.
TabControllervsync 를 반드시 필요로 하는데 TabBar의 애니메이션 동작을 동기화하기 위한 객체를 나타낸다.
즉, 필요로 하는 탭의 수만큼 지정해주면 된다. 이를 위해서 Mixin을 이용한다.

SingleTickerProviderStateMixin

플러터는 애니메이션에 관련된 API를 제공해주는데 이들중 하나가 Ticker클래스다.
Ticker 클래스는 다수의 애니메이션을 동시에 제어할 수 있다.

플러터에서 애니메이션을 구현할 때는 AnimationController 클래스를 사용한다.
SingleTickerProviderStateMixinAnimationController 클래스의 객체를 생성하고 제어하는 데 사용되는 Mixin이다.
또한 다른 애니메이션과의 충돌을 방지하는 장점이 있다.

Mixin을 통해 현 상태클래스가 TickerProvider객체에 접근 가능해진다.
TabBarControllervsync 프로퍼티를 통해 TickerProvider 타입의 객체를 받게 된다.
이를 통해 탭전환을 하는 애니메이션을 구현하게 된다.


Widget build(BuildContext context) {
  return Column(
    children: [
      TabBar(controller: _tabController, tabs: [
        Tab(
          icon: Icon(Icons.directions_car),
        ),
        Tab(
          icon: Icon(Icons.directions_transit),
        ),
      ]),
      Expanded(
        child: TabBarView(controller: _tabController, children: [
          GridView.builder(
              itemCount: 42,
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3, // 3열 고정
                  crossAxisSpacing: 10, // 갭 지정
                  mainAxisSpacing: 10),
              itemBuilder: (context, index) {
				// print("실행 : ${index+1}"); 
                // return Image.network("http://picsum.photos/id/${index+1}/200/200");
                return CachedNetworkImage(
                  imageUrl: "http://picsum.photos/id/${index + 1}/200/200", // 다운받은 이미지
                  placeholder: (context, url) => CircularProgressIndicator(), // 다운받는중 (기본이미지)
                  errorWidget: (context, url, error) => Icon(Icons.error), // 다운실패
                );
                Image.network("");
              }),
          Container(
            color: Colors.green,
          ),
          Container(
            color: Colors.grey,
          ),
        ]),
      )
    ],
  );
}
}

Row나 Column은 모두 크기가 있어야 한다.
내부의 요소가 외부보다 커지면 에러가 터지기 때문에 TabBarView는 남은 영역을 모두 차지하라고 Expanded 위젯으로 감싼다

CachedNetworkImage

캐싱을 사용하지 않고 다운로드를 한다면

return Image.network("http://picsum.photos/id/${index+1}/200/200");

뷰홀더에 15장만 다운받게 된다. ( print로 확인)
또한 스크롤이 길어지면 이미 다운받았던 이미지를 날려버려 15장을 초과하는 순서는 버리고 다시 다운받는 행위를 반복한다. 이러한 자원낭비를 최소화하기 위해 캐싱을 이용한다.

캐싱을 사용하기 위해 의존성을 추가한다.

dependencies:
  flutter:
    sdk: flutter
  cached_network_image: ^3.2.3  # 추가

이후 CachedNetworkImage를 사용할 수 있게 되는데 캐싱을 이용하므로 한번 다운받은 이미지를 다시 다운받지 않아 자원의 낭비를 최소화 한다.

profile
작은것부터
post-custom-banner

0개의 댓글