Slide-out menu in iOS app (swift) - ios

I'm trying to build my own slide out menu in swift, but I'm having some troubles.
Now, I coded a function that change the view.frame.origin.x so that I got my view to slide on the right.
Now, I added a subview at index: 0 and I want to make it show when I slide the main view (content) out.
let navView: NavigationViewController = self.storyboard?.instantiateViewControllerWithIdentifier("navView") as NavigationViewController
view.insertSubview(navView.view, atIndex: 0)
addChildViewController(navView)
navView.didMoveToParentViewController(self)
And that's what happen when I click on the menu logo (at the top-left corner):
#IBAction func showMenu(sender: AnyObject) {
println("showMenu")
if !self.menuIsOpen{
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: .CurveEaseInOut, animations: { () -> Void in
self.view.frame.origin.x = 150
}) { (isHappen: Bool) -> Void in
if isHappen {
println("OpenedUp!")
self.menuIsOpen = true
}
}
} else {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: .CurveEaseInOut, animations: { () -> Void in
self.view.frame.origin.x = 0
}) { (isHappen: Bool) -> Void in
if isHappen {
println("Closed!")
self.menuIsOpen = false
}
}
}
}
So, now, this works but I suppose that the subview slides together with the rest of the main view.
How can I make the navigationView not to hide? Or better, to stay there (I mean with the origin.x: 0)

Could you have a navigation view, associated with a view controller (1), and then have the slide out menu view controller (2) inside that view controller (vc1.addSubview(vc2.view)? Then you could just keep view controller (1)'s navigation bar up and the view controller (2) would be inside it so it does not slide view controller (1)'s navigation bar.

I know I'm a bit late, but in case anyone else has the same problem: I've implemented a similar mechanic on an app I'm currently working on. To achieve it I used custom interactive transitions, which were introduced in iOS7. I would recommend checking out the following links:
See Custom Transitions Using View Controllers https://developer.apple.com/videos/wwdc/2013/
http://www.thinkandbuild.it/ios7-custom-transitions/ In this tutorial, the presented view is rotated to appear on screen; but it's not to much work to adapt the code to silde your menu in from the side and only fill part of the screen.
http://www.appcoda.com/custom-view-controller-transitions-tutorial/ This gives many examples of the kind of effects you can achieve using custom transitions.
Hope that helps.

Related

iOS - How To Fix This Animation In Table View Cell To Go Left and Then Back Again

The goal is to have the first table view cell content move left for a time and then back again.
The bigger goal is that we will bounce the cell's content view slightly to the left and bounce in a red box then return the cell to normal.
Although similar to another SO question, the answer does not reveal how to do this. Plus, this question would apply to anyone who wants to animate moving the cell content to the left temporarily and then back again. Thus, that's why it's a separate question.
The environment is iOS 11+ and iPhone app.
I have a new Table View project created that is animating the contentView moving via transform. However, it doesn't seem to remotely start in the normal position and then move as desired. The content starts off centered and then moves into place instead.
How can I get the contentView to animate moving a little to the left and then back again into its normal position?
Project: https://github.com/mikefinney/peekabooswipe
I rewrote your code a little. You were applying a transform to the content view and the documentation suggests instead animating the center property when shifting the location.
func applyCellAnimations() {
let originalCenter = contentView.center
let offsetCenter = originalCenter.applying(.init(translationX: -44, y: 0))
animateToCenter(offsetCenter) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
self.animateToCenter(originalCenter)
})
}
}
private func animateToCenter(_ center: CGPoint, completionHandler: #escaping () -> Void = { }) {
layoutIfNeeded()
UIView.animate(
withDuration: 1,
delay: 0,
options: [.curveEaseInOut],
animations: {
self.contentView.center = center
}, completion: { didComplete in
if didComplete { completionHandler() }
})
}

How to show an UIView on top of an UITableView?

I have an UIViewController which contains a table view and a simple view. Both of them are at the same level.
At startup my view starts hidden at the bottom and when I press a button I want my view to slide up. When I do this only 1/4 of the view is shown and not the complete view.
This worked okay before adding the table view, but now I don't understand why it doesn't fully show.
Here is the code to show and hide my view:
func showPicker(date: Date?) {
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: {
self.timePickerView.transform = CGAffineTransform(translationX: 0, y: 0)
}, completion: { _ in
})
}
func hidePicker() {
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: {
self.timePickerView.transform = CGAffineTransform(translationX: 0, y: self.timePickerView.frame.size.height)
}, completion: { _ in
})
}
And here is a screenshot with the view (below the buttons there should be an UIDatePicker which is not shown):
Someone know what the issue is ? I am trying to do this from the storyboards.
edit:
This is what I have right now, but it still doesn't work. It doesn't animate and it also shows just a part of the view. Apparently if I increase the height the view is shown even more, so somehow it says that the shown part is exactly 220 height, which is strange :/
func hidePicker() {
self.pickerBottomConstraint.constant = -220
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: {
self.timePickerView.layoutIfNeeded()
}, completion: { _ in
})
}
func showPicker(date: Date?) {
self.pickerBottomConstraint.constant = 0
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: {
self.timePickerView.layoutIfNeeded()
}, completion: { _ in
})
}
If you're using autolayout, I bet you do and you should, then the easiest way to do what you wanna do is to toggle the constraint of your view, see the gif I added below.
First is to have a reference to your either top or bottom constraint of your view you wanna show and hide. Then modify the constant of the constraint to adjust its position, in that way, you get the illusion that the view is hidden and shown. The demo below uses tableView too.
Hope this helps.
See a demo here showHide that accomplish what you want
Rather then transform, change your views center y position.
ex:
#IBOutlet weak var viewToAnimateOutlet: UIView!
#IBAction func showViewButtonAction(_ sender: Any) {
UIView.animate(withDuration: 1.5) {
self.viewToAnimateOutlet.center.y -= self.viewToAnimateOutlet.frame.height
}
}
#IBAction func hideViewButtonAction(_ sender: Any) {
UIView.animate(withDuration: 1.5) {
self.viewToAnimateOutlet.center.y += self.viewToAnimateOutlet.frame.height
}
}
What i did:
I used autolayout and provided constraint for ViewToAnimate View is
ViewToAnimates.leading = safeArea.leading "constant = 8"
ViewToAnimates.trailing = safeArea.trailing "constant = 8"
This constraint will place ViewToAnimate view outside of the main views bottom. so view will not visible until showViewButtonAction method called.
ViewToAnimates.top = safeArea.bottom "constant = 0"
ViewToAnimates.height = 130

How To Only Animate Contents of UIImageView

How do you animate only the contents of a UIImageView? If the image view is centered in the middle of the screen how do you animate the image to slide in from the left but only be shown within the frame of the image view?
As if you are looking at a wall with a window and someone walks by. You don't see them until they are in the frame of the window.
The code below certainly does not do it. I had it a few days ago with ease and erased it and now I can't remember how I did it. It was pretty simple but now it's driving me crazy.
self.lockImages[button.tag].center.x -= self.lockImages[button.tag].bounds.width
UIView.animateWithDuration(2.0, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: nil, animations: { () -> Void in
self.lockImages[button.tag].center.x += self.lockImages[button.tag].bounds.maxX
}, completion: { (Bool) -> Void in
})
UIImageView a subclass of UIView, inherits the .clipsToBounds() method, which will create the desired effect.

swift animateWithDuration animation not right

I am hiding my navigation bar and a UIView under it that acts as a extension bar to it when I scroll my page.
My app is built like:
VC that holds a container view with an embedded table view.
From the table view I have delegates that notify VC1 once a user scrolls up or down.
My problem now is that the animation dont looks that good. What I am trying to do is to animate the extension bar to animate up or down with a fade in or fade out effect as well. When that occurs I also update the top contraint on my container view so that the table view will fill the whole screen. (I am not sure if I use layoutneeded() right or if something else should be used when updating constraints)
My code:
func ContainerTableViewControllerScrolledUp(controller: ContainerTableViewController) {
self.navigationController?.setNavigationBarHidden(false, animated: true)
println("UP")
UIView.animateWithDuration(
1.5,
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: nil,
animations: {
self.extensionV.alpha = 1
self.tableVConst.constant = 0
}, completion: { finished in
self.view.layoutIfNeeded()
}
)
}
func ContainerTableViewControllerScrolledDown(controller:ContainerTableViewController) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
println("DOWN")
UIView.animateWithDuration(
1.5,
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: nil,
animations: {
self.extensionV.frame.origin.y = CGFloat(-10)
self.tableVConst.constant = -41
self.extensionV.alpha = 0
}, completion: { finished in
self.view.layoutIfNeeded()
}
)
}
extensionV is the extension view
tableVConst is the top constraint for my container view that holds my table view
So how should I edit my code in order to get the extension view to animate up/down with a fade in/fade out effect?
Instead of calling self.view.layoutIfNeeded() in the completion block, try calling it inside the animation block on the last line before it returns.

UIView Subviews Do Not Smoothly Animate

I am attempting to animate a tab bar to move from below the bottom of the screen to the top while simultaneously adjusting a view's height to shrink by the height of the tab bar. Essentially, I have a "hidden" tab bar that when it unhides should animate into view and the displayView should adjust for the space the tab bar now takes up.
However, the animation is jumpy for the display view. It seems that the display view animates fine, but the subviews automatically adjust their height without any animation. Any direction on fixing this would be appreciated.
I will accept aid in either objective-c or swift, as the translation is fairly easy.
//Displays tab bar with slide up animation. If animated is false, all other params are unused
func displayTabBar(animated:Bool, duration:NSTimeInterval = 0.5, delay:NSTimeInterval = 0, options:UIViewAnimationOptions = UIViewAnimationOptions.CurveLinear, completion:((Bool) -> Void)? = nil){
if(animated){
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
self.adjustTabBarDisplayed()
}, completion: completion)
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
self.adjustDisplayViewTabDisplayed()
}, completion: nil)
}
else{
self.adjustTabBarDisplayed()
self.adjustDisplayViewTabDisplayed()
}
}
//Adjusts frame of tab bar to display tab bar
private func adjustTabBarDisplayed(){
self.tabBar.frame = CGRectMake(0,UIScreen.mainScreen().bounds.height - self.tabBar.bounds.height, self.tabBar.bounds.width, self.tabBar.bounds.height)
}
//Adjusts frame of display view to match displayed tab bar
private func adjustDisplayViewTabDisplayed(){
self.displayView.frame = CGRectMake(0,0,self.displayView.bounds.width, UIScreen.mainScreen().bounds.height - self.tabBar.bounds.height)
}
When you modify a view's size, it doesn't lay out its subviews immediately. Instead, it sets a flag indicating that it needs layout. Later, after the system has finished dispatching the event that ended up calling displayTabBar, it runs the display refresh code. The display refresh code finds views that have the needs-layout flag set and tells them to lay themselves out (by sending them layoutSubviews).
Here, you are changing your display view's size inside an animation block. Therefore change to your display view's frame will be animated. But the frames of its subviews are changing outside the animation block; they're changing later during the layout phase. You need to make them change inside the animation block.
Lucky for you, that's easy. Just call self.displayView.layoutIfNeeded() inside the animation block. Also, you only need one animation block, since all of the animation parameters are identical:
func displayTabBar(animated:Bool, duration:NSTimeInterval = 0.5, delay:NSTimeInterval = 0, options:UIViewAnimationOptions = UIViewAnimationOptions.CurveLinear, completion:((Bool) -> Void)? = nil){
if(animated){
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
self.adjustTabBarDisplayed()
self.adjustDisplayViewTabDisplayed()
// ADD THIS LINE
self.displayView.layoutIfNeeded()
}, completion: completion)
}
else{
self.adjustTabBarDisplayed()
self.adjustDisplayViewTabDisplayed()
}
}
Use the below line of code in animation block
scrollView.layoutIfNeeded()

Resources