이번에는 StatefulWidget에 대해 알아보겠습니다.
지금까지 사용하던 StatelessWidget은 위젯의 속성을 변경할 수 없는데,
StatefulWidget을 사용하면 변경시킬 수 있다고 합니다.
실시간으로 상태가 변하는 복잡한 앱에 반드시 쓰일 것 같습니다.
내용이 좀 어렵지만, 이해한대로 간단히 설명해본다면,
기본적으로 State가 dirty 상태일때 build가 실행된 후 clean 상태가됩니다.
그런데 StatefulWidget은 State를 변경 시킬 수 있어서 setState를 사용하면 State가 dirty로 변하면서 반복..
즉, 이걸 이용하면 build를 여러번 실행시킬 수 있는겁니다. (StatelessWidget은 한번)
이번에는 이미지 슬라이딩을 해볼건데, assets에 바로 이미지를 넣었던 것을, img 폴더를 추가하고 그곳으로 옮기겠습니다.
assets:
- assets/img/
pubspec.yaml 을 수정하고, 이미지를 이동 및 추가 했습니다.
그리고 지금까지는 main.dart를 수정해서 사용했었는데,
Practice라는 폴더에 하나씩 추가하도록 하겠습니다.
일단 slide.dart라는 파일을 만들었습니다.
import 'package:flutter/material.dart';
class Slide extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}
StatefulWidget을 상속받으면 반드시 createState를 구현해주어야 합니다.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Slide extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return SildeState();
}
}
class SildeState extends State<Slide>{
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}
State를 상속받는 SlideState라는 클래스를 만들고, 이걸 createState에서 반환받도록 하겠습니다.
class Slide extends StatefulWidget{
const Slide({Key? key}) :super(key:key);
@override
State<StatefulWidget> createState() {
return SildeState();
}
}
class SildeState extends State<Slide>{
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
children: ['perth_lfet.png','hika_outpost.png'].map((img) => Image.asset(
'assets/img/$img',
fit:BoxFit.cover,
),
).toList(),
),
);
}
}
생성자를 만들어 두고, build를 구현합시다. 이번에는 PageView를 사용합니다.
PageView는 children을 사용하는데, 대괄호에는 이미지 이름들을 넣어두고 map을 통해서
Image 위젯의 실제 이미지 경로를 설정합니다.
그리고 이미지가 부모 위젯을 덮도록 fit: BoxFit.cover을 추가합니다.
이렇게 하면 이미지 위젯 두개가 만들어지고, 이걸 toList 함수를 통해 리스트로 만들어 반환합니다.
컨트롤러를 만들고, PageView에 contoller을 추가했습니다. ( PageView 조작에 필요합니다.)
그리고 페이지 길이를 구하기 위해서 컨트롤러 아래 선언해놓고,
map에서 페이지의 개수를 하나씩 더하도록 코드를 수정했습니다.
이미지 이름에 오타가 있어서 고치고 이미지가 적은 것 같아 3개를 더 넣었습니다.
class SildeState extends State<Slide>{
final PageController pageController= PageController();
int pageLength=0;
@override
void initState() {
super.initState();
Timer.periodic(
Duration(seconds: 2),
(timer){
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
children: ['perth_left.png','hika_outpost.png','blen_castle_out_ai.png',
'blen_map1.jpg','blen_map1_ai.jpg'].map((img) {
pageLength++;
return Image.asset(
'assets/img/$img',
fit:BoxFit.cover,
);
}
).toList(),
),
);
}
}
2초마다 화면을 갱신하도록 하기 위해서 initState에 Timer를 넣었습니다.
이부분 구현하겠습니다.
class SildeState extends State<Slide>{
final PageController pageController= PageController();
int pageLength=0;
@override
void initState() {
super.initState();
Timer.periodic(
Duration(seconds: 2),
(timer){
int? next = pageController.page?.toInt();
if(next==null){
return;
}
if(next==pageLength-1){
next=0;
}else{
next++;
}
pageController.animateToPage(next, duration: Duration(microseconds: 1000), curve: Curves.easeInCubic)
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
children: ['perth_left.png','hika_outpost.png','blen_castle_out_ai.png',
'blen_map1.jpg','blen_map1_ai.jpg'].map((img) {
pageLength++;
return Image.asset(
'assets/img/$img',
fit:BoxFit.cover,
);
}
).toList(),
),
);
}
}
페이지가 없을 경우 예외처리,
페이지가 마지막 페이지일 경우 처음으로 돌리기,
마지막이 아니면 페이지 증가,
실제 페이지 이동시키는 함수 순서대로 코딩했습니다.
마지막의 매개변수는
1. 이동시킬 페이지 인덱스
2. 이동에 걸릴 시간 (저는 1000밀리초인 1초로 해놓았습니다.)
3. 이동을 어떤 방식으로 보여줄 것인지? (이건 ctrl+space로 여러가지 방법을 직접 설정해볼 수 있습니다.)
를 나타냅니다.
오류가 안나길 기도하며 한번 실행해보겠습니다.
실행하려는데 main.dart만 보이고 slide.dart가 안보여서 잘 살펴보니 main을 안써줬더라고요.
runApp도 없는데 돌아갈리가 없죠..
void main(){
runApp(MaterialApp(
home: Slide(),
),
);
}
다시 실행해보겠습니다.
코드에 대고 우클릭하면 run 할 수 있는 옵션이 있습니다. 그걸로 실행하겠습니다.
만약 실행 자체가 안되신다면,
이거 설정 되어있나 확인해주세요. 새로 만든건 이 값이 비어있더라고요.
크롬과 안드로이드를 둘다 돌려 봤는데,
둘다 2초마다 이미지가 변경되긴 했지만 다른점이 있었습니다.
크롬은 스와이프가 안먹히고, 안드로이드만 먹히더라고요.
둘다 마우스 가지고 밀긴 했지만, 웹 자체는 스와이프를 인지할 수 있는 기능이 기본적으로는 없지 않은가 생각해봅니다.
이번 글은 여기까지입니다.
감사합니다~