UISegmentedControl Best Practice - PullRequest
       17

UISegmentedControl Best Practice

22 голосов
/ 22 января 2010

Я пытаюсь найти «лучший» способ использования UISegmentedControl для приложения iPhone.Я прочитал несколько постов здесь на stackoverflow и видел идеи нескольких людей, но я не могу разобраться, как лучше всего это сделать.Должности, на которые я ссылаюсь:

Изменение видов из UISegmentedControl и Как использовать UISegmentedControl для переключения видов?

Было быКажется, что варианты:

  • Добавьте каждое из представлений в IB и расположите их друг над другом, затем покажите / скройте их
  • Создайте каждое из представлений отдельно в IBЗатем создайте контейнер в главном представлении, чтобы заполнить его нужным подпредставлением
  • Установите один действительно высокий или очень широкий UIView и анимируйте его влево / вправо или вверх / вниз в зависимости от выбранного сегмента
  • Использование UITabBarController для замены подпредставлений - кажется глупым
  • Для таблиц перезагрузите таблицу и в cellForRowAtIndex и заполните таблицу из разных источников данных или разделов на основе параметра сегментавыбрано (не относится к моему приложению)

Итак, какой подход лучше всего подходит для подходов с подпредставлением / вне таблицы?Что проще всего реализовать?Не могли бы вы поделиться примером кода для подхода?

Спасибо!

Ответы [ 3 ]

19 голосов
/ 23 мая 2010

Я также сталкивался с этим требованием в приложении для iPad.

Решением, к которому я пришел, было создание специализированных контроллеров представления для каждый стиль представления для обработки бизнес-логики, связанной с этими представлениями (т.е. относящиеся к каждому сегменту), и программно добавляйте / удаляйте их как подпредставления «управляющему» контроллеру в ответ на выбранный сегмент изменения индекса.

Для этого необходимо создать дополнительный подкласс UIViewController, который управляет UISegmentedControl изменяет и добавляет / удаляет подпредставления.

Код ниже делает все это, также принимая во внимание несколько предостережений / дополнений:

  • viewWillAppear / viewWillDisappear / etc, не вызывается для подпредставлений автоматически, и нужно сообщить через «управляющий» контроллер
  • viewWillAppear / viewWillDisappear / и т. Д. Не вызываются для «управления» контроллер, когда он находится внутри контроллера навигации, следовательно, делегат навигационного контроллера
  • Если вы хотите нажать на стек навигации из подпредставление сегмента, вам нужно перезвонить на «управляющий» вид чтобы сделать это, так как подпредставление было создано за пределами иерархия навигации, и не будет ссылки на навигацию контроллер.
  • Если используется в сценарии контроллера навигации, кнопка «Назад» автоматически устанавливается на имя сегмента.

Интерфейс:

@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

Реализация:

@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

Надеюсь, это поможет.

11 голосов
/ 22 января 2010

Я бы выбрал второй вариант, который вы упомянули, создав подпредставления в IB и поменяв их местами в главном представлении. Это было бы хорошей возможностью использовать UIViewController, без подкласса: в вашей первоначальной настройке создайте контроллер, используя -initWithNibName:bundle: (где первый параметр - это имя NIB, содержащего отдельное подпредставление, а второй параметр - nil ) и добавьте его view как подпредставление вашего основного представления по мере необходимости. Это поможет сохранить низкую долю памяти: поведение по умолчанию UIViewController при получении предупреждения о памяти заключается в освобождении его представления, если у него нет суперпредставления. Пока вы удаляете скрытые представления из иерархии представлений, вы можете хранить контроллеры в памяти и не беспокоиться об их освобождении.

(отредактировано в ответ на комментарий:)

Вам не нужно создавать подкласс UIViewController, но вам нужны отдельные XIB для каждого представления. Вам также не нужно ничего добавлять к содержащему представлению в IB.

Переменные экземпляра в интерфейсе любого класса обрабатывают все это:

 UIViewController *controllerOne;
 UIViewController *controllerTwo;

 UIViewController *currentController;

 IBOutlet UIView *theContainerView;

В вашей настройке (-applicationDidFinishLaunching: или что-то еще)

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

Чтобы переключиться на контроллер:

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

      if(newCtl != nil)
           [theContainerView addSubview:newCtl.view];

      currentController = newCtl;
 }

Тогда просто позвоните, например, с

 [self switchToController:controllerOne];
3 голосов
/ 13 февраля 2012

Вот отличный учебник, который объясняет эту концепцию дальше: http://redartisan.com/2010/5/26/uisegmented-control-view-switching

и местонахождение github: https://github.com/crafterm/SegmentedControlExample.git

...