我的应用程序的第一个屏幕是没有导航栏的UITableViewController
,这意味着内容在状态栏下流动,因此会发生很多文本冲突。我已经调整了Under top bars
和Adjust scroll view insets
的两个属性,这些属性实际上阻止了它滚动,但代价是保持表格视图的顶部。我尝试将UITableView
帧设置为偏移20像素,但它似乎没有生效,因为我目前需要该应用与iOS 6兼容,我可以'跳转到iOS 7故事板以强制自动布局使用顶部高度指南。有没有人找到适用于这两个版本的解决方案?
我尝试过的事情:设置edgesForExtendedLayout
,更改故事板中Under top bars
和Adjust scroll view
的设置,将框架强制转换为新区域。
一张图片胜过千言万语:
答案 0 :(得分:364)
对于有兴趣复制此内容的任何人,只需按照以下步骤操作:
UIViewController
UITableViewController
如果您按照上述步骤操作,当您运行该应用程序时,您将看到没有任何内容,包括调整Xcode的复选框“在{顶部,底部,不透明}条形图下延伸边缘”可以阻止第一行出现在状态栏,也不能以编程方式解决此问题。
E.g。在上面的场景中,以下内容将具有无效果:
// These do not work
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;
这个问题非常令人沮丧,我相信这是Apple的一个错误,特别是因为它出现在他们自己的预先连线的UITableViewController
对象库中。
我不同意所有试图通过使用任何形式的“幻数”来解决这个问题的人,例如: “使用20px的delta”。这种紧密耦合的编程绝对不是Apple希望我们在这里做的。
我发现了两个解决这个问题的方法:
保留UITableViewController
的场景:
如果您希望将UITableViewController
保留在故事板中,而无需手动将其放入另一个视图中,则可以将UITableViewController
嵌入UINavigationController
(编辑器>嵌入>导航控制器) )并在检查器中取消选中“显示导航栏”。这解决了这个问题,无需额外调整,并且还在故事板中保留了UITableViewController
的场景。
使用AutoLayout并将UITableView
嵌入到另一个视图中 (我相信这就是Apple希望我们这样做的方式):
创建一个空的UIViewController
并将UITableView
拖入其中。然后,按住Ctrl键并从UITableView
向状态栏拖动。当鼠标到达状态栏的底部时,您将看到一个显示“顶部布局指南”的Autolayout气泡。释放鼠标并选择“垂直间距”。这将告诉布局系统将其放置在状态栏的正下方。
我已经在空应用程序上测试了两种方式,但它们都有效。您可能需要做一些额外的调整才能使它们适合您的项目。
答案 1 :(得分:84)
如果您以编程方式执行操作并使用UITableViewController
而没有UINavigationController
,则最好的选择是在viewDidLoad
中执行以下操作:
Swift 3
self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
早先的Swift
self.tableView.contentInset = UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f);
UITableViewController
仍然会滚动到状态栏后面,但滚动到顶部时不会在它下面。
答案 2 :(得分:23)
请注意:这适用于以下配置:
如果不符合上述两项要求,您的身份可能会有所不同。
原帖
我以编程方式创建了我的视图,最终为我工作了:
- (void) viewDidLayoutSubviews {
// only works for iOS 7+
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
CGRect viewBounds = self.view.bounds;
CGFloat topBarOffset = self.topLayoutGuide.length;
// snaps the view under the status bar (iOS 6 style)
viewBounds.origin.y = topBarOffset * -1;
// shrink the bounds of your view to compensate for the offset
viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1);
self.view.bounds = viewBounds;
}
}
Source(位于第39页底部的 topLayoutGuide 部分)。
答案 3 :(得分:20)
添加到最佳答案:
在第二种方法最初似乎没有工作后,我做了一些额外的修补,并找到了解决方案。
<强> TLDR;最佳答案的第二个解决方案几乎可以工作,但对于某些版本的xCode ctrl +拖动到&#34;顶部布局指南&#34;并选择Vertical Spacing不做任何事情。但是,首先调整表格视图的大小,然后选择&#34;顶部空间到顶部布局指南&#34;作品强>
将空白ViewController拖到故事板上。
将UITableView 对象拖到视图中。 (不是UITableViewController)。使用蓝色布局指南将其放置在正中心。
创建UIViewController的自定义子类,并添加<UITableViewDataSource, UITableViewDelegate>
协议。不要忘记在Identity Inspector中将故事板的ViewController设置为此类。
在您的实施文件中为您的TableView创建一个插座,并将其命名为&#34; tableView&#34;
现在是没有剪切到状态栏的部分。
现在您可以像平常一样设置表格视图,但它不会剪切状态栏!
答案 4 :(得分:11)
- (void) viewDidLayoutSubviews {
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone; // iOS 7 specific
CGRect viewBounds = self.view.bounds;
CGFloat topBarOffset = self.topLayoutGuide.length;
viewBounds.origin.y = topBarOffset * -1;
self.view.bounds = viewBounds;
self.navigationController.navigationBar.translucent = NO;
}
}
答案 5 :(得分:8)
这是如何在&#34; Swift&#34; 调整@ lipka的答案:
tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
答案 6 :(得分:6)
在故事板上选择UIViewController,取消选中“在顶栏下扩展边缘”选项。 为我工作。 :)
答案 7 :(得分:5)
答案 8 :(得分:3)
这将修复UITableViewController(没有任何幻数)。我无法解决的唯一问题是,如果您正在打电话,在这种情况下,tableView的顶部会被推下太多。如果有人知道如何解决这个问题,请告诉我们。
class MyTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureTableViewTop()
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (context) -> Void in
}, completion: { (context) -> Void in
self.configureTableViewTop()
})
}
func configureTableViewTop() {
tableView.contentInset.top = UIApplication.sharedApplication().statusBarFrame.height
}
}
答案 9 :(得分:2)
我不知道Kosher是怎么回事,但我发现这个方案将ViewController的视图向下移动并为状态栏提供了坚实的背景:
- (void)viewDidLoad {
[super viewDidLoad];
// Shove everything down if iOS 7 or later
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {
// Move the view down 20 pixels
CGRect bounds = self.view.bounds;
bounds.origin.y -= 20.0;
[self.view setBounds:bounds];
// Create a solid color background for the status bar
CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
statusBar.backgroundColor = [UIColor redColor];
[self.view addSubview:statusBar];
}
当然,用您想要的背景颜色替换redColor
。
您必须单独执行其中一个调配以在状态栏中设置字符/符号的颜色。我在plist中使用View controller-based status bar appearance = NO
和Status bar style = Opaque black style
来全局执行此操作。
似乎工作,我有兴趣听到它的任何错误或问题。
答案 10 :(得分:2)
chappjc的答案在使用XIB时效果很好。
我以编程方式创建TableViewControllers时发现最干净的解决方案是将UITableViewController实例包装在另一个UIViewController中并相应地设置约束。
这是:
UIViewController *containerLeftViewController = [[UIViewController alloc] init];
UITableViewController *tableViewController = [[UITableViewController alloc] init];
containerLeftViewController.view.backgroundColor = [UIColor redColor];
hostsAndMoreTableViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
[containerLeftViewController.view addSubview:tableViewController.view];
[containerLeftViewController addChildViewController:tableViewController];
[tableViewController didMoveToParentViewController:containerLeftViewController];
NSDictionary * viewsDict = @{ @"tableView": tableViewController.view ,
@"topGuide": containerLeftViewController.topLayoutGuide,
@"bottomGuide": containerLeftViewController.bottomLayoutGuide,
};
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|"
options:0
metrics:nil
views:viewsDict]];
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide][tableView][bottomGuide]"
options:0
metrics:nil
views:viewsDict]];
干杯,本
答案 11 :(得分:1)
我认为使用UITableViewController的方法可能与之前的方法略有不同。它对我有用,但你可能不喜欢它。我所做的是有一个视图控制器,其容器视图指向我的UItableViewController。通过这种方式,我可以使用提供给我的故事板中的TopLayoutGuide。只需将约束添加到容器视图中,就应该为iOS7和iOS6注意。
答案 12 :(得分:1)
以下解决方案在代码中运行良好而不使用魔术常量,并且考虑用户更改大小等级,例如通过ipads上的轮换或并排应用程序:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
[super traitCollectionDidChange:previousTraitCollection];
// Fix up content offset to ensure the tableview isn't underlapping the status bar.
self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.0, 0.0, 0.0);
}
答案 13 :(得分:1)
适用于swift 3 - 在viewDidLoad();
中let statusBarHeight = UIApplication.shared.statusBarFrame.height
let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
tableView.contentInset = insets
tableView.scrollIndicatorInsets = insets
此代码: 1.获取状态栏的高度 2.使表格顶部的内容插入等于状态栏的高度。 3.使滚动指示器具有相同的插图,因此它显示在状态栏下方。
答案 14 :(得分:1)
我为Retina /非Retina显示器做了这个
BOOL isRetina = FALSE;
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
isRetina = TRUE;
} else {
isRetina = FALSE;
}
}
if (isRetina) {
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;
}
答案 15 :(得分:1)
对于那些不想将UITableViewController
嵌入UIViewController
中的人,请尝试以下方法:
自定义UITableViewController
子类可以将蒙版视图附加到tableView的超级视图。在viewDidAppear上添加遮罩,并在viewWillDisappear上删除遮罩。
private var statusBarMaskView: UIView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let superview = self.tableView.superview {
self.statusBarMaskView = UIView(frame: CGRect.zero)
superview.insertSubview(self.statusBarMaskView, aboveSubview: self.tableView)
self.statusBarMaskView.backgroundColor = self.tableView.backgroundColor
// using a nice constraint layout library to set the frame
self.statusBarMaskView.pinTop(to: superview)
self.statusBarMaskView.pinLeft(to: superview)
self.statusBarMaskView.pinRight(to: superview)
self.statusBarMaskView.addHeightConstraint(with: 22.0)
////
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.statusBarMaskView.removeFromSuperview()
self.statusBarMaskView = nil
}
答案 16 :(得分:1)
我最终使用了一个具有所需背景的额外视图,在TableView之后添加并放置在状态栏下:
self.CoverView = [[UIView alloc]init];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
self.CoverView.frame = CGRectMake(0,0,self.view.bounds.size.width,20);
}
self.CoverView.backgroundColor = [UIColor whiteColor];
self.TableView = [[UITableView alloc]initWithFrame:CGRectMake(0,
self.CoverView.bounds.size.height,XXX, YYY)];
[self.view addSubview:self.TableView];
[self.view addSubview:self.CoverView];
它不是很漂亮,但它是一个相当简单的解决方案,如果你需要使用xib-less视图,以及IOS6和IOS7
答案 17 :(得分:0)
我在ios 11中遇到了这个问题,但ios 8 - 10.3.3的布局是正确的。对于我的情况,我为Superview.Top Margin而不是Superview.Top设置了一个垂直空间约束,适用于ios 8 - 11。
答案 18 :(得分:0)
这是一个Swift 2.3。 (Xcode 8.0)解决方案。我已经创建了UITableView的子类。
class MYCustomTableView: UITableView
{
override func drawRect(rect: CGRect) {
super.drawRect(rect)
contentInset = UIEdgeInsetsZero
}
}
内容插入应始终为零(默认情况下)。我手动设置为零。您还可以添加一个检查方法来进行检查,如果它不是您想要的任何东西,只需获取正确的矩形。只有在绘制了tableview时才会反映这种变化(这种情况并不经常发生)。
不要忘记更新IB中的TableView(在TableViewController中或只是ViewController中的TableView)。
答案 19 :(得分:0)
答案 20 :(得分:0)
override func viewDidLoad() {
// your code
if let nc = self.navigationController {
yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height
}
}
答案 21 :(得分:0)
我正在使用带有navigationcontroller和tableviewcontroller的UISplitViewController。在尝试了许多解决方案之后,这在主视图中对我有用:
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {
// Move the view down 20 pixels
CGRect bounds = self.view.bounds;
bounds.origin.y -= 20.0;
[self.navigationController.view setBounds:bounds];
// Create a solid color background for the status bar
CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
statusBar.backgroundColor = [UIColor whiteColor];
[statusBar setAlpha:1.0f];
[statusBar setOpaque:YES];
[self.navigationController.view addSubview:statusBar];
}
它类似于Hot Licks&#39;解决方案,但将子视图应用于navigationController。
答案 22 :(得分:0)
Abrahamchez的解决方案 https://developer.apple.com/library/ios/qa/qa1797/_index.html 为我工作如下。我有一个UITableviewcontroller作为我的初始视图。我曾尝试过偏移代码并嵌入到navcon中,但都没有解决状态栏的透明度问题。
添加Viewcontroller并使其成为初始视图。这应该显示你的关键Top&amp;底部布局指南。
将旧的Tableview拖到新控制器的View中。
将所有内容改装为新控制器:
将旧的视图controller.h文件从UIViewController而不是UITableViewController更改为继承/子类。
将UITableViewDataSource和UITableViewDelegate添加到viewcontroller的.h。
重新连接故事板中所需的任何内容,例如搜索栏。
重要的是要设置约束,就像在Apple Q&amp; A中那样。我没有费心插入工具栏。不确定确切的顺序。但是布局指南中出现了一个红色图标,也许是在我建造的时候。我点击它,让Xcode安装/清理约束。
然后我点击了所有地方,直到我找到了“垂直空间”约束并将其最高值从-20更改为0并且效果非常好。
答案 23 :(得分:0)
我通过将大小设置为自由格式来实现它的工作
答案 24 :(得分:0)
我在UITableView的顶部有一个UISearchBar,以下工作;
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
self.tableView.contentOffset = CGPointMake(0, -20);
分享并享受......
答案 25 :(得分:-1)
查看所有解决方案: 我的项目只是使用xib,因此,故事板的解决方案对我不起作用。 self.edgesForExtendedLayout = UIRectEdgeNone; 如果导航栏可见,则适用于控制器。 但如果您的视图只有状态栏,那将无效。 所以我结合了两个条件。
- (void) viewDidLayoutSubviews {
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {
CGRect bounds = self.view.bounds;
if(self.navigationController == nil || self.navigationController.isNavigationBarHidden == YES){
bounds.origin.y -= 20.0;
[self.view setBounds:bounds];
}
else{
self.edgesForExtendedLayout = UIRectEdgeNone;
}
}
帮助这项工作。
答案 26 :(得分:-2)
如果您还需要支持iOS 6,则必须有条件地将其移除。也就是说,在iOS 7中你应该将它向下移动20分(通过frame
操作或使用自动布局),而在iOS 6中你可以不管它。我不相信你可以在IB中这样做,所以你必须在代码中这样做。
修改强>
您可以在IB中使用iOS6 / iOS7增量实际执行此操作。在iOS 7中设置您的位置,然后在iOS 6中将delta Y设置为-20磅。有关详细信息,请参阅this SO question。