Swift: Changing the hight of subview programmatically - ios

I'm implementing a subview but I need to change the subview high programmatically but. This is how I'm changing the high:
func changeHigh() {
UIView.animate(withDuration: 1.0, animations: {
self.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height - 50)
self.buttonConstraint.constant = 10
})
}
But the problem with this implementation is animating also the position of the view. All I want is to change the high with out changing the position.
Any of you knows why is changing the position of the subview?
I'll really appreciate you help.

First, to change the height, you can just modify the size.height property of the frame.
self.frame.size.height -= 50 /// this will make it 50 pts less
Also, you should change constraints outside the animation block, not inside. Then, call layoutIfNeeded() to animate it.
Here's how your code should look:
func changeHigh() {
self.buttonConstraint.constant = 10
UIView.animate(withDuration: 1.0, animations: {
self.frame.size.height -= 50
self.layoutIfNeeded()
})
}

Related

Up and down image view and vice versa Swift/iOS

For my personal project, I try to make an image of a leaf go up for 5 seconds and then lower it for 5 seconds.
It works well, only after raising and lowering the sheet, it changes position and is transported well to the bottom of the screen.
I would like it to go up from the place of the end of the descent. I have tried several things but nothing works. I wish I could restore the original position after descent but I think it will make the image flicker on the screen.
Any ideas ?
func upLeaf(){
let xPosition = imageLeaf.frame.origin.x
let yPosition = imageLeaf.frame.origin.y - 100 // Slide Up - 20px
let width = imageLeaf.frame.size.width
let height = imageLeaf.frame.size.height
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
})
}
func downLeaf(){
let xPosition = imageLeaf.frame.origin.x
let yPosition = imageLeaf.frame.origin.y + 100 // Slide Up - 20px
let width = imageLeaf.frame.size.width
let height = imageLeaf.frame.size.height
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
})
secondUp = true
}
Instead of using frame to perform the animation you could use CGAffineTransform. It's more powerful and equally easy:
UIView.animate(withDuration: 5.0, animations: {
line3.transform = CGAffineTransform(translationX: 0, y: 100)
})
When you want to return to the initial state you should type:
UIView.animate(withDuration: 5.0, animations: {
line3.transform = CGAffineTransform.identity
})
CGAffineTransform remembers the initial parameters for your view, so that you don't have to do any calculations yourself.
If you only want the leaf to go up and down, you can just animate imageLeaf's frame.origin.y (no need to keep track of origin.x, width, or height).
func upDownLeaf() {
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame.origin.y -= 100 /// go up
}) { _ in
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame.origin.y += 100 /// go down
})
}
}

Swift PDFView jumps when frame is animated

I have an app that has a fullscreen PDFView, and I'm trying to add an animatable tab bar on the top of the screen. However, any time I animate the PDFView's frame to show the tab bar, the PDF loaded in the view jumps to another position.
I've tried to animate with UIView.animate and with UIViewPropertyAnimator, and adding the PDFView as a subview and animating the parent, but all result in the same problem.
Has anyone encountered this problem? Any ideas on how to create the animation in a way that would result in a smooth user experience? The tab bar could obviously animate itself on top of the PDFView, but I don't like the idea of it covering the PDF.
Thanks!
func CreatePDFView() {
pdfView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
view.addSubview(pdfView)
}
func AnimatePDFView() {
UIView.animate(withDuration: 1) {
self.pdfView.frame = CGRect(x: 0, y: 40, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 40)
}
}
I've been looking to add this functionality for months, but haven't been able to solve this. As soon as I asked this question, though, it seems that I did.
You need to animate pdfView.documentView?.frame, and compensate for the current frame. I did this with UIEdgeInsets, and it seems to work.
if tabDocumentBrowserIsVisible {
tabDocumentBrowser.Animate(toState: .hidden)
UIView.animate(withDuration: 0.3) {
let inset = UIEdgeInsets(top: -80, left: 0, bottom: 0, right: 0)
self.pdfView.documentView?.frame = self.pdfView.documentView?.frame.inset(by: inset) as! CGRect
}
tabDocumentBrowserIsVisible = false
} else {
tabDocumentBrowser.Animate(toState: .visible)
UIView.animate(withDuration: 0.3) {
let inset = UIEdgeInsets(top: 80, left: 0, bottom: 0, right: 0)
self.pdfView.documentView?.frame = self.pdfView.documentView?.frame.inset(by: inset) as! CGRect
}
tabDocumentBrowserIsVisible = true
}
The PDF still behaves a bit funny if you are scrolling it while you animate it, but it's not too bad.

Swift || Bug when Animating and Removing Subview from Superview

Im made and DropDown Menu to select Action like the GIF below.
Therefore I made a Subview and animated it in.
When animating the Subview out, it looks really weird.
In particular the problem is that it just looks like a blank small bar and not like the Menu.
Does anyone know where the problem might be?
The ViewController I'm making the Subview of is a simple ViewController with a TableView inside and 1 prototype cell.
Code:
let blackView = UIView()
var tvx: OptionsVC = OptionsVC()
var h: CGFloat!
.
func optionsClicked() {
self.h = CGFloat(70 + (52 * (OptionsVC().arrayFunctionCellNames.count)))
navigationController?.hidesBarsOnTap = false
tvx = self.storyboard?.instantiateViewController(withIdentifier: "options") as! OptionsVC
if let window = UIApplication.shared.keyWindow {
blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
view.addSubview(blackView)
view.addSubview(tvx.view)
let y = (self.navigationController?.navigationBar.frame.size.height)! + UIApplication.shared.statusBarFrame.height
tvx.view.frame = CGRect(x: 0, y: (y - self.h), width: view.frame.width, height: h)
blackView.frame = CGRect(x: 0, y: y, width: view.frame.width, height: view.frame.height)
blackView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackView.alpha = 1
self.tvx.view.frame = CGRect(x: 0, y: y, width: self.view.frame.width, height: self.h)
self.blackView.frame = CGRect(x: 0, y: (y + self.h), width: self.view.frame.width, height: self.view.frame.height)
}, completion: nil)
}
}
.
func handleDismiss() {
UIView.animate(withDuration: 5.5, animations: {
let y = (self.navigationController?.navigationBar.frame.size.height)! + UIApplication.shared.statusBarFrame.height
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow {
self.blackView.frame = CGRect(x: 0, y: y, width: self.view.frame.width, height: self.view.frame.height)
self.tvx.view.frame = CGRect(x: 0, y: (y - self.h), width: self.view.frame.width, height: self.h)
}
}, completion: {(finished:Bool) in
self.blackView.removeFromSuperview()
self.tvx.view.removeFromSuperview()
self.navigationController?.hidesBarsOnTap = true
})
}
GIF of BUG:
I made it so slow so you can better see it
Edit: My Solution
The problem was the constraints I set on my subview controller. Normally you set them to all sides, in my case, with was really weird I had to set them only to the bottom and sides. If I set some to the top, it would always do this bug.
You haven't really provided enough information for us to understand what's going on. What are tvx, blackView and self? What is the self.h variable? (From the animation it looks like you're changing the height of your "menu" view to be much shorter before you begin the animation code.)
Do you have a view controller contained inside another one using an embed segue?
If so, you should probably animate the constraints on the container view, not the child view controller's view.
As Glenn and D. Greg say in their comments, you should really be adding constraints to your views, hooking up outlets to those constraints, and animating changes to the constraint's constants rather than manipulating your view's frames directly. Animating changes to your view's frames isn't reliable when you're using AutoLayout, since AutoLayout can change your view's size and position out from under your animation code. That code looks like this, (in broad terms, no specific to your code)
myViewAConstraint.constant = someNewValue
myViewBConstraint.constant = someOtherValue
UIView.animate(withDuration: 5.5,
animations: {
someView.alpha = 0 //If you want the view to fade as it animates
self.view.layoutIfNeeded()
},
completion: { (finished:Bool) in
}
)

How to embed a UILabel inside a UIView in swift

I need to create a UIView programmaticaly in swift, that view should contain an image and a label. Also I need to embed that label and the imageview inside that created view so that as I animate the constraints of the view, the label and the image shold also reposition itseld relative to the view. This is my code co far -
func banner(viewController:UIViewController){
let width = UIScreen.main.bounds.width
let dynamicView=UIView(frame: CGRect(x:0,y: -70, width:width, height:70))
let label = UILabel(frame: CGRect(x:0,y: 35, width:width, height:20))
dynamicView.backgroundColor=UIColor.green
label.center = CGPoint(x: width/2, y: 35)
label.textAlignment = .center
label.text = "I'am a test label"
UIView.animate(withDuration: 1) {
dynamicView.frame = dynamicView.frame.offsetBy( dx: 0, dy: 70 )
viewController.view.addSubview(DynamicView)
viewController.view.addSubview(label)
}
UIView.animate(withDuration: 1, delay: 3, usingSpringWithDamping: 1, initialSpringVelocity: 4, options: .curveEaseIn, animations: {
dynamicView.frame = DynamicView.frame.offsetBy( dx: 0, dy: -70 )
}, completion: nil)
}
}
I could achieve that by changing x and y position of each views,labels etc separately. But that code would not be clean and consise.
From the question, it is seen that you are adding the label as subview to the viewController's view. Since you wish to embed the label to the Dynamic view try adding the label to Dynamic view like
UIView.animate(withDuration: 1) {
dynamicView.frame = dynamicView.frame.offsetBy( dx: 0, dy: 70 )
viewController.view.addSubview(DynamicView)
dynamicView.addSubview(label)
}

Programmatically add label to Message App in Swift?

I know this is new with iOS10 and all, but Im trying to build a simple ms messageappextension app, and all the tutorials Ive found add their labels, buttons, etc via storyboard.
I hate autlayout and don't use storyboard, so I need to find how to add elements programmatically. This is what Ive tried:
//main label
pointsLabel.frame = CGRect(x: 0, y: 0, width: view.bounds.width * 0.5, height: view.bounds.height * 0.1)
pointsLabel.center = CGPoint(x: view.bounds.width * 0.5, y: view.bounds.width * 0.7)
pointsLabel.textColor = UIColor.red
pointsLabel.textAlignment = .center
pointsLabel.text = "Testing 123"
pointsLabel.font = UIFont(name: "Helvetica", size: screenSize.height * (30/screenSize.height))
view.addSubview(pointsLabel)
This is how Id normally make a label, and this works when the MSMessagesAppViewController is in full view like this:
However when its like this even though the positioning of the center is based on view.bounds, when the view shrinks here, the label is still displayed out of view:
Ive found that this is called when the size changes, however even resetting the center here does nothing:
override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
// Called before the extension transitions to a new presentation style.
// Use this method to prepare for the change in presentation style.
print(view.bounds.height)
pointsLabel.center = CGPoint(x: view.bounds.width * 0.5, y: view.bounds.width * 0.7)
}
Other than just switching back in forth between different heights, what is the correct way to add a label programmatically?
Change your center calculation to use the height of the superview for y, rather than a portion of the width:
pointsLabel.center = CGPoint(x: view.bounds.width * 0.5, y: view.bounds.height * 0.5)
While compact, the width is actually greater than the height, so view.bounds.width * 0.7 was pushing your label off the screen.

Resources