在一个 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 之间切换