SwiftUI 视图在安全区域附近自行调整

Posted

技术标签:

【中文标题】SwiftUI 视图在安全区域附近自行调整【英文标题】:SwiftUI view is adjusting itself near the safe area 【发布时间】:2021-11-20 19:56:06 【问题描述】:

我在将包含 SwiftUI 视图的视图移动到屏幕边缘附近时遇到问题。 SwiftUI 视图会自行移动以避免被安全区域插图阻挡

我正在使用 UIKit 来处理通过UIHostingControllerUIPanGestureRecognizer 拖动视图。这是代码

import UIKit

class ViewController: UIViewController 
    
    var contentView: UIView!

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let contentVc = UIHostingController(rootView: Content())
        addChild(contentVc)
        contentView = contentVc.view
        let contentHeight = contentView.sizeThatFits(view.bounds.size).height
        contentView.frame = CGRect(x: 0, y: 200, width: view.bounds.width, height: contentHeight)
        view.addSubview(contentView)
        contentVc.didMove(toParent: self)
        
        let drag = UIPanGestureRecognizer(target: self, action: #selector(drag(_:)))
        contentView.addGestureRecognizer(drag)
        
        view.backgroundColor = .orange
    
    
    var startingPoint = CGPoint.zero
    @objc func drag(_ gesture: UIPanGestureRecognizer) 
        switch gesture.state 
        case .began:
            startingPoint = contentView.frame.origin
        case .changed:
            let location = gesture.translation(in: view)
            contentView.frame.origin.y = startingPoint.y + location.y
        default:
            break
        
    



import SwiftUI

struct Content: View 
    var body: some View 
        VStack 
            ForEach(0..<10)  i in
                Text(String(i))
            
        
        .background(Color.blue)
        .padding(.vertical, 32)
        
        .ignoresSafeArea()
    

我期望的是蓝色视图不会垂直调整自身(在预览中,蓝色视图的顶部填充正在缩小)

【问题讨论】:

你总是在期待从一开始就没有的东西。当视图命中 safeArea 时,该修饰符会修改视图。 @swiftPunk 好的,这就解释了为什么当我将视图拖到 safeArea 时,蓝色会延伸 bc,因为它忽略了安全区域。我理解的对吗? 没错。 @ErickES7 好的,所以 ignoreSafeArea 不是用来解决这个问题的修饰符。我的标题不包括 ignoresSafeArea 不工作 我不确定您的 SwiftUI 视图是否需要该修饰符!你为什么需要它?我会删除它! 【参考方案1】:

我找到了两种解决此问题的方法:

方式一:使用 UIKit 手势!

class ViewController: UIViewController 
    
    var contentView: UIView!

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let contentVc = UIHostingController(rootView: Content())
        addChild(contentVc)
        contentView = contentVc.view
        let contentHeight = contentView.sizeThatFits(view.bounds.size).height
        contentView.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: contentHeight)
        contentView.backgroundColor = .clear
        view.addSubview(contentView)
        contentVc.didMove(toParent: self)
        
        let drag = UIPanGestureRecognizer(target: self, action: #selector(drag(_:)))
        contentView.addGestureRecognizer(drag)
        
        view.backgroundColor = .orange
    
    
    var startingPoint = CGPoint.zero
    @objc func drag(_ gesture: UIPanGestureRecognizer) 
        switch gesture.state 
        case .began:
            startingPoint = contentView.frame.origin
        case .changed:
            let location = gesture.translation(in: view)
            contentView.frame.origin.y = startingPoint.y + location.y
        default:
            break
        
    



import SwiftUI

struct Content: View 

    var body: some View 

        VStack 
            ForEach(0..<10)  i in
                Text(String(i))
            
        
        .padding()
        .background(Color.blue)
        .frame(maxWidth: .infinity)
        .background(Color.white)

    

方式二:使用 SwiftUI 手势!

class ViewController: UIViewController 

    var contentView: UIView!

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let contentVc = UIHostingController(rootView: Content())
        addChild(contentVc)
        contentView = contentVc.view
        contentView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)
        contentView.backgroundColor = .clear
        view.addSubview(contentView)
        contentVc.didMove(toParent: self)

        view.backgroundColor = .orange
    




struct Content: View 

    @State private var offset: CGFloat = .zero
    @State private var lastOffset: CGFloat = .zero

    var body: some View 

        VStack 
            ForEach(0..<10)  i in
                Text(String(i))
            
        
        .padding()
        .background(Color.blue)
        .frame(maxWidth: .infinity)
        .background(Color.white)
        .offset(y: offset)
        .gesture(DragGesture(minimumDistance: .zero, coordinateSpace: .local).onChanged  value in

            offset = lastOffset + value.translation.height

        
        .onEnded  value in
            lastOffset = lastOffset + value.translation.height
            offset = lastOffset
        )

    

【讨论】:

以上是关于SwiftUI 视图在安全区域附近自行调整的主要内容,如果未能解决你的问题,请参考以下文章

如何使 AVFoundation 预览视图占据 SwiftUI 中的所有屏幕,而不考虑安全区域?

如何在swiftUI中删除顶部安全区域

如何使 SwiftUI 列表行背景颜色扩展整个宽度,包括安全区域之外

文本视图的 lineBreakMode 是不是有 SwiftUI 等效项?

视图中的 SwiftUI Picker 会在点击时自行禁用

通过 Swift 泛型初始化 SwiftUI 视图