ferryawijayanto
ferryawijayanto

Reputation: 649

How to set content hugging and compression programmatically

I want to animate hide show when one of my view is hidden. so I'm using content hugging priority to animate that, but it failed it has a gap between view. here I show you the ui and my code

gap

This is 3 uiview code like the picture above

    scrollView.addSubview(chooseScheduleDropDown)
        chooseScheduleDropDown.translatesAutoresizingMaskIntoConstraints = false
        chooseScheduleDropDown.setContentCompressionResistancePriority(.required, for: .vertical)
        NSLayoutConstraint.activate([
            chooseScheduleDropDown.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            chooseScheduleDropDown.topAnchor.constraint(equalTo: scrollView.topAnchor),
            chooseScheduleDropDown.widthAnchor.constraint(equalToConstant: 285),
            chooseScheduleDropDown.heightAnchor.constraint(equalToConstant: 60)
        ])

        scrollView.addSubview(entryView)
        entryView.isHidden = true
        entryView.setContentHuggingPriority(.defaultLow, for: .vertical)
        entryView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            entryView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            entryView.topAnchor.constraint(equalTo: chooseScheduleDropDown.bottomAnchor, constant: topPadding),
            entryView.widthAnchor.constraint(equalToConstant: 285),
            entryView.heightAnchor.constraint(equalToConstant: 60)
        ])

        scrollView.addSubview(chooseDateView)
        chooseDateView.setContentHuggingPriority(.defaultLow, for: .vertical)
        chooseDateView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            chooseDateView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            chooseDateView.topAnchor.constraint(equalTo: entryView.bottomAnchor, constant: topPadding),
            chooseDateView.widthAnchor.constraint(equalToConstant: 285),
            chooseDateView.heightAnchor.constraint(equalToConstant: 60)
        ])

Upvotes: 0

Views: 5510

Answers (2)

DonMag
DonMag

Reputation: 77442

After exchanging comments, you have a number of different tasks to work on.

But, to give you an example of one approach to showing / hiding the "middle" view and having the bottom view move up / down, here is something to try. It will look like this:

enter image description here

Tapping the top (red) view will hide the middle (green) view and slide the bottom (blue) view up. Tapping the top (red) view again will slide the bottom (blue) view down and show the middle (green) view.

This is done by creating two top constraints for the Bottom view. One relative to the bottom of the Top view, and the other relative to the bottom of the Middle view, with different .priority values.

The example code is fairly straight-forward, and the comments should make things clear. All done via code - no @IBOutlet or @IBAction connections - so just create a new view controller and assign its custom class to AnimTestViewController:

class DropDownView: UIView {

}

class AnimTestViewController: UIViewController {

    let scrollView: UIScrollView = {
        let v = UIScrollView()
        return v
    }()

    let chooseScheduleDropDown: DropDownView = {
        let v = DropDownView()
        return v
    }()

    let entryView: DropDownView = {
        let v = DropDownView()
        return v
    }()

    let chooseDateView: DropDownView = {
        let v = DropDownView()
        return v
    }()

    var visibleConstraint: NSLayoutConstraint = NSLayoutConstraint()
    var hiddenConstraint: NSLayoutConstraint = NSLayoutConstraint()

    override func viewDidLoad() {
        super.viewDidLoad()

        [chooseScheduleDropDown, entryView, chooseDateView].forEach {
            v in
            v.translatesAutoresizingMaskIntoConstraints = false
            scrollView.addSubview(v)
        }

        scrollView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(scrollView)

        let g = view.safeAreaLayoutGuide

        let topPadding: CGFloat = 20.0

        // chooseDateView top anchor when entryView is visible
        visibleConstraint = chooseDateView.topAnchor.constraint(equalTo: entryView.bottomAnchor, constant: topPadding)

        // chooseDateView top anchor when entryView is hidden
        hiddenConstraint = chooseDateView.topAnchor.constraint(equalTo: chooseScheduleDropDown.bottomAnchor, constant: topPadding)

        // we will start with entryView visible
        visibleConstraint.priority = .defaultHigh
        hiddenConstraint.priority = .defaultLow

        NSLayoutConstraint.activate([

            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -40.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),

            chooseScheduleDropDown.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            chooseScheduleDropDown.topAnchor.constraint(equalTo: scrollView.topAnchor),
            chooseScheduleDropDown.widthAnchor.constraint(equalToConstant: 285),
            chooseScheduleDropDown.heightAnchor.constraint(equalToConstant: 60),

            entryView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            entryView.topAnchor.constraint(equalTo: chooseScheduleDropDown.bottomAnchor, constant: topPadding),
            entryView.widthAnchor.constraint(equalToConstant: 285),
            entryView.heightAnchor.constraint(equalToConstant: 60),

            chooseDateView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),

            //chooseDateView.topAnchor.constraint(equalTo: entryView.bottomAnchor, constant: topPadding),
            visibleConstraint,
            hiddenConstraint,

            chooseDateView.widthAnchor.constraint(equalToConstant: 285),
            chooseDateView.heightAnchor.constraint(equalToConstant: 60),

        ])

        //entryView.isHidden = true

        chooseScheduleDropDown.backgroundColor = .red
        entryView.backgroundColor = .green
        chooseDateView.backgroundColor = .blue

        let tap = UITapGestureRecognizer(target: self, action: #selector(toggleEntryView(_:)))
        chooseScheduleDropDown.addGestureRecognizer(tap)

    }

    @objc func toggleEntryView(_ sender: UITapGestureRecognizer) -> Void {
        print("tapped")

        // if entryView IS hidden we want to
        //  un-hide entryView
        //  animate alpha to 1.0
        //  animate chooseDateView down

        // if entryView is NOT hidden we want to
        //  animate alpha to 0.0
        //  animate chooseDateView up
        //  hide entryView when animation is finished

        let animSpeed = 0.5

        if entryView.isHidden {

            entryView.isHidden = false
            hiddenConstraint.priority = .defaultLow
            visibleConstraint.priority = .defaultHigh

            UIView.animate(withDuration: animSpeed, animations: {
                self.entryView.alpha = 1.0
                self.view.layoutIfNeeded()
            }, completion: { _ in
            })

        } else {

            visibleConstraint.priority = .defaultLow
            hiddenConstraint.priority = .defaultHigh

            UIView.animate(withDuration: animSpeed, animations: {
                self.entryView.alpha = 0.0
                self.view.layoutIfNeeded()
            }, completion: { _ in
                self.entryView.isHidden = true
            })

        }

    }

}

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100503

Do

// declare an instance property 
var hCon:NSLayoutConstraint! 

// get only the height constraint out of the activate block
hCon = entryView.heightAnchor.constraint(equalToConstant: 60) 
hCon.isActive = true

and play with

hCon.constant = 300 / 0
view.layoutIfNeeded()

Upvotes: 1

Related Questions