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

82

Я пытаюсь понять, как использовать различные состояния UISegmentedControl для переключения представлений, аналогично тому, как Apple делает это в App Store при переключении между «Top Paid» и «Top Free».

Марк Адамс
источник

Ответы:

113

Самый простой подход - иметь два представления, видимость которых можно переключать, чтобы указать, какой вид был выбран. Вот пример кода того, как это можно сделать, определенно не оптимизированный способ обработки представлений, а просто демонстрация того, как вы можете использовать UISegmentControl для переключения видимого представления:

- (IBAction)segmentSwitch:(id)sender {
  UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
  NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;

  if (selectedSegment == 0) {
    //toggle the correct view to be visible
    [firstView setHidden:NO];
    [secondView setHidden:YES];
  }
  else{
    //toggle the correct view to be visible
    [firstView setHidden:YES];
    [secondView setHidden:NO];
  }
}


Вы, конечно, можете дополнительно изменить коэффициент кода, чтобы скрыть / показать правильное представление.

Ронни Лью
источник
4
«определенно не оптимизированный способ обработки просмотров» - почему?
Adam Waite
3
@AdamWaite, потому что все представления должны постоянно храниться в памяти. Если ваши представления слишком сложны и / или содержат много других элементов, это повлияет на общую производительность. Этот фрагмент кода тоже можно отредактировать.
Стас
@Stas Вы правы, лучше разделить логику между несколькими контроллерами представления, каждый из которых отвечает за свои действия и поведение
tf.alves
использование контейнерных представлений может привести к проблемам с панелью навигации. особенно если вы используете полупрозрачный. по моему опыту это не рекомендуемое решение
DamirDiz
45

В моем случае мои представления довольно сложны, и я не могу просто изменить скрытое свойство разных представлений, потому что это займет слишком много памяти.

Я пробовал несколько решений, и ни одно из них не сработало для меня или работало беспорядочно, особенно с titleView в navBar, не всегда отображающим segmentedControl при нажатии / открытии представлений.

Я нашел это сообщение в блоге о проблеме, в котором объясняется, как это сделать правильно. Кажется, ему помогли инженеры Apple на WWDC'2010, чтобы придумать это решение.

http://redartisan.com/2010/6/27/uisegmented-control-view-switching-revisited

Решение по этой ссылке - лучшее решение, которое я нашел до сих пор. С небольшой настройкой он также отлично работал с tabBar внизу

Марк М
источник
Спасибо за отличную находку. Определенно красивое и элегантное решение для этой методологии.
Shiun
1
Я безуспешно пытался заставить это работать правильно с панелью инструментов внизу, stackoverflow.com/questions/4748120/ ... Не могли бы вы мне помочь?
Эрик
Есть ли способ иметь анимацию горизонтального переворота между видами. Или работает только без анимации?
аневризм
Да, кажется, это отличное решение, но как мне настроить его для работы с tabBarController с уже находящимися внутри navigationController?
Владимир Стажилов
2
К счастью, реализация Контроллера представления контейнера работала безупречно! Даже сегменты работают как положено.
jweyrich
17

Или, если это таблица, вы можете перезагрузить таблицу и в cellForRowAtIndex заполнить таблицу из разных источников данных в зависимости от выбранного параметра сегмента.

lostInTransit
источник
7

Одна из идей состоит в том, чтобы представление с сегментированными элементами управления имело представление контейнера, которое вы заполняете различными подпредставлениями (добавляйте как единственное подпредставление представления контейнера при переключении сегментов). У вас даже могут быть отдельные контроллеры представления для этих подпредставлений, хотя вы должны пересылать важные методы, такие как «viewWillAppear» и «viewWillDisappear», если они вам нужны (и им нужно будет сообщить, под каким контроллером навигации они находятся).

Как правило, это работает очень хорошо, потому что вы можете выложить основное представление с контейнером в IB, а вложенные представления будут заполнять все пространство, которое контейнер позволяет им (убедитесь, что ваши маски автоматического изменения размера настроены правильно).

Кендалл Хельмштеттер Гельнер
источник
3

Попробуйте использовать SNFSegmentedViewControllerкомпонент с открытым исходным кодом, который делает именно то, что вы ищете, с подобной настройкой UITabBarController.

Sethfri
источник
2

Из ответа @Ronnie Liew я создаю это:

//
//  ViewController.m
//  ResearchSegmentedView
//
//  Created by Ta Quoc Viet on 5/1/14.
//  Copyright (c) 2014 Ta Quoc Viet. All rights reserved.
//
#define SIZE_OF_SEGMENT 56
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize theSegmentControl;
UIView *firstView;
UIView *secondView;
CGRect leftRect;
CGRect centerRect;
CGRect rightRect;
- (void)viewDidLoad
{
    [super viewDidLoad];
    leftRect = CGRectMake(-self.view.frame.size.width, SIZE_OF_SEGMENT, self.view.frame.size.width, self.view.frame.size.height-SIZE_OF_SEGMENT);
    centerRect = CGRectMake(0, SIZE_OF_SEGMENT, self.view.frame.size.width, self.view.frame.size.height-SIZE_OF_SEGMENT);
    rightRect = CGRectMake(self.view.frame.size.width, SIZE_OF_SEGMENT, self.view.frame.size.width, self.view.frame.size.height-SIZE_OF_SEGMENT);

    firstView = [[UIView alloc] initWithFrame:centerRect];
    [firstView setBackgroundColor:[UIColor orangeColor]];
    secondView = [[UIView alloc] initWithFrame:rightRect];
    [secondView setBackgroundColor:[UIColor greenColor]];
    [self.view addSubview:firstView];
    [self.view addSubview:secondView];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)segmentSwitch:(UISegmentedControl*)sender {
    NSInteger selectedSegment = sender.selectedSegmentIndex;
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.2];
    if (selectedSegment == 0) {
        //toggle the correct view to be visible
        firstView.frame = centerRect;
        secondView.frame = rightRect;
    }
    else{
        //toggle the correct view to be visible
        firstView.frame = leftRect;
        secondView.frame = centerRect;
    }
    [UIView commitAnimations];
}
@end
Envil
источник
2

Назначьте .H в

 UISegmentedControl *lblSegChange;

- (IBAction)segValChange:(UISegmentedControl *) sender

Объявить .M

- (IBAction)segValChange:(UISegmentedControl *) sender
{

 if(sender.selectedSegmentIndex==0)
 {
  viewcontroller1 *View=[[viewcontroller alloc]init];
  [self.navigationController pushViewController:view animated:YES];
 }
 else 
 {
  viewcontroller2 *View2=[[viewcontroller2 alloc]init];
  [self.navigationController pushViewController:view2 animated:YES];
 }
} 
Анбу.Картик
источник
2

Быстрая версия:

Контроллер родительского представления отвечает за установку размера и положения представления каждого контроллера дочернего представления. Представление дочернего контроллера представления становится частью иерархии представлений родительского контроллера представления.

Определите ленивые свойства:

private lazy var summaryViewController: SummaryViewController = {
   // Load Storyboard
   let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

   // Instantiate View Controller
   var viewController = storyboard.instantiateViewController(withIdentifier: "SummaryViewController") as! SummaryViewController

   // Add View Controller as Child View Controller
   self.add(asChildViewController: viewController)

   return viewController
}()

private lazy var sessionsViewController: SessionsViewController = {
    // Load Storyboard
    let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

    // Instantiate View Controller
    var viewController = storyboard.instantiateViewController(withIdentifier: "SessionsViewController") as! SessionsViewController

    // Add View Controller as Child View Controller
    self.add(asChildViewController: viewController)

    return viewController
}()

Показать / скрыть дочерние контроллеры представления:

private func add(asChildViewController viewController: UIViewController) {
    // Add Child View Controller
    addChildViewController(viewController)

    // Add Child View as Subview
    view.addSubview(viewController.view)

    // Configure Child View
    viewController.view.frame = view.bounds
    viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    // Notify Child View Controller
    viewController.didMove(toParentViewController: self)
}

private func remove(asChildViewController viewController: UIViewController) {
    // Notify Child View Controller
    viewController.willMove(toParentViewController: nil)

    // Remove Child View From Superview
    viewController.view.removeFromSuperview()

    // Notify Child View Controller
    viewController.removeFromParentViewController()
}

Управление SegmentedControl tapEvent

private func updateView() {
    if segmentedControl.selectedSegmentIndex == 0 {
        remove(asChildViewController: sessionsViewController)
        add(asChildViewController: summaryViewController)
    } else {
        remove(asChildViewController: summaryViewController)
        add(asChildViewController: sessionsViewController)
    }
}

И, конечно же, вы можете использовать в своих дочерних классах контроллера представления:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    print("Summary View Controller Will Appear")
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    print("Summary View Controller Will Disappear")
}

Ссылка: https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/

Славиша Петкович
источник
1
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из
отзыва
2
@BasilePerrenoud Только что обновил ответ, указав важнейшую и наиболее важную часть решения.
SlavisaPetkovic
1

Быстрая версия Swift:

@IBAction func segmentControlValueChanged(_ sender: UISegmentedControl) {

    if segmentControl.selectedSegmentIndex == 0 {

        // do something
    } else {

        // do something else
    }
}
Светлое будущее
источник