3
\$\begingroup\$

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.

  1. Is a center view that contains all subviews the right approach?
  2. 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();
 }
}
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 25, 2014 at 11:00
\$\endgroup\$
5
  • \$\begingroup\$ "Is the animation is correctly done" -- does it animate correctly? \$\endgroup\$ Commented 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\$ Commented Aug 25, 2014 at 11:30
  • \$\begingroup\$ Okay, I just wanted clarification that it was actually working as you expected. \$\endgroup\$ Commented 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\$ Commented 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\$ Commented Aug 25, 2014 at 11:37

1 Answer 1

2
\$\begingroup\$
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.

answered Aug 25, 2014 at 11:41
\$\endgroup\$
4
  • \$\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\$ Commented 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\$ Commented 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\$ Commented Aug 25, 2014 at 12:18
  • \$\begingroup\$ As I said, put the willAppear/willDisappear before the animations, put the didAppear/didDisappear in the animation completion block. \$\endgroup\$ Commented Aug 25, 2014 at 21:20

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.