简体   繁体   English

iOS 启动屏幕 storyboard 更改用户界面 rest 的约束

[英]iOS Launch Screen storyboard changes constraints on rest of user interface

I have an iPad app that includes a mix of xib files and storyboard files.我有一个 iPad 应用程序,其中混合了 xib 文件和 storyboard 文件。 The app uses Launch Images but since they are deprecated in iOS 13, I am migrating the app to use a Launch Screen Storyboard instead.该应用程序使用启动图像,但由于它们在 iOS 13 中已弃用,我正在迁移该应用程序以使用启动屏幕 Storyboard

To do this, I added a new Launch Screen storyboard file to the project, changed the background color of the Launch Screen UIView to purple, and set the app's Target > General > Launch Screen File to my new Launch Screen storyboard file.为此,我向项目添加了一个新的 Launch Screen storyboard 文件,将 Launch Screen UIView 的背景颜色更改为紫色,并将应用程序的Target > General > Launch Screen File设置为我的新 Launch Screen storyboard 文件。 When I run the app, the purple Launch Screen comes up for a second as expected.当我运行该应用程序时,紫色的启动屏幕会按预期出现一秒钟。

However, when using a Launch Screen Storyboard on any iPad device that has the swipe up indicator bar, the position of views on the user interface get messed up for both xib files and storyboard files.但是,当在具有向上滑动指示条的任何 iPad 设备上使用启动屏幕 Storyboard 时,用户界面上的 position 视图对于 xib 文件和 storyboard 文件都会变得混乱。 Their constraints are no longer honored.他们的约束不再受到尊重。

Below are examples.以下是示例。 The left column shows what various iPad devices look like in their correct form when the original Launch Images are used.左列显示了使用原始 Launch Images 时各种 iPad 设备的正确形式。 The right column shows what those same iPad devices look like when a Launch Screen Storyboard is used instead.右列显示了当使用启动屏幕 Storyboard 时,相同的 iPad 设备的外观。 The interface of the screen shown below is built from a xib file, however the same behavior happens for other screens that are built as storyboard files.下面显示的屏幕界面是从 xib 文件构建的,但是对于构建为 storyboard 文件的其他屏幕也会发生相同的行为。

(1) Why are the constraints of other views in the app getting altered by simply switching to using a Launch Screen Storyboard instead of Launch Images? (1)为什么通过简单地切换到使用启动屏幕 Storyboard 而不是启动图像来更改应用程序中其他视图的约束?

(2) How do I use a Launch Screen Storyboard without having to alter the existing xib files and storyboards such that the views are displayed correctly for all iPad devices (ie, with or without the swipe up bar)? (2)我如何使用启动屏幕 Storyboard 而不必更改现有的 xib 文件和情节提要,以便为所有 iPad 设备正确显示视图(即,有或没有向上滑动条)?

(Using XCode 13.3, iOS 15.4, Objective-C) (使用 XCode 13.3、iOS 15.4、Objective-C)

LAUNCH SCREEN IMAGES启动屏幕图像 LAUNCH SCREEN STORYBOARD启动屏幕 STORYBOARD
iPad Mini 6th gen iPad 迷你6代在此处输入图像描述 iPad Mini 6th Gen - ERROR: Gap at right-hand side, yellow/cyan aspect not retained, table row width is longer iPad Mini 6th Gen -错误:右侧有间隙,未保留黄色/青色方面,表格行宽更长在此处输入图像描述
iPad Pro 12.9inch 5th gen iPad Pro 12.9inch 第五代在此处输入图像描述 iPad Pro 12.9inch 5th gen - ERROR: Gap at right-hand side and under cyan, table row width is longer iPad Pro 12.9inch 5th gen -错误:右侧和青色下方的间隙,表格行宽更长在此处输入图像描述
iPad Pro 9.7inch iPad Pro 9.7寸在此处输入图像描述 iPad Pro 9.7inch - Looks OK iPad Pro 9.7 英寸 -看起来不错在此处输入图像描述

The following is the Size Inspector for the UIView that contains the Detail View of the Split View Controller (ie, the "1 2 3" Seg Control, "Endpoint" Button, yellow UIImageView and cyan UIView).以下是 UIView 的大小检查器,其中包含拆分视图 Controller 的详细视图(即“1 2 3”段控件、“端点”按钮、黄色 UIImageView 和青色 UIView)。 The Size Inspector parameters of the Window referenced by the Application Delegate look the exact same as this too. Application Delegate 引用的 Window 的 Size Inspector 参数看起来也与此完全相同。 No sizes like width or height are being set in the code programatically.没有以编程方式在代码中设置宽度或高度等尺寸。

在此处输入图像描述

The size of the two iPad Landscape images in the Launch Images assets are: Launch Images 资产中的两个 iPad 风景图像的大小是:

  • iPad Landscape 1x iOS7+ slot: 1024x768 iPad 横向 1x iOS7+ 插槽:1024x768
  • iPad Landscape 2x iOS7+ slot: 2048x1536 iPad 横向 2x iOS7+ 插槽:2048x1536

It's unfortunate that your app was designed for one specific device ...不幸的是,您的应用程序是为一种特定设备设计的……

I played around a bit with (essentially) putting your entire app into a "container" view, with not-great results.我尝试了一下(基本上)将您的整个应用程序放入“容器”视图中,但效果并不理想。

If you want to see the general idea - you might be able to get it to work for you...如果您想了解总体思路 - 您也许可以让它为您工作......

Add a RootContainerViewController :添加一个RootContainerViewController

RootContainerViewController.h RootContainerViewController.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface RootContainerViewController : UIViewController

@property (nonatomic, strong) UIView *container;

@end

NS_ASSUME_NONNULL_END

RootContainerViewController.m RootContainerViewController.m

#import "RootContainerViewController.h"

@interface RootContainerViewController ()

@end

@implementation RootContainerViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor blackColor];
    
    self.container = [UIView new];
    self.container.backgroundColor = [UIColor redColor];
    [self.container setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:self.container];
    
    UILayoutGuide *g = [self.view safeAreaLayoutGuide];
    
    [NSLayoutConstraint activateConstraints:@[
        
        [self.container.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],
        [self.container.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],
        [self.container.widthAnchor constraintEqualToAnchor:self.container.heightAnchor multiplier:1024.0 / 768.0],
        [self.container.centerXAnchor constraintEqualToAnchor:g.centerXAnchor],
        
    ]];

}

- (UIStatusBarStyle)preferredStatusBarStyle {
    if (@available(iOS 13.0, *)) {
        return UIStatusBarStyleLightContent;
    } else {
        // Fallback on earlier versions
    }
}

@end

and change your ApplicationDelegate_Pad.m to this:并将您的ApplicationDelegate_Pad.m更改为:

#import "ApplicationDelegate_Pad.h"
#import "MPRootViewController.h"
#import "MPDetailViewController.h"

#import "RootContainerViewController.h"

@implementation ApplicationDelegate_Pad

@synthesize tabBarController;
@synthesize splitViewController;
@synthesize rootViewController;
@synthesize detailViewController;
@synthesize splitViewControllerD;

-(void) makeSplitViewController {
    
    // Create an array of controllers that will correspond to each tab in the tab bar vc.
    NSMutableArray *controllers = [NSMutableArray arrayWithArray:self.tabBarController.viewControllers];
    
    int index = 0; 
    for (UIViewController *controller in self.tabBarController.viewControllers) {
        
        // Set the split vc in the Presentation tab to hold the playlist in the root vc and the presenter controls in the detail vc.
        if (index == 0) {
            // Set up a storyboard for the root vc and initialize the root vc.
            UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"PlaylistVC" bundle:nil];
            self.rootViewController = [storyboard instantiateInitialViewController];
            
            // Initialize the detail vc and assign it to the root vc.
            detailViewController = [[MPDetailViewController alloc] initWithNibName:@"MPDetailViewController" bundle:nil];
            self.rootViewController.detailViewController = self.detailViewController;
            
            // Set up a split vc to hold the root vc and detail vc we just created.
            splitViewController = [[UISplitViewController alloc] init];
            self.splitViewController.tabBarItem = controller.tabBarItem;
            self.splitViewController.viewControllers = @[self.rootViewController, self.detailViewController];
            
            // Set the split vc's delegate.
            self.splitViewController.delegate = self.detailViewController;
            
            // Other.
            self.splitViewController.presentsWithGesture = NO;
            
            // limit Primary Column Width to 320
            [self.splitViewController setMaximumPrimaryColumnWidth:320.0];
            
            // Add the split vc to the list of controllers that will correspond to each tab in tab bar vc).
            controllers[index] = self.splitViewController;
        }
        
        // Set the split vc in the Datasets tab.
        if (index == 1) {
            // Set up a storyboard for the root vc and initialize the root vc.
            UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"DatasetsVC" bundle:nil];
            self.splitViewControllerD = [storyboard instantiateViewControllerWithIdentifier:@"DatasetsVC"];
            
            // Set the title and icon of the Datasets tab bar item.  Tried to do this in Interface Builder, but it would
            // always show up blank.
            self.splitViewControllerD.tabBarItem.title = @"Data Catalog";
            
            // Add the split vc to the list of controllers that will correspond to each tab in tab bar vc.
            controllers[index] = self.splitViewControllerD;
        }
        
        index++;
    }
    
    // Set the tab bar's array of vc's with the split vc's controllers we just created.
    self.tabBarController.viewControllers = controllers;
    self.tabBarController.delegate = self;
    self.tabBarController.viewControllers = controllers;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
    [super application:application didFinishLaunchingWithOptions:launchOptions];

    // This helps us to get a split view controller inside a tab.
    [self makeSplitViewController];
    
    // setup a new Root controller with a "container" view
    if (YES) {
        
        // instantiate RootContainerViewController
        RootContainerViewController *vc = [RootContainerViewController new];
        
        [vc loadViewIfNeeded];
        
        // add tabBarController as child of RootContainerViewController
        [vc addChildViewController:self.tabBarController];
        
        // add tabBarController's view to container
        [vc.container addSubview:self.tabBarController.view];
        // resizing mask
        [self.tabBarController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
        // set frame to container bounds
        [self.tabBarController.view setFrame:vc.container.bounds];
        // finsish child load
        [self.tabBarController didMoveToParentViewController:vc];
        
        // window rootViewController is now RootContainerViewController instead of tabBarController
        self.window.rootViewController = vc;

    } else {

        // Set the window view to the tab bar vc.
        self.window.rootViewController = self.tabBarController;
        [self.window addSubview:self.tabBarController.view];

    }
    
    // Make the receiver the main window and display it in front of other windows.
    [self.window makeKeyAndVisible];
    
    // iOS 15 added a default vertical content offset (i.e., padding) for table views that is non-zero that
    // pushes the table view down. Force this offset to be zero for all table views.
    if (@available(iOS 15.0, *)) {
        UITableView.appearance.sectionHeaderTopPadding = 0;
    }
    
    
    
    return YES;
}

#pragma mark - Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /*
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
     */
}

@end

The results...结果...

First, using your original App Delegate code without LaunchScreen :首先,使用不带LaunchScreen的原始 App Delegate 代码:

在此处输入图像描述

Then, * using LaunchScreen with modified App Delegate code:然后,*LaunchScreen与修改后的 App Delegate 代码一起使用:

在此处输入图像描述

At first glance, it looks like it might work, however... the Secondary pane of the split view controller is not sizing correctly (note that the "Overlays" button is not visible, because it is outside the bounds of the view).乍一看,它似乎可以工作,但是......拆分视图 controller 的辅助窗格大小不正确(请注意,“覆盖”按钮不可见,因为它在视图的边界之外)。

Worth mentioning -- Apple's docs state:值得一提——苹果文档state:

Although it's possible to install a split view controller as a child in some other container view controllers, doing so is not recommended in most cases.尽管可以在其他一些容器视图控制器中将拆分视图 controller 作为子视图安装,但在大多数情况下不建议这样做。

So, using a split view controller as a tab in a Tab Bar Controller is throwing another wrench into the process.因此,使用拆分视图 controller 作为选项卡栏 Controller中的选项卡是在该过程中投入另一个扳手。

You might want to play around with the container idea, but I don't have high hopes for it (no idea what else might be affected in your actual app).您可能想尝试一下容器的想法,但我对此并不抱太大希望(不知道您的实际应用程序中还有什么可能会受到影响)。

I think you're just going to have to "bite the bullet" and restructure your app to run on modern devices.我认为您将不得不“咬紧牙关”并重组您的应用程序以在现代设备上运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM