how to create the transition with animations in the link - ios

I have to create a transition animation like in the link below.. please help if anyone knows how to do this
https://dribbble.com/shots/6488787-Music-App-UI-Pages
I tried to zoom image.. and i need this view in every view controller in the app so i tried to do it as a base view controller
I tried to add the bar in the right side of the screen. but now struggling to do the effect as the design shows
import UIKit
class BaseViewController: UIViewController {
var location = CGPoint(x: 0, y: 0)
var buttonImage = UIImageView()
var strechyImage = UIImageView()
var boxviewImage = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
}
override func touchesMoved(_ touches: Set<UITouch>?, with event: UIEvent?) {
let touch : UITouch! = touches?.first
location = touch.location(in: self.view)
strechyImage.center = location
}
func setUpView() {
let viewHeight = UIScreen.main.bounds.height
//FloatButton.setImage(UIImage(named: "Icon ionic-md-sad"), for: .normal)
boxviewImage.image = UIImage(named: "nfc box")
boxviewImage.frame = CGRect(x: 0, y: 0, width: 5, height: 200)
let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(boxviewImage)
//view.addSubview(boxviewImage)
strechyImage.image = UIImage(named: "nfc curve")
strechyImage.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
view.addSubview(strechyImage)
buttonImage.image = UIImage(named: "nfc floating")
buttonImage.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
strechyImage.addSubview(buttonImage)
//view.bringSubviewToFront(buttonImage)
buttonImage.translatesAutoresizingMaskIntoConstraints = false
strechyImage.translatesAutoresizingMaskIntoConstraints = false
boxviewImage.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
strechyImage.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 1),
strechyImage.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.142),
strechyImage.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.3),
strechyImage.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -(viewHeight / 20)),
buttonImage.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.1),
buttonImage.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.055),
buttonImage.centerXAnchor.constraint(equalToSystemSpacingAfter: strechyImage.centerXAnchor, multiplier: -0.9),
buttonImage.centerYAnchor.constraint(equalToSystemSpacingBelow: strechyImage.centerYAnchor, multiplier: 0),
boxviewImage.trailingAnchor.constraint(equalTo: currentWindow!.safeAreaLayoutGuide.trailingAnchor, constant: 2.2),
boxviewImage.widthAnchor.constraint(equalTo: currentWindow!.widthAnchor, multiplier: 0.0255),
boxviewImage.heightAnchor.constraint(equalToConstant: viewHeight),
])
}
}
Need to create this transition as close as possible to the design in the link

Related

Calling 'scrollView.zoom' Does Not Zoom

For some reason scrollView.zoom does not zoom in on an imageView.
I have an imageView inside a scrollView.
in ViewDidLoad:
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 2.0
scrollView.delegate = self
viewForZooming:
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
Now, I'm calling below after both scrollView and imageView are initialized.
var scale: CGFloat = 2
let location = CGPoint(x: imageView.frame.width/2, y: imageView.frame.height/2)
scrollView.zoom(to: zoomRectForScale(scale, center: location), animated: true)
Nothing is happening after scrollView.zoom is called. I tried doing
view.setNeedsDisplay()
view.layoutIfNeeded()
Still nothing happens, imageView is not zooming in.
UPDATE:
As requested, here is the code for scrollView and imageView initialization:
func createscrollView(image: UIImage?){
if image == nil{
let img = UIImage(named: "demo image.jpg")
let imgCorrected = scaleAndOrient(image: img!)
//created user selecged images
userSelectedImage_UI = img
userSelectedImage_UI_Corrected = imgCorrected
}
// create image scroll view
scrollView = UIScrollView(frame: CGRect(x: 0, y: 0,width: 100, height: 100))
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.bouncesZoom = false
scrollView.bounces = false
scrollView.contentMode = .scaleAspectFill
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -150),
scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0)
])
// add image view to scrollview
imageView = UIImageView(frame: CGRect(x: 0, y: 0,width: 100, height: 100))
scrollView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: 0),
imageView.leftAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leftAnchor, constant: 0),
imageView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: 0),
imageView.rightAnchor.constraint(equalTo: scrollView.contentLayoutGuide.rightAnchor, constant: 0),
imageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1),
imageView.heightAnchor.constraint(equalTo: scrollView.heightAnchor, multiplier: 1)
])
imageView.contentMode = .scaleAspectFit
if image == nil{
imageView.image = userSelectedImage_UI_Corrected
} else {
imageView.image = scaleAndOrient(image: image!)
}
}
Based on comments...
It sounds like you are creating / setting up your scrollView and its content imageView from viewDidLoad() and then immediately trying to "zoom" it.
If so, that will be problematic, as auto-layout hasn't finished laying out the UI elements.
You can call it from:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var scale: CGFloat = 2
let location = CGPoint(x: imageView.frame.width/2, y: imageView.frame.height/2)
scrollView.zoom(to: zoomRectForScale(scale, center: location), animated: true)
}
I have a feeling the problem is in your zoomRectForScale function, though it isn't posted. It should be something like this:
func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = scrollView.convert(center, from: imageView)
zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
Additionally, I've verified that double-tapping to zoom works to the correct location using:
var gestureRecognizer: UITapGestureRecognizer!
// Sets up the gesture recognizer that receives double taps to auto-zoom
func setupGestureRecognizer() {
gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
gestureRecognizer.numberOfTapsRequired = 2
scrollView.addGestureRecognizer(gestureRecognizer)
}
// Handles a double tap by either resetting the zoom or zooming to where was tapped
#IBAction func handleDoubleTap() {
if scrollView.zoomScale == 1 {
scrollView.zoom(to: zoomRectForScale(scrollView.maximumZoomScale, center: gestureRecognizer.location(in: gestureRecognizer.view)), animated: true)
} else {
scrollView.setZoomScale(1, animated: true)
}
}
Don't forget to call this in viewDidLoad:
setupGestureRecognizer()
If this doesn't solve your issue, please adjust your question with missing code functions and variable declarations.

Image view moves to aside when scrolling vertically in scroll view

I've got a view controller that has a UIView (featuredStoryView) and inside that view, I've added a scroll view (scrollView) and inside the scroll view, I've added an ImageView (bookCover), one on top of the other. Here is the code for all of those elements:
func setupFeaturedStoryView() {
featuredStoryView.backgroundColor = .white
featuredStoryView.layer.cornerRadius = 12
// Let the user tap on the featured story image view
featuredStoryView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(featuredStoryViewTapped))
featuredStoryView.addGestureRecognizer(tapGesture)
view.addSubview(featuredStoryView)
addFeaturedStoryViewConstraints()
}
func setupScrollView() {
scrollView.backgroundColor = UIColor(red: 10/255, green: 10/255, blue: 20/255, alpha: 0.5)
scrollView.layer.cornerRadius = 15
featuredStoryView.addSubview(scrollView)
// Add the constraints to the scroll view
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: featuredStoryView.topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: featuredStoryView.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: featuredStoryView.trailingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: featuredStoryView.bottomAnchor).isActive = true
}
func setupBookCover() {
bookCover.backgroundColor = .yellow
bookCover.layer.cornerRadius = 15
bookCover.contentMode = .scaleAspectFill
scrollView.addSubview(bookCover)
addBookCoverConstraints()
}
// Add the constraints to the featured story view
func addFeaturedStoryViewConstraints() {
featuredStoryView.translatesAutoresizingMaskIntoConstraints = false
featuredStoryView.topAnchor.constraint(equalTo: view.centerYAnchor, constant: -130).isActive = true
featuredStoryView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100).isActive = true
featuredStoryView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -100).isActive = true
featuredStoryView.bottomAnchor.constraint(equalTo: view.centerYAnchor, constant: 130).isActive = true
}
// Add constraints to the book cover
func addBookCoverConstraints() {
bookCover.translatesAutoresizingMaskIntoConstraints = false
bookCover.topAnchor.constraint(equalTo: featuredStoryView.topAnchor).isActive = true
bookCover.leadingAnchor.constraint(equalTo: featuredStoryView.leadingAnchor).isActive = true
bookCover.trailingAnchor.constraint(equalTo: featuredStoryView.trailingAnchor).isActive = true
bookCover.bottomAnchor.constraint(equalTo: featuredStoryView.bottomAnchor).isActive = true
}
When you tap on the featuredStoryView, the following code snippet runs:
#objc func featuredStoryViewTapped() {
scrollView.contentSize.height = 1500
let animator = UIViewPropertyAnimator(duration: 0.6, dampingRatio: 0.8) {
self.featuredStoryView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.scrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.layoutIfNeeded()
self.bookCover.frame = CGRect(x: self.featuredStoryView.frame.midX - (bookCoverWidth / 2), y: 90, width: bookCoverWidth, height: bookCoverHeight)
self.view.layoutIfNeeded()
}
animator.startAnimation()
}
Now take a look at this Gif:
The problem here is, when I scroll, the yellow imageView(bookCover) moves to the top left corner, why does this happen? It should just go up with the scroll view. Is there any way to fix this?
You can not set frame directly like self.featuredStoryView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height) and contentSize like scrollView.contentSize.height = 1500 in auto layout. So try to set constraints as per your requirement.

My textView bottomAnchor does not seem to work?

I have a textView and I have a line, I set the line's frame without contraints and set textView frame with constraints. Simply what I want is the textView to follow the line, so I put a bottomAnchor to textView equal to the topAnchor of the line. Yet when I animate the line the textView does not follow? What am I doing wrong?
var button = UIButton()
var testLine = UIView()
let textView = UITextView()
var textViewBottomAnchorConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
testLine.backgroundColor = .black
testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
view.addSubview(testLine)
view.addSubview(textView)
textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
textView.backgroundColor = UIColor.yellow
textView.text = ""
textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isHidden = false
textView.translatesAutoresizingMaskIntoConstraints = false
// textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
textViewBottomAnchorConstraint?.isActive = true
UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {
self.testLine.transform = CGAffineTransform.identity.translatedBy(x: 0, y: 30)
}) { (true) in
self.view.layoutIfNeeded()
}
}
As #Vollan correctly said animating transform property is not the best option. Here is quote from Apple documentation: "In iOS 8.0 and later, the transform property does not affect Auto Layout. Auto layout calculates a view’s alignment rectangle based on its untransformed frame." Therefore animation of transform property doesn't change layout of textView. I recommend you to animate frame property instead of transform.
However, if you switch to frame animation it doesn't fix all your problems. If you keep your animation inside viewDidLoad method you may encounter very strange behavior. The reason is that in viewDidLoad the view itself is not yet laid out properly. Starting animation inside viewDidLoad may lead to unpredicted results.
At last you need adjust your animation block. Apple recommends to apply layoutIfNeeded inside the animation block. Or at least they used to recommend it then autolayout was introduced - watch this WWDC video (starting from 30th minute) for further details.
If you apply all recommendations above your code should look like this:
var button = UIButton()
var testLine = UIView()
let textView = UITextView()
var textViewBottomAnchorConstraint: NSLayoutConstraint?
var triggeredAnimation = false
override func viewDidLoad() {
super.viewDidLoad()
testLine.backgroundColor = .black
testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
view.addSubview(testLine)
view.addSubview(textView)
textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
textView.backgroundColor = UIColor.yellow
textView.text = ""
textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isHidden = false
textView.translatesAutoresizingMaskIntoConstraints = false
// textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
textViewBottomAnchorConstraint?.isActive = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// viewDidAppear may be called several times during view controller lifecycle
// triggeredAnimation ensures that animation will be called just once
if self.triggeredAnimation {
return
}
self.triggeredAnimation = true
let oldFrame = self.testLine.frame
UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {
self.testLine.frame = CGRect(x: oldFrame.minX, y: oldFrame.minY + 30, width: oldFrame.width,
height: oldFrame.height)
self.view.layoutIfNeeded()
})
}
Anchor points make references to others positions, meaning. It is still referensed to y = 355 as you transform it and not actually "move" it.
What i recommend is that you don't mix using frame-based layout and anchorpoints / layout constraints.

How can I create reusable view controllers inside of UIScrollView?

I am trying to create a full page sized horizontally scrolling UIScrollView. On each page I am adding instances of the same UIViewController class. I would like to create some kind of reusable functionality to conserve both memory and processor use needed. Below is a basic implementation I have created with some toying around with how reusability might work although Im not quite sure. Thank you for any help you can offer.
Current UIScroll ViewController Model
let scrollView:UIScrollView = {
let scrollView = UIScrollView(frame: CGRect.zero)
scrollView.isPagingEnabled = true
scrollView.backgroundColor = UIColor.gray
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = true
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
scrollView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.view.bounds.size)
self.view.addSubview(scrollView)
scrollView.delegate = self
scrollView.contentSize = CGSize(width: 3 * self.view.frame.width, height: self.view.frame.height)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0),
scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0)
])
let viewController1 = UIViewController()
viewController1.view.backgroundColor = UIColor.red
let viewController2 = UIViewController()
viewController2.view.backgroundColor = UIColor.blue
let viewController3 = UIViewController()
viewController3.view.backgroundColor = UIColor.green
self.addChild(viewController1)
viewController1.view.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController1.view)
addViewControllerContraints(viewController: viewController1, index: 0)
viewController1.didMove(toParent: self)
self.addChild(viewController2)
viewController2.view.frame = CGRect(origin: CGPoint(x: self.view.bounds.width, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController2.view)
addViewControllerContraints(viewController: viewController2, index: 1)
viewController2.didMove(toParent: self)
self.addChild(viewController3)
viewController3.view.frame = CGRect(origin: CGPoint(x: 2 * self.view.bounds.width, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController3.view)
addViewControllerContraints(viewController: viewController3, index: 2)
viewController3.didMove(toParent: self)
}
func addViewControllerContraints( viewController: UIViewController, index:Int){
guard let view = viewController.view else{
print("View found nil")
return
}
view.translatesAutoresizingMaskIntoConstraints = false
let offset:CGFloat = UIScreen.main.bounds.width * CGFloat(index)
print("Offset: \(offset)")
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0),
view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: offset),
view.heightAnchor.constraint(equalToConstant: self.view.bounds.height),
view.widthAnchor.constraint(equalToConstant: self.view.bounds.width)
])
}
Is there a good way to create some type of reuse functionality this is something I was playing around with based on This Answer although I realize that is primarily for UIPageViewControllers where allocation and deallocation of UIViewController's is handled for you.
Possible Reuse Functionality
var reuseableViewControllers:[UIViewController] = [UIViewController]()
private func unusedViewController() -> UIViewController {
let unusedViewControllers = reuseableViewControllers.filter { $0.parent == nil }
if let someUnusedViewController = unusedViewControllers.first {
return someUnusedViewController
} else {
let newViewController = UIViewController()
reuseableViewControllers.append(newViewController)
return newViewController
}
}

Fill gradually a shape using swift and UIViewAnimation?

I have an iOS 10 app that contains a button ("Press Me!"), and a UIView containing a blue outlined rectangle, with no fill. I want to fill the rectangle gradually (in like 5 seconds) with red, using any possible method (I tried using UIView.animation(withDuration:, animations:)). I will include the code below:
Here's the viewController:
class ViewController: UIViewController {
#IBOutlet weak var tronkyy: tronc!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func didPress(_ sender: UIButton) {
tronkyy.full = true
tronkyy.setNeedsDisplay()
} }
And the view:
#IBDesignable class tronc: UIView {
//var value = 0.0
var full = false
override func draw(_ rect: CGRect) {
UIColor.blue.setStroke()
boxPath().stroke()
drawDynamic()
}
private func boxPath() -> UIBezierPath {
let path = UIBezierPath(rect: CGRect(x: 0.1 * frame.width, y: 0.1 * frame.height, width: 0.8 * frame.width, height: 0.8 * frame.height))
UIColor.blue.setStroke()
return path
}
func drawDynamic() {
if full {
UIView.animate(withDuration: 10) { _ in
//while self.value < 1 {
let path = UIBezierPath(rect: CGRect(x: 0.1 * self.frame.width, y: 0.1 * self.frame.height, width: (0.8 * self.frame.width), height: 0.8 * self.frame.height)) //* CGFloat(value)))
UIColor.red.setFill()
path.fill()
//self.value += 0.1
//}
}
full = false
}
} }
Ah, and yes, please ignore that the red view cover the rectangle.
The problem is that there is no gradual filling. it just fills it once and for all.
Edit: I commented out the "value" property and the while loop, as suggested in the answers, but it still doesn't work.
This is an approach using a view with a subview. For a more complex shape than a rectangle, it could be done with masks.
You can run this directly in a Playground page:
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let btn: UIButton = {
let b = UIButton()
b.setTitle("Tap Me", for: .normal)
b.backgroundColor = .blue
b.frame = CGRect(x: 20, y: 20, width: 200, height: 30)
return b
}()
let blueRect: UIView = {
let v = UIView()
v.layer.borderColor = UIColor.blue.cgColor
v.layer.borderWidth = 2.0
v.backgroundColor = .clear
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let redRect: UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
var redRectHeightConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(btn)
btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
blueRect.addSubview(redRect)
self.view.addSubview(blueRect)
redRect.leftAnchor.constraint(equalTo: blueRect.leftAnchor, constant: 0.0).isActive = true
redRect.rightAnchor.constraint(equalTo: blueRect.rightAnchor, constant: 0.0).isActive = true
redRect.bottomAnchor.constraint(equalTo: blueRect.bottomAnchor, constant: 0.0).isActive = true
redRectHeightConstraint = NSLayoutConstraint(item: redRect,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1.0,
constant: 0.0)
redRect.addConstraint(redRectHeightConstraint!)
blueRect.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5).isActive = true
blueRect.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.5).isActive = true
blueRect.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
blueRect.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
}
func didTap(_ sender: Any?) -> Void {
UIView.animate(withDuration: 5.0, animations: {
_ in
self.redRectHeightConstraint!.constant = self.blueRect.frame.size.height
self.view.setNeedsLayout()
}, completion: {
finished in
})
}
}
let vc = TestViewController()
vc.view.backgroundColor = .yellow
vc.view.frame = CGRect(x: 0, y: 0, width: 600, height: 600)
PlaygroundPage.current.liveView = vc
Note: this is just sample, demonstration code... not meant to be a copy/paste solution.
You should not use a while loop in an animation function. Try this version
UIView.animate(withDuration: 10) { _ in
let path = UIBezierPath(rect: CGRect(x: 0.1 * self.frame.width, y: 0.1 * self.frame.height, width: (0.8 * self.frame.width), height: 0.8 * self.frame.height))
UIColor.red.setFill()
path.fill()
}

Resources