Remove views in UIstackview swift
Asked Answered
O

6

48

I am new to swift. I have added view to stackview using addArrangedSubview(). But I am not able to remove this view using removeArrangedSubview(). Even after removing arranged subView the view is still present

import Foundation
import UIKit

class render: UIViewController {

  let subview    = UIStackView()
  let mainview   = UIStackView()

  override func viewDidLoad() {
    super.viewDidLoad()

    self.mainviewlet()
    self.login()
  }

  func login() {

    let username = UITextField()
    // text field

    let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 40))
    //button

    // Adding to subview  
    subview.axis  = UILayoutConstraintAxis.vertical
    subview.distribution  = UIStackViewDistribution.equalSpacing
    subview.alignment = UIStackViewAlignment.center
    subview.spacing   = 16.0

    subview.addArrangedSubview(username)
    subview.addArrangedSubview(button)

    subview.translatesAutoresizingMaskIntoConstraints = false;

    // Adding subview to another stackview
    mainview.addArrangedSubview(subview)
    self.view.addSubview(mainview)

}

In another function I am removing the arranged subview

func signup(sender: UIButton!) {

    // Remove subview
    mainview.removeArrangedSubview(subview)
    subview.removeFromSuperview()

    let firstname = UITextField()
    firstname.textAlignment = NSTextAlignment.center
    firstname.textColor = UIColor.black
    firstname.frame = CGRect()
    firstname.frame.size.height = 30;
    firstname.text = "firstname"

    subview.addArrangedSubview(firstname)
    mainview.addArrangedSubview(subview)
    self.view.addSubview(mainview)
}

and my mainview is created as:

func mainviewlet {

  mainview.axis  = UILayoutConstraintAxis.vertical
  mainview.distribution  = UIStackViewDistribution.equalSpacing
  mainview.alignment = UIStackViewAlignment.center
  mainview.spacing   = 16.0
  mainview.translatesAutoresizingMaskIntoConstraints = false;

  self.view.addSubview(mainview)
}

I want the username & button to be deleted and add new field firstname to the subview.

Am I doing it the right way ? How to delete subview ? Thanks for any help

Obsolesce answered 5/1, 2017 at 11:16 Comment(4)
What is the issue?Tatouay
@Tatouay , the buttons and text boxes are still present even after I remove the subviewObsolesce
You are not removing them. Missing is somethng like subview.removeArrangedSubview(username).Tatouay
@shallowThought, u mean I need to remove them one by one ? what if there are more controls like that ?Obsolesce
B
75

In Swift 5.4

removeArrangedSubview method removes the provided view from the stack’s arrangedSubviews array. The view’s position and size will no longer be managed by the stack view. However, this method does not remove the provided view from the stack’s subviews array; therefore, the view is still displayed as part of the view hierarchy.

To prevent the view from appearing on screen after calling the stack’s removeArrangedSubview: method, explicitly remove the view from the subviews array by calling the view’s removeFromSuperview() method, or set the view’s isHidden property to true.

So:

myStackView.removeArrangedSubview(myView)
myView.removeFromSuperview()

Extended If you have a series of arranged subview, and you want to clean them, You can also create an extension:

extension UIStackView {
    
    func removeFully(view: UIView) {
        removeArrangedSubview(view)
        view.removeFromSuperview()
    }
    
    func removeFullyAllArrangedSubviews() {
        arrangedSubviews.forEach { (view) in
            removeFully(view: view)
        }
    }
    
}
Besetting answered 12/11, 2018 at 10:52 Comment(2)
Why not just myView.removeFromSuperview? That will also work.Cella
Maybe but my question was based on the apple developer one.Besetting
W
36

If you want to hide a view within a stack view, all you have to do is set the contained view’s hidden property to true and the stack view handles the rest.

So what you must call as far as I understood from your code is the following:

subview.hidden = true
Welton answered 5/1, 2017 at 14:20 Comment(1)
This is the correct answer! You don't need to remove view from super view. Hiding it does the trick! thanksUlani
E
14

By my experience backed by actually testing the implementation (😉), all you have to do to remove subview from stackView is call removeFromSuperview() method on every subview of the stackView:

stackView.subviews.forEach { (view) in
    view.removeFromSuperview()
}

This is how it looks in console:

(lldb) po stackView.arrangedSubviews
▿ 3 elements
  - 0 : <UIStackView: 0x7f840c8297d0; frame = (0 0; 375 95); layer = <CATransformLayer: 0x600003f48c80>>
  - 1 : <UIStackView: 0x7f840c82f5e0; frame = (0 125; 375 95); layer = <CATransformLayer: 0x600003f54520>>
  ▿ 2 : <UIView: 0x7f840b3c93a0; frame = (0 250; 375 47); opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x600006bdae20>; layer = <CALayer: 0x600003f4a7e0>>

(lldb) po stackView.subviews
▿ 3 elements
  - 0 : <UIStackView: 0x7f840c8297d0; frame = (0 0; 375 95); layer = <CATransformLayer: 0x600003f48c80>>
  - 1 : <UIStackView: 0x7f840c82f5e0; frame = (0 125; 375 95); layer = <CATransformLayer: 0x600003f54520>>
  ▿ 2 : <UIView: 0x7f840b3c93a0; frame = (0 250; 375 47); opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x600006bdae20>; layer = <CALayer: 0x600003f4a7e0>>

Then you remove all subviews:

(lldb) expression stackView.subviews.forEach { (view) in view.removeFromSuperview() }

And the result:

(lldb) po stackView.subviews
0 elements

(lldb) po stackView.arrangedSubviews
0 elements

You can make extension to UIStackView to save you some typing in the future:

extension UIStackView {
    func removeAllSubviews() {
        subviews.forEach { (view) in
            view.removeFromSuperview()
        }
    }
}
Easiness answered 30/7, 2019 at 7:16 Comment(0)
W
0

You are on the right track, but there are a few issues with your code.

First, you should only call self.view.addSubview(mainview) once, in mainviewlet. You should not be doing this again in login and signup.

EDIT: removed second comment because it was incorrect.

Third, your calls to addArrangedSubview and removeArrangedSubview should be balanced. You are adding username and button to your subview but never removing them. You need to remove them if you want them to disappear.

Weasel answered 5/1, 2017 at 14:32 Comment(2)
You might want to check the docs for removeArrangedSubview:. ”However, this method does not remove the provided view from the stack’s subviews array; therefore, the view is still displayed as part of the view hierarchy.”Yttria
@robmayoff Thank you, Rob, I stand corrected. That was an incorrect assumption on my part.Weasel
N
0

If you want to remove the view without referencing it again:

  1. Make sure the view is connected via outlets
  2. fooView.removeFromSuperview()

The stackView will be drawn with fooView removed

Nosey answered 16/7, 2020 at 1:28 Comment(0)
M
0

You can do it use a while loop.

let stack = UIStackView()
while let v = stack.arrangedSubviews.first {
    stack.removeArrangedSubview(v)
}
Mcmillan answered 1/9, 2021 at 3:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.