⭐️ 개발/플러터

[프로젝트] 전자액자 (3) PageController 사용

짱구러버 2022. 11. 5. 20:39
728x90

들어가기 앞서...

이번 게시글에는 PageVIew() 에서 PageController 를 사용해 페이지를 1초마다 한장씩 넘어가게끔 진행을 할 것이다.

 

주의 깊게 봐야하는 점...

웹뷰를 썼을때는 onWebViewCreated 함수에서 controller 를 받을 수 있었는데, PageView 같은 경우에는 우리가 알아서 만들어 집어넣어줘야한다.


본문으로...

  • State클래스에 PageController 를 선언해주자!
class _HomeScreenState extends State<HomeScreen> {
  Timer? timer;
  PageController controller = PageController(
	// 초기에 몇번째 페이지를 실행할지 
	initialPage: 0,
  );
}
...
  • PageController 를 선언해주고 PafeView() 에 controller를 넣어주자!
...
@override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

    return Scaffold(
      body: PageView(
      // 추가!
        controller: controller,
        children: [2, 3, 4].map(
                (e) => Image.asset('asset/img/img$e.HEIC', fit: BoxFit.cover)
        ).toList(),
      ),
    );
  }
}

PageView가 생성이 되는 순간 controller 가 PageView 에 붙는다.

그리고  controller 를 조정을 할 수 있다!

 

controller 에page 의 타입

page 를 쓰려고 하니깐 double? 가 타입으로 나오게 되는 것을 볼 수 있다.

? controller 가 생성만 되고 PageView 에 자동으로 붙지 않았을 경우 페이지를 찾을 수 없으니 null 이될 수도 있다. 그래서 ? 가 들어가는것이다.

그리고 double 인 이유는 페이지가 중간일 경우 소수점으로 나오게 되는데, 그 소수점 떄문에 double 이라는 타입이 되는 것이다!

하지만 우리는 currentPage 는 null 이 안오는 게 확실하고, 양수형으로만 받길 원하니깐 밑에 코드 처럼 작성을 해주자

int currentPage = controller.page!.toInt();
class _HomeScreenState extends State<HomeScreen> {
  Timer? timer;
  PageController controller = PageController(
    initialPage: 0,
  );

  @override
  void initState() {
    super.initState();

    timer = Timer.periodic(Duration(seconds: 4), (timer) {
      int currentPage = controller.page!.toInt();
    // 다음 페이지는 현재페이지 + 1 
      int nextPage = currentPage + 1;
    // 다음 페이지가 현재 내가 등록해놓은 사진의 배열의 인덳스 보다 많다면? 다음페이지를 0 으로!
      if (nextPage > 2) {
        nextPage = 0;
      }
    // controller 의 animateToPage 로 페이지 이동시켜준다.
      controller.animateToPage(
          nextPage, duration: Duration(milliseconds: 400), curve: Curves.ease);
    });
  }

페이지를 바꿀수 있는 기능 이다.

controller.animateToPage( page: 어떤 페이지로 이동 시킬것인지, duration 이동하는 속도, curve : 애니메이션 지정)
  • 이제는 Controller 도 disPose 해주자!

모든 Controller 는 메모리 누수가 일어 날 수 있기에 종료를 시켜줘야한다! 

방금 만든 Controller 도 State 가 삭제 될때 Controller 도 종료되게끔, disPose 해주자!

...
@override
void dispose() {
// 추가!
 controller.dispose();

 if (timer != null) {
   timer!.cancel();
 }
 super.dispose();
}
...
꿀팁💡 상단 시간과 위젯 이미지들 색상 바꾸는 방법 💡
이미지의 배경화면 색상이 흰색이라면 상단 부분의 컬러가 white 이기 떄문에 안보인다. 그래서 바꿔주자!
...
import 'package:flutter/services.dart';

...

SystemChrome.setSystemUIOverlayStryle(SystemUiOverlayStyle.light); // 흰색
SystemChrome.setSystemUIOverlayStryle(SystemUiOverlayStyle.dark); // 검은색

완성 코드 ) 

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Timer? timer;
  PageController controller = PageController(
    initialPage: 0,
  );

  @override
  void initState() {
    super.initState();

    timer = Timer.periodic(Duration(seconds: 4), (timer) {
      int currentPage = controller.page!.toInt();

      int nextPage = currentPage + 1;

      if (nextPage > 2) {
        nextPage = 0;
      }

      controller.animateToPage(
          nextPage, duration: Duration(milliseconds: 400), curve: Curves.ease);
    });
  }

  @override
  void dispose() {
    controller.dispose();

    if (timer != null) {
      timer!.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

    return Scaffold(
      body: PageView(
        controller: controller,
        children: [2, 3, 4].map(
                (e) => Image.asset('asset/img/img$e.HEIC', fit: BoxFit.cover)
        ).toList(),
      ),
    );
  }
}

끝으로...

  1. pageController 를 따로 생성해 pageView 가 생성될때 controller 를 넣어 줄 수 있다!
  2. 현재 페이지, 다음 페이지를 변수 선언해서 controller.animateToPage() 로 페이지를 이동 시킬수 있다! 
  3. 메모리 누수 방지를 위한 Controller 를 disPose() 할 수 있다.

 

728x90