Xcode如何利用预览(Preview)让SwiftUI视图快速适配不同尺寸的设备

Posted 大熊猫侯佩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xcode如何利用预览(Preview)让SwiftUI视图快速适配不同尺寸的设备相关的知识,希望对你有一定的参考价值。

概览

有时候,我们需要根据不同尺寸的设备适配最合适的视图布局。

这在SwiftUI项目中如何操作呢?

如上图所示,我们在SwiftUI中自定义了一个多项列表视图,不过它在不同尺寸的设备中显示的并不完美。在大屏设备尾部留出了太多空间,而在小屏设备中最后一列又显示不全,真是让人伤脑筋啊!

不过别急!

在本篇博文中,我们将介绍一些在不同设备中适配SwiftUI视图的小技巧,相信小伙伴们看完之后一定能妥妥的搞定适配问题了。

那还等什么呢?

Let’s go! 😉

所见即所得

要想适配不同尺寸的设备,首先我们要做的第一件是就是能够快速预览不同设备的界面。

我们可以通过为SwiftUI视图添加特定的修改器,在Xcode预览界面中快速浏览其在对应设备中的外观:

struct TestView_Previews: PreviewProvider 
    static var body: some View 
        NavigationView 
            // 实际测试视图的布局描述
        
    
    
    static var previews: some View 
        Group 
            body
                .previewDevice(.init(rawValue: "iPhone 13 Pro Max"))
            
            body
                .previewDevice(.init(rawValue: "iPhone 13 Pro"))
            
            body
                .previewDevice(.init(rawValue: "iPhone 12 mini"))
            
            body
                .previewDevice(.init(rawValue: "iPod touch (7th generation)"))
            
        
    

在以上预览视图代码中,我们分别将测试视图放到 iPhone 13 Pro Max、iPhone 13 Pro、iPhone 12 mini以及iPod touch等四种不同尺寸设备中去预览显示。

获取设备尺寸

在不同设备中预览我们的视图只是第一步,接着我们需要在运行中确定到底当前在何种设备中运行。

或者换句话说:当前运行的设备屏幕尺寸是多少?

为了获取当前运行设备的名称,我们只需一行代码:

UIDevice.current.name

同样,为了获取当前运行设备屏幕的尺寸,即逻辑分辨率,同样只需一行代码:

UIScreen.main.bounds

这里,我们只需要设备屏幕的尺寸。

动如脱兔,静若处子

能够在运行中确定设备的尺寸之后,我们就可以根据不同设备的尺寸大小,来动态调整我们视图的界面了。

首先,写一个对应的布局尺寸结构:

fileprivate enum LayoutSize 
    case tiny, small, middle, large
    
    // 根据当前设备计算实际的布局尺寸
    static func calc() -> Self 
        let width = UIScreen.main.bounds.width
        
        if width <= 320 
            return .tiny
        else if width <= 360 
            return .small
        else if width <= 390 
            return .middle
        else
            return .large
        
    
    
    // 列表中单个列的宽度
    var unitWidth: CGFloat 
        let w: CGFloat
        switch self 
        case .tiny, .small, .middle:
            w = 30
        case .large:
            w = 38
        
        return w
    

在以上代码中,我们根据前面4种典型iPhone设备的宽度,创建了4种对应的尺寸枚举类型。

我们希望在 large 和 middle 尺寸类型的设备中,最大化每列的宽度;而在较小尺寸 small 和 tiny 等设备中,紧凑的显示每列,并按需合并若干列,达到最优利用空间的目的:

if layoutSize == .large || layoutSize == .middle 
    Text("\\(trace.totalGainedScore)")
        .fontWeight(.heavy)
        .font(.body)
        .foregroundColor(scoreColor)
        .opacity(1.0)
        .frame(minWidth: layoutSize.unitWidth)
    
    baseScoreView
        .underline(true, color: stateColor)
        .fontWeight(.bold)
        .font(.callout)
        .foregroundColor(stateColor)
        .frame(minWidth: layoutSize.unitWidth)
else
    HStack(alignment: .top, spacing: 5) 
        Text("\\(trace.totalGainedScore)")
            .fontWeight(.heavy)
            .font(.body)
            .foregroundColor(scoreColor)
            .opacity(1.0)
        
        baseScoreView
            .underline(true, color: stateColor)
            .fontWeight(.bold)
            .font(.callout)
            .foregroundColor(stateColor)
    .frame(minWidth: 50)

不过,即使采用上面的优化方法,在最小的 tiny 设备界面中,最后一列的显示仍然捉襟见肘。

这时,我们需要更进一步,大幅度更改列表的布局,将第二列的内容放到第一列最底部显示,继续压榨显示空间:

if layoutSize == .tiny 
    VStack(spacing: 2) 
        Text(Model.shortDateFt.string(from: trace.date ?? Date.distantPast))
            .fontWeight(.light)
            .font(.footnote)
            .foregroundColor(.slateGray)
        
        CommonUI.hiveScoringTracesView(trace, model: model)
        
        // tiny设备中,需要将第二列显示的状态内容放到第一列的底部
        stateView
            .foregroundColor(stateColor)
            .frame(minWidth: layoutSize.unitWidth)
    .frame(minWidth: 65.0)
else
    VStack 
        Text(Model.shortDateFt.string(from: trace.date ?? Date.distantPast))
            .fontWeight(.light)
            .font(.footnote)
            .foregroundColor(.slateGray)
        
        CommonUI.hiveScoringTracesView(trace, model: model)
    .frame(minWidth: 65.0)
        
    stateView
        .foregroundColor(stateColor)
        .frame(minWidth: layoutSize.unitWidth)

现在,运行代码看一下布局适配的效果:

如上图所示,现在不同设备中的显示效果是不是比一开始要好很多呢?

我们最大化的利用了空间,做到了视图适配的收放自如,棒棒哒!🚀

总结

在本篇博文中,我们利用SwiftUI代码,在Xcode预览中快速查看了不同设备的界面,并据此动态调整视图的布局,达到了最优空间之利用的目的。

最后,感谢各位观赏,我们下次再会!😎

以上是关于Xcode如何利用预览(Preview)让SwiftUI视图快速适配不同尺寸的设备的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI项目如何在Xcode预览(Preview)中开启调试支持

SwiftUI项目如何在Xcode预览(Preview)中开启调试支持

Xcode13模拟器和预览(Preview)导致Mac处理器占用率急剧飙升的解决方法

Xcode13模拟器和预览(Preview)导致Mac处理器占用率急剧飙升的解决方法

Xcode13模拟器和预览(Preview)导致Mac处理器占用率急剧飙升的解决方法

Xcode如何在预览(Preview)调试中避免与SwiftUI正常运行时环境不一致导致的崩溃