이번에는 전자 액자 앱을 만들어 보자!!
여러 이미지를 슬라이딩하여 볼 수 있는 전자 액자이다.
Layout
- 위젯을 좌우로 스와이프 할 수 있는 PageView 하나로 구성
1. 앱에서 사용할 이미지를 가져온다.
- [프로젝트 디렉토리]/asset/img 폴더 아래에 이미지를 복사한다.
√ [프로젝트 디렉토리]/asset/img/image_1.jpeg
√ [프로젝트 디렉토리]/asset/img/image_2.jpeg
√ [프로젝트 디렉토리]/asset/img/image_3.jpeg
√ [프로젝트 디렉토리]/asset/img/image_4.jpeg
√ [프로젝트 디렉토리]/asset/img/image_5.jpeg
2. 추가된 이미지(에셋)을 pubspec.yaml 에 등록한다.
- [프로젝트 디렉토리]/pubspec.yaml
....
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- asset/img/
....
3. 앱의 기본 홈 화면으로 사용할 HomeScreen 위젯을 생성한다.
- [프로젝트 디렉토리]/lib/screen/home_screen.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Text('Home Screen'),
);
}
}
4. 앱 실행 시 HomeScreen 을 사용하도록 한다.
- [프로젝트 디렉토리]/lib/main.dart
import 'package:[프로젝트 이름]/screen/home_screen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeScreen(),
),
);
}
5. PageView 구현
- PageView 는 여러개의 위젯을 독립적인 페이지로 생성하고 가로 또는 세로 스와이프로 페이지를 넘길 수 있게 하는 위젯이다.
- PageView 는 material 패키지에서 기본으로 제공
- children 변수에 페이지로 생성하고 싶은 위젯을 넣어준다.
- 핸드폰 크기와 이미지의 크기가 달라서 위아래로 흰색 여백이 생길수 있다. 핸드폰 화면 비율에 따라 위아래 대신 좌우가 남거나 운좋게 딱 맞을 수 도 있다. 여러 비율의 화면에 대응할 수 있게 이미지 fit 을 조절해줘서 항상 전체 화면을 차지하도록 설정한다.(fit: BoxFit.cover)
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
// ➊ PageView 추가
children: [1, 2, 3, 4, 5] // ➋ 샘플 리스트 생성
.map(
// ➌ 위젯으로 매핑
(number) => Image.asset(
'asset/img/image_$number.jpeg',
fit: BoxFit.cover,
),
)
.toList(),
),
);
}
}
- BoxFit 관련해서는 Flutter 설명 페이지를 참고.
6. 상태 바 변경
- 상태바 : 앱 실행중에 배터리, 시간, 와이파이 연결 상태 등을 보여주는 영역
- 상태바의 글자 및 아이콘 색상이 검정색이라 잘 안보여 흰색으로 변경.
- SystemChrome 클래스 : 시스템 UI 의 그래픽 설정을 변경하는 기능 제공.
- 상태바 변경 : SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 상태바가 이미 흰색이면 light 대신 dark 로 설정하여 검정색으로 변경.
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
return Scaffold(
body: PageView(
controller: pageController,
children: [1, 2, 3, 4, 5]
.map(
(number) => Image.asset(
'asset/img/image_$number.jpeg',
fit: BoxFit.cover,
),
)
.toList(),
),
);
}
}
7. 타이머 추가
- 일정 시간이 지나면 자동으로 페이지가 변경되도록 Timer 클래스를 사용하여 자동 롤링 기능 추가.
※ Timer 를 추가하려면 HomeScreen 위젯을 StatelessWidget 이 아닌 StatefulWidget 으로 변경해야 한다. StatelessWidget 위젯을 사용하면 Timer 를 build() 에서 등록해야 하는데 이럴경우 위젯이 새로 생성될 때마다 매번 새로운 Timer 가 생성된다. 이렇게 구현하면 Memory leak 이 발생한다.
- 따라서, StatefulWidget 위젯을 사용하여 initState() 에서 한번만 Timer 를 등록하여 구현하면 된다.
- Timer 를 사용하기 위해 async 패키지를 import 한다.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async'; // ❶ async 패키지
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
// ❷ State 정의
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState(); // ➌ 부모 initState() 실행
Timer.periodic(
// ➍ Timer.periodic() 등록
Duration(seconds: 3),
(timer) {
print('실행!');
},
);
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
return Scaffold(
body: PageView(
controller: pageController,
children: [1, 2, 3, 4, 5]
.map(
(number) => Image.asset(
'asset/img/image_$number.jpeg',
fit: BoxFit.cover,
),
)
.toList(),
),
);
}
}
① Timer 를 사용하기 위해 async 패키지를 import 한다.
② initState() 함수를 override 하면 StatefulWidget 생명주기에서의 initState() 함수를 사용할 수 있다.
③ 모든 initState() 함수는 부모의 initState() 함수를 호출해야 한다.
④ 3초마다 실행되는 Timer 등록.
8. PageController 사용
- PageView 를 조작하기 위해 PageController 사용.
- PageController 를 State 에 선언하고 PageView 에 매개변수로 입력
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// ❶ PageController 생성
final PageController pageController = PageController();
@override
void initState() {
super.initState();
Timer.periodic(
Duration(seconds: 3),
(timer) {
// ➌ 현재 페이지 가져오기.
int? nextPage = pageController.page?.toInt();
// 페이지 값이 없을 때 예외 처리
if (nextPage == null) {
return;
}
// 첫페이지와 마지막 페이지 분기 처리
if (nextPage == 4) {
nextPage = 0;
} else {
nextPage++;
}
pageController.animateToPage(
// ➍ 페이지 변경
nextPage,
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
);
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
return Scaffold(
body: PageView(
// ❷ PageController 등록
controller: pageController,
children: [1, 2, 3, 4, 5]
.map(
(number) => Image.asset(
'asset/img/image_$number.jpeg',
fit: BoxFit.cover,
),
)
.toList(),
),
);
}
}
① PageController 사용을 위한 생성.
② PageView 에 매개변수로 PageController 등록
③ pageController.page Getter 를 사용하여 PageView 의 현재 페이지를 가져올 수 있다. 페이지가 변경 중인 경우 소수점으로 표현돼서 double 로 값이 반환된다. animateToPage() 함수 실행시 정수값을 넣어줘야해서 toInt() 로 변환한다.
④ animateToPage() 함수를 이용해서 PageView 의 현재 페이지를 변경할 수 있다. curve 매개변수는 페이지가 변경되는 애니메이션의 작동 방식을 정의한다. 공식 홈페이지에서 애니메이션을 확인할 수 있다.
이제 모든 코드 작성이 끝났다.
열심히 만든 앱을 실행 시켜보자.
짜잔~~~ 나만의 액자 앱이 잘~~ 만들어 진 것을 확인할 수 있다!!
'프로그래밍 > 플러터 Flutter' 카테고리의 다른 글
[플러터] 20. setState() 상태 관리 (0) | 2023.05.12 |
---|---|
[플러터] 19. 빌드 에러(FAILURE: Build failed with an exception. You need Java 11) (1) | 2023.05.10 |
[플러터] 17. 위젯의 생명주기(Life Cycle) (0) | 2023.05.08 |
[플러터] 16. 웹 앱 만들기 (2/2) - 구현 (0) | 2023.05.05 |
[플러터] 15. 웹 앱 만들기 (1/2) - 플러그인 및 설정 (0) | 2023.05.04 |