IOS 11 brings a bolder, more dynamic new style to UI elements across the ecosystem. This article looks at some of the UI updates that have been made in iOS11. Some of the updates will provide a better user experience, while others may cause bugs in current apps
preface
A few days ago, I found that the animation of the APP I was working on was abnormal on iOS11 system, which is normal on devices of other systems. The animation operation was performed after observing the change of contentOffset in tableView, and the abnormal animation happened after tableView reloadData. That is, the contentOffset of TableViews has changed several times since tableView reloadData. Updating Your App for iOS11. WWDC 2017 Session204 Updating Your App for iOS11. The third part below will have the cause analysis and solution of the above animation abnormality.
This article includes updates and more powerful slides that integrate search with the big title bar, the landscape TAB bar, Margins and Insets, as well as UIScrollView and UITableView.
New features added to UIKit’s Bars
WWDC starts with a new iOS file management App: Files. In this App, you can see some new features of UIKit’s Bars in iOS11: The title view on the browsing function (swiping up will return the title to the original UI effect), and the text and icon on the TAB in landscape mode will be arranged left and right. I used the simulator of iOS11 to experience the vertical and horizontal screens of Files APP, as shown below:
(Command + left arrow makes simulator landscape)
In landscape mode, on the iPhone, the TAB icon and TAB bar are smaller, allowing more vertical space for content. If someone cannot clearly see the icon or text on TAB Bar, long press any item on TAB Bar and the item will be displayed on the HUD, so that icon and text can be clearly seen. Similarly for tool bar and Navigation bar, long press item to enlarge display. As shown below:
UIBarItem
UIBarItem is the parent of UI TAB BarItem and UIBar Button Item. To realize the overall image phone property of the UIBarItem, this setting is also supported in the storyboard. Another New iOS11 attribute for HUD images is largeContentSizeImage. For a more detailed discussion of this, see WWDC2017 Session 215: What’s New in Accessibility
Controls the display of headings
Add a BOOL property prefersLargeTitles to the UI Navigation bar. Set this property to true and the navigation Bar will display titles across the APP. You can set the largeTitleDisplayMode property of the navigationItem of the current page.
typedef NS_ENUM(NSInteger, UINavigationItemLargeTitleDisplayMode) {
// automatic mode depends on the properties of the previous item
UINavigationItemLargeTitleDisplayModeAutomatic,
/// Always enable the header feature for the current item
UINavigationItemLargeTitleDisplayModeAlways,
/// Never
UINavigationItemLargeTitleDisplayModeNever,
}
Copy the code
Integrated Navigation UISearchController
To integrate UISearchController into Navigation, assign your UISearchController to navigationItem.
NavigationItem. SearchController / / iOS 11 new properties
NavigationItem. HidesSearchBarWhenScrolling / / hidden search box to determine whether the when the sliding; New iOS 11 properties
Copy the code
UINavigationController and scroll interaction
When scrolling, the following interactions are invoked by the UINavigationController:
-
UIsearchController Search box effect updated
-
Control of headline effects
-
Rubber banding effect // As you start to pull down, the title gets bigger in response to the wheel
So, if you use navigation bar and assemble push and pop experiences, you won’t get searchController integration, big title control updates, and Rubber banding. Because all of this is controlled by the UINavigationController.
UIToolbar and UINavigationBar – Layout
In iOS 11, while Apple was making all of these new features, there were other optimizations as well, including new auto-layout extension support for UIToolbar and UINavigaBar, Custom bar button items and custom titles can be expressed by layout. Note that your constraints need to be set inside the view, so if you have a custom header view, you need to make sure that any constraints depend only on the header view and any of its subviews. When you use automatic layout, the system assumes that you know what you’re doing.
Avoiding Zero-Sized Custom Views
Custom view size is 0 because you have some fuzzy constraint layout. To avoid view size 0, do the following:
-
UINavigationBar and UIToolbar provide locations
-
The developer must provide the size of the view in three ways:
-
Constraints on width and height;
-
Achieve intrinsicContentSize;
-
Associate your subviews with constraints;
Managing margins and InSets
layout margins
Constraint-based Auto Layout allows us to build user interfaces that dynamically respond to internal and external changes. Auto Layout defines a margin for each view. Margin refers to the distance between the edge of the content portion of the control and the edge of the control. You can use the layoutMargins or layoutMarginsGuide property to get the margin of the view, which is the inner part of the view. LayoutMargins allows the Margins of the UIEdgeInsets to be fetched or set. LayoutMarginsGuide gets the read-only UILayoutGuide object.
New iOS11 directional layout navigation property NSDirectionalEdgeInsets constructor type:
typedef struct NSDirectionalEdgeInsets { CGFloat top, leading, bottom, trailing; } NSDirectionalEdgeInsets API_AVAILABLE (ios (11.0), tvos (11.0), watchos (4.0));
Copy the code
The layoutMargins property is of type UIEdgeInsets:
typedef struct UIEdgeInsets {
CGFloat top, left, bottom, right;
} UIEdgeInsets;
Copy the code
As you can see from the comparison of the two constructs above, the NSDirectionalEdgeInsets attribute replaces the left and right attributes with leading and trailing.
The Directional Layout Navigation property is described as follows:
directionalLayoutMargins.leading is used on the left when the user interface direction is LTR and on the right for RTL.
Vice versa for directionalLayoutMargins.trailing.
Example: When you set trailing = 30; When the trailing value is set to the left of the view in a right to Left language, it can be read from the Layout Navigation left property. As shown below:
There are other updates as well. Since the introduction of layout navigation, when adding a view to the viewController, the viewController fixes the view’s layoutMargins to a value that is simply closed to the UIKit. Starting with iOS11, these are no longer fixed values, they’re actually minimum values, and you can change the layoutMargins on your view to any larger value. Also, the viewController adds a new property: ViewRespectsSystemMinimumLayoutMargins, if you set this attribute to “false”, you can change your layout margins for any you want to set the value of the including 0, as shown in the figure below:
Safe Area
Picture: Photo application
We’ve had these translucent bars throughout the operating system since iOS 7, and Apple encouraged us to draw content through these bars, which we did with the edgesForExtendedLayout property of the viewController.
From iOS 7, the topLayoutGuide and bottomLayoutGuide introduced in UIViewController were scrapped in iOS 11, replaced by the safeArea concept, SafeArea is a way to describe how parts of your view are not covered by anything. SafeAreaInsets or safeAreaLayoutGuide provide you with safeArea reference values, namely, InSets or LayoutGuide. The safeArea area is shown in the figure below:
If you have a custom viewController, you may want to add your own bars and increase the value of safeAreaInsets via a new property: AddtionalSafeAreaInsets to change safeAreaInsets. When your viewController changes its safeAreaInsets, there are two ways to get the callback:
UIView.safeAreaInsetsDidChange()
UIViewController.viewSafeAreaInsetsDidChange()
Copy the code
New features for UIScrollView and UITableView
Scroll Views
If you have some text inside the UI scrollView that is contained in the navigation controller, now normally navigationContollers will pass in a contentInset to its topmost viewController’s scrollView, AdjustedContentInset: adjustContentInset (adjustedContentInset) adjustContentInset (AdjuadjustContentInSet) : adjustContentInset (adjustedContentInset)
New contentInsetAdjustmentBehavior attributes used to configure adjustedContentInset behavior, the structure has the following several types:
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
UIScrollViewContentInsetAdjustmentAutomatic,
UIScrollViewContentInsetAdjustmentScrollableAxes,
UIScrollViewContentInsetAdjustmentNever,
UIScrollViewContentInsetAdjustmentAlways,
}
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
@property(nonatomic, readOnly) uiedGeInAdjustedContentInSet;
//adjustedContentInset Delegate when the value is changed
- (void)adjustedContentInsetDidChange;
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView;
Copy the code
Table Views: Self-sizing is enabled by default in iOS 11
This is probably the biggest change to UITableView. We know that with the introduction of self-sizing in iOS8, we can show dynamic content by implementing the estimatedRowHeight attribute, which gives us an initial contenSize estimate. This is achieved by estimatedRowHeight x cell number, which is not the final contenSize, so instead of counting all the cell heights at once, the tableView calculates the number of cells that can be displayed on the current screen plus a few. When sliding, The tableView keeps getting new cells, updating its own contenSize, and when it slides to the end, it gets the correct contenSize. In the test Demo, in the process of creating a tableView to display, the calculation process of contentSize is shown as follows:
Self-sizing is enabled by default in iOS11, Headers, footers, and cells are enabled by default, All estimated height default values from 0 before iOS11 UITableViewAutomaticDimension change to:
@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
Copy the code
If the estimateRowHeight attribute is not currently used in the project, you should be careful in iOS11 because self-sizing turns on the estimateRowHeight attribute in the tableView, This can cause changes in contentSize and contentOffset values, which can cause animation exceptions if you are observing changes in these properties, because contentSize is constantly updated under the row height estimation mechanism. The final contentSize value is displayed only after all the cells are displayed. Because the correct row height is not cached, the contentSize is recalculated when tableView reloadData, which can cause changes to contentOffset.
If you don’t want to use self-sizing in iOS11, you can turn it off by using the following method:
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
Copy the code
In iOS11, if the estimateRowHeight value is not set, and the rowHeight value is not set, then the initial value of contentSize calculation is 44 x cell number, as shown in the following figure: RowHeight and estimateRowHeight is the default UITableViewAutomaticDimension and rowNum = 15; ContentSize = 44 15 = 660;
Table Views: separatorInset extension
The separatorInset property was introduced in iOS 7 to set the separator line margin of a cell, and extended in iOS 11. Can pass new UITableViewSeparatorInsetReference separatorInsetReference of an enum type to set the separatorInset attribute reference value.
Typedef NS_ENUM (NSInteger UITableViewSeparatorInsetReference) {UITableViewSeparatorInsetFromCellEdges, / / the default value, SeparatorInset indicates the offset from the edge of the cell
UITableViewSeparatorInsetFromAutomaticInsets / / said separatorInset attribute values from a insets offset
}
Copy the code
The following chart clearly shows the difference between these two reference values:
Table Views and Safe Area
The following points need to be noted:
-
SeparatorInset is automatically associated with safe Area Insets, so by default, the entire contents of a table view avoid inserting the security zone of its root view controller.
-
UITableviewCell and UITableViewHeaderFooterView content view in a safe area; So you should always use add-Subviews in the Content View.
-
All the headers and footers should use UITableViewHeaderFooterView, including table headers and footers, section headers and footers.
Swipe Actions
After iOS8, apple has officially added a right slider interface for UITableVIew, which adds a proxy method (tableView: EditActionsForRowAtIndexPath:) and a class (UITableViewRowAction), proxy method returns an array, we can be defined in the proxy method required action buttons (delete, placed at the top, etc.), The class for these buttons is UITableView Action. This class can only define the button’s display text, background color, and button events. And returns the first element of the array to the far right of the UITableViewCell and the last element to the far left. Starting from the iOS 11 had some changes, first is to add images to these buttons, and then if the implementation for the following two iOS 11 new proxy method, will replace (tableView: editActionsForRowAtIndexPath:) proxy method:
// Swipe actions
// These methods supersede -editActionsForRowAtIndexPath: if implemented
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
Copy the code
The two proxy method returns the UISwipeActionsConfiguration object of type, create the object and assignment to see the following code snippet:
- ( UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { [self.titleArr removeObjectAtIndex:indexPath.row]; completionHandler (YES); }]; deleteRowAction.image = [UIImage imageNamed:@"icon_del"]; deleteRowAction.backgroundColor = [UIColor blueColor]; UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:
@[deleteRowAction]];
return config;
}
Copy the code
Create UIContextualAction object, UIContextualActionStyle there are two types, if use UIContextualActionStyleNormal is placed at the top and read button type, Delete button can use UIContextualActionStyleDestructive type, when using this type, if it is right, has been sliding a cell, to the right will be executed directly delete, don’t have to click on the delete button, it is also a fun updates.
typedef NS_ENUM(NSInteger, UIContextualActionStyle) {
UIContextualActionStyleNormal,
UIContextualActionStyleDestructive
} NS_SWIFT_NAME(UIContextualAction.Style)
Copy the code
Another thing to note here is that when the cell height is small, only image is displayed and title is not displayed. When the cell height is large enough, both image and title are displayed. When I wrote the demo test, the height of each cell was small, so only image was displayed. After I increased the height of the cell, image and title could be displayed at the same time. See the comparison below:
conclusion
Most of the content has been tested with code. Some of the updates are really useful and can be adapted to iOS 11. Some of the updates may cause bugs in existing apps, so it is necessary to learn about them.
References:
Updating Your App for iOS 11 – WWDC 2017 – Session 204 – iOS
Mysteries of Auto Layout, Part 1 – WWDC2015
Mysteries of Auto Layout, Part 2 – WWDC2015
If you think our content is good, please forward it to moments and share it with your friends