https://product.kyobobook.co.kr/detail/S000208993133
본격적인 대회 작업물 개발 전 마지막으로, 이 책의 챕터 3/4를 보고 개발에 들어갈 예정이다
< chap 3 : 앱 개발 과정 빠르게 훑어보기 >
데일리 캣츠 앱 -> 고양이 사진 리스트 조회, 상세 조회, 업로드, 댓글, 좋아요, 신고 등의 기능 구현 예정
화면 구성 -> 사진 리스트 화면, 사진 상세 화면, 사진 업로드 화면
컴포넌트 구성 -> 사진 리스트화면 : 앱바(제목, 업로드버튼) / 고양이 사진 목록
사진 상세 화면 : 앱바(제목, 뒤로가기) / 고양이 사진 / 작성자 이름 및 좋아요 수 / 댓글관련
사진 업로드 화면 : 앱바(저장,취소 버튼) / 고양이사진 업로드 버튼
//나는 이전에 다운받은 풍경 사진을 이용해서, 데일리 풍경 앱으로 만들어볼 예정
파일 구조는 이전에 했던 것과 유사 (assets / lib - models/screens/main.dart)
1) 풍경 클래스 작성
각각의 풍경 게시물을 하나의 scenery 클래스로 정의
- 풍경과 게시물 간의 관계가 1대1이라고 가정
- 하나의 풍경이 여러 게시물에 대응될 경우, 풍경과 게시물을 별개 클래스로 작성
- 풍경 클래스의 필드값 : id(게시물 고유 아이디), name, title(제목), link(사진 링크), likeCount, replyCount, created(생성시각)
- lib 폴더 안에 model 폴더를 생성하고, 그 안에 scenery.dart 파일 생성
scenery.dart를 위와 같이 작성한다 (필드와 생성자 작성)
required 키워드 : 해당 클래스를 초기화하기 위해 꼭 넣어주어야 하는 값임을 의미 - 위 클래스에서 필드값들은 모두 final이며, null일 수 없음 -> 무조건 초기값 존재해야 -> required 키워드 필요 (null이 가능하다면 이 키워드 필수 아님)
위의 생성자 문법은 다트에서의 축약된 생성자 문법
* { } 는 명명된 매개변수 (네임드 파라미터) 임을 의미 -> 명명된 매개변수는 호출할 때 매개변수의 이름을 명시하여 값을 전달할 수 있는 방식, 함수 호출 시 인자의 순서를 신경 쓰지 않고도, 매개변수에 원하는 값을 할당할 수 있음
Scenery scenery = Scenery(
id: '001',
name: 'Beautiful Mountain',
title: 'A breathtaking view',
link: 'http://example.com',
likeCount: 100,
replyCount: 20,
created: DateTime.now(),
);
추후 이런식으로 사용이 가능
2) ui 작업
- 화면의 ui 작성하고, 화면 네비게이션 구현
- 리스트 화면을 작성하기 위해, screens 폴더 밑에 list_screen.dart 파일을 생성하고 stf를 입력하면 자동으로 stateful 위젯 코드 틀을 만들어준다 (stateless는 stl)
- 이 상태에서 ListScreen이라는 텍스트를 입력하면 관련 이름을 다 자동으로 바꿔준다
- build 부분만 스캐폴드로 바꾸고 일단 넘어감
- main.dart 코드
- MaterialApp의 theme 속성은 앱 전체의 테마를 정의한다. 이를 통해 버튼, 텍스트, 배경 등의 스타일이 앱 전체에서 통일되도록 관리할 수 있음
- primarySwatch는 앱의 주요 색상을 정의한다. Colors.indigo는 미리 정의된 색상 팔레트 중 하나로, indigo 색상 계열의 다양한 음영을 포함하고 있음. 이 색상 팔레트는 버튼, AppBar, 강조 표시 등에서 기본적으로 사용됨
- primarySwatch는 색상 하나만 설정하는 것이 아니라, 여러 단계의 음영을 포함하는 색상 팔레트로, 밝은 색상부터 어두운 색상까지 다양한 음영을 포함하고 있다 -> Flutter 위젯에서 필요한 곳에 자동으로 이 팔레트의 다양한 음영이 적용됨
3) 앱바 작성하기
이렇게 해서 앱바를 만들었다 (근데 카메라 아이콘까지 기본제공을 해준다... 진짜신기)
4) Body 작성
- ListView 위젯은 가로 혹은 세로 하나의 축으로만 항목 배열 가능 -> 우린 바둑판 모양으로 이미지 배열 할거니까 그리드뷰 사용
- GridView.builder 형태로 사용하면 itemCount번 만큼 itemBuilder가 반복되어 각 항목 생성(인덱스는 0부터 itemCount-1까지)
아직 서버가 없으니 풍경 객체를 수동으로 생성해줌
위와 같은 화면 ui가 완성된다
5) 상세 화면
코드 기본 틀과 설명(사진 속 주석)
이후 ListView의 children을 작성한다 (기본적으론 위에서 밑으로 위젯 배치, 같은 줄에 배치해야하는 위젯은 row위젯의 children으로 묶어줌)
리스트뷰의 자식은 다음과 같다
- AspectRatio를 통해, 이미지를 1:1 비율로 넣어준다
- 그 밑에 row 위젯으로 글 제목과 (아이콘+좋아요수)를 넣어준다
- 그 밑에 댓글 개수를 넣고
- 댓글 내용들을 넣는다 (익명과 댓글 내용은 가로배치)
- 그 후 ListScreen으로 이동하여 그리드 사진들 중 하나를 누르면 DetailScreen으로 이동하도록 한다
-> 이렇게 하면 그리드 화면에서 사진을 하나 선택하면 위의 상세화면으로 이동한다
<네비게이션>
- 네비게이션의 출발점은 리스트화면, 도착지점은 상세화면
- 화면 전환 과정에서 현재 풍경 객체 정보(사용자가 클릭한)를 넘겨주어야 한다
- 네비게이션의 트리거는 개별 풍경 사진을 터치하는 것 : GestureDetector의 onTap에 해당
- push()메소드를 사용하면, 앱바의 뒤로가기 버튼 및 동작은 자동으로 구현된다
- 스택의 원리
6) 상태관리
- 앱 내에는 고정된 텍스트도 있는 반면, 사용자와의 상호작용에 의해 변화하는 텍스트도 있다
- 텍스트 외에도, 화면에 보이는 모든 것들은 변화하는 요소 / 변화하지 않는 요소로 나눌 수 있다
- 이 중 변화하는 요소, 즉 자기 자신의 값이 바뀜에 따라 화면을 갱신하게 되는 데이터를 상태(state)라고 한다
- 또한 이러한 상태를 관리하는 것을 상태 관리라고 한다
- 우리가 만들고 있는 앱 중, 좋아요 버튼 동작을 구현해보자
- 좋아요 버튼은 일종의 스위치이다 (좋아요가 해제된 상태에서 버튼을 터치하면 좋아요가 설정되고, 반대로 좋아요가 설정된 상태에서 버튼을 터치하면 좋아요가 해제된다) -> 좋아요는 설정 상태/해제 상태 단 두가지 경우만 존재 -> 불리언타입 변수로 나타낼 수 있다
- 기본값은 좋아요 해제(false)
- 좋아요 상태의 값이 바뀔 때마다 화면에 반영되어야 한다 = 해당 변수가 상태 여야 한다
- 상태에 해당하는 변수의 값이 바뀔 땐 화면이 업데이트되고, 상태가 아닌 변수의 값이 바뀔땐 화면이 업데이트되지 않는 것이 플러터의 원칙
- 변수가 상태가 되려면? state를 상속받은 클래스 내부에서 선언되어야 하고, 변수 값을 변경할 때 플러터가 제공하는 방식을 사용해야한다
- 우선 이런 변수를 하나 선언한다 (state를 상속받은 클래스 내부에서 선언)
- 그 후 아이콘 부분에서의 코드를 위와 같이 변경한다 : isLiked가 true이면 색칠된 따봉 이모티콘, 아니면 색칠 안된 따봉 이모티콘 나오도록
- onPressed 시에, setState(이게 앞서 말한 플러터에서 제공하는 방식)를 사용해서, isLiked를 기존의 반대값(참->거짓, 거짓->참) 으로 바꿔주도록 설정한다
- 이제 좋아요 이모티콘을 누르면 위 사진처럼 변경되는 것 확인 가능
+ 전역상태란? 풍경 사진 목록에서, 목록은 업로드 화면에서 만들어지지만 리스트 화면에서 표시가 되어야함 -> 이렇게 여러 위젯을 넘나들며 사용되는 상태가 전역상태 -> 추후 더 다룸
완전하진 않지만 상태관리까지 대략 느낌을 살펴보았고, 다음 챕터에서 앱 개발에서의 전반적 내용들을 더 딥하게 다룬다
'dev > 프론트엔드' 카테고리의 다른 글
SeQR 개발일지 (0) | 2024.09.25 |
---|---|
flutter : 앱 개발 과정 정확하게 톺아보기 (0) | 2024.09.22 |
코드팩토리 flutter : 3장 chap 8 (0) | 2024.09.18 |
코드팩토리 flutter - 2장 chap 6 (0) | 2024.09.18 |
코드팩토리 flutter : 2장 - chap 4,5 (0) | 2024.09.16 |