탭뷰 추가하기 전에
폴더 정리한다고 파일 옮겨 줬는데
캔버스 맛탱이가 가버림...
종종 겪는 거 같은데 해결 어떻게 했더라
앱 경로 재설정 해주니까 돌아옴
탭뷰안에 뷰, 그리고 이 뷰들에 .tabItem 만들면 탭뷰가 되는거죠~
칼라 extension 만들어주고
탭 중 하나인 FeedView를 스크롤이 되게 만들어주고
SubView로 PostView를 구성해줬다!
요런 정보들이 필요하겠죠
이 모델을 사용해서 PostView에서 데이터 갈아낄 수 있게 해줍시다
그리고 PostArray가 담기게 될 Object를 하나 만들어줌
나중에 DataBase를 받아올 거라 지금처럼 init될 때 append 되는 느낌으로 만들어줬다
class PostArrayObject: ObservableObject {
@Published var dataArray = [PostModel]()
init() {
print("Fetch from DataBase Here")
let post1 = PostModel(postID: "", userID: "", username: "Woozoobro", caption: "This is a caption", dateCreated: Date(), likeCount: 0, likedByUser: false)
let post2 = PostModel(postID: "", userID: "", username: "Jessica", caption: nil, dateCreated: Date(), likeCount: 0, likedByUser: false)
let post3 = PostModel(postID: "", userID: "", username: "Emily", caption: "This is a really really long caption hahahahahaha", dateCreated: Date(), likeCount: 0, likedByUser: false)
let post4 = PostModel(postID: "", userID: "", username: "Christopher",caption: nil, dateCreated: Date(), likeCount: 0, likedByUser: false)
self.dataArray.append(post1)
self.dataArray.append(post2)
self.dataArray.append(post3)
self.dataArray.append(post4)
}
}
피드뷰에 posts 어레이 넣어주고 ForEach로 그려주면 됩니다
한가지 생각 못했던 건 LazyVStack으로 감싸는 거!
이건 한번에 진짜 많은 포스트 안뿌릴라고 감싸줌
struct CommentsView: View {
@State var submissionText: String = ""
var body: some View {
VStack {
ScrollView {
Text("PlaceHolder")
Text("PlaceHolder")
Text("PlaceHolder")
Text("PlaceHolder")
Text("PlaceHolder")
}
HStack {
Image("dog1")
.resizable()
.scaledToFill()
.frame(width: 40, height: 40)
.cornerRadius(20)
TextField("Add a comment here...", text: $submissionText)
Button {
} label: {
Image(systemName: "paperplane.fill")
.font(.title2)
}
.tint(Color.MyTheme.purpleColor)
}
.padding(.all, 6)
}
.navigationTitle("Comments")
.navigationBarTitleDisplayMode(.inline)
}
}
Comments 뷰를 구성!
메시지뷰 만들어주고
그리고 메시지뷰에 들어갈 내용들이 될 CommentModel도 작성해줘야함
코멘트 모델 만들어주고
메시지뷰에서 @State로 선언해줬습니다
이제 코멘트뷰에서 commentArray를 선언해두고 가져와주면 되겠죠
우선은 onAppear일 때 getComments 메소드로 가져와지게 임시로 해둠
글구 피드뷰에서 댓글버튼 누르면 들어가져야겠죠
NavigationLink 써서!!
BrowseView 만들자
요 안에 Carousel 뷰 들어갈거!
TabView 페이징 되는 형태로 만들어주고
여기에 도그 이미지 7개 다 넣어줄 건데 ForEach써서 그려주자
ForEach 범위에 1부터 시작한건 dog이미지가 1부터 네이밍되어 있어서 그럼
timer 만들고 페이징되게 해줬으
확장성 위해서 사진의 끝 이미지의 Index를 maxCount라는 상수로 빼주고
(이 때 노랑에러 해결할라면 id: .self 붙여주면 됨)
이제 이거를 브라우즈 뷰에 넣어줘야하는데
지금 타이머로직을 .onAppear에 넣어줬잖음
그럼 .onAppear일 때 타이머가 여러번 실행될겨
이거 수정해주자
타이머added로직 추가하고
이게 온 어피어일때 딱 한번 트루로 바뀌게해주면
한번만 로직이 실행되겠죠
그리드 뷰를 만듭시다
LazyVGrid를 사용하는데
여기 들어갈 내용들은 PostView를 재사용하면 될 거 같다
그러려면 PostView구조를 쪼꼼 바꿔줘야함
showHeaderAndFooter라는 불 값을 만들고 if 문으로 헤더랑 푸터 선택적으로 보여지게 해줌
ImageGridView에도 PostArrayObject를 @ObservedObject로 받게 해주고 여기있는 dataArray를 가지고 뿌려지게 해줌
BrowseView로 돌아와서 ImageGridView를 작성해주는데
여기 들어갈 posts 데이터들 시초가 되는 PostArrayObject를 여기서 선언해줬다
그리고 ImageGridView 아이템들 터치하면 네비게이션 링크 되게도 해주고!
근데 여기서 터치해서 들어가면 FeedView처럼 여러개가 나오는 게 아니라 하나의 PostView (클릭한 내용이 담긴) 가 보여져야함
PostArrayObject에 또 다른 init메소드를 작성해줌!!
🤔(이러면 다른 객체로 init을 하게 되는 걸까?)
오호오오 그렇네요!! 새로운 객체가 만들어집니다
그럼 정리해보자면 ImageGridView에선 PostArrayObject를 받는데 이 때 사용하는 친구는 init()
으로 생성된 애고, 얘가 가지고 있는 dataArray를 이용해서 ForEach로 그려주는데 이 때 post를 넘겨서 destination이 되는 애는 FeedView에다가 PostArrayObject(post: )
로 생성한 하나짜리 dataArray를 가지고 있는 객체!!
호오오...
이렇게하면 어떤 장점이 있을까?
네트워크로 받는 dataArray랑 post 단일 객체로 쓰는 거랑 구분을 지어서 하나의 class로 만들 수 있어서 그런가?
지금처럼 Browse 뷰에서 ForEach 써서 NavigationLink 만들면 한번에 데이터들 많이 로드 되서 앱 속도가 느려질 거 같음
Crypto App에서 그랬던 것처럼 옵셔널로 받아서 한번 감싸주는 로딩 뷰를 구성해줘야하는 건 아닐지..
하나 더 수정할 건
BrowseView에서 FeedView로 네비게이션 타고 들어가졌을 때 navigationTitle을 수정해줘야할 거 같습니다
요렇게 title구멍 뚫어줘서 말이죠!
그럼 피드탭에서랑 Browse뷰에서 네비게이션 타고 들어갔을 때
제목을 다르게 설정할 수 있습니다~!~!
ImagePicker를 사용하기 위해선
UIKit의 UiViewController를 변환해서 사용해야함
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.dismiss) var dismiss
@Binding var imageSelected: UIImage
@Binding var sourceType: UIImagePickerController.SourceType
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
picker.sourceType = sourceType
picker.allowsEditing = true
return picker
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext<ImagePicker>) { }
func makeCoordinator() -> ImagePickerCoordinator {
return ImagePickerCoordinator(parent: self)
}
class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage {
// select the image for our app
parent.imageSelected = image
// dismiss the screen
parent.dismiss()
}
}
}
}
업로드 뷰로 돌아와서 만들어준 ImagePicker뷰를 넣어줍니다
🤔 photoLibrary의 경우 PHPicker로 추후에 대체해서 사용해야 한다! Deprecated 된다고 함
그리고 이제 액세스에 대한 권한을 물어볼 수 있게 해줘야 하는데
info 리스트에 두가지 (photo library, camera usage) 추가해줍시다
.textInputAuto 메소드로 캐피털 설정 가능
import SwiftUI
struct PostImageView: View {
@Environment(\.dismiss) var dismiss
@State var captionText: String = ""
@Binding var imageSelected: UIImage
var body: some View {
VStack(spacing: 0) {
HStack {
Button {
dismiss()
} label: {
Image(systemName: "xmark")
.font(.title)
.padding()
}
.tint(.primary)
Spacer()
}
ScrollView(.vertical, showsIndicators: false) {
Image(uiImage: imageSelected)
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.cornerRadius(12)
.clipped()
TextField("Add your caption here...", text: $captionText)
.padding()
.frame(height: 60)
.frame(maxWidth: .infinity)
.background(Color.MyTheme.beigeColor.cornerRadius(12))
.font(.headline)
.padding(.horizontal)
.textInputAutocapitalization(.sentences)
Button {
postPicture()
} label: {
Text("Post Picture!".uppercased())
.font(.title3)
.fontWeight(.bold)
.frame(height: 60)
.frame(maxWidth: .infinity)
.background(Color.MyTheme.purpleColor.cornerRadius(12))
.padding(.horizontal)
}
.tint(Color.MyTheme.yellowColor)
}
}
}
//MARK: - Functions
func postPicture() {
print("Post Picture To Database Here")
}
}
struct PostImageView_Previews: PreviewProvider {
@State static var image = UIImage(named: "dog1")!
static var previews: some View {
PostImageView(imageSelected: $image)
}
}
UI구성해주고 button눌렸을 때
postPicture메소드가 호출되게 해줌
지금은 없지만 데이터베이스에 저장되게 해줄 예정
업로드 뷰로 돌아와서
.sheet이랑 겹치지 않게 .fullScreenCover를 달아줬다!
그리고 imageSelected에 이미지 바인딩해줌
이 풀스크린으로 뜨는건 .sheet이 디스미스 될 때 일어날 예정이니까
아래의 onDismiss까지 있는 메소드로 바꿔주자
그리고 헤더를 따로 빼줌!
ImageGridView를 재사용합시다!
재사용할 수 있는 것들은 SubView로 만들어줬다!!
재사용 가능한 SubView에서 let이 아니라 var 로 파라미터를 뚫어줬는데 왜그럴까?
SettingsRowView 네비게이션 링크 넣으려구 했는데
색깔 바껴서 .foregroundColor 추가해줌!
.tint로 바꾸는 것 말고도 .foreground로도 가능하다는 걸 알게됐다!
텍스트 필드 가끔 캔버스에서 텍스트입력하려구 하면 스캔텍스트 뜰 때 있는데
시뮬레이터로 한번 실행해주면 돌아온다!
이미지 수정해주는 뷰
어플리케이션 정책 같은 것들은 사이트로 넘어가지면 될 거 같다
struct내에 openCustomURL이라는 메소드를 작성해줌
Link를 쓰는 방법 말고 요렇게도 할 수 있구나!
세팅뷰 프로필뷰에서 띄워주려고 하는데
sheet으로 띄워줄라고 했음!
근데 처음 토글될땐 괜찮은데 두번째부터 캔버스 프리뷰 크래쉬 난다
🤔 왜지?
시뮬레이터에선 잘나옴!
콘텐트뷰에서 signin을 했냐 안했냐에 따라서 profileView를 보여줘야함
.tabItem같은 경우에 안에 있는 애들이 어떤 애든 상관없이 나와야해서 밖에 빼줬다
애플 같은 경우 로그인 버튼의 디자인을 특정해놔서 이거에 맞춰서 만들어야함
애플 로그인 버튼을 넣어줄건데
UIKit을 조금 사용해야한다
요호!
구글 로그인 버튼도 만들어주고~
이렇게 하고 지금까지 만든 뷰들 .sheet이나 .fullScreen으로 열리게 연결해줌
ImageGridView에서 LikeAnimationView때문에 PostView 레이아웃이 이상해졌다
닉은 Bool값을 하나더 만들어줬는데 나는 그냥 overlay로 올려줬으
PostView에 ActionSheet 추가해주자
actionSheet은 deprecated 될 예정 다르게 바꾼다면?
confirmationDialogue가 있긴한데 지금처럼 여러개의 버튼이 나오지는 않네요
오오 요렇게 구현해주면 됨!!
다시 actionsheet으로 돌아와서
func getActionSheet() -> ActionSheet {
switch self.actionSheetType {
case .general:
return ActionSheet(title: Text("What would you like to do?"), message: nil, buttons: [
.destructive(Text("Report"), action: {
print("Report Post")
self.actionSheetType = .reporting
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.showActionSheet.toggle()
}
}),
.default(Text("Learn more..."), action: {
print("Laern more Pressed")
}),
.cancel()
])
case .reporting:
return ActionSheet(title: Text("Why are you reporting this post?"), message: nil, buttons: [
.destructive(Text("This is inappropriate")) {
reportPost(reason: "This is inappropriate")
},
.destructive(Text("This is spam")) {
reportPost(reason: "This is spam")
},
.destructive(Text("It made me uncomfortable")) {
reportPost(reason: "It made me uncomfortable")
},
.cancel({
self.actionSheetType = .general
})
])
}
}
func reportPost(reason: String) {
print("Report Post Now")
}
report를 누르면 actionSheetType이 바뀌고 다시 actionSheet이 뜨게 해줬음
cancel할 때 다시 general로 바뀌게 해주고!
Share를 고도화해서 만들 수 있는데
지금은 그냥 간단하게 만들어봅시다
🤔ViewController를 선언해준 UIApplication.shared.windows가
deprecated 예정임.. 다른 표현 찾아보기!!!
요렇게 ColorScheme추가해줄수도 있습니다~!
안녕하세요! 글 잘 봤습니다 ㅎㅎㅎ
혹시 피드에서 오른쪽으로 스와이프 했을때 카메라가 나오게 하는 인터렉션은 어떻게 구현할 수 있을까요?