如何使用UISegmentedControl切换视图?

83

我正在尝试弄清如何使用 UISegmentedControl 的不同状态来切换视图,类似于 Apple 在 App Store 中在“收费最高”和“免费榜单”之间进行切换的方式。

9个回答

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
由于所有视图必须永久存储在内存中,如果你的视图太复杂和/或包含许多其他元素,则会影响整体性能。那段代码也可以进行重构。 - Stas
@Stas 你说得对,最好将逻辑分散在多个视图控制器之间,每个控制器负责自己的操作和行为。 - tf.alves
使用容器视图可能会导致导航栏出现问题,特别是当您使用半透明的导航栏时。从我的经验来看,这不是一个可推荐的解决方案。 - DamirDiz

44

在我的情况下,我的观点非常复杂,我不能仅仅改变不同视图的隐藏属性,因为这将占用太多内存。

我尝试了几种解决方案,但都没有起作用,或者表现不稳定,特别是当推送/弹出视图时,navBar 的 titleView 并不总是显示 segmentedControl。

我发现了这篇博客文章,它解释了如何以正确的方式解决这个问题。看起来他在 WWDC'2010 上得到了苹果工程师的帮助来想出这个解决方案。

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

这个链接里的解决方案是迄今为止我找到的关于这个问题最好的解决方案。稍微调整一下,它也可以很好地适用于底部的 tabBar。


1
我尝试在底部工具栏上使其正常工作,但没有成功,http://stackoverflow.com/questions/4748120/uisegmentedcontroller-to-switch-between-uiviewcontrollers-calendar-app-style 你能帮我吗? - Erik
是否有一种方法能够在视图之间实现水平翻转动画?或者它只能在没有动画的情况下工作? - aneuryzm
2
幸运的是,_实现容器视图控制器_ 运行得非常顺利!甚至segue也按预期工作。 - jweyrich
好的解决方案,但有点令人困惑。 - Vladimir Stazhilov
我知道这很老了,但你们有没有解决方案?答案中提供的链接已经失效了:( - sudoExclaimationExclaimation
显示剩余4条评论

17
如果它是一个表格,您可以重新加载表格,并在 cellForRowAtIndex 中根据所选段选项从不同的数据源填充表格。

7
一种方法是在分段控件的视图中添加一个容器视图,该容器视图填充不同的子视图(在切换段时作为唯一子视图添加到容器视图中)。甚至可以为这些子视图单独创建视图控制器,但如果需要重要的方法如“viewWillAppear”和“viewWillDisappear”,则必须将它们转发(并且必须告诉它们所属的导航控制器)。
通常情况下,这种方法效果很好,因为您可以使用IB在主视图中布局容器,并且子视图将填充容器让它们拥有的任何空间(确保正确设置自动调整大小掩码)。

3

Swift版本:

父视图控制器负责设置每个子视图控制器的视图大小和位置。子视图控制器的视图成为父视图控制器视图层次结构的一部分。

定义延迟加载属性:

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()
}

管理分段控件的点击事件

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")
}

Reference: https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/


2
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。- 来自审查 - Basile Perrenoud
2
@BasilePerrenoud 刚刚更新了答案,加入了解决方案中至关重要的部分。 - SlavisaPetkovic

3

尝试使用SNFSegmentedViewController,这是一个开源组件,可以像UITabBarController一样设置,完全符合你的需求。


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

根据 @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

0

快速的 Swift 版本:

@IBAction func segmentControlValueChanged(_ sender: UISegmentedControl) {

    if segmentControl.selectedSegmentIndex == 0 {

        // do something
    } else {

        // do something else
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接