Swift View Animation from Line - swift

Swift View Animation from Line
Swift 4.2, Xcode 10.0
I want to perform an animation with a view wherein it builds out or into a line.
Build out of line:
Build into line:
My only solution at this point is to put another view on the opposite side of the line to cover the view before it starts to animate. But this is a bad solution and it can sometimes block other views. Also, I would like to avoid stretching my content because I want to be able to perform this animation with images. What would be the best way to integrate this. Thank you in advance for the help!

So you want this:
A subview can extend outside the bounds of its superview. When this happens, the part of the subview that is outside the superview is visible if the superview's clipsToBounds property is false, and hidden if the superview's clipsToBounds is true.
I used this clipping to hide the part of the green view that is below the line. Perhaps these side views at the halfway point of the animation will help explain how I set it up:
The superview (labelled “hider”) has been shrunk here to half the height of the green view. With clipping enabled, half of the green view is hidden. With clipping disabled, the bottom of the green view is visible below the line.
Here is how I set up the demo:
I put the green view in a new superview. I call this new superview the “hider”.
I turned on the “Clips to Bounds” check box in the hider's Attributes inspector.
I set width and height constraints on the green view. You could use other constraints (like leading/trailing) to control its size.
I constrained the leading, trailing, and top edges of the green view to equal the corresponding edges of the hider.
I constrained the height of the hider to equal the height of the green view plus 12. The 12 will make the white margin between the green view and the line. I set this constraint's priority to 999. This means auto layout will try very hard to satisfy the constraint, but will break this constraint if necessary in order to satisfy all required constraints.
I created a constraint setting the hider's height to zero. I connected this constraint to an outlet named hiderHeightConstraint in my view controller. Note that this means there are two constraints on the hider's height. This one forces the hider's height to zero and is required. The other (created in the prior step) sets the hider's height to the green view's height plus padding, but is not required. When you are editing the layout in the storyboard, you probably want to turn off this constraint by turning off its “Installed” check box in the constraint's Attributes inspector.
I connected the “Toggle Secret Message” button to this action:
#IBAction private func toggleButtonWasTapped() {
UIView.animate(withDuration: 0.7) {
self.hiderHeightConstraint.isActive.toggle()
self.view.layoutIfNeeded()
}
}
Here's how it works. When the hiderHeightConstraint is active, the hider is forced to zero height. Since it clips its subviews, the green view is not visible. Since the constraint between the hider's height and the green view's height is not required, the green view can still be its natural size. The other constraints (leading/trailing/top) force the green view to stick out beyond the bottom edge of the hider.
When the hiderHeightConstraint is not active, the hider grows to the height of the green view plus the padding, allowing the green view to be fully visible.
Here is what my storyboard looks like:

This is one approach you can follow to achieve this:
Take 2 Container UIView and 2 line view (you may take UIView again) and 2 UIImageView (or any for green view). So your StoryBoard should look like this :
Make sure your container views are clips to bound (you can set it from storyboard only).
Now you can achieve the animation easily by CGAffineTransform.
I will call outlet names for animated view as imageViewOne and imageViewTwo.
In viewDidLoad() write this (if initially views are hidden):
imageViewOne.transform = CGAffineTransform(translationX: 0.0, y: containerViewOne.bounds.height)
imageViewTwo.transform = CGAffineTransform(translationX: 0.0, y: -containerViewOne.bounds.height)
Then to show it with animation:
//To build out of line
UIView.animate(withDuration: 1.0, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.imageViewOne.transform = .identity
self.imageViewTwo.transform = .identity
}, completion: nil)
//To build into line
UIView.animate(withDuration: 1.0, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.imageViewOne.transform = CGAffineTransform(translationX: 0.0, y: containerViewOne.bounds.height)
self.imageViewTwo.transform = CGAffineTransform(translationX: 0.0, y: -containerViewOne.bounds.height)
}, completion: nil)

Use a view but then put in that view the line to make it look authentic.
Then when you are done make the whole animation disappear or if you want to make other animations go over it , you can call functions to move views above others
https://stackoverflow.com/a/38780829/4674760

Related

Center a subview horizontally with custom vertical distance | Swift

I have the following subview that I would like to centered in horizontally on the screen and set the vertical distance manually.
let customImageView = AnimationView(name: "image")
customImageView.frame = CGRect(x: -140, y: 40, width: 700, height: 700)
customImageView.contentMode = .scaleAspectFill
self.view.addSubview(customImageView)
Is it possible to ensure that the vertical distance set will account if the screen size of the phone is smaller.
This sounds like a job for Auto Layout (https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html), which is Apple's constraint-based system made specifically to dynamically size views in relation to other views and screen sizes. In your case, you could set a greater than/less than to constraint to the top of the view and your subview, so that it will be at least a certain amount of spacing with the option to grow if the screen is larger/smaller.
If you would like to still do frame based layouts (e.g. creating a CGRect/frame), you'll have to do the math yourself based on the view.frame.size.height value. Be aware that a view controller's view frame might not be set before viewDidLayoutSubviews is called.

UITextField shrinks text when animation starts

When I try to animate UiTextField width constraints, it makes content looking like on the final animation frame (just shrinks it). How to avoid that and make animation forwards same as you see it works backwards? (animation slowed down in emulator here)
textFieldWidthConstraint.constant = 0.0
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}

UIView transition problem from bottom to up

In my application I want to animate a view from bottom to up in override func viewDidLayoutSubviews(). So far I have done this way to transit the view from bottom but in different device it is showing different UI. UIView transition is working but view is not fully transitioning from bottom expect iPhone XS. So far I have done these two ways :
First Step:
let currentFrame = self.animationVIew.frame
self.animationVIew.frame = CGRect(x: 0, y: self.view.frame.height, width: currentFrame.size.width, height: currentFrame.size.height)
UIView.animate(withDuration: 1.0) {
self.animationVIew.frame = currentFrame
self.loadViewIfNeeded()
}
Second Step:
UIView.transition(with: animationVIew,
duration: 0.5,
options: [.transitionFlipFromBottom],
animations: {
},
completion: nil)
But for both way I am facing same problem. No luck!!
It was my mistake I did not think in proper way to solve it.Anyway if anyone face similar kind of problem then may be this answer will help them. I have just changed the current autolayout to fix this issue.This problem was happening because of constraint between animationView and topView. The distance constraint between these two view was fixed, That is why when animation was happening it was resizing the animationView to adjust the constraints.So my solution was making the animation view height constraint fixed and have changed the priority required to low of distance constraint between animationView and topView in storyboard

UIButton action is not triggered after constraint layouts changed

I have got an UIButton on a storyboard ViewController. When I load data into the form and the layout is significantly changing the button does not recognise the touch action.
I have figured out that when button is visible on the scrollview right after it if filled with data, the touch action works.
If the data too long and the button is not visible at first, just when it is scrolled into the display, the touch action does not work.
I was checking if something is above the button, but nothing. I have tried to change the zPosition of the button, not solved the problem.
What can be the issue?
I have made custom classes from the UIScrollView and the UIButton to check how the touches event triggered. It is showing the same behaviour, which is obvious. If the button is visible right at the beginning, the UIButton's touchesBegan event is triggered. If the button moves down and not visible at the beginning, it is never triggered, but the scrollview's touchesBegan is called instead.
Depending on the size of the data I load into the page sometimes the button is visible at the beginning, but the form can be still scrolled a bit. In this case the button still work, so it seems that this behaviour is not depending on if the scrollview is scrolled before or not, just on the initial visibility of the button.
Is there any layout or display refresh function which should be called to set back the behaviour to the button?
The code portion which ensures that the contentview is resized for the scroll if the filled data requires bigger space.
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.frame.size.height = contentRect.size.height
scrollview.contentSize = contentview.bounds.size
}
Ok, so another update. I have coloured the contentview background to blue and the scrollview background to white. When I load the data and resize the layout constraints, the contentview is resizing as expected, however now the scrollview is going to the bottom. After I scroll the view it is resizing to the original size which fits the screen. Now the button is only recognised when I touch the are which is blue behind. With the white background it is not recognised anymore, so it seems that the scrollview is hiding the button.
Let me get this clear the button is added in storyboard and it is a spritekit project?? If you are using zPosition?? Why don’t u connect the UIButton via the assistant editor as an IBAction then the action is always tied to the button.
You can also do it differently
Create an SKLabelNode and put it on the screen where you want to have the button and then set a name to it as myButton
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let tappedNodes = nodes(at: location)
for node in tappedNodes {
if node.name == "myButton" {
// call your action here
}
}
}
}
EDIT 1:
You could also try auto resizing your scrollView.content this works also if you are adding any views via the app or programmatically
private func resizeScrollView(){
print("RESIZING THE SCROLLVIEW from \(scrollView.contentSize)")
for view in scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
scrollView.contentSize = CGSize(width: contentRect.size.width, height: contentRect.size.height + 150)
print("THE CONTENT SIZE AFTER RESIZING IS: \(scrollView.contentSize)")
}
EDIT 2: I think I found the issue with your project. You need to move the MessageButton(UzenetButton) above DispDescription label in the object inspector in that way it will always be above your message textView.
At the moment the UzeneButton is at the very far back in your view hierarchy so if your textView is resizing whilst editing it covers the button that is why you cannot click on it.
See #Endre Olah,
To make situation more clear do one more thing, set clipToBound property of contentview to true.
you will notice that after loading of data your button not fully visible, it means it is shifting out of bound of its parentView (ContentView)
And that's why button is not taking your touch. However, if you carefully touch upper part of button it still do its job. Because upper part is still in bound of ContentView
Solution :
After loading of data you have to make sure that you increase height of ContentView such that button should never go out of bound of its parentView(ContentView).
FOR EXAMPLE
#IBOutlet var heightConstraintOfContentView : NSLayoutConstraint!
After loading of data
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
heightConstraintOfContentView.constant = contentRect.size.height
contentView.layoutIfNeeded()
I use following steps when I need to use scrollview with dynamic content:
1) Firstly add a scrollView with top, bottom, trailing and leading is 0 to super view.
2) Add a view to scrollView and view's trailing, leading bottom and top space to scrollView can be set to 0 (or you can add margin optionally).
3) Now, you should add UI elements like buttons, labels with appropriate top, bottom, trailing and leading margins to each other.
4) Lastly, add equal height and equal width constraint to view with Safe Area:
and change equal height priority of view to 250:
It should solve your problem with UIScrollView.
Finally, I have found the solution in another chain, once it became clear that the scrollview's contentview is resizing on scroll event to the original size. (Not clear why this is like this, but that is the fact.)
So I had to add a height constraint to the contentview in the storyboard and create an outlet to it and adjust this constraint when the content size is changing, like this:
#IBOutlet weak var ContentViewHeight: NSLayoutConstraint!
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.bounds = contentRect
scrollview.contentSize = contentRect.size
----------- This is the key line to the success ----------
ContentViewHeight.constant = contentRect.size.height
----------------------------------------------------------
}
After this is added, it works perfectly.

Rounded Rect UIButton with outer border

i wants to make outer border for UIButton.
When i click on button add border width, not inside rounded button - outside of this button.
P.S. i use this code to make button round:
button.layer.cornerRadius = 0.5 * button.frame.size.width
button.clipsToBounds = true
And this for border:
self.button.layer.borderWidth = CGFloat(10)
Now i have this result:
But i need border outside of the button. if someone help me, it's will be amazing, thanx.
Just add alpha (transparency) and instead of adding the border, change its alpha value. set the border color as follow:
let borderColor = UIColor(red: 0.0/256.0, green: 0.0/256.0, blue: 0.0/256.0, alpha: 0.0)
and modify the alpha value. This way it will look like you are adding the frame on the outside of the button.
Now, you didn't specify if you wanted the animation as well. If you do want the animation, you should just draw the frame outside the button's boundary, it might be trickier to do, and the frame would not have the button's functionality.
Another option of keeping the button and the animation is to draw a circle with behind the button and set the border to transparent, then animate.
These are only three of your options, I'm sure there are more...