在一个 UIVIewController 中有两个垂直的全屏 UIViews?

Posted

技术标签:

【中文标题】在一个 UIVIewController 中有两个垂直的全屏 UIViews?【英文标题】:Having two full-screen UIViews vertically in a single UIVIewController? 【发布时间】:2017-03-15 14:28:48 【问题描述】:

我正在寻找一种在单个 Viewcontroller 中拥有两个全屏 UIView 的方法,这样会有一个按钮,当用户点击该按钮时,它会将其带到第一个视图下方的视图,反之亦然反之亦然...简单来说,我想将两个全屏 UIView 垂直放在一个 UIViewcontroller 中

我正在寻找这样的东西:

【问题讨论】:

在视图之间转换时是否需要视觉效果? uiscrollview 是一种常见的方式来呈现比一次容纳更多的视图。这可以关闭(为用户)滚动,并让应用在按下按钮时执行滚动——向上或向下滚动一整页。 一个小的滚动效果(不要太多)会很好 【参考方案1】:

您可以在该场景中使用滚动视图。将两个视图作为子视图添加到滚动视图,并在用户点击按钮(或在我的示例中为分段控件)时更新滚动视图的 contentoffset:

var scrollView: UIScrollView!

override func viewDidLoad() 
    super.viewDidLoad()

    let scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.scrollEnabled = false
    view.addSubview(scrollView)
    self.scrollView = scrollView

    let firstView = UIView()
    firstView.translatesAutoresizingMaskIntoConstraints = false
    firstView.backgroundColor = UIColor.lightGrayColor()
    scrollView.addSubview(firstView)

    let secondView = UIView()
    secondView.translatesAutoresizingMaskIntoConstraints = false
    secondView.backgroundColor = UIColor.darkGrayColor()
    scrollView.addSubview(secondView)

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[sv]|", options: [], metrics: nil, views: ["sv": scrollView]))
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[sv]|", options: [], metrics: nil, views: ["sv": scrollView]))

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[fv]|", options: [], metrics: nil, views: ["fv": firstView]))
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[fv][sv]|", options: [.AlignAllLeading, .AlignAllTrailing], metrics: nil, views: ["fv": firstView, "sv": secondView]))

    firstView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
    firstView.heightAnchor.constraintEqualToAnchor(scrollView.heightAnchor).active = true

    firstView.widthAnchor.constraintEqualToAnchor(secondView.widthAnchor).active = true
    firstView.heightAnchor.constraintEqualToAnchor(secondView.heightAnchor).active = true

    let segmentedControl = UISegmentedControl(items: ["firstView", "secondView"])
    segmentedControl.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(segmentedControl)
    segmentedControl.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[sc]-20-|", options: [], metrics: nil, views: ["sc": segmentedControl]))

    segmentedControl.selectedSegmentIndex = 0
    segmentedControl.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), forControlEvents: .ValueChanged)


func segmentedControlValueChanged(segmentedControl: UISegmentedControl) 
    scrollView.setContentOffset(CGPointMake(0, CGFloat(segmentedControl.selectedSegmentIndex) * scrollView.frame.height), animated: true)

希望我没听错。有什么不清楚的地方欢迎追问!

更新(OBJ-C)

@interface ViewController ()

@property (strong, nonatomic) UIScrollView *scrollView;

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];

    UIScrollView *scrollView = [UIScrollView new];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.scrollEnabled = NO;
    [self.view addSubview:scrollView];
    self.scrollView = scrollView;

    UIView *firstView = [UIView new];
    firstView.translatesAutoresizingMaskIntoConstraints = NO;
    firstView.backgroundColor = [UIColor lightGrayColor];
    [scrollView addSubview:firstView];

    UIView *secondView = [UIView new];
    secondView.translatesAutoresizingMaskIntoConstraints = NO;
    secondView.backgroundColor = [UIColor darkGrayColor];
    [scrollView addSubview:secondView];

    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[sv]|" options:0 metrics:nil views:@@"sv": scrollView]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[sv]|" options:0 metrics:nil views:@@"sv": scrollView]];

    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[fv]|" options:0 metrics:nil views:@@"fv": firstView]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fv][sv]|" options:NSLayoutFormatAlignAllLeading|NSLayoutFormatAlignAllTrailing metrics:nil views:@@"fv": firstView, @"sv": secondView]];

    [firstView.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor].active = YES;
    [firstView.heightAnchor constraintEqualToAnchor:scrollView.heightAnchor].active = YES;

    [firstView.widthAnchor constraintEqualToAnchor:secondView.widthAnchor].active = YES;
    [firstView.heightAnchor constraintEqualToAnchor:secondView.heightAnchor].active = YES;

    UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"firstView", @"secondView"]];
    segmentedControl.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:segmentedControl];
    [segmentedControl.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[sc]-20-|" options:0 metrics:nil views:@@"sc": segmentedControl]];

    segmentedControl.selectedSegmentIndex = 0;
    [segmentedControl addTarget:self action:@selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];


- (void)segmentedControlValueChanged:(UISegmentedControl *)segmentedControl 
    [self.scrollView setContentOffset:CGPointMake(0, segmentedControl.selectedSegmentIndex * CGRectGetHeight(self.scrollView.frame)) animated:YES];


@end

【讨论】:

谢谢安德烈,你在 Obj-C 中是否有相同的代码库? 欣赏它:)【参考方案2】:

您可以使用 2 个单元格的 UITableView,每个单元格占据整个屏幕(查看如何动态设置高度)。

您可以有 2 个自定义单元格,每个视图一个,显然有自己的类和逻辑。

这可行,您将能够使用各种滚动视图优势,例如捕捉视图顶部以避免仅显示部分视图,或手动控制滚动。

此外,如果您需要更改视图数量,您将成为未来的证明:您可以拥有任意数量的视图!

它们也可能比屏幕尺寸更大/更小,因为它们位于滚动视图中。

【讨论】:

【参考方案3】:

只要你使用autoLayout,它真的很简单。将UIView 拖放到情节提要上,并在超级视图中添加前导、尾随、底部和顶部。让我们称之为 view1。现在将另一个UIView 拖放到与view1 相同的层次结构级别的情节提要上,我们将这个新视图称为view2。现在将 view2 的尺寸检查器中的 y 偏移量设置为 800。

现在在您的视图层次结构中,control + 单击 view1 并拖放到您的 view2 上并按 shift 并选择前导、尾随、垂直间距和等高约束。确保所有常量都设置为 0(如果您希望根据内容推断的高度不等于全屏高度,请将等高约束优先级设置为 250)。

您的屏幕现在应该如下所示:

现在选择您的 view1 并选择顶部约束。附加到超级视图的那个。为这个约束创建一个出口到你的UIViewController 类中,我们称之为viewOneTopSpaceConstraint

现在您所要做的就是在IBAction 中为 toggle 按钮:

if viewOneTopSpaceConstraint.constant == 0

     viewOneTopSpaceConstraint.constant = -UIScreen.main.bounds.size.height
else

     viewOneTopSpaceConstraint.constant = 0


UIView.animate(withDuration: 0.2, animations: 

     self.view.layoutIfNeeded()


【讨论】:

感谢您的解决方案!【参考方案4】:

尽管我读过的所有答案都很好,但最后一个选择是让用户感觉一个视图在屏幕外,而另一个视图在屏幕上,同时基本上将所有内容都固定到超级视图。这是我的设置和使用 CATransitions。

主容器固定在主视图上,但如果控件应该放在那里,您可以在顶部添加空间。它包含两个都固定到 masterContainer 的视图。两者都有一个按钮来调用更改。我在 Storyboard view2 中预设为在应用程序启动时隐藏。这里是控制器。当您在视图 1 中按下按钮时,视图 2 将从底部向上滑动。当您按下 view2 按钮时,view1 将向下滑动 view2。这是控制器和所需的代码。

import UIKit

class CATransitionDemoViewController: UIViewController 

    @IBOutlet weak var masterContainer: UIView!
    @IBOutlet weak var view2: UIView!
    @IBOutlet weak var view1: UIView!
    override func viewDidLoad() 
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        view2.isHidden = true
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    


    @IBAction func viewButton1DidPress(_ sender: Any) 
            let transition = CATransition()
            transition.duration = 0.4
            transition.type = kCATransitionMoveIn
            transition.subtype = kCATransitionFromTop
            self.masterContainer.layer.add(transition, forKey: nil)
            view1.isHidden = !view1.isHidden
            view2.isHidden = !view2.isHidden
    

    @IBAction func viewButton2DidPress(_ sender: Any) 
            let transition = CATransition()
            transition.duration = 0.4
            transition.type = kCATransitionPush
            transition.subtype = kCATransitionFromBottom
            self.masterContainer.layer.add(transition, forKey: nil)
            view1.isHidden = !view1.isHidden
            view2.isHidden = !view2.isHidden
    

目标 C 中的 OR

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *masterContainer;
@property (weak, nonatomic) IBOutlet UIView *view1;
@property (weak, nonatomic) IBOutlet UIView *view2;

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [_view2 setHidden:YES];



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

- (IBAction)buttonView1DidPress:(id)sender 
    CATransition *transition = [[CATransition alloc]init];
    transition.duration = 0.5;
    //or for some real fun uncomment the next line and comment the two lines out after that one
    //transition.type = @"suckEffect";
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromTop;
    [_masterContainer.layer addAnimation:transition forKey:nil];
    [_view1 setHidden:!_view1.hidden];
    [_view2 setHidden:!_view2.hidden];


- (IBAction)buttonView2DidPress:(id)sender 
    CATransition *transition = [[CATransition alloc]init];
    transition.duration = 0.5;
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromBottom;
    [_masterContainer.layer addAnimation:transition forKey:nil];
    [_view1 setHidden:!_view1.hidden];
    [_view2 setHidden:!_view2.hidden];


@end

这样做的好处是,当您在情节提要中工作时,无需设置滚动视图即可轻松访问所有内容。此外,CATransitions 还有更多选项。

【讨论】:

能不能也分享一下obj-c的源码?

以上是关于在一个 UIVIewController 中有两个垂直的全屏 UIViews?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式在两个 UIViewController 之间切换

在两个 UIViewController 堆栈之间转换

一个 UIViewController 中的两个 UICollectionView

错误 UIViewController 没有成员

定位 UIViewController 包含子项

XCode IOS初学者UIViewController类更改按钮