IOS 11, iPhone X, and Xcode9 adaptation guide, ios11iphone
After iOS11 is updated, it is found that adaptation is required in some areas. After sorting, the priority is divided into the following three categories:
1. changes caused by upgrade of iOS11;
2. changes caused by Xcode9 packaging;
3. Compatibility with iPhone x
I. changes caused by upgrade of iOS11
1. after the upgrade, you will find that the UI with tableView is disordered, and the group spacing and contentInset are disordered. Because the automaticallyAdjustsScrollViewInsets attribute of UIViewController in iOS11 is discarded, when tableView exceeds the safe area, the system automatically adjusts the SafeAreaInsets value to affect the adjustedContentInset value.
// Some interfaces use proxy method to set, and found that it has not taken effect
-(CGFloat) tableView: (UITableView *) tableView heightForHeaderInSection: (NSInteger) section;
-(CGFloat) tableView: (UITableView *) tableView heightForFooterInSection: (NSInteger) section;
// This principle is because only the high-level proxy method was implemented before, but the View's proxy method was not implemented. It is okay to write in iOS10 and before. IOS11 opened the bug caused by the line height estimation mechanism, so there are the following Solution:
// Solution 1: Add a proxy method that implements View. The method (CGFloat) tableView: heightForFooterInSection: will only take effect if the following two methods are implemented:
-(UIView *) tableView: (UITableView *) tableView viewForFooterInSection: (NSInteger) section {
return nil;
}
-(UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: (NSInteger) section {
return nil;
}
// Solution two: directly set the tableView property to fix the UI disorder
self.tableView.sectionHeaderHeight = 0;
self.tableView.sectionFooterHeight = 5;
[_optionTableView setContentInset: UIEdgeInsetsMake (-35, 0, 0, 0)];
// Solution 3: Add the following code to close the estimated line height
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
2. If Masonry is used for layout, safeArea must be adapted.
if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) {
make.edges.equalTo(self.view.safeAreaInsets);
} else {
make.edges.equalTo(self.view);
}
3. for the original image sending function of IM, iOS11 starts a new HEIC format image, and the live photo from iPhone 7 and above + iOS11 is ". heic "Format Image, same live Format Image, no problem when sending iOS10 (converted to jpg), iOS11 won't work
Is converted to jpg format
QQ and dingtalk are directly compressed, and even the source image is compressed as a non-source image.
The final solution is to convert the following code into jpg format:
// 0.83 can ensure that the image size is consistent before and after compression
// The reason for the inconsistency is that the bitmap of the picture is 8-bit and one is 16-bit
imageData = UIImageJPEGRepresentation ([UIImage imageWithData: imageData], 0.83);
Ii. Problems found after Xcode9 Compilation
1. The third-party error "fastSocket" is found. The specific cause is that the header file C99 is missing. Just introduce "# include ".
2. New features in the navigation bar
The style of the native search bar has changed
The iOS11 style is displayed on the right. The search area height increases and the font size increases.
After checking the API, I found that the searchController is assigned to NavigationItem after iOS11, And the hidesSearchBarWhenScrolling attribute can be used to control whether the search bar is hidden and displayed when sliding.
// A view controller that will be shown inside of a navigation controller can assign a UISearchController to this property to display the search controller’s search bar in its containing navigation controller’s navigation bar.@property (nonatomic, retain, nullable) UISearchController *searchController API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);// If this property is true (the default), the searchController’s search bar will hide as the user scrolls in the top view controller’s scroll view. If false, the search bar will remain visible and pinned underneath the navigation bar.@property (nonatomic) BOOL hidesSearchBarWhenScrolling API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
In addition, the BOOL value prefersLargeTitles of the UINavigationBar attribute is added to achieve the following effect. You can use largeTitleTextAttributes to set the text style of a large title. After setting the title, the height of the navigation bar will change from 64pt to 96pt. If there is an operation such as writing a dead height directly in the project or hiding the navigation bar, you need to adapt it.
A frame related to the buttons in the navigation bar is used on the UI, and UI disorder occurs. After you view the UI hierarchy, you can find that the buttons were directly added to the UINavigationBar before iOS11, iOS11 adds the button to _ UITAMICAdaptorView first, then _ UIButtonBarStackView, _ UINavigationBarContentView, and then UINavigationBar. Therefore, if you need to obtain the navigation bar button frame or superView, here you need to make specific adaptation
Hierarchical relationship diagram of buttons in iOS10 and earlier versions of the navigation bar
Hierarchical relationship diagram of buttons in the iOS11 navigation bar
3. iPhone X adaptation
After Xcode9 is downloaded, the first thing to do is to enjoy it on the iPhone X (simulator). After compilation, an error is reported.
The Status Bar of iPhone X differs greatly from that of other mobile phones, so the api changes a lot.
The following adaption has been made successively:
Adaption Point 1: Use the icon in the status bar in the project to determine the specific status of the current network
Error Code
1 |
The printed Log reports the following error: Trapped uncaught exception'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key foregroundView.' |
IPhone X
Other mobile phones
Use runtime to print all its attributes and find the following differences:
// test code
#import NSMutableString * resultStr = [NSMutableString string];
// Get the Ivar list and Ivar number of the specified class
unsigned int count = 0;
Ivar * member = class_copyIvarList ([[application valueForKeyPath: @ "_ statusBar"] class], & count);
for (int i = 0; i <count; i ++) {
Ivar var = member [i];
// Get the name of Ivar
const char * memberAddress = ivar_getName (var);
// Get the type of Ivar
const char * memberType = ivar_getTypeEncoding (var);
NSString * str = [NSString stringWithFormat: @ "key =% s type =% s \ n", memberAddress, memberType];
[resultStr appendString: str];
}
NSLog (@ "% @", resultStr);
// other versions of the phone
key = _inProcessProvider type = @ ""
key = _showsForeground type = B
key = _backgroundView type = @ "UIStatusBarBackgroundView"
key = _doubleHeightLabel type = @ "UILabel"
key = _doubleHeightLabelContainer type = @ "UIView"
key = _currentDoubleHeightText type = @ "NSString"
key = _currentRawData type = {super long. . }
key = _interruptedAnimationCompositeViews type = @ "NSMutableArray"
key = _newStyleBackgroundView type = @ "UIStatusBarBackgroundView"
key = _newStyleForegroundView type = @ "UIStatusBarForegroundView"
key = _slidingStatusBar type = @ "UIStatusBar"
key = _styleAttributes type = @ "UIStatusBarStyleAttributes"
key = _waitingOnCallbackAfterChangingStyleOverridesLocally type = B
key = _suppressGlow type = B
key = _translucentBackgroundAlpha type = d
key = _showOnlyCenterItems type = B
key = _foregroundViewShouldIgnoreStatusBarDataDuringAnimation type = B
key = _tintColor type = @ "UIColor"
key = _lastUsedBackgroundColor type = @ "UIColor"
key = _nextTintTransition type = @ "UIStatusBarStyleAnimationParameters"
key = _overrideHeight type = @ "NSNumber"
key = _disableRasterizationReasons type = @ "NSMutableSet"
key = _timeHidden type = B
key = _statusBarWindow type = @ "UIStatusBarWindow"
// iPhone X
key = _statusBar; type = @ "_ UIStatusBar"
// Therefore, it can be seen that the status bar of iPhone X is an extra layer, which can be taken once more. The final adaptation code is:
NSArray * children;
// Can't use [[self deviceVersion] isEqualToString: @ "iPhone X"] to judge, because iPhone X's simulator will not return iPhone X
if ([[application valueForKeyPath: @ "_ statusBar"] isKindOfClass: NSClassFromString (@ "UIStatusBar_Modern")]) {
children = [[[[application valueForKeyPath: @ "_ statusBar"] valueForKeyPath: @ "_ statusBar"] valueForKeyPath: @ "foregroundView"] subviews];
} else {
children = [[[application valueForKeyPath: @ "_ statusBar"] valueForKeyPath: @ "foregroundView"] subviews];
}
Warning the above processing, the Code does not seem to report an error, however !! The Code does not take effect! Because only view-level information is obtained from the iPhone X, the following method is used to determine 2G/3G/4G. This method is effective in API visual testing.
NSArray * typeStrings2G = @ [CTRadioAccessTechnologyEdge,
CTRadioAccessTechnologyGPRS,
CTRadioAccessTechnologyCDMA1x];
NSArray * typeStrings3G = @ [CTRadioAccessTechnologyHSDPA,
CTRadioAccessTechnologyWCDMA,
CTRadioAccessTechnologyHSUPA,
CTRadioAccessTechnologyCDMAEVDORev0,
CTRadioAccessTechnologyCDMAEVDORevA,
CTRadioAccessTechnologyCDMAEVDORevB,
CTRadioAccessTechnologyeHRPD];
NSArray * typeStrings4G = @ [CTRadioAccessTechnologyLTE];
// This API is only valid on iOS7 and above
if ([[[UIDevice currentDevice] systemVersion] floatValue]> = 7.0) {
CTTelephonyNetworkInfo * teleInfo = [[CTTelephonyNetworkInfo alloc] init];
NSString * accessString = teleInfo.currentRadioAccessTechnology;
if ([typeStrings4G containsObject: accessString]) {
NSLog (@ "4G 网络");
} else if ([typeStrings3G containsObject: accessString]) {
NSLog (@ "3G 网络");
} else if ([typeStrings2G containsObject: accessString]) {
NSLog (@ "2G 网络");
} else {
NSLog (@ "unknow network");
}
} else {
NSLog (@ "unknow network");
}
Adaptation Point 2: After this problem is solved, The project runs up and finds that the entire app interface has a height of approximately 40 PT
Download the project from Github frequently. The old drivers know that some old projects only have the layout space of iPhone 4 (320480) after running on the simulator, the reason for this is that when the Launch graph is set using Launch Images Source, the corresponding image (11252436) is not checked and set. The solution is as follows:
However, even after performing the preceding operations, you will find that the UITabBar at the bottom is still a little higher. After you view the hierarchy, you will find that the UITabBar height is changed from 49pt to 83pt due to the security zone, therefore, we need to adapt the iPhone X and Its simulator here.
Adaptation Point 3: iPhone X only has faceID and no touchID. If the in application uses the touchID to unlock, the model must be adapted here.
Adaptation Point 4: Previously, the status bar height was replaced by 20, which must be re-obtained by the status bar height.
CGRectGetHeight([UIApplication sharedApplication].statusBarFrame)
Adaptation Point 5: However, the bigger pitfall of iPhone X is screen adaptation.
First, check the screen size.
This figure shows a lot of information:
Although the width of iPhone X is the same as that of 7, the height is 145pt
Three times the image is the focus, and the highest screen density that can be identified by the naked eye is generally considered to be 300ppi, and the iPhone X has reached 458ppi (the Samsung galaxy series screen density is found to be 522ppi)
In terms of design, the apple Official Document "human-interface-guidelines" has clear requirements. The following is a description based on the legend:
The displayed design layout requires filling up the entire Screen
When filling up, be sure not to hide the control from the large rounded corner and the sensor part.
Controls other than security zones cannot interact with users.
The figure above contains a little more information.
The header navigation bar does not allow user interaction, which means that the following two cases are not officially allowed by Apple.
The virtual area at the bottom replaces the traditional home key with a height of 34pt. by sliding up, you can call multiple task management. Considering gesture conflicts, this part is not allowed to have any interactive controls, however, the designed background image must cover non-secure areas.
The status bar is in a non-secure area, which is also mentioned in this document. Unless you can hide the status bar to bring additional value to the user, it is best to return the status bar to the user.
Do not disturb elements in the interface with the home screen indicator at the bottom
Pay attention to the aspect ratio difference when reusing existing images. The aspect ratio of the iPhone X screen is different from that of the conventional iPhone. Therefore, the full-screen 4.7-inch screen image will show cropping or adaptive width display on the iPhone X screen. Therefore, this part of the view needs to be adapted according to the device.
Note the bitmap adaptation.
Adaptation Point 6: horizontal screen adaptation
For safe area, using safeAreaLayoutGuide and safeAreaInset can solve most problems, but there may be some problems in the horizontal screen, and additional adaptation is required.
The code for this reason is: [headerView. contentView setBackgroundColor: [UIColor headerFooterColor]. This method looks correct, but there is only a problem with iPhone X.
By setting this attribute, the content view is embedded into the safe area, but the contentView does not
Solution: Set the backgroundView color [headerView. backgroundView setBackgroundColor: [UIColor headerFooterColor]
Adaptation Point 7: device information
if ([deviceString isEqualToString: @ "iPhone10,1"]) return @ "State Bank (A1863) 、 Japanese Bank (A1906) iPhone 8";
if ([deviceString isEqualToString: @ "iPhone10,4"]) return @ "American (Global / A1905) iPhone 8";
if ([deviceString isEqualToString: @ "iPhone10,2"]) return @ "National Bank (A1864), Japanese Bank (A1898) iPhone 8 Plus";
if ([deviceString isEqualToString: @ "iPhone10,5"]) return @ "American(Global / A1897) iPhone 8 Plus";
if ([deviceString isEqualToString: @ "iPhone10,3"]) return @ "State Bank (A1865) 、
Japanese Bank
(A1902) iPhone X";
if ([deviceString isEqualToString: @ "iPhone10,6"]) return @ "
American
(Global / A1901) iPhone X";