Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS view visibility gone

I am new to iOS development.I want to toggle (hide/visible) a subview from parent view.In android there is a way to hide the visibility to gone.

In android

subView.setVisibility(View.GONE);

In iOS

subView.removeFromSuperview()

when i use above function it remove subViewConstraints and mess up my scroll view constraints.

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

when i use the above code it works fine and hide subView.but when i want to make subView visible,it is not showing the subView.

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

Hope you understand my problem.Thanks in Advance.

like image 406
John Avatar asked Feb 05 '18 12:02

John


People also ask

What is the difference between invisible and gone for the view visibility status?

A View's visibility status is of Integer type and can have one of three options: VISIBLE (0) - The View is visible to the user. INVISIBLE (4) - The View is invisible to the user, but still takes up space in the layout. GONE (8) - The View is invisible, and it does not take up space in the layout.

What does Visibility gone do?

When a View is gone, it means it doesn't take any space in the layout. When it is invisible, it will take the necessary room in a layout but you just don't see it.

How do I know if a Viewcontroller is visible?

The view's window property is non-nil if a view is currently visible, so check the main view in the view controller: Invoking the view method causes the view to load (if it is not loaded) which is unnecessary and may be undesirable. It would be better to check first to see if it is already loaded.

What is view gone?

From Android official documentation, View. GONE This view is invisible, and it doesn't take any space for layout purposes. View. INVISIBLE This view is invisible, but it still takes up space for layout purposes.


3 Answers

As I have worked on both iOS & Android, You need to play with constraint outlet in ios to achieve Android functioning. iOS Does not support automatically like Android native support on visibility GONE & VISIBLE

You need to hook the outlet of particular constraint(it may vertical/horizontal/height) you need to set it to 0 & need to manage your UI.

To Hide:

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

To Show:

self.viewYourConstraint.constant = 100//your constant value
self.yourView.hidden = false
self.view.layoutIfNeeded()

Note: If other constraints will be affected because of the update to the constraint above, the following must also need to be called:

self.yourView.setNeedsUpdateConstraints()
like image 55
Mukesh Lokare Avatar answered Oct 22 '22 17:10

Mukesh Lokare


Try this extension:

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
        }
    }
}

How you can use this....

@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)
  
}

Here is result:

enter image description here

like image 21
Krunal Avatar answered Oct 22 '22 15:10

Krunal


Maybe you'd prefer this solution

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
            }
        }
    }
}

then the usage is:

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

edit:

improving capabilities: will work from storyboard (just write: 'visible', 'invisible', 'gone') in the "Visibility State"

all constraints inside view should be less then a 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()
        }
    }
}
like image 19
amit Avatar answered Oct 22 '22 17:10

amit