iOS视图可见性消失

45

我是iOS开发新手。我想从父视图中切换(隐藏/显示)一个子视图。在Android中,有一种将可见性隐藏的方法。

在Android中

subView.setVisibility(View.GONE);
在iOS中
subView.removeFromSuperview()

当我使用上述函数时,它会移除子视图的约束并破坏我的滚动视图约束。

topsubView.bottomAnchor.constraint(equalTo: bottomSubView.topAnchor, constant: 8).isActive = true

当我使用上述代码时,它可以正常工作并隐藏子视图。但是当我想让子视图可见时,它没有显示子视图。

topsubView.bottomAnchor.constraint(equalTo: bottomSubView.topAnchor, constant: 8).isActive = false
self.view.layoutIfNeeded()

希望您理解我的问题。提前感谢。


使用 subView.isHidden = true - RajeshKumar R
3
谢谢,但我想移除子视图的空间。subView.isHidden没有移除空间。 - John
看看我的解决方案 - Shehata Gamal
设置您的视图高度约束,并在想要移除空间时将其设置为0。 - Shivam Tripathi
感谢Mukesh和RajeshKumar...使用Stack View(堆栈视图)也运行良好。 - John
显示剩余2条评论
5个回答

43

由于我在iOS和Android上都有经验,您需要在iOS中使用约束来实现Android的功能。iOS不像Android本机支持可见性GONE和VISIBLE那样自动支持。

您需要钩住特定约束的outlet(它可能是垂直/水平/高度),将其设置为0并管理您的UI。

隐藏:

self.viewYourConstraint.constant = 0
self.yourView.hidden = true
self.view.layoutIfNeeded()

展示:

self.viewYourConstraint.constant = 100//your constant value
self.yourView.hidden = false
self.view.layoutIfNeeded()
注意:如果更新上述约束条件会影响其他约束条件,则还必须调用以下内容:
self.yourView.setNeedsUpdateConstraints()

1
当您将高度约束设置为0时,隐藏部分是否必要? - C. Kontos
这就是iOS的工作原理,该功能在iOS上已经消失。不过,即使您从superview中删除了视图,则仍然需要重新创建该视图。 - Mukesh Lokare
我有类似的代码,没有使用 self.yourView.hidden = true,一切都正常工作,因为当我想要隐藏视图时,我将视图的高度约束设置为0。 - C. Kontos
是的,没错。但在iOS中最佳实践是我们也应该将视图隐藏起来。 - Mukesh Lokare

26

试试这个扩展:

extension UIView {
    
    func visiblity(gone: Bool, dimension: CGFloat = 0.0, attribute: NSLayoutAttribute = .height) -> Void {
        if let constraint = (self.constraints.filter{$0.firstAttribute == attribute}.first) {
            constraint.constant = gone ? 0.0 : dimension
            self.layoutIfNeeded()
            self.isHidden = gone
        }
    }
}

你如何使用这个....

@IBOutlet weak var testView: UIView?
@IBAction func testVisibilty(switchbutton: UISwitch) -> Void {
    
    let viewHeight:CGFloat = switchbutton.isOn ? 100 : 0.0
    self.testView?.visiblity(gone: !switchbutton.isOn, dimension: viewHeight)
    
    // set visibility for width constraint
    //let viewWidth:CGFloat = switchbutton.isOn ? 300 : 0.0
    //self.testView?.visiblity(gone: !switchbutton.isOn, dimension: viewWidth, attribute: .width)
  
}

这是结果:

在此输入图片描述


为什么属性被这个扩展重置了? - Naveed Ahmad

23

也许您更喜欢这个解决方案

extension UIView {

    enum Visibility {
        case visible
        case invisible
        case gone
    }

    var visibility: Visibility {
        get {
            let constraint = (self.constraints.filter{$0.firstAttribute == .height && $0.constant == 0}.first)
            if let constraint = constraint, constraint.isActive {
                return .gone
            } else {
                return self.isHidden ? .invisible : .visible
            }
        }
        set {
            if self.visibility != newValue {
                self.setVisibility(newValue)
            }
        }
    }

    private func setVisibility(_ visibility: Visibility) {
        let constraint = (self.constraints.filter{$0.firstAttribute == .height && $0.constant == 0}.first)

        switch visibility {
        case .visible:
            constraint?.isActive = false
            self.isHidden = false
            break
        case .invisible:
            constraint?.isActive = false
            self.isHidden = true
            break
        case .gone:
            if let constraint = constraint {
                constraint.isActive = true
            } else {
                let constraint = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 0)
                self.addConstraint(constraint)
                constraint.isActive = true
            }
        }
    }
}

那么使用方法如下:

someView.visibility = .visible
someView.visibility = .invisible
someView.visibility = .gone

编辑:

提升能力:将从故事板中工作(只需写:“可见”,“不可见”,“隐藏”)在“可见状态”中。

所有视图内的约束都应小于1000

extension UIView {

    enum Visibility: String {
        case visible = "visible"
        case invisible = "invisible"
        case gone = "gone"
    }

    var visibility: Visibility {
        get {
            let constraint = (self.constraints.filter{$0.firstAttribute == .height && $0.constant == 0}.first)
            if let constraint = constraint, constraint.isActive {
                return .gone
            } else {
                return self.isHidden ? .invisible : .visible
            }
        }
        set {
            if self.visibility != newValue {
                self.setVisibility(newValue)
            }
        }
    }

    @IBInspectable
    var visibilityState: String {
        get {
            return self.visibility.rawValue
        }
        set {
            let _visibility = Visibility(rawValue: newValue)!
            self.visibility = _visibility
        }
    }

    private func setVisibility(_ visibility: Visibility) {
        let constraints = self.constraints.filter({$0.firstAttribute == .height && $0.constant == 0 && $0.secondItem == nil && ($0.firstItem as? UIView) == self})
        let constraint = (constraints.first)

        switch visibility {
        case .visible:
            constraint?.isActive = false
            self.isHidden = false
            break
        case .invisible:
            constraint?.isActive = false
            self.isHidden = true
            break
        case .gone:
            self.isHidden = true
            if let constraint = constraint {
                constraint.isActive = true
            } else {
                let constraint = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 0)
                // constraint.priority = UILayoutPriority(rawValue: 999)
                self.addConstraint(constraint)
                constraint.isActive = true
            }
            self.setNeedsLayout()
            self.setNeedsUpdateConstraints()
        }
    }
}

太棒了,非常感谢!对于像我这样的iOS新手非常有用。点赞! - Ashraf Amin

8

您想隐藏子视图并删除其占用的空间。如果您想避免操作约束,可以尝试使用堆叠视图:

  • 创建一个UIStackView并设置堆叠视图与其父视图之间的适当约束;
  • 将视图添加到堆叠视图中;
  • 现在,您可以通过将view.isHidden设置为true或false来切换堆叠视图内这些视图的可见性,布局会自动调整。

2
如果视图没有恒定的间距怎么办? - sandpat
这是最快最简单的解决方案,但可能并不适用于所有情况!@sandpat,您只需要在堆栈内设置视图而不固定大小,并为此视图内的视图的顶部和底部(或前导和尾随)设置两个约束条件。 - Pelanes

3

我相信您正在寻找view.isHidden = true。这仅仅是在原地隐藏视图,而不改变视图层次结构或约束映射。您可以随后使用view.isHidden = false重新显示您的视图。


4
谢谢,但我想要删除子视图的空格。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接