(※ iOS 16+ 지원)
.presentataionDents()를 사용하면 sheet이 얼만큼 올라올 건지 조정할 수 있다.현재 sheet을 사용하면 거의 화면 끝까지 올라오기 때문에, half-size sheet을 구현하기 위한 workaround나 라이브러리를 많이 볼 수 있었다.
.presentataionDents([.medium, .large]) // slide-up하여 sheet을 끝까지 끌어올릴 수 있음
.presentataionDents([.height(300)]) // 높이를 300으로 고정
.presentataionDents([.fraction(0.5)]) // 화면 높이에 따라 크기 유동적, 화면 높이의 절반만 차지
.presentationDragIndicatior(.hidden)을 사용하면, sheet의 상단에 위치한 기본 indicator를 숨길 수 있따.
2차원에서 horizontal row 를 표현
gridCellUnsizedAxes(_:)사용하면, Color나 Spacer과 같이 flextible View를 그려야 할 때 불필요한 공간 차지하는 것을 방지할 수 있다.
onTapGesture시, 탭한 위치를 알 수 있는 기능이 생겨서 굉장히 편리할 것 같다. 심지어, local과 global상의 위치를 알 수 있다.
Circle()
.fill(Color.red)
.frame(width: 100, height: 100)
.onTapGesture { location in
print("Tapped \(location)") // Circle 내에서 location, 즉 local 위치
}
Circle()
.fill(Color.red)
.frame(width: 100, height: 100)
.onTapGesture(coordinator: .gloval) { location in
print("Tapped \(location)") // 전체 화면 내에서 location, 즉 global 위치
}
'URL 공유하기' 기능을 구현함에 있어 심플해졌으며, 3가지 방식으로 구현할 수 있다.
private var link = "https://www.naver.com"
ShareLink(item: link) // default, share아이콘 + "share
ShareLink("Naver", item: link)
ShareLink(item: link) {
Label("Naver", systemImage: "swift")
}
이 외에도, message 와 preview 프로퍼티를 이용할 수 있다.
다수의 날짜를 선택할 수 있는 캘린더 기능이 추가되었다.
@State private var dates = Set<DateComponents>()
@Environment(\.calendar) var calendar
VStack {
MultiDatePicker("Select dates," selection: $dates) // in: Date.now... 를 추가하면 오늘 날짜부터만 선택이 유효함
Text(summary) // June 21, 2022, June 3, 2022, June 11, 2022
}
var summary: String {
dates.compactMap { components
calendar.date(from: components)?.formatted(date: .long, time: .omitted)
}.formatted
}
View에 Search TextField와 검색 범위를 설정할 수 있도록 편리한 기능을 제공
struct Message: Identifiable, Codable {
let id: Int
var user: String
var text: String
}
enum SearchScope: String, CaseIterable {
case inbox, favorites
}
struct SearchView: View {
@State private var messages: [Message] = []
@State private var searchText: String = ""
@State private var searchScope: SearchScope = .inbox
var body: some View {
VStack {
ForEach(filteredMessages) { msg in
Text(msg.text)
}
}
.onSubmit(of: .search, runSearch)
.onChange(of: searchScope, perform: { _ in runSearch() })
}
private var filteredMessages: [Message] {
if searchText.isEmpty {
return messages
} else {
return messages.filter { $0.text.localizedCaseInsensitiveContains(searchText)}
}
}
func runSearch() {
Task {
guard let url = URL(string: "https://hws.dev/\(searchScope.rawValue).json") else { return }
let (data, _ ) = try await URLSession.shared.data(from: url)
messages = try JSONDecoder().decode([Message].self, from: data)
}
}
}
참고