FloatingActionButton 넣는 법
MaterialApp(
home: Scaffold(
floatingActionButtion: FloatingActionButton(
child : Text('버튼'),
onPressed: (){}
),
appBar: AppBar(),
body: 생략
),
)
이러면 하단에 공중에 뜬 버튼을 만들 수 있습니다.
이상하지만 FAB이라고 줄여서 많이 부릅니다.
버튼 누르면 기능을 실행해보자
버튼 눌렀을 때 코드를 실행하고 싶은 경우
onPressed(){ 여기에 다 담으면 됩니다~~~ }
그래서 테스트삼아서 버튼을 누르면
위에 있는 a 라는 변수를 +1 해봅시다.
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
var a = 1;
@override
Widget build(BuildContext context) {
return MaterialApp(
home : Scaffold(
floatingActionButton: FloatingActionButton(
child: Text(a.toString()),
onPressed: (){ a++; print(a); },
),
body: ,
appBar: AppBar(),
)
);
}
}
a라는 변수가 너무 자랑스러운 나머지
실제 위젯안에서 확인하고 싶어서
(Text 위젯 안엔 문자만 입력가능해서 문자변환 함수를 붙여줬습니다)
근데 버튼 눌러도 a의 변화사항이 반영되지 않습니다.
이게 어떻게된 일입니까
답은 그냥 위젯이 다시 렌더링되지 않아서 그렇습니다.
위젯은 재렌더링해야 변경사항이 보임
위젯 안에 있는 변수같은게 변해도 위젯이 똑같이 보이는 이유는
변수는 +1이 되었지만 위젯이 재렌더링되지 않아서 그렇습니다.
그래서 변수가 변하면 재렌더링을 강제로 시켜주든 그러셔야합니다.
재렌더링은 위젯을 다시 그린다는 소리입니다.
근데 어떻게 재렌더링할지는 생각만해도 복잡할듯
state라는걸 이용하면 자동으로 재렌더링되게 만들 수 있습니다.
state는 변수랑 똑같은건데 근데 state는 변경사항이 생기면 state를 쓰고 있는 위젯이 자동으로 재렌더링됩니다.
그냥 그렇게 동작합니다.
그래서 님들이 좋아요 숫자를 일반 변수가 아니라 state 라는걸로 만들어서 저장해놓으면
이제 좋아요가 +1 될 때마다 자동으로 재렌더링 될겁니다.
state 만드는 법을 알아봅시다.
StatefulWidget 만들기
실은 state 만들어 쓰려면 state 보관함 + 커스텀 widget 이렇게 한 세트를 만들어야합니다.
어려운건 아니고 아래처럼 몇줄 쓰면 됩니다.
복붙할 필요는 없고 stful 이라고 아무데나 입력하고 탭이나 엔터 누르시면 자동완성 됩니다.
class 테스트 extends StatefulWidget {
const 테스트({Key? key}) : super(key: key);
@override
_테스트State createState() => _테스트State();
}
class _테스트State extends State {
var a = 1; //여기 만드는 변수는 state가 됩니다
@override
Widget build(BuildContext context) {
return Container();
}
}
딱봐도 예전에 했던 커스텀위젯만드는 문법이랑 비슷하군요.
근데 이번 커스텀위젯은 state기능을 쓸 수 있는 위젯입니다.
1. 위에 있는 class는 건드릴 필요 없습니다.
2. 둘째 class 안에 변수를 만들면 자동으로 state가 됩니다.
이제 a라는 state 변경하면 자동으로 재렌더링되는 것임
아니면 기존 위젯을 StatefulWidget으로 바꾸기
우리가 계속 쓰던 MyApp이라는 위젯을 잘 보면 StatelessWidget입니다.
이걸 StatefulWidget으로 바꾸면 그냥 거기에 state를 만들어쓸 수도 있겠군요.
그럼 MyApp 여기에 커서 올리고 왼쪽 전구버튼 눌러서 StatefulWidget으로 바꾸기 누르면 됩니다.
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
var a = 1; //여기 만드는 변수는 state가 됩니다
@override
Widget build(BuildContext context) {
return Scaffold(생략);
}
}
MyApp안에서 state기능을 쓰고 싶으니 MyApp을 StatefulWidget으로 변경한 상태로 시작해봅시다.
그래서 state를 변경해봤는데
그래서 버튼 누르면 a를 ++ 해주라고 코드를 짜봤습니다.
MaterialApp(
home: Scaffold(
floatingActionButtion: FloatingActionButton(
child : Text(a.toString()),
onPressed: (){ a++ }
),
appBar: AppBar(),
body: 생략
),
)
a는 state이므로
a를 변경했으니 자동으로 위젯도 재렌더링 되어야하지 않겠습니까
그럼 변화하는 a 모습도 잘 보일 것 같습니다.
근데 안되는데요 사기꾼인듯
state 변경은 무조건 setState 함수로
문법 하나만 더 배우셔야합니다.
state 변경을 하고 싶으면 setState((){ 변경할내용 }) 여기 안에 하셔야합니다.
MaterialApp(
home: Scaffold(
floatingActionButtion: FloatingActionButton(
child : Text(a.toString()),
onPressed: (){
setState((){
a++
});
}
),
appBar: AppBar(),
body: 생략
),
)
setState((){ }) 안에 넣었더니
이제 진짜로 버튼 누르면 a가 +1 되고
state가 변화했으니 진짜 재렌더링까지 잘 됩니다.
https://aloe-study.tistory.com/50
setState((){ }) 를 사용 하는 이유는 immutable 프로그래밍을 한다고 생각하면 됨
정리
1. 데이터 변동사항이 잦을 것 같은 커스텀위젯은 전부 StatefulWidget (stful) 으로 만드십시오.
2. StatefulWidget 안에서 만든 변수는 state라고 합니다. state 바꾸면 해당 위젯도 자동 재렌더링 됩니다.
3. 근데 state 변경하고 싶으면 setState((){ }) 써서 바꾸셔야합니다.
변수랑 state 차이가 뭔가요?
A. 그냥 StatefulWidget안에 변수만들면 다 state입니다 다른데 만든건 그냥 변수
Q. 그럼 우리 사이트 로고 이런 것도 state로 만들어놓으면 좋겠군요?
A. 로고는 10년에 한번 바뀌기 때문에 굳이 state로 넣을 필요가 없습니다.
자주 바뀌는 데이터들을 주로 state에 보관하시길 바랍니다.
참고 : class 대신 변수 함수 써도 됩니다
변수와 함수 문법은 긴 코드 짧은 단어로 바꿔주는 문법일 뿐이라
길고 긴 위젯들을 변수 함수에 담아써도 전혀 문제없습니다.
하지만 변수 함수에 담아써도 문제 없는 위젯들은 재렌더링이 거의 필요없는 위젯들입니다.
앱바, 하단바, 다이얼로그 안내문 이런 것들이요
재렌더링이 자주 되는 것들은 stateful 아니면 stateless 클래스로 만들어야 성능저하가 없습니다.
친구 이름도 state로 만들어서 넣어보자
지금 친구이름이 Text('홍길동') 이렇게 하드코딩 되어있는데
이것도 state로 보관한다음에 위젯으로 보여주면
나중에 친구이름 변동사항이 생기면 바로바로 재렌더링되겠군요?
유용할 것 같으니 state로 만들어둡시다.
class _MyAppState extends State {
var a = 1;
var name = ['김영숙', '홍길동', '피자집'];
@override
(생략)
}
▲ MyApp안에 state를 만들고 이름 3개를 집어넣어봤습니다.
[] 이건 List 문법입니다 변수 하나에 여러 문자나 숫자를 동시에 저장하고 싶으면 [] 안에 저렇게 담습니다.
앞으로 꺼낼 땐 name[1] 이렇게 하면 '홍길동' 나옴
ListView.builder(
itemCount: 3,
itemBuilder: (context, i) {
return ListTile(
leading : Image.asset('profile.png'),
title : Text(name[i]),
)
}
);
▲ 중간에 친구 이름으로 리스트 3개 만들어주는 부분도 이렇게 바꿔봤습니다.
그럼 진짜 친구 이름을 하나씩 출력해주는군요.
하지만 Text(name[i]) 이게 뭔지 모르겠다고요?
i는 리스트가 복붙될 때 마다 1씩 증가하는 정수입니다.
첫째 리스트가 생성되면 Text(name[0])이 그 자리에 남습니다.
둘째 리스트가 생성되면 Text(name[1])이 그 자리에 남습니다.
셋째 리스트가 생성되면 Text(name[2])이 그 자리에 남습니다.
이름 옆에 좋아요 버튼과 좋아요 갯수를 만들어봅시다.
그리고 좋아요 버튼 누르면 옆에 있는 숫자가 +1 되어야합니다.
코드를 어떻게 짜야할까요?
(힌트) 일단 좋아요 갯수를 저장해둘 state가 필요하겠군요.
var like = [0, 0, 0]; 이렇게 만드는게 어떨까요
class _MyAppState extends State {
var name = ['김영숙', '홍길동', '피자집'];
var like = [0, 0, 0];
@override
(생략)
}
▲ MyApp안에 state를 만들어놨습니다. 각각 첫 친구 둘째 친구 셋째 친구의 좋아요 갯수를 기록할 공간입니다.
var like = 0; 왜 이렇게 안했냐고요?
세명 다 각각 좋아요 갯수가 개별적으로 기록되어야하니까요
ListView.builder(
itemCount: 3,
itemBuilder: (context, i) {
return ListTile(
title : Text(name[i]),
trailing: ElevatedButton(child: Text('좋아요'), onPressed: (){
setState(() {
like[i]++;
});
}),
)
}
);
▲ 목록에 버튼 하나추가해봤고
그 버튼을 누르면 like가 +1 되게 했습니다.
정확히 말하면
0번째 버튼을 누르면 like[0]++
1번째 버튼을 누르면 like[1]++
2번째 버튼을 누르면 like[2]++
이러라고 했습니다.
like[i]++
이렇게 쓰면 됩니다.
왜냐면 i라는 변수는 반복문이 돌 때 마다 0부터 1씩 증가하는 변수라 그렇습니다.
님들이 좋아요 갯수를 출력해보고 싶으면 이미지 있던 자리에
leading: Text(like[i].toString())
넣어보면 좋아요 갯수도 잘 보이겠군요.
--------------
코딩애플님 플러터 강의를 참고해서 작성한 정리 글입니다. 강추 꼭 들으시길 바랍니다
'APP > Flutter' 카테고리의 다른 글
플러터 state를 자식 위젯에서 쓰고 싶다면 3 step 이용 (0) | 2022.08.07 |
---|---|
플러터 Dialog/모달창 만드는 법과 context가 뭔지 (0) | 2022.08.05 |
플러터 스크롤바 만들어주는 ListView 위젯 (0) | 2022.08.05 |
코드가 길어지면 커스텀 위젯만들기 (0) | 2022.08.05 |
플러터 화면 비율 조절하기 Expanded() Flexible() 위젯 (0) | 2022.08.05 |