iPad App Navigation with SlideView - change size of UIView? - ios

i want to create a slide out menu which has a normal width of about 50 pixels, and if the user press the expand button i will also show the labels for the button.
Like in this example:
What is the correct way to create such a menu? I though about using 2 views and set the size of contentview to width-50pixels.
But i am unable to change the frame of my UIView in the ViewDidLoad function. (this is an example)
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = CGRect(x:50, y:0, width:974, height:768)
sidebarIsOpen = false
}
And if the user click on the expand Button
#IBAction func expandButtonClicked(sender : AnyObject) {
var x = self.sidebarIsOpen! ? 50 : 300
UIView.animateWithDuration(0.2, animations: {
self.view.frame = CGRect(x:x, y:0, width:300, height:768)
}, completion: { _ in
self.sidebarIsOpen = !(self.sidebarIsOpen!)
})
}
If i click the button again, everything is fine. But on ViewDidLoad i am unable to move the contentview to right.
Thanks in advance

Ill found already the solution by myself.
Created 2 views and animate the "contentview" on button click.
#IBOutlet weak var menuView: UIView!
#IBAction func toggleMenuButton(sender: UIBarButtonItem) {
var x = self.sidebarIsOpen! ? 50 : 200
UIView.animateWithDuration(0.2, animations: {
self.contentView.frame = CGRect(x:x, y:0, width:974, height:768)
}, completion: { _ in
self.sidebarIsOpen = !(self.sidebarIsOpen!)
})
}

Related

Use SegmentController to Make TableView Disappear and UIContainerView Appear

I'm trying to use a segment controller to switch between my tableView and a container view, but when I try to switch between them it only half works. The TableView appears and disappears, but the container view never appears.
Here is my code:
#IBAction func switchAction(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
profileTableView.isHidden = false
modelsContainerView.isHidden = true
} else {
profileTableView.isHidden = true
modelsContainerView.isHidden = false
}
}
UPDATE
If i use this code the simulation sort of works. The container view appears but it doesn't fill the screen like the tableview did.
#IBAction func switchAction(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
UIView.animate(withDuration: 0.5, animations: {
self.profileTableView.alpha = 1
self.modelsContainerView.alpha = 0
})
} else {
UIView.animate(withDuration: 0.5, animations: {
self.profileTableView.alpha = 0
self.modelsContainerView.alpha = 1
})
}
}
I can tell it's not working because I've set the container view's background color to pink. And this is what it looks like when I try to switch from TableView(which works) to container View:
All of the outlets appear to be connected. And my UI set up is a green view behind the segment controller, with a tableView below and a containerView that in the same place.
Thank you very much for your help in advanced.
Try this approach...
Seg Background view is 45-pts height, and pinned top, leading, trailing all equal to 0.
Profile Container is pinned leading, trailing, bottom all equal to 0, and the top is pinned to the bottom of Seg Background.
But you can't see Profile Container (red background), because Models Container (orange background) is on top of it, and...
Models Container is equal width and height, and centered Horizontally and Vertically, all to Profile Container.
Profile Container has Profile Table VC embedded in it.
Models Container has Models VC embedded in it.
The idea is:
When Seg 0 is selected, Profile Container is alpha 1 and not hidden, while Models Container is alpha 0 and is hidden.
When Seg 1 is selected, Profile Container is alpha 0 and is hidden, while Models Container is alpha 1 and not hidden.
class SegContainerViewController: UIViewController {
#IBOutlet weak var profileContainerView: UIView!
#IBOutlet weak var modelsContainerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// start with Profile visible
// so hide Models and set its alphs to 0
self.modelsContainerView.alpha = 0
self.modelsContainerView.isHidden = true
}
#IBAction func switchAction(_ sender: UISegmentedControl) {
// on segment select, the "other" container will be
// transparent and hidden, so
// un-hide it, then animate the alpha for both (for cross-fade)
// on animation completion, hide the now transparent container
if sender.selectedSegmentIndex == 0 {
self.profileContainerView.isHidden = false
UIView.animate(withDuration: 0.5, animations: {
self.profileContainerView.alpha = 1
self.modelsContainerView.alpha = 0
}, completion: { (finished: Bool) in
self.modelsContainerView.isHidden = true
})
} else {
self.modelsContainerView.isHidden = false
UIView.animate(withDuration: 0.5, animations: {
self.profileContainerView.alpha = 0
self.modelsContainerView.alpha = 1
}, completion: { (finished: Bool) in
self.profileContainerView.isHidden = true
})
}
}
}
Edit:
To access the Embedded View Controllers, override prepareForSegue:
var theProfileVC: ProfileTableViewController?
var theModelsVC: ModelsViewControler?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ProfileTableViewController {
// do something here if desired, like setting a property of the VC
// save a reference so we can use it later
theProfileVC = vc
}
if let vc = segue.destination as? ModelsViewControler {
// do something here if desired, like setting a property of the VC
// save a reference so we can use it later
theModelsVC = vc
}
}
I've also updated the GitHub repo with an example of this.
I put this up as a sample project, if you'd like to dig into it: https://github.com/DonMag/SegmentsAndContainers

UIViewAnimationOptions.TransitionFlipFromLeft not show UIView second time

I am trying to Flip two UIViews. I've try to flip UIView using programmatically and it works perfect. But when i've try to flip UIView that i created in storyboard it not works, First time it flip UIView but second time it flip blank UiViews? Any one have any idea is there any mistake in my code?
In this picture Top left Debug view Hierarchy picture is before animating button and bottom left Debug view Hierarchy picture is after animating picture.
When second time i animate the UIView it Flip like this below picture.
class ViewController: UIViewController {
#IBOutlet var container: UIView!
#IBOutlet var blueSquare : UIView!
#IBOutlet var redSquare : UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func animateButtonTapped(sender: AnyObject) {
// create a 'tuple' (a pair or more of objects assigned to a single variable)
var views : (frontView: UIView, backView: UIView)
if ((self.redSquare.superview) != nil) {
views = (frontView: self.redSquare, backView: self.blueSquare)
}
else {
views = (frontView: self.blueSquare, backView: self.redSquare)
}
// set a transition style
let transitionOptions = UIViewAnimationOptions.TransitionFlipFromLeft
// with no animation block, and a completion block set to 'nil' this makes a single line of code
UIView.transitionFromView(views.frontView, toView: views.backView, duration: 1.0, options: transitionOptions, completion: nil)
}
}
Programmatically
That code is perfectly works.
let container = UIView()
let redSquare = UIView()
let blueSquare = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// set container frame and add to the screen
self.container.frame = CGRect(x: 60, y: 60, width: 200, height: 200)
self.view.addSubview(container)
// set red square frame up
// we want the blue square to have the same position as redSquare
// so lets just reuse blueSquare.frame
self.redSquare.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
self.blueSquare.frame = redSquare.frame
// set background colors
self.redSquare.backgroundColor = UIColor.redColor()
self.blueSquare.backgroundColor = UIColor.blueColor()
// for now just add the redSquare
// we'll add blueSquare as part of the transition animation
self.container.addSubview(self.redSquare)
}
#IBAction func animateButtonTapped(sender: AnyObject) {
// create a 'tuple' (a pair or more of objects assigned to a single variable)
var views : (frontView: UIView, backView: UIView)
if((self.redSquare.superview) != nil){
views = (frontView: self.redSquare, backView: self.blueSquare)
}
else {
views = (frontView: self.blueSquare, backView: self.redSquare)
}
// set a transition style
let transitionOptions = UIViewAnimationOptions.TransitionFlipFromLeft
// with no animation block, and a completion block set to 'nil' this makes a single line of code
UIView.transitionFromView(views.frontView, toView: views.backView, duration: 1.0, options: transitionOptions, completion: nil)
}
UPDATE
var check = true
#IBAction func animateButtonTapped(sender: AnyObject) {
// create a 'tuple' (a pair or more of objects assigned to a single variable)
var views : (frontView: UIView, backView: UIView)
if (check == true) {
views = (frontView: self.redSquare, backView: self.blueSquare)
check = false
}
else {
views = (frontView: self.blueSquare, backView: self.redSquare)
check = true
}
// set a transition style
let transitionOptions : UIViewAnimationOptions = [UIViewAnimationOptions.TransitionFlipFromLeft, UIViewAnimationOptions.ShowHideTransitionViews]
// with no animation block, and a completion block set to 'nil' this makes a single line of code
UIView.transitionFromView(views.frontView, toView: views.backView, duration: 1.0, options: transitionOptions, completion: nil)
}
The default behaviour for transitionFromView removes the view after animation.
let transitionOptions: UIViewAnimationOptions = [.TransitionFlipFromLeft, .ShowHideTransitionViews]
From the documentation: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/swift/struct/c:#E#UIViewAnimationOptions
ShowHideTransitionViews
When present, this key causes views to be hidden or shown (instead of removed or added) when performing a view transition. Both views must already be present in the parent view’s hierarchy when using this key. If this key is not present, the to-view in a transition is added to, and the from-view is removed from, the parent view’s list of subviews.
Ah in storyboard I see that you add both views to the container but in code you only add the redsquare. Perhaps remove the bluesquare from being within the container in storyboard?

How the flip animation works in swift 2

I have a UIView, inside this view I have UIImageView. Also I have a button inside this UIView. What I want to do is when I click this button I want to make a flip animation and remove my UIImageView and load another view into this super view. In my button click even I did something like this
func shareClick()
{
print("SHARE CLICK")
if showingBack {
UIView.transitionWithView(shareView, duration: 1.0, options: .TransitionFlipFromRight, animations: {
self.imgVwTop.removeFromSuperview()
}, completion: nil)
showingBack=false
}
else
{
UIView.transitionWithView(imgVwTop, duration: 1.0, options: .TransitionFlipFromRight, animations: {
self.shareView.removeFromSuperview()
}, completion: nil)
showingBack=true
}
}
I'm confused with the ebhaviour and don't understand exactly how to do it. This button click event doing nothing here.
You can do the following (I assume that share view contains the image view and the button):
override func viewDidLoad()
{
super.viewDidLoad()
shareView = UIView(frame: CGRectMake(30, 100, 300, 400)) //set the frame of the holder view
flippedView = UIView(frame: shareView!.bounds) //setup flipped view
flippedView!.backgroundColor = UIColor.redColor() //for test
isFlipped = false //initially not flipped
//set up the initial view with image and button
aImageView = UIImageView(frame: shareView!.bounds)
aImageView!.image = UIImage(named: "1.jpg")
shareButton = UIButton(type: .System)
shareButton!.setTitle("share", forState: .Normal)
shareButton!.frame = CGRectMake(0, 0, 150, 50)
shareButton!.addTarget(self, action: "shareButtonAction", forControlEvents: .TouchUpInside)
//add both imageview and button to holder view
shareView!.addSubview(aImageView!)
shareView!.addSubview(shareButton!)
//finally add holder to self view
self.view.addSubview(shareView!)
}
Here, you can't remove the super view of the image view if you use the transitionWithView method. The best you can do is replace the image view with new view that you want to show after being flipped. Once again, you can flip back to the image view by adding it as subview. For example:
func shareButtonAction()
{
if (self.isFlipped! == false)
{
UIView.transitionWithView(shareView!, duration: 0.5, options:.TransitionFlipFromRight, animations: { () -> Void in
// self.aImageView!.image = UIImage(named: "2.jpg")
//hear remove the imageview add new view, say flipped view
self.aImageView!.removeFromSuperview()
self.shareView!.addSubview(self.flippedView!)
}, completion: { (Bool) -> Void in
self.isFlipped! = true
self.shareView!.bringSubviewToFront(self.shareButton!) //button should be top of the holder view
})
}
else
{
UIView.transitionWithView(shareView!, duration: 0.5, options:.TransitionFlipFromRight, animations: { () -> Void in
//move back, remove flipped view and add the image view
self.flippedView!.removeFromSuperview()
self.shareView!.addSubview(self.aImageView!)
}, completion: { (Bool) -> Void in
self.isFlipped! = false
self.shareView!.bringSubviewToFront(self.shareButton!)
})
}
}
So it looks like you have the right idea, I believe you have things set up correctly with the view you want to flip in some sort of container.
I think it would help if you instantiated both your views programmatically, in your case a UIImageView and a Button. When you transition the other view will become unloaded because they are listed as weak so best to create them on the fly.
I made up a view controller to test the idea, initially the currentView will be instantiated from the storyboard, and then after that would be created programmatically, every time the button is pressed it will create a new view that will replace the other, perform the animation and set the new view as the currentView for the next time the button is pressed.
class ViewController: UIViewController {
#IBOutlet weak var currentView: UIView!
#IBOutlet weak var container: UIView!
var flipped = false
#IBAction func buttonPressed(sender: AnyObject) {
let new: UIView!
if flipped {
new = UIImageView(frame: container.bounds)
new.backgroundColor = UIColor.redColor()
flipped = false
}
else {
new = UIButton(frame: container.bounds)
new.backgroundColor = UIColor.blueColor()
flipped = true
}
let options: UIViewAnimationOptions = [.TransitionFlipFromLeft, .AllowUserInteraction, .BeginFromCurrentState]
UIView.transitionFromView(currentView, toView: new, duration: 0.5, options: options, completion: nil)
self.currentView = new
}
}
Hope this helps :)
This piece of code works...
self.debug.hidden = true
let image = UIImage(data: data!)
self.debug.image = image
if (swipe.direction == UISwipeGestureRecognizerDirection.Left) {
UIView.transitionWithView(self.debug, duration: 1.0, options: [.TransitionFlipFromRight], animations: {
self.debug.hidden = false
}, completion: { _ in })
}
I load a new image into my image after I hide it.

Changing the appearance of my #IBAction button in Swift out of its func

I'm writing an app in which there's a scrollview and what I want is to set the button's alpha to 0 at first and change it into 1 when the user scrolls to the last page. I'm writing code like this:
#IBAction func startButton(sender: UIButton) {
sender.layer.cornerRadius = 2.0
sender.alpha = 0.0
}
extension UserGuideViewController: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
let offset = scrollView.contentOffset
pageControl.currentPage = Int(offset.x / view.bounds.width)
if pageControl.currentPage == numberOfPages - 1 {
UIView.animateWithDuration(0.5) {
self.startButton.alpha = 1.0
}
} else {
UIView.animateWithDuration(0.2) {
self.startButton.alpha = 0.0
}
}
}
}
and it says the Value of type (UIButton)->() has no member alpha. I don't know how to do this.
I know it would be easy if this button is an #IBOutlet but I need to set it as an #IBAction so that when it gets touched I can show another view controller.
You need to create both an #IBOutlet and an #IBAction for the button. Drag twice from Interface Builder to your view controller and select the appropriate values (outlet or action) from the popup menu and give them different names. Then access the outlet in your scrollViewDidScroll method.

UIView.transitionWithView breaks the loader's layout

I am trying to animate the root-view-controller-change in my app. After I swap the view controllers, I load the data necessary for the 2nd controller right away. While the data is loading, I show a loader(MBProgressHUD). This is my function for swapping the view controllers:
class ViewUtils {
class func animateRootViewController(duration: NSTimeInterval, changeToViewController: UIViewController) {
let window = UIApplication.sharedApplication().delegate?.window?
if window == nil {
return
}
UIView.transitionWithView(window!,
duration: duration,
options: UIViewAnimationOptions.TransitionFlipFromLeft | UIViewAnimationOptions.AllowAnimatedContent,
animations: {
window!.rootViewController = changeToViewController
},
completion: nil
)
}
}
All good with this but one thing - it totally breaks the loader. I am attaching an imagine of what's happening:
This is the 2nd view controller while rotating. Once the rotation is complete, the loader appears just fine, both the spinner and the text tween to the correct position in the rounded rectangle.
I really don't understand why this happens, would somebody explain it to me, please? Is there a way to prevent it?
The code of the 2nd view controller where I show the loader:
override func viewDidLoad() {
super.viewDidLoad()
hud = HUD(containingView: view)
hud.show()
createBackground()
}
And my hud class:
class HUD {
private var hudBG: UIView!
private var view: UIView!
private(set) var isShown = false
init(containingView: UIView) {
view = containingView
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func show() {
if !isShown {
if(hudBG == nil) {
hudBG = UIView(frame: CGRectMake(0, 0, view.bounds.width, view.bounds.height))
hudBG.backgroundColor = UIColor(white: 0, alpha: 0.4)
}
view.addSubview(hudBG)
let hud = MBProgressHUD.showHUDAddedTo(view, animated: true)
hud.mode = MBProgressHUDModeIndeterminate
hud.labelText = "Cargando"
hudBG.alpha = 0
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.hudBG.alpha = 1
})
isShown = true
}
}
func hide() {
if isShown {
UIView.animateWithDuration(0.3, animations: {
() -> Void in
self.hudBG.alpha = 0
}, completion: {
(b) -> Void in
self.hudBG.removeFromSuperview()
})
MBProgressHUD.hideHUDForView(view, animated: true)
isShown = false
}
}
}
Thanks a lot for any ideas!
You are adding the hud to a view that is not properly initialized yet.
If you are loading the view controller from a xib or storyboard, the view and it's subviews have the size as they were loaded from interface.
You have to add the hud after the views have been resized to their final size.
If you move
hud = HUD(containingView: view)
hud.show()
to viewDidLayoutSubviews, it should work fine.
I noticed a similar problem when moving an app from iOS 7 to iOS 8. During animations, especially when scaling was involved, the view positions got distorted.
I am pretty sure it's a bug. The simplest workaround is to animate only screenshots or view snapshots, not actual views - it's more work and you can't have views animating when the main animation is in progress but in general it's a more stable solution.

Resources