개발노트

66. AnimatedSwitcher 페이지 변경 시, 배경 애니메이션 효과 주기(with PageView, ValueKey적용) 본문

앱 개발/Flutter

66. AnimatedSwitcher 페이지 변경 시, 배경 애니메이션 효과 주기(with PageView, ValueKey적용)

mroh1226 2024. 2. 13. 15:59
반응형

AnimatedSwitcherPageView와 함께 사용하여 PageView의 Page가 변할 때마다 배경의 색도 동일하게 변하는 화면을 만들어봅니다.

  • AnimatedSwitcher는 child 속성에 지정된 자식 위젯의 변화를 감지하여 해당 자식 위젯이 변경되었을 때만 애니메이션을 적용합니다. 이를 위해 자식 위젯이 변경되었음을 AnimatedSwitcher에 알려주는 것이 중요합니다.
  • 기존의 key가 변하지 않으면 Flutter는 해당 위젯을 다시 빌드하지 않습니다. 따라서 자식 위젯의 key 속성을 변경하여 Flutter에게 새로운 위젯임을 알려주는 것이 필요합니다. 
  • 기존의 key가 변하지않을 경우, 새로 리빌드하지않기 때문에 자식 위젯의 key속성에 ValueKey를 사용하여 key를 변환시켜줍니다.
  • key가 변경됨으로써 자식 위젯이 새로 빌드되고, AnimatedSwitcher 애니메이션 효과를 새롭게 부여합니다.

 


구현할 화면.

좌(key 적용) / 우(key 미적용)

  • 자식의 key: 속성을 이용하여, key 값이 변경됨을 AnimatedSwitcher에게 알려주어 효과가 적용되도록 구현합니다.

예제소스
import 'dart:ui';
import 'package:flutter/material.dart';

class TestScreen extends StatefulWidget {
  static String routeName = "testscreen";
  static String routeURL = "testscreen";
  const TestScreen({super.key});

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  // 페이지 컨트롤러 초기화
  //viewportFraction: 수치가 낮을 수록 크기가 작아지며, 이전,이후 page가 보여지는 비율이 높아짐
  final PageController _pageController = PageController(viewportFraction: 0.6);

  // 현재 색상 인덱스 변수
  int currentColor = 0;

  // 변경 가능한 색상 목록
  List<Color> colorList = [
    Colors.red,
    Colors.orange,
    Colors.yellow,
    Colors.green,
    Colors.blue,
    Colors.indigo,
    Colors.purple,
  ];

  // 페이지 변경 함수
  void changePage(int newPage) {
    currentColor = newPage; // 색상 변경
    setState(() {}); // 상태 갱신
  }

  @override
  void initState() {
    _pageController.addListener(() {
      // 페이지 컨트롤러 리스너 추가
      if (_pageController.page == null) return;
    });
    super.initState();
  }

  @override
  void dispose() {
    // 페이지 컨트롤러 해제
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black, // 배경 색상 지정
      body: Stack(children: [
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 500), // 전환 애니메이션 시간
          switchInCurve: Curves.linear, // 전환 애니메이션 커브
          // 배경이 되는 Container
          child: Container(
            // key를 사용하여 새로 리빌드되는 효과를 줌
            key: ValueKey(currentColor),
            color: colorList[currentColor], // 현재 색상 지정
            child: BackdropFilter(
              // blur 필터효과를 사용하여 흐리게 만들어 줌
              filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
              child: Container(
                color: Colors.black.withOpacity(0.3), // 투명도 지정
              ),
            ),
          ),
        ),
        Center(
          child: PageView.builder(
            controller: _pageController, // 페이지 컨트롤러 연결
            onPageChanged: changePage, // 페이지 변경 콜백 함수
            scrollDirection: Axis.vertical, // 수직 스크롤 지정
            itemCount: colorList.length, // 아이템 개수
            itemBuilder: (context, index) => Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // PageView에 포함된 Container
                Container(
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: colorList[index], // 현재 색상 지정
                    borderRadius: const BorderRadius.all(Radius.circular(45)), // 테두리 지정
                  ),
                  width: 300, // 너비
                  height: 300, // 높이
                  child: Text(colorList[index].value.toString()), // 색상값 표시
                ),
              ],
            ),
          ),
        ),
      ]),
    );
  }
}

소스설명.

PageController

  • PageController.page 는 현재 Page의 위치를 나타냅니다. 알아둬야 할 점은 1, 2, 3, 4 이렇게 int형 값이 아닌 double형 값이며, 예를 들어 1에서 2로 넘어갈때 위치에 따라 소수점으로 나타냅니다.(1.0 > 1.1 >1.2 >1.3 >1.4 ... 2.0)
  • PageController의 viewportFraction: 속성은 PageView에서 Page를 한번에 보는 비율을 나타냅니다. (0.5인 경우, 한 번에 페이지뷰의 절반만 보이게 됩니다.)

changePage() 메서드

  • PageView에서 Page가 변할 때 changePage() 메서드를 호출합니다.
  • changePage()의 역할은 AnimatedSwitcher의 자식 위젯(배경 Container) key로 사용될 currentColor의 값에 현재 Page 값을 업데이트 시켜주는 것입니다.
  • changePage에서 페이지가 변할 때마다 key를 변경해주기 때문에 AnimatedSwitcher는 자식 위젯의 변화를 감지하여  매번 애니메이션 효과를 적용시킵니다.

BackDropFilter

  • BackdropFilter의 sigmaX와 sigmaY는 이미지 필터의 블러(blur) 강도를 조절하는 데 사용됩니다.
    sigmaX: 가로 방향으로의 블러 강도를 나타냅니다. 값이 클수록 이미지가 가로 방향으로 더 많이 흐려집니다.
    sigmaY: 세로 방향으로의 블러 강도를 나타냅니다. 값이 클수록 이미지가 세로 방향으로 더 많이 흐려집니다.
    sigma 값이 클수록 더 강한 블러 효과가 발생하며, 이미지가 더 많이 흐려집니다. 일반적으로 sigmaX와 sigmaY에 동일한 값을 지정하여 가로와 세로 방향의 블러가 동일하게 적용되도록 합니다.
  • 배경이 되는 Container에 블러 효과를 주기위해 Black 색상으로 지정하고 0.3의 투명도를 부여합니다.

*나머지는 소스 주석을 참고하시면됩니다.

반응형
Comments