MyLayout and TangramKit are OC and Swift versions of frame based UI layout libraries. The latest versions are MyLayout1.7.0 and TangramKit1.4.0.

👉 OC1.7.0: github.com/youngsoft/M…

👉 Swift1.4.0: github.com/youngsoft/T…

The main purpose of this upgrade is to integrate AutoLayout more closely.

This is not a promotional article, but rather an introduction to how AutoLayout and MyLayout&TangramKit achieve view sizing adaptation and how the two are combined. So please bear with me and read on 👇👇👇👇👇

AutoLayout’s sizing is adaptive

There are two types of size adaptation in AutoLayout: one is the size adaptation of views represented by UILabel and UITextView. The width and height of such views sometimes need to be determined according to their own content. That is, these views have their own intrinsicContentSize. The UIView class provides a method that can be overloaded:

- (CGSize)intrinsicContentSize NS_AVAILABLE_IOS(6_0);
Copy the code

If a class view has its own inherent content size, override the implementation of this method. This method returns the size of the intrinsic content size calculated from its own content, or a special default UIViewNoIntrinsicMetric(-1) if there is no intrinsic content size. Obviously the UIView class returns the default value, whereas the UILabel and UITextView classes override this method and return the size calculated from their contents. When a view has its own inherent content size, there is no need to set width or height constraints for the view. This is why the layout normally works without setting width and height constraints on UILabel views. Intrinsically, if the layout engine finds that a view has no height or width constraints during layout, it calls the view’s intrinsicContentSize method. If this method returns a normal size, the view renders and displays its intrinsicContentSize. If one of the dimensions returned by this method is UIViewNoIntrinsicMetric it indicates that one of the dimensions has no intrinsic content size, thus implementing the constraint absence.

Another category is some container view whose height or width you want to determine based on its subviews. For example, in some interfaces, the size of the parent view is determined by the size of the child view; For example, in UIScrollView you need to adjust the contentSize of the subview to allow scrolling; For example, some UITableViewCell heights are dynamic, and their dimensions are determined by their subviews. There is no implementation of overloading intrinsicContentSize in these classes, so a new setting method needs to be provided to implement this sizing capability.

1. Container view realizes size adaptation

For a container superview, when the size of the superview depends on the size of all its children for self-adaptation, the constraint dependencies to be set are implemented not by size constraints but by position constraints. Suppose you have the following layout:

We want the size of the parent container view S to be adaptive, so we need to set the right edge of view S to be equal to the right edge of child view B, and we need to set the bottom edge of view S to be equal to the bottom edge of child view C. So you can see that the way you do sizing for the parent view S is not by setting the width and height dimensioning but by setting the boundaries of the parent view depending on the boundaries of some child view. The specific code is shown as follows:

// View creation code is ignored here. // In this article, AutoLayout constraint Settings are provided by iOS9 after the simple method of constraint Settings. [A.leftAnchor constraintEqualToAnchor:S.leftAnchor constant:10].active = YES; [A.topAnchor constraintEqualToAnchor:S.topAnchor constant:10].active = YES; [A.widthAnchor constraintEqualToConstant:100].active = YES; [A.heightAnchor constraintEqualToConstant:30].active = YES; [B.leftAnchor constraintEqualToAnchor:S.leftAnchor constant:80].active = YES; [B.topAnchor constraintEqualToAnchor:A.bottomAnchor constant:20].active = YES; [B.widthAnchor constraintEqualToConstant:200].active = YES; [B.heightAnchor constraintEqualToConstant:30].active = YES; [C.leftAnchor constraintEqualToAnchor:S.leftAnchor constant:30].active = YES; [C.topAnchor constraintEqualToAnchor:B.bottomAnchor constant:20].active = YES; [C.widthAnchor constraintEqualToConstant:50].active = YES; [C.heightAnchor constraintEqualToConstant:40].active = YES; // Suppose S is added to some view controller. [S.leftAnchor constraintEqualToAnchor:self.view.leftAnchor constant:20].active = YES; [S.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:90].active = YES; Boundary depends on the right side of the child view B / / right, bottom border dependence C child view below size adaptive [S.r ightAnchor constraintEqualToAnchor: B.r ightAnchor constant: 20]. Active = YES; [S.bottomAnchor constraintEqualToAnchor:C.bottomAnchor constant:20].active = YES;Copy the code

You can see the limitations of this implementation mechanism! The adaptive constraint Settings of the parent view need to be adjusted when adding or removing child views and when adjusting the position and size of a child view.

2. The UIScrollView rolling

For UIScrollView you need to set the contentSize to enable scrolling. However, in a layout based on constraint Settings, it is not easy to calculate contentSize because many constraints are implemented through dependencies. So when UIScrollView is used in combination with AutoLayout to implement the scrolling capability, instead of adding all the child views to UIScrollView, you need to create a container view in the middle, and first add the container view to UIScrollView, Then add all the child views to the container view. When setting constraint dependencies, the top, bottom, and left sides of the container view depend on the top, left, and right sides of the UIScrollView view, and the bottom edge of the bottommost child of the container view depends on the bottom edge of the container view if scrolling up and down is required. If you don’t need to scroll up and down, set the height of the container view to the height of the UIScrollView view. If scrolling left and right is required, the right edge of the rightmost child in the container view depends on the right edge of the container view. If horizontal scrolling is not required, set the width of the container view to the width of the UIScrollView view instead. With this setting, the contentSize of the UIScrollView view is automatically computed. Here is an example code:

//1. Create a scroll view and set the constraint. The constraint can be AutoLayout or frame. UIScrollView *scrollView = [UIScrollView new]; [self.view addSubview:scrollView]; scrollView.frame = CGRectMake(100, 100, 100, 100); //2. Create a container view and place it in the scroll view. Ensure that the scroll view has only one container child view. UIView *containerView = [UIView new]; containerView.translatesAutoresizingMaskIntoConstraints = NO; containerView.backgroundColor = [UIColor orangeColor]; [scrollView addSubview:containerView]; //3. Add all subviews A,B, and C to the container view. UILabel *A = [UILabel new]; A.text = @"A";
    A.translatesAutoresizingMaskIntoConstraints = NO;
    A.backgroundColor = [UIColor redColor];
    [containerView addSubview:A];
    
    UILabel *B = [UILabel new];
    B.text = @"B";
    B.translatesAutoresizingMaskIntoConstraints = NO;
    B.backgroundColor = [UIColor greenColor];
    [containerView addSubview:B];
    
    UILabel *C = [UILabel new];
    C.text = @"C"; C.translatesAutoresizingMaskIntoConstraints = NO; C.backgroundColor = [UIColor blueColor]; [containerView addSubview:C]; //4. Set constraint dependencies for the subview of the container view. [A.leftAnchor constraintEqualToAnchor:containerView.leftAnchor constant:10].active = YES; [A.topAnchor constraintEqualToAnchor:containerView.topAnchor constant:10].active = YES; [A.widthAnchor constraintEqualToConstant:100].active = YES; [A.heightAnchor constraintEqualToConstant:30].active = YES; [B.leftAnchor constraintEqualToAnchor:containerView.leftAnchor constant:80].active = YES; [B.topAnchor constraintEqualToAnchor:A.bottomAnchor constant:20].active = YES; [B.widthAnchor constraintEqualToConstant:200].active = YES; [B.heightAnchor constraintEqualToConstant:30].active = YES; [C.leftAnchor constraintEqualToAnchor:containerView.leftAnchor constant:30].active = YES; [C.topAnchor constraintEqualToAnchor:B.bottomAnchor constant:20].active = YES; [C.widthAnchor constraintEqualToConstant:50].active = YES; [C.heightAnchor constraintEqualToConstant:40].active = YES; //5. Set the container view dependency constraint so that the container view's four boundaries are equal to the scroll view's four boundaries. [containerView.leftAnchor constraintEqualToAnchor:scrollView.leftAnchor].active = YES; [containerView.topAnchor constraintEqualToAnchor:scrollView.topAnchor].active = YES; [containerView.rightAnchor constraintEqualToAnchor:scrollView.rightAnchor].active = YES; [containerView.bottomAnchor constraintEqualToAnchor:scrollView.bottomAnchor].active = YES; //6. The key step, if you need to scroll up and down, is to move the bottom subview of the container view. Here is the bottom boundary of C depending on the bottom boundary of the container view. Do not set this if you do not need to scroll up and down, but instead set the height of the container view to equal the height of the scroll view. [C.bottomAnchor constraintEqualToAnchor:containerView.bottomAnchor].active = YES; //[containerView.heightAnchor constraintEqualToAnchor:scrollView.heightAnchor].active = YES; //7. The key step, if you need to scroll left or right, is to move the rightmost subview of the container view, where the right edge of B depends on the right edge of the container view. If you don't need to scroll horizontally, don't do this set, but instead is equal to the width of the container view the width of the scroll view [B.r ightAnchor constraintEqualToAnchor: containerView. RightAnchor]. Active = YES; //[containerView.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor].active = YES;Copy the code

The steps and flow are the same if the Storyboard is used to set constraint dependencies. The constraint Settings above also have some limitations for implementing the mechanism of view scrolling! Once you add child views to the container view, you need to readjust the constraint dependencies on the right and bottom boundaries of the container view. This requires remembering the old constraint dependencies and removing the old constraint dependencies before setting the new one.

3. Height adaptation of UITableViewCell

To implement a highly adaptive UITableViewCell, you need methods in the UITableViewDelegate:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

Copy the code

Implementation for a cell to return to a certain height value UITableViewAutomaticDimension. Then in the view code layout of the derived class of UITableViewCell or in -(UITableViewCell*)tableView:(UITableView *)tableView CellForRowAtIndexPath :(NSIndexPath *)indexPath method to set the special constraint. In section 1 above, I explained how to set the size of a container view to be adaptive. Normally, when writing the layout code of a UITableViewCell, all the subviews are added to the contentView view. Therefore, when implementing the height adaptation of a UITableViewCell, Just think of the contentView as a container view and follow the layout constraint Settings described in Section 1 to achieve a high degree of adaptation.

MyLayout&TangramKit is sizing adaptive

One of the most important features of MyLayout&TangramKit is the ability to automatically calculate the layout view size adaptively, which means that the width or height of the layout view can be determined according to the size of its subviews, without explicitly relying on a subview to implement this capability. This is achieved by setting wrapContentHeight or wrapContentWidth for the layout view to YES for MyLayout, For TangramKit, you can do this by setting the layout view’s tg_width and tg_height to.wrap. For example, A layout superview S has three child views A,B, and C. If the height and width of S are required to be adaptive to the height and width of the three sub-views, then we only need to set the constraint of layout view S as follows:

//OC version s.rapcontentSize = YES; //Swift version s.g_size (width:.wrap, height:.wrap)Copy the code

1. Container view realizes size adaptation

The concept of a special layout view is defined in MyLayout&TangramKit. All constraints set for subviews must be placed in a layout view to be valid. The overall layout framework provides multiple layout views, and the sub-views in each layout view are arranged and laid out according to specific rules. The container view is very simple when it comes to resizing the layout view. It doesn’t need to rely on any constraint dependencies on its subviews, but just needs to set the layout view’s size to Wrap. In the case of MyLayout&TangramKit, you can define the S view as A vertical linear layout view and add A,B, and C to the layout view. Here is the code for the layout part of the implementation:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / OC version, S is a vertical linear layout arjun yLeft = 10; A.myTop = 10; Arjun ySize = CGSizeMake (100, 30); B.myLeft = 80; B.myTop = 20; B.mySize = CGSizeMake(200, 30); C.myLeft = 30; C.myTop = 20; C.mySize = CGSizeMake(50, 40); // Just set the corresponding property of the layout view to YES. There is no need to rely on a specific subview. S.wrapContentSize = YES; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / Swift version, S is a vertical linear layout A.tg_origin(x:10,y:10).and().tg_size(width:100,height:30) B.tg_origin(x:80,y:20).and().tg_size(width:200,height:30) C. g_origin(x:30,y:20). And ().tg_size(width:50,height:40) // The size of the layout view is adaptive to the subview. S.tg_size(width:.wrap, height:.wrap)Copy the code

Since the sizing adaptive constraints in MyLayout&TangramKit do not require a subview that is explicitly dependent on, the system will automatically re-size the layout view when the subviews in the layout view change without any adjustment. This is one of the biggest advantages of using MyLayout&TangramKit!

2. The UIScrollView rolling

MyLayout&TangramKit deals specifically with processing when combined with UIScrollView. When a layout view is added to a scroll view, the layout system internally handles the scroll view’s contentSize. To implement UIScrollView scrolling, simply add a layout view to a scroll view, add all other subviews to the layout view, and do the same with AutoLayout. Finally, set the size adaptation property of the layout view to YES. The OC code is as follows:

//1. Create a scroll view and set the constraint. The constraint can be AutoLayout or frame. UIScrollView *scrollView = [UIScrollView new]; [self.view addSubview:scrollView]; scrollView.frame = CGRectMake(100, 100, 100, 100); //2. Create a container view and place it in the scroll view. Ensure that the scroll view has only one container child view. MyLinearLayout *containerView = [MyLinearLayout new]; containerView.backgroundColor = [UIColor orangeColor]; // Set the size adaptation property of the container layout view to YES. containerView.wrapContentSize = YES; [scrollView addSubview:containerView]; //3. Add all subviews A,B, and C to the container view. UILabel *A = [UILabel new]; A.text = @"A";
    A.backgroundColor = [UIColor redColor];
    [containerView addSubview:A];
    
    UILabel *B = [UILabel new];
    B.text = @"B";
    B.backgroundColor = [UIColor greenColor];
    [containerView addSubview:B];
    
    UILabel *C = [UILabel new];
    C.text = @"C"; C.backgroundColor = [UIColor blueColor]; [containerView addSubview:C]; //4. Set constraint dependencies for the subview of the container view. A.myLeft = 10; A.myTop = 10; Arjun ySize = CGSizeMake (100, 30); B.myLeft = 80; B.myTop = 20; B.mySize = CGSizeMake(200, 30); C.myLeft = 30; C.myTop = 20; C.mySize = CGSizeMake(50, 40); //5. Then there is no then! No special additional Settings are required with MyLayout!!Copy the code

Since the sizing constraint in MyLayout&TangramKit does not need to explicitly depend on a subview, the system automatically resize the layout view when the subview changes, and adjusts the contentSize of UIScrollView when the layout view changes.

3. Height adaptation of UITableViewCell

To implement a highly adaptive UITableViewCell, you need methods in the UITableViewDelegate:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}
Copy the code

Implementation for a cell to return to a certain height value UITableViewAutomaticDimension. Then create a root layout view in a derived class of the UITableViewCell and add the root layout view as a child to the contentView as follows:

// Assume the root layout view is a vertical linear layout view. self.rootLayout= [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert]; self.rootLayout.cacheEstimatedRect = YES; / / cache acceleration calculation self. RootLayout. MyHorzMargin = 0; / / layout width equal to the width of the contentView self. RootLayout. WrapContentHeight = YES; // The layout view is highly adaptive. [self.contentView addSubview:self.rootLayout]; // Add all subviews to rootLayout and set constraints.Copy the code

Then override the view’s methods in a derived class of the UITableViewCell:

- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority { / / system on UITableVeiwCell layout will call systemLayoutSizeFittingSize method to get the size of the view, we calculate the cell size of the task to a layout view sizeThatFits method to complete.return [self.rootLayout sizeThatFits:targetSize];  
}
Copy the code

MyLayout&TangramKit and AutoLayout

MyLayout&TangramKit’s layout system is based on the calculation of the native frame to achieve layout, while AutoLayout no longer relies on frame but on constraints between views to achieve layout. Here are just a few ways to add MyLayout&TangramKit layout views to AutoLayout layout architecture.

1. Add the layout view to the non-layout superview

Because layout view is also a view, it’s all derived from UIView. So to add a layout view to a layout architecture that uses AutoLayout constraints, set constraint dependencies on the layout view just as you would on a regular view.

2. Use the sizing adaptive properties of the layout view

Because the layout view in MyLayout&TangramKit has the property of setting resizability, in order to integrate with AutoLayout, the layout view of the latest library overloads its intrinsicContentSize method. Therefore, if you want to use layout view sizing, you can set the size of the layout view to Wrap, just as with UILabel, without setting the width and height constraints on the layout view. Let’s say I have two sibling views A and B. View A is A MyLayout&TangramKit layout view whose width is equal to the width of the parent view S, and whose height ADAPTS to the height of the children in the layout view, while view B is below view A and the width is equal to view A. Then the implementation of the mixed constraint code is as follows:

// Only the OC code is shown here. MyLinearLayout *A = [MyLinearLayout new]; A.translatesAutoresizingMaskIntoConstraints = NO; // Set the height adaptation of view A. A.wrapContentHeight = YES; [S addSubView:A]; // Add subview code to A layout view. UIView *B = [UIView new]; B.translatesAutoresizingMaskIntoConstraints = NO; [S addSubView:B]; //A Layout view constraint setting, there is no need to set the height constraint, because the layout view's height adaptive property is used. [A.leftAnchor constraintEqualToAnchor:S.leftAnchor].active = YES; [A.topAnchor constraintEqualToAnchor:S.topAnchor].active = YES; [A.widthAnchor constraintEqualToAnchor:S.widthAnchor].active = YES; / / B view must be set full constraints [B.l eftAnchor constraintEqualToAnchor: S.l eftAnchor]. Active = YES; [B.topAnchor constraintEqualToAnchor:A.bottomAnchor].active = YES; [B.widthAnchor constraintEqualToAnchor:A.widthAnchor].active = YES; [B.heightAnchor constraintEqualToConstant:30].active = YES;Copy the code

A more complex and detailed code for how layout views interact with AutoLayout is available in the layout library MyLayout :AllTest12ViewController. You can see in this DEMO the code for how to implement the size of the parent view and the size and position of the sibling view depending on the size adaptation of the layout view.

3. A highly adaptive implementation of UITableViewCell for MyLayout&TangramKit

If all of your views don’t use AutoLayout then you can use MyLayout&TangramKit to implement a highly adaptive solution to the UITableViewCell described above. The downside, however, is that you need to overload specific methods. This problem has been solved in the new version! Since the layout view overwrites the intrinsicContentSize method, if you want to use the sizing capabilities of the layout view when using a layout view as a child of the UITableViewCell, simply set the size of the layout view to wrap and add the layout view to the other views. You no longer need to set width and height constraints for layout views, you no longer need to restrict how you can only add layout views to contentViews, and you no longer need to overload specific methods to use a layout view as a UILabel view. In the specific code can refer to the layout of library MyLayout AllTest1TableViewCellForAutoLayout. M.


Welcome to ouyang Big Brother 2013Making the address