Reputation: 7240
I'm updating an iOS Swift app (that someone else created) which contains a view ("View A") which initially fills the entire screen. For what it's worth, this view is a map. When a user taps on a point of interest on the map, the height of the map view ("View A") shrinks to 75% of the height of the screen and another view ("View B") is shown in the bottom 25% of the screen. Here's a visual depiction of that scenario.
Currently, this is being accomplished like this:
// this is "View A"
var mapView: MGLMapView!
// this is "View B"
var pageViewController : UIPageViewController!
var pageViewControllerFrame = CGRect()
override func viewDidLoad() {
super.viewDidLoad()
// setup map view
mapView = MGLMapView(frame: view.bounds, styleURL: styleUrl)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
// setup UIPageViewController
pageViewControllerFrame = CGRect(x: 0, y: self.view.bounds.height * 0.75, width: mapView.bounds.width, height: self.view.bounds.height / 4)
pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageViewController.view.frame = pageViewControllerFrame
pageViewController.view.autoresizingMask = [.flexibleWidth]
pageViewController.view.translatesAutoresizingMaskIntoConstraints = true
view.addSubview(pageViewController.view)
pageViewController.view.isHidden = true
}
@objc func handleMapTap(sender: UITapGestureRecognizer) {
if userTappedOnPoi == true {
self.mapView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height * 3/4)
pageViewController.view.isHidden = false
} else {
// user tapped on the map but not on a POI so hide pageViewController and reset map frame to take up the entire screen
pageViewController.view.isHidden = true
mapView.frame = view.bounds
}
}
As you can see, there's a tap gesture recognizer on the map view. If the user taps on a POI, then the map view's frame will be adjusted so the height is 75% of the view's height and then the bottom view ("View B") is made visible. This is working but I think it would look better if it were animated so as the height of the map view is shrinking, the view at the bottom is sliding up onto the screen.
I've been playing with animate(withDuration:delay:options:animations:completion:)
but so far haven't had any luck getting the animation to work properly. Most of the things I've tried (even with a duration of something like 3.0 seconds) still seem to result in the map view changing it's height immediately. I'm guessing this might be because there are no auto layout constraints in place to animate?
Upvotes: 0
Views: 905
Reputation: 100503
Using auto-layout is better in your case as with the pager pageViewController.view.isHidden = true/false
is hidden/shown instantly and with no sync to the collapse of the map , so set constraints like
Mapview : top , leading , trailing and multiplier height
pager : top to map , leading , trailing and bottom to view
Then animate the change of the map's height multiplier like
var heightCon:NSLayoutConstraint!
heightCon.constant = self.view.bounds.height * 0.75
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
Upvotes: 1
Reputation: 2906
You can also use UIStackView
so you can easily get animations by changing isHidden
property.
Example:
import UIKit
import PlaygroundSupport
class VC: UIViewController {
private let view1 = UIView()
private let view2 = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view1.backgroundColor = .red
view2.backgroundColor = .green
view2.isHidden = true
let stackView = UIStackView(arrangedSubviews: [view1, view2])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stackView.topAnchor.constraint(equalTo: view.topAnchor),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
view2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25)
])
view1.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleMapTap(sender:))))
}
@objc func handleMapTap(sender: Any) {
UIView.animate(withDuration: 0.3) {
self.view2.isHidden = !self.view2.isHidden
self.view.layoutIfNeeded()
}
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = VC()
Upvotes: 1