WWDC21:用可定制的 Sheet 改造模态窗口

发布
更新
字数 492
阅读 3 分钟
阅读量 1269

新的 UISheetPresentationController 类实现可定制的弹出层,所有样式可以使用实例属性修改。最简单的使用方法就是,获取之前弹出层控制器的 sheetPresentationController 属性并设置。

例如 present(viewController, animated: true) 变为

// Get a sheet
if let sheet = viewController.sheetPresentationController {
    // Customizee the sheet
}

present(viewController, animated: true)

Detent

可以按比例控制弹出层高度,全屏高度或一半。

// Detents

if let sheet = picker.sheetPresentationController {
    // `[.large()]` 只能全屏
    // `[.medium()]` 只能半屏
    // `[.medium(), .large()]` 默认半屏,可以手动拖拽切换
    sheet.detents = [.medium(), .large()]
}
present(picker, animated: true)

示例

func showImagePicker() {
    let picker = PHPickerViewController()
    picker.delegate = self
    
    // 1. Present at medium detent
    if let sheet = picker.sheetPresentationController {
        sheet.detents = [.medium(), .large()]
        
        // 为了可以在 `.medium` detent 滚动内容,设置 `false` 阻止滚动到边缘时展开 sheet
        sheet.prefersScrollingExpandsWhenScrolledToEdge = false
        
        // 移除 `.medium` detent 时的暗色背景,允许同时交互
        sheet.smallestUndimmedDetentIdentifier = .medium
        
        // 如果需要,可以设置横屏时,不铺满屏幕
        sheet.prefersEdgeAttachedInCompactHeight = true
        sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
        
        // 拖拽显示条
        sheet.prefersGrabberVisible = true
        
        // 圆角
        sheet.preferredCornerRadius = 24.0
    }
    
    present(picker, animated: true)
}

// MARK: - PHPickerViewControllerDelegate
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
	// assign result to imageView.image
    // ...
    
    // 2. And don't dismiss automatically
    // dismiss(animated: true)
    
    // 3. 当选中一张图片时,保持 `.medium` detent
    if let sheet = picker.sheetPresentationController {
        // 5. 加入动画效果
        sheet.animateChanges {
            sheet.selectedDetentIdentifier = .medium
        }
    }
}

在 iPad 上,使用 popover 形式的弹出层:

func showImagePicker(_ sender: UIBarButtonItem) {
    let picker = PHPickerViewController()
    picker.delegate = self
    
    // 设置弹层样式
    picker.modalPresentationStyle = .popover
    // 使用弹层 sheet
    if let popover = picker.popoverPresentationController {
        popover.barButtonItem = sender
        
        // 自动响应布局,例如在分屏模式如果尺寸够窄(?)就会像手机上一样展示弹层
        let sheet = popover.adaptiveSheetPresentationController
        sheet.detents = [.medium(), .large()]
        sheet.prefersScrollingExpandsWhenScrolledToedge = false
        sheet.smallestUndimmedDetentIdentifier = .medium
    }
    
    present(picker, delegate: self)
}

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    // ...
    
    // 同样要修改这里的 sheet
    if let sheet = picker.popoverPresentationController?.adaptiveSheetPresentationController {
        sheet.animateChanges {
            sheet.selectedDetentIdentifier = .medium
        }
    }
}

_Via WWDC 2021: _Customize and resize sheets in UIKit