Productivity Improvements → desktop class IPad 앱을 위한 업데이트
Control enhancements
UICalendarView: UIDatePicker에서 쓰던 뷰를 완전히 독립적으로 쓸 수 있게 됨.
let calendarView = UICalendarView()
calendarView.delegate = self
calendarView.calendar = Calendar(identifier: .gregorian)
view.addSubView(calendarView)
let multiDateSelection = UICalendarSelectionMultiDate(delegate: self)
multiDateSelection.selectedDates = myDatabase.selectedDates()
calendarView.selectionBehavior = multiDateSelection
func multiDateSelection(
_ selection: UICalendarSelectionMultiDate,
canSelectDate dateComponents: DateComponents
) -> Bool {
return myDatabase.hasAvailabilities(for: dateComponents)
}
// Configuring Decorations
func calendarView(
_ calendarView: UICalendarView,
decorationFor dateComponents: DateComponents
) -> UICalendarView.Decoration? {
switch myDatabase.eventType(on: dateComponents) {
case .none:
return nil
case .busy:
return .default()
case .travel:
return .image(airplaneImage, color: .systemOrange)
case .party:
// 인터렉션 불가
// 가용 크기를 넘어가면 짤림
return .customView {
MyPartyEmojiLabel()
}
}
}
UIPageControl
커스텀 인디케이터 적용 가능(선택 여부에 따라 다른 이미지 적용)
Orientation과 Direction도 커스텀 가능
// Vertical page control with custom indicators
pageControl.direction = .topToBottom
pageControl.preferredIndicatorImage = UIImage(systemNamed: "square")
pageControl.preferredCurrentIndicatorImage = UIImage(systemNamed: "square.fill")
UIPasteBoard
API refinements
UISheetPresentationController의 detent에 커스텀 기능 제공
하단 safe Area는 고려하지 않은 값을 내보내야 한다.
// 상수
sheet.detents = [
.large(),
.custom { _ in
200.0
}
]
// 비율
sheet.detents = [
.large(),
.custom { context in
0.3 * context.maximumDetentValue
}
]
identifier를 제공해서, 다른 API에서 써먹을 수도 있다.
// Define a custom identifier
extension UISheetPresentationController.Detent.Identifier {
static let small = UISheetPresentationController.Detent.Identifier("small")
}
// Assign identifier to custom detent
sheet.detents = [
.large(),
.custom (identifier: .small) { context in
0.3 * context.maximumDetentValue
}
]
// Disable dimming above the custom detent
sheet.largestUndimmedDetentIdentifier = .small
System Symbol이 렌더링 모드 지정이 안된경우, 원래는 무조건 monochrome이였는데, 이제는 자체적으로 가지고 있는 기본값으로 렌더링 된다.
monochrome을 명시적으로 지정하려면 다음 API를 사용.
UIImage.SymbolConfiguration.preferringMonochrome()
variable symbol 지원
0~1 사이의 값을 지정해서, 해당 값을 기반으로 다양한 variation을 제공하는 심볼
UIImage(
systemName: "wifi",
variableValue: 0.6,
configuration: redPalleteConfiguration // 다른 렌더링 모드와 섞는 것도 가능
)
Sendable 지원 추가 - 이는 해당 타입들이 immutable하기 때문
UIImage
UIColor
UIFont
UITraitCollection
actor Processor { ... }
class ImageView: UIViewController {
let processor = Processor()
func sendImageForProcessing(_ image: UIImage) async {
let fancyImage = await processor.process(image)
/// display fancyImage
}
}
Stage Manager 등장
Self-Sizing Cell
Self-Resizing이 기본값이 되었다.
visible Cell안의 content가 변하면, cell이 자동으로 리사이징 된다.
class UICollecitonView {
// 기본값은 .enabled
var selfSizingInvalidation: SelfSizingInvalidation
}
resizing을 하기 위한 원리
selfSizingInvalidation이 켜져 있으면 셀은 자신을 가지고 있는 tableView혹은 CollectionView에 자신을 리사이징 해달라고 요청할 수 있다.
기본적으로 애니매이션이 적용되는데, 애니매이션을 끄고 싶은 경우, UIView.performWithoutAnimation 메소드 안에서 invalidateIntrinsicContentSize를 호출하면 된다.
호출한다고 바로바로 하는 건 아니고 모았다가 한꺼번에 적절한 타임에 한다.(coaleasing)
오토레이아웃을 쓰는 경우, contentView 내부에서의 레이아웃 변화에 따라 자동으로 invalidateIntrinsicContentSize를 호출하게 할 수 있다.
selfSizingInvalidation = .enabledIncludingConstraints
UIKit and SwiftUI
UITableView와 UICollectionView의 셀 안에서 SwiftUI 뷰를 그릴 수 있게 되었다.
cell.contentConfiguration = UIHostingConfiguration {
VStack {
Image(systemName: "wand.and.stars")
.font(.title)
Text("Like magic!")
.font(.title2).bold()
}
.foregroundStyle(Color.purple)
}
UIDevice deprecations