I have create a UISegmentedControl
and a view under it. The view under contains all a view for each segment. I am doing an animation when the segment is changing.
- Is a center view that contains all subviews the right approach?
- Is the animation is correctly done (this is my first animation in swift) or is there a better way to achieve that effect?
import UIKit;
class ViewLikes:UIViewController {
var innerViews:[UIViewController] = [UIViewController]()
var currentIndex:Int = 0;
var centerView:UIViewController = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
title = "some title";
var view1:UIViewController = UIViewController()
var lab1:UILabel = UILabel(frame: CGRectMake(0, 10, 200, 21))
lab1.center = CGPointMake(160, 284)
lab1.textAlignment = NSTextAlignment.Center
lab1.text = "I'am a label1"
view1.view.addSubview(lab1)
var view2:UIViewController = UIViewController()
var lab2:UILabel = UILabel(frame: CGRectMake(0, 10, 200, 21))
lab2.center = CGPointMake(160, 284)
lab2.textAlignment = NSTextAlignment.Center
lab2.text = "I'am a label2"
view2.view.addSubview(lab2)
var view3:UIViewController = UIViewController()
var lab3:UILabel = UILabel(frame: CGRectMake(0, 10, 200, 21))
lab3.center = CGPointMake(160, 284)
lab3.textAlignment = NSTextAlignment.Center
lab3.text = "I'am a label3"
view3.view.addSubview(lab3)
innerViews.append(view1)
innerViews.append(view2)
innerViews.append(view3)
var segmentControl:UISegmentedControl = UISegmentedControl(items:["blah", "blah1", "blah2"]);
segmentControl.selectedSegmentIndex = currentIndex;
segmentControl.addTarget(self, action:"segmentSwitch:" , forControlEvents:UIControlEvents.ValueChanged )
segmentControl.setTranslatesAutoresizingMaskIntoConstraints(false)
self.centerView.view.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(segmentControl)
self.view.addSubview(self.centerView.view)
var currentView = self.innerViews[0]
currentView.viewWillAppear(false)
self.centerView.view.addSubview(currentView.view)
currentView.viewDidAppear(false)
//Set layout
var viewsDict = Dictionary <String, UIView>()
viewsDict["segment"] = segmentControl;
viewsDict["center"] = self.centerView.view;
self.view.addConstraint(NSLayoutConstraint(item: segmentControl,
attribute: NSLayoutAttribute.Top,
relatedBy: NSLayoutRelation.Equal,
toItem: self.topLayoutGuide,
attribute: NSLayoutAttribute.Bottom,
multiplier: 1, constant: 10))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[segment]-|",
options: NSLayoutFormatOptions(0),
metrics: nil,
views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[center]-0-|",
options: NSLayoutFormatOptions(0),
metrics: nil,
views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[segment]-[center]-0-|",
options: NSLayoutFormatOptions(0),
metrics: nil,
views: viewsDict))
}
func segmentSwitch(control:UISegmentedControl) {
selectView(control.selectedSegmentIndex)
}
func selectView(index:Int) {
var currentView = self.innerViews[self.currentIndex]
var nextView = self.innerViews[index]
nextView.viewWillAppear(false)
self.centerView.view.addSubview(nextView.view)
nextView.viewDidAppear(false)
if(index > currentIndex) {
nextView.view.frame.origin.x = nextView.view.frame.width;
} else {
nextView.view.frame.origin.x -= nextView.view.frame.width;
}
UIView.animateWithDuration(0.8,
animations: {
var currentFrame = currentView.view.frame;
var nextFrame = nextView.view.frame;
if(index > self.currentIndex) {
currentFrame.origin.x -= currentFrame.size.width;
} else {
currentFrame.origin.x = currentFrame.size.width;
}
nextFrame.origin.x = 0.0;
currentView.view.frame = currentFrame
nextView.view.frame = nextFrame
}, completion: {finished in
currentView.viewWillDisappear(false)
currentView.view.removeFromSuperview()
currentView.viewDidDisappear(false)
}
);
self.currentIndex = index
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
for innerView in self.innerViews {
innerView.didReceiveMemoryWarning();
}
}
}
-
\$\begingroup\$ "Is the animation is correctly done" -- does it animate correctly? \$\endgroup\$nhgrif– nhgrif2014年08月25日 11:22:51 +00:00Commented Aug 25, 2014 at 11:22
-
\$\begingroup\$ yes, its working as expected, the views are moving from left to right, or right to left, but is it the way this animation should be implemented ? \$\endgroup\$shay te– shay te2014年08月25日 11:30:41 +00:00Commented Aug 25, 2014 at 11:30
-
\$\begingroup\$ Okay, I just wanted clarification that it was actually working as you expected. \$\endgroup\$nhgrif– nhgrif2014年08月25日 11:31:02 +00:00Commented Aug 25, 2014 at 11:31
-
\$\begingroup\$ again, i am asking this cause this is my first animation , want to know that i am programming correctly in swift, and not hacking things . \$\endgroup\$shay te– shay te2014年08月25日 11:35:17 +00:00Commented Aug 25, 2014 at 11:35
-
1\$\begingroup\$ I understand. We just always make sure the results are what you intend. I'm working on an answer at the moment. \$\endgroup\$nhgrif– nhgrif2014年08月25日 11:37:34 +00:00Commented Aug 25, 2014 at 11:37
1 Answer 1
func segmentSwitch(control:UISegmentedControl) {
selectView(control.selectedSegmentIndex)
}
Is it strictly necessary for this to be a separate method? Can we not just do this:
func selectView(control:UISegmentedControl) {
let index = control.selectedSegmentIndex
// do stuff
}
The only reason I can think not to do this would be if you've got other methods calling selectView
or if you intend to more than just selectView
within the segmentSwitch
method, but as far as I can tell, neither of these are the case.
You have this:
nextView.viewWillAppear(false)
self.centerView.view.addSubview(nextView.view)
nextView.viewDidAppear(false)
Followed later by this in a completion block:
currentView.viewWillDisappear(false)
currentView.view.removeFromSuperview()
currentView.viewDidDisappear(false)
My first problem is that despite animating this change, we're sending false
as the animate
argument to all of the willAppear
-esque methods of these view controllers.
My other problem is the order in which these methods are called.
The viewWillAppear
and viewWillDisappear
methods for both view controllers should be called just before the animation block. Meanwhile, the viewDidAppear
and viewDidDisappear
methods should be called in the completion
block of the animations.
It's been a while since I've truly looked at the exact synching of these events between two view controllers, but I highly suggest you put an NSLog
statement in all of the view life cycle events and use a regular storyboard segue transition between the two to see the order and timing of which these are called. And better yet, do it in a navigation controller and use the swipe-left-to-right gesture to navigate backward. Notice as you start that gesture, the current view controller has viewWillDisappear:
called, but it waits until the transition is complete for viewDidDisappear:
. And ultimately, this means that if you start your gesture then go back, viewWillDisappear:
can be called without viewDidDisappear:
.
You have a lot of code in viewDidLoad
. I'd highly recommend jobbing this out to other smaller functions, each of which get called by viewDidLoad
.
Finally, I'd highly recommend that you create a custom subclass of UIViewController
(or maybe UITabBarController
). Ultimately, this seems like a very custom looking UITabBarController
, right? Rather than writing all this code each time you wanted to implement it, it seems it'd be better if you narrowed it down to the navigation code and made it work for any (reasonable) number of contained view controllers, just as UITabBarController
does.
-
\$\begingroup\$ i am going to extract this view to a generic view that i will use latter on this is the beginning :) , as for selectView i moved the functionality to segmentSwitch, i showed the first view using selectView before the animation, when the animation added it was no longer needed, fixed. \$\endgroup\$shay te– shay te2014年08月25日 12:04:51 +00:00Commented Aug 25, 2014 at 12:04
-
\$\begingroup\$ as for viewWillDisappear/willAppear i just copy the implementation from here redartisan.com/2010/5/26/uisegmented-control-view-switching so i don't fully understand what is to correct approach, i am only beginning with uikit \$\endgroup\$shay te– shay te2014年08月25日 12:07:20 +00:00Commented Aug 25, 2014 at 12:07
-
\$\begingroup\$ can i give me a snippet of the correct way to viewWillDisappear/willAppear i am not fully understand \$\endgroup\$shay te– shay te2014年08月25日 12:18:30 +00:00Commented Aug 25, 2014 at 12:18
-
\$\begingroup\$ As I said, put the
willAppear/willDisappear
before the animations, put thedidAppear/didDisappear
in the animation completion block. \$\endgroup\$nhgrif– nhgrif2014年08月25日 21:20:21 +00:00Commented Aug 25, 2014 at 21:20