코딩시 참고
View의 body 기본 구성
Section titled “View의 body 기본 구성”일반적으로 아래와 같이 배경색 지정
struct MyView: View { var body: some View { ZStack { Color.{색상}.ignoresSafeArea()
// 생략 } }}@State
Section titled “@State”@State private var currentUser: User? = nilprivate var초기값지정
memberwise init()
Section titled “memberwise init()”struct SpotifyCategoryCell: View { var title: String = "All"
// 생략}struct의 var는 기본적으로 자동으로 생성되는 memberwise init()함수의 인자로 받을 수 있게 됨
참고로, let을 사용하면 init()함수를 직접 작성해주어야 하기에 번거로움
SO, 보통 var를 사용하여 작업
var를 사용하더라도, internal(기본 접근 제한자)이 아닌 접근제한자를 사용해 선언하면, 제일 좁은 의미의 접근 제한자로 init()함수가 생성됨
SO, 외부에서 호출이 필요한 함수이기에 아무런 접근제한자도 두지 않고, internal로 자동 생성되는게 가장 좋음
@Binding
Section titled “@Binding”- 아무런 접근제한자 명시하지 않고 사용(기본
internal) - 외부에서 주입받을 값이라
초기값 지정하지 않음
#Preview
Section titled “#Preview”#Preview { ZStack { Color.black.ignoresSafeArea() // 배경색 검정인 상태로 preview를 보고 싶어서
VStack(spacing: 40) { // var 상태별로 preview 하고 싶어서 SpotifyCategoryCell(title: "Title gores here") SpotifyCategoryCell(title: "Title gores here", isSelected: true) SpotifyCategoryCell(isSelected: true)) } }}ZStack으로 감싸, 미리보기에 편한 배경색을 지정함VStack등으로 여러 상태의View들을 리스트업 함
하위뷰의 @State를 상위뷰로 옮겨서, 상위뷰에서 더 쉽게 상태 관리 가능하도록
Section titled “하위뷰의 @State를 상위뷰로 옮겨서, 상위뷰에서 더 쉽게 상태 관리 가능하도록”struct NetfilixFilterBarView: View { // 생략 var filters: [FilterModel] = FilterModel.mockArray //@State private var selectedFilter: FilterModel? = nil var selectedFilter: FilterModel? = nil var onFilterPressed: (() -> Void)? = nil // 생략}
// Preview도 외부에서 이제 줘야 하므로fileprivate struct NetflixFilterBarViewPreview: View { @State private var filters = FilterModel.mockArray @State private var selectedFilter: FilterModel? = nil
var body: some View { NetflixFilterBarView( filters: filters, selectedFilter: selectedFilter, onFilterPressed: { newFilter in selectedFilter = newFilter // State로 뺐지만, 어떤 상황에서 그 세팅할지도 외부에서 넘김 }}, // 생략 ) }}ForEach
Section titled “ForEach”struct SpotifyHomeView: View { @State private var selectedCategory: Category? = nil
var body: some View { // 생략 HStack(spacing: 8) { ForEach(Category.allCase, id: .\self) { category in SpotifyCategoryCell( title: category.rawValue, // rawValue는 enum값이 String으로 했으니 이름과 같은 문자열이 됨 isSelected: category == selectedCategory ) .onTapGesture { selectedCategory = category } } } }}String은rawValue에enum값과 동일한 이름의 문자열이 들어감Int는rawValue에0부터 자동 증가한 값이 들어감
KeyPath 표현식
Section titled “KeyPath 표현식”\ 기호로 KeyPath 생성
\Type.property
타입 추론 가능하면,Type생략 가능
ex. \.name
.\self: Identity KeyPath(자기 자신 참조)
View 담는 변수 사용
Section titled “View 담는 변수 사용”var body: some View { ZStack { // 배경색 설정, 생략
header // 이렇게 변수에 View 담은걸 여기서 사용 } // 생략}
private var header: some View { // 생략}전체 화면 세로 스크롤
Section titled “전체 화면 세로 스크롤”ScrollView(.vertical) { // 전체를 감싸고 // 생략}.scrollIndicators(.hidden) // 스크롤바 숨김보통, 스크롤바를 숨김
스크롤시, header는 위에 고정되고, 아래 뷰들만 스크롤 되도록
Section titled “스크롤시, header는 위에 고정되고, 아래 뷰들만 스크롤 되도록”Lazy류 Stack을 사용하면 됨
거기엔 pinnedViews 항목이 존재함
ScrollView(.vertical) { LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders], content: { Section { ForEach(0..<20) { _ in Rectangle() .frame(width: 200, height: 200) } } header: { // sectionHeaders header } }) .padding(.top, 8) // 화면 상단에 너무 붙어서, 좀 띄어놓음}스크롤시, 고정된 header 뒷쪽으로 셀들이 지나가지 않도록
Section titled “스크롤시, 고정된 header 뒷쪽으로 셀들이 지나가지 않도록”헤더에 배경색 추가해야
BUT, 그래도 안전영역 쪽에는 배경색이 없어서, 셀들이 뒤로 올라가는게 보임
WHY? ScrollView는 일반적으로 안전영역 무시하고 스크롤 해줌
SO, 부모뷰 경계를 넘어서 보여지지 않도록, 우리가 클리핑 해줘야 함
ScrollView(.vertical) { // 셀}.clipped() // 이렇게화면 구성 방법
Section titled “화면 구성 방법”- 강렬한 원색(빨강, 파랑 등)을
backgroundColor로 사용해서 영역들을 체크 - 가짜 셀뷰들을 넣어 동작 화면 예상
화면 상단 네비게이션바 숨김
Section titled “화면 상단 네비게이션바 숨김”나중에 View 들락날락시, 상단 navigationBar 안나오도록 숨김
보통, 화면을 풀스크린으로 보이게 하고, 커스텀 네비게이션 UI 만들때 유용
보통, NavigationStack or NavigationView안의 제일 루트뷰에 적용
❓여기선 안그랬는데 나중에 체크해봐야
var body: some View { ZStack { // 생략 } // 생략 //.navigationBarHidden(true) // SwiftUI 3 이상에서는 이거 이제 안씀 .toolbar(.hidden, for: .navigationBar)}텍스트 추가
Section titled “텍스트 추가”텍스트는 엄청 긴 문자열로 세팅해서 테스트
lineLimit() 사용
var title: String = "asdlkfjasldgkjasldkfjalsdgjal;sdjalsdfjd" // 엄청 긴 문자열도 테스트
var body: some View { // 생략 Text(title) .font(.callout) .fontWeight(.semibold) // 약간 볼드 .lineLimit(2) // 라인 제한 걸어둠 // 생략}전체 레이아웃 잡기
Section titled “전체 레이아웃 잡기”.background()로 영역 확인
.padding()으로 간격 조정
HStack(spacing: 16) { Text(title) // 생략 .background(Color.green) // 원색으로 표시 영역 확인 } .foregroundStyle(.red) .padding(.trailing, 8) // 오른쪽에서 좀 띄워줌, HStack의 spacing은 좌우끝에는 영향X .frame(maxWidth: .inifinity, alignment: .leading) // .background(Color.blue) // 원색으로 영역 확인alignment:, spacing:, .padding() 활용
ZStack(alignment: .bottomLeading) { // 이렇게 1 // ImgaeLoaderView(urlString: user.image)
VStack(alignment: .leading, spacing: 8) { // 이렇게 2 // Text HStack(spacing: 4) { // 이렇게 3 // Image // Text } HStack(spacing: 4) { // 이렇게 4 // Image // Text } } .padding(24) // 이렇게 5}아이콘 넣기
Section titled “아이콘 넣기”Image(systemName: "plus.circle")- 우상단
+버튼 - 제일 우측
symbol버튼 - 찾는 심볼 검색
뷰의 재사용성 높이기
Section titled “뷰의 재사용성 높이기”.padding() 지정을 뷰 내부가 아니라, #Preview에서 해보는 이유
뷰에 .padding()을 주는건, 이 뷰를 사용하는 곳에서 원하는 만큼 설정하는 것
#Preview { ZStack { Color.black.ignoresSafeArea()
SpotifyNewReleaseCell() .padding() }}.onTapGesture를 뷰 안에 하드코딩하면 안됨
Section titled “.onTapGesture를 뷰 안에 하드코딩하면 안됨”뷰를 사용하는 측에서 동작을 세팅 할 수 있도록 해야
이 동작을 받는 변수는 optional로 만들어야 좋음
WHY? 그렇지 않으면, #Preview쪽에 항상 인자로 동작을 넘겨야 하기에 번거롭기 때문
BUT, 사용하는 로직에도 ?를 붙여 호출해야 함
WHY? nil인 경우, 아무 동작도 하지 않도록(런타임 오류 방지)
struct SpotifyNewReleaseCell: View { var onAddToPlaylistPressed: (() -> Void)? = nil // 버튼 눌렸을때의 동작을 받도록, optional로 var onPlayPressed: (() -> Void)? = nil
var body: some View { // 생략 HStack { Image(systemName: "plus.circle") .padding(4) //.background(Color.blue) // 이렇게 터치 영역을 확인하면서, 위의 .padding() 수치를 조절해야 .offset(x: -4) // 위치 미세 조정 .onTapGesture { onAddToPlaylistPressed?() // ?를 붙이면, nil일때 아무 동작 안함 } Image(systemName: "play.circle.fill") //.onTapGesture { // 이 동작은 이 버튼을 눌렀을때만 아니라, 셀 전체를 눌렀을때의 동작으로 하고 싶어서 더 상위에 //} } .onTapGesture { onPlayPressed?() } }}
// 사용 예시struct SpotifyHomeView: View { //생략
var body: some View { // 생략 SpotifyNewReleaseCell( onAddToPlaylistPressed: { // 동작 }, onPlayPressed: { // 동작 } ) }}함수 호출시, 자동 완성되는 인자들 넣는 영역 개행 해주기
Section titled “함수 호출시, 자동 완성되는 인자들 넣는 영역 개행 해주기”Ctrl+M 누르면, 여러 줄로 나옴
ScrollView
Section titled “ScrollView”.scrollIndicators(.hidden)많이 함- 안에
Rectangle()n개 배치해서 레이아웃 확인
ScrollView(.horizontal) { ForEach(0..<20) { _ in Rectangle() }}.foregroundStyle(), .font(), .fontWeight()를 보통 지정
//Text("N") .foregroundStyle(.netflixRed) // 글자색 지정 .font(.largeTitle) // 폰트 지정 .fontWeight(.black) // 굵기 지정