728x90
- PageController를 사용해 슬라이드를 제어
- Timer.periodic으로 3초마다 다음 페이지로 이동
- 마지막 이미지에 도달하면 처음으로
- 페이지 이동에는 animateToPage를 사용해 부드러운 전환을 구현
- dispose()에서 타이머와 컨트롤러 정리
전체 코드
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '자동 이미지 갤러리',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AutoSlidingGallery(), // 홈 화면 지정
);
}
}
class AutoSlidingGallery extends StatefulWidget {
const AutoSlidingGallery({super.key});
@override
_AutoSlidingGalleryState createState() => _AutoSlidingGalleryState();
}
class _AutoSlidingGalleryState extends State<AutoSlidingGallery> {
final PageController _pageController = PageController();
final List<String> _imageUrls = [
'https://picsum.photos/id/1018/600/400',
'https://picsum.photos/id/1023/600/400',
'https://picsum.photos/id/1043/600/400',
'https://picsum.photos/id/1057/600/400',
];
int _currentPage = 0;
Timer? _timer;
@override
void initState() {
super.initState();
// 3초마다 페이지 넘기기
_timer = Timer.periodic(Duration(seconds: 3), (Timer timer) {
if (_currentPage < _imageUrls.length - 1) {
_currentPage++;
} else {
_currentPage = 0;
}
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
});
}
@override
void dispose() {
_pageController.dispose();
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("자동 이미지 갤러리")),
body: PageView.builder(
controller: _pageController,
itemCount: _imageUrls.length,
itemBuilder: (context, index) {
return Image.network(
_imageUrls[index],
fit: BoxFit.cover,
width: double.infinity,
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return Center(child: CircularProgressIndicator());
},
);
},
),
);
}
}
전체 코드 구조
MyApp
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '자동 이미지 갤러리',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AutoSlidingGallery(), // 홈 화면
);
}
}
- 앱 전체의 테마와 구조를 설정하는 루트 위젯
- MaterialApp은 Material 스타일 앱을 생성
- home: 속성으로 앱 시작 시 보여줄 화면을 AutoSlidingGallery로 지정
AutoSlidingGallery
class AutoSlidingGallery extends StatefulWidget {
@override
_AutoSlidingGalleryState createState() => _AutoSlidingGalleryState();
}
- StatefulWidget으로 만든 이유: 시간마다 자동으로 상태 변경(페이지 전환) 되기 때문
- createState()가 연결된 _AutoSlidingGalleryState가 실제 동작 처리
_AutoSlidingGalleryState
class _AutoSlidingGalleryState extends State {
final PageController _pageController = PageController();
final List _imageUrls = [
'https://picsum.photos/id/1018/600/400',
'https://picsum.photos/id/1023/600/400',
'https://picsum.photos/id/1043/600/400',
'https://picsum.photos/id/1057/600/400',
];
- PageController: 페이지를 프로그래밍적으로 제어 (전환할 때 사용)
List<String>: 갤러리에 보여줄 이미지 URL 리스트
int _currentPage = 0;
Timer? _timer;
- _currentPage: 현재 보여지고 있는 페이지 번호 저장
- _timer: 3초마다 자동 슬라이드를 수행할 타이머
initState()
@override
void initState() {
super.initState();
_timer = Timer.periodic(Duration(seconds: 3), (Timer timer) {
if (_currentPage < _imageUrls.length - 1) {
_currentPage++;
} else {
_currentPage = 0;
}
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
});
}
- 위젯이 처음 생성될 때 호출됨
- Timer.periodic()을 사용해 3초마다 실행되는 함수 등록
- 페이지 끝까지 갔다면 다시 처음으로 돌아가도록 로직 작성
- animateToPage()로 부드럽게 전환
dispose()
@override
void dispose() {
_pageController.dispose();
_timer?.cancel();
super.dispose();
}
- 위젯이 제거될 때 호출
- 리소스 정리:
- PageController 해제
- Timer 중지
- 메모리 누수 방지 필수 처리!
build()
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("자동 이미지 갤러리")),
body: PageView.builder(
controller: _pageController,
itemCount: _imageUrls.length,
itemBuilder: (context, index) {
return Image.network(
_imageUrls[index],
fit: BoxFit.cover,
width: double.infinity,
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return Center(child: CircularProgressIndicator());
},
);
},
),
);
}
}
- 화면 UI 구성
- Scaffold: 기본 머티리얼 앱 구조 (AppBar + Body)
- PageView.builder: 페이지 형태로 이미지 넘기기 구현
- controller: 우리가 선언한 _pageController
- itemBuilder: 각 페이지에 보여줄 Image.network
- BoxFit.cover: 이미지를 화면 가득 채우되, 비율 유지
- loadingBuilder: 이미지 로딩 중에는 로딩 인디케이터 표시
BoxFit 속성
속성 이름 | 설명 |
BoxFit.fill | 위젯의 크기에 정확히 맞게 이미지가 강제로 맞춰짐. 비율 무시. |
BoxFit.contain | 이미지의 비율을 유지하면서, 컨테이너 안에 완전히 들어가도록 축소/확대됨. (여백 생길 수 있음) |
BoxFit.cover | 이미지의 비율을 유지하면서, 컨테이너를 가득 채우도록 잘림 없이 확대됨. (일부 잘릴 수 있음) |
BoxFit.fitWidth | 이미지가 컨테이너의 너비에 맞춰짐, 비율 유지. 세로는 잘릴 수 있음. |
BoxFit.fitHeight | 이미지가 컨테이너의 높이에 맞춰짐, 비율 유지. 가로는 잘릴 수 있음. |
BoxFit.none | 이미지의 실제 크기로 표시됨. 컨테이너보다 크면 잘림. |
BoxFit.scaleDown | none과 같지만, 이미지가 너무 크면 축소됨. 크면 줄이고, 작으면 그대로. |
BoxFit 사용 예시
- 사진 썸네일: BoxFit.cover (잘라도 이쁨)
- 로고/아이콘: BoxFit.contain (비율 유지가 중요)
- 배경 이미지: BoxFit.cover or BoxFit.fill
- 이미지 원본 그대로: BoxFit.none
PageController
기능 | 설명 |
현재 페이지 추적 | .page, .hasClients, .initialPage 등을 통해 현재 위치 확인 가능 |
특정 페이지로 이동 | animateToPage(), jumpToPage() 등으로 프로그래밍적으로 페이지 전환 |
스크롤 위치 제어 | jumpTo()나 animateTo() 등으로 픽셀 단위 이동 가능 |
PageView 연결 | controller 속성에 넣어서 PageView와 연결 |
final PageController _controller = PageController(initialPage: 0);
1. 초기 페이지 지정
PageController(initialPage: 2); // 2번째 페이지부터 시작
2. 페이지 강제로 이동 (즉시)
_controller.jumpToPage(3); // 4번째 페이지로 "바로" 이동
3. 페이지 부드럽게 이동
_controller.animateToPage(
1,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
4. 현재 페이지 확인
double? currentPage = _controller.page; // 예: 2.0, 2.3 (스크롤 중이면 소수점)
5. 픽셀 위치로 이동
_controller.jumpTo(200.0); // 200픽셀 위치로 이동 (세부 스크롤 제어)
사용 예
- 자동 슬라이드 구현할 때 (animateToPage)
- 사용자 입력 없이 특정 페이지 보여줄 때
- 커스텀 페이지 인디케이터 만들 때
- 페이지 위치 감지해서 상태 반영할 때
728x90
'Flutter for Beginners' 카테고리의 다른 글
Flutter 디지털 시계에 주사위 굴리기 추가 (0) | 2025.04.03 |
---|---|
Flutter 디지털 시계 + 나침반 + 날씨정보 (0) | 2025.03.25 |
Flutter WebViewController를 이용한 블로그 앱 만들기 (0) | 2025.03.21 |
Flutter의 상태 관리 기본 개념 (setState vs. Provider) (0) | 2025.03.14 |
Flutter의 배치(Layout) 관련 위젯 (0) | 2025.03.14 |