UISegmentedControl Best Practice

后端 未结 3 1536
醉酒成梦
醉酒成梦 2020-12-04 11:25

I\'m trying to work out the \"best\" way to use a UISegmentedControl for an iPhone application. I\'ve read a few posts here on stackoverflow and seen a few peo

相关标签:
3条回答
  • 2020-12-04 11:58

    Here's a great tutorial that explains this concept further: http://redartisan.com/2010/5/26/uisegmented-control-view-switching

    and the github location to it: https://github.com/crafterm/SegmentedControlExample.git

    0 讨论(0)
  • 2020-12-04 12:10

    I'd go with the second option you mention, creating the subviews in IB and swapping them in and out of a main view. This would be a good opportunity to use UIViewController, unsubclassed: in your initial setup, create a controller using -initWithNibName:bundle: (where the first parameter is the name of the NIB containing the individual subview, and the second parameter is nil) and add its view as a subview of your main view as necessary. This will help keep your memory footprint low: the default behavior of a UIViewController when receiving a memory warning is to release its view if it has no superview. As long as you remove hidden views from the view hierarchy, you can keep the controllers in memory and not worry about releasing anything.

    (edited in response to comment:)

    You don't need to subclass UIViewController, but you do need separate XIBs for each view. You also don't need to add anything to the containing view in IB.

    Instance variables, in the interface of whatever class is handling all this:

     UIViewController *controllerOne;
     UIViewController *controllerTwo;
    
     UIViewController *currentController;
    
     IBOutlet UIView *theContainerView;
    

    In your setup (-applicationDidFinishLaunching: or whatever)

     controllerOne = [[UIViewController alloc] initWithNibName:@"MyFirstView" bundle:nil];
     controllerTwo = [[UIViewController alloc] initWithNibName:@"MySecondView" bundle:nil];
    

    To switch to a controller:

     - (void)switchToController:(UIViewController *)newCtl
     {
          if(newCtl == currentController)
               return;
          if([currentController isViewLoaded])
               [currentController.view removeFromSuperview];
    
          if(newCtl != nil)
               [theContainerView addSubview:newCtl.view];
    
          currentController = newCtl;
     }
    

    Then just call that with, e.g.,

     [self switchToController:controllerOne];
    
    0 讨论(0)
  • 2020-12-04 12:17

    I've come across this requirement as well in an iPad application.

    The solution I came to was to create specialized view controllers for each style of view to handle business logic relating to those views (ie. relating to each segment), and programatically add/remove them as subviews to a 'managing' controller in response to selected segment index changes.

    To do this, one has to create an additional UIViewController subclass that manages UISegmentedControl changes, and adds/removes the subviews.

    The code below does all this, also taking care of a few caveats/extras:

    • viewWillAppear/viewWillDisappear/etc, aren't called on the subviews automatically, and need to be told via the 'managing' controller
    • viewWillAppear/viewWillDisappear/etc, aren't called on 'managing' controller when it's within a navigation controller, hence the navigation controller delegate
    • If you'd like to push onto a navigation stack from within a segment's subview, you need to call back on to the 'managing' view to do it, since the subview has been created outside of the navigation hierarchy, and won't have a reference to the navigation controller.
    • If used within a navigation controller scenario, the back button is automatically set to the name of the segment.

    Interface:

    @interface SegmentManagingViewController : UIViewController <UINavigationControllerDelegate> {
        UISegmentedControl    * segmentedControl;
        UIViewController      * activeViewController;
        NSArray               * segmentedViewControllers;
    }
    
    @property (nonatomic, retain) IBOutlet UISegmentedControl * segmentedControl;
    @property (nonatomic, retain) UIViewController            * activeViewController;
    @property (nonatomic, retain) NSArray                     * segmentedViewControllers;
    
    @end
    

    Implementation:

    @interface SegmentManagingViewController ()
    - (void)didChangeSegmentControl:(UISegmentedControl *)control;
    @end
    
    @implementation SegmentManagingViewController
    
    @synthesize segmentedControl, activeViewController, segmentedViewControllers;
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        UIViewController * controller1 = [[MyViewController1 alloc] initWithParentViewController:self];
        UIViewController * controller2 = [[MyViewController2 alloc] initWithParentViewController:self];
        UIViewController * controller3 = [[MyViewController3 alloc] initWithParentViewController:self];
    
        self.segmentedViewControllers = [NSArray arrayWithObjects:controller1, controller2, controller3, nil];
        [controller1 release];
        [controller2 release];
        [controller3 release];
    
        self.navigationItem.titleView = self.segmentedControl =
        [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Seg 1", @"Seg 2", @"Seg 3", nil]];
        self.segmentedControl.selectedSegmentIndex = 0;
        self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
    
        [self.segmentedControl addTarget:self action:@selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged];
    
        [self didChangeSegmentControl:self.segmentedControl]; // kick everything off
    }
    
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [self.activeViewController viewWillAppear:animated];
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self.activeViewController viewDidAppear:animated];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self.activeViewController viewWillDisappear:animated];
    }
    
    - (void)viewDidDisappear:(BOOL)animated {
        [super viewDidDisappear:animated];
        [self.activeViewController viewDidDisappear:animated];
    }
    
    #pragma mark -
    #pragma mark UINavigationControllerDelegate control
    
    // Required to ensure we call viewDidAppear/viewWillAppear on ourselves (and the active view controller)
    // inside of a navigation stack, since viewDidAppear/willAppear insn't invoked automatically. Without this
    // selected table views don't know when to de-highlight the selected row.
    
    - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        [viewController viewDidAppear:animated];
    }
    
    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        [viewController viewWillAppear:animated];
    }
    
    #pragma mark -
    #pragma mark Segment control
    
    - (void)didChangeSegmentControl:(UISegmentedControl *)control {
        if (self.activeViewController) {
            [self.activeViewController viewWillDisappear:NO];
            [self.activeViewController.view removeFromSuperview];
            [self.activeViewController viewDidDisappear:NO];
        }
    
        self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex];
    
        [self.activeViewController viewWillAppear:NO];
        [self.view addSubview:self.activeViewController.view];
        [self.activeViewController viewDidAppear:NO];
    
        NSString * segmentTitle = [control titleForSegmentAtIndex:control.selectedSegmentIndex];
        self.navigationItem.backBarButtonItem  = [[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil];
    }
    
    #pragma mark -
    #pragma mark Memory management
    
    - (void)dealloc {
        self.segmentedControl = nil;
        self.segmentedViewControllers = nil;
        self.activeViewController = nil;
        [super dealloc];
    }
    
    @end
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题