MyLayout

  • Powerful. It reduces the amount of time we spend developing the UI and adapting it to multiple devices. Practice shows that using MyLayout for interface layout can reduce the workload by almost 50%.

  • Superior performance. The internal implementation of MyLayout is based on frame calculation to complete the layout, so the performance of the same interface is about 5 times that of AutoLayout, so it is the best practice to select MyLayout in complex interface.

  • The layout system is rich. MyLayout provides all the popular layout implementations in the front end of iOS, Android, HTML/CSS, etc. Therefore, no matter what platform you have worked on before, you can choose the layout classes you are familiar with. MyLayout also supports the ability to deliver dynamic layouts from the server.

  • The system is tightly integrated. MyLayout can be combined with AutoLayout, visualizations in xiBs and storyboards, and SizeClass for multi-device adaptation.

  • Multilingual implementation. MyLayout provides the OC language version of the implementation, but also provides the Swift language version of the implementation: TangramKit. The syntax and usage of both are similar, and you can choose either language for your code layout.

  • Internationalization support. MyLayout supports both LTR and RTL layouts. The RTL mode can be used to support Hebrew language layouts.

  • There is no version limit. There are no operating system version restrictions on MyLayout, and in theory it can be used as low as iOS5.0.

The following table lists the functions of MyLayout’s nine layout classes and their ability to compare with other systems:

Layout of the name of the class Function is introduced On the function
MyLinearLayout Linear layout:

Provides the ability to arrange views in single rows and columns from top to bottom or left to right
iOS:UIStackView

Android:LinearLayout

Flutter: the Row and Column

SwiftUI: HStack, VStack
MyFloatLayout Liquid layout:

Provides the ability to lay out views by floating up, down, left, and right
CSS: float
MyFlowLayout Fluid layout:

Provides the ability to arrange views vertically or horizontally and to continue the layout with a newline if certain conditions are met (the number and size values within a row meet the convention values)
unique
MyFlexLayout Elastic layout:

Provides a layout capability that allows subviews in a box to be flex-aligned and newlined and to meet flex specifications
CSS:flexbox
MyGridLayout Grid layout:

The grid layout provides the ability to layout based on infinite vertical and horizontal splitting of cells. The grid layout also has the ability to dynamically distribute the layout
CSS: Similar to Bootstrap and Grid
MyTableLayout Table layout:

Provides the ability to layout tables based on row and column control
Android:TableLayout, GridLayout

HTML:Table, tr, td
MyRelativeLayout Relative to the layout:

Provides the ability to implement layouts by setting interdependent constraints on size and location between views
iOS:AutoLayout

Android:RelativeLayout, PercentRelativeLayout, ConstraintLayout
MyFrameLayout Frame layout:

Provides the ability for views to be docked at a location on a superview and to lay them out in layers
Android:FrameLayout
MyPathLayout Path layout:

Provides the ability to arrange the positions of subviews by mathematical function operation
unique
SizeClass Provides the ability to set different layouts based on screen size and portrait and portrait. All of the above layouts support SizeClass functionality iOS:SizeClass

CSS:Similar to the Bootstrap

Some of these layout classes provide regular placement of subviews, such as linear, streaming, table, floating, path, elastic, and raster. Some layout classes, such as floating layout, relative layout, and frame layout, provide the ability to arrange layouts with constraints between subviews. Some layout classes, such as linear layout, streaming layout, tabular layout, and elastic layout, require multiple layers of nesting to meet interface requirements. Some layout classes, such as floating, relative, and grid layouts, allow you to flatline the interface requirements and use a single layer of layout to achieve the desired functionality. Some layout classes allow for special permutations, such as path layouts, where views are arranged according to a particular path curve based on mathematical functions provided. Some layout classes provide the ability to dynamically deliver from the server and describe the layout in JSON, such as raster layout. Some layout classes implement HTML/CSS markup, such as floating layouts and flexible layouts. Therefore, we can use it flexibly when realizing the interface requirements. For your reference, I have listed the priority of the layout classes used when selecting the layout:


Liquid layout – > fluid layout – > linear layout – > elastic layout – > grid layout – > relative layout – > frame layout – > table layout – > path layout


You can download both versions of the project DEMO from:

👉OC language version MyLayout: github.com/youngsoft/M… 👉Swift TangramKit: github.com/youngsoft/T…

1.9.0 new features

The 1.9.0 update includes a number of new features, code refactoring, and performance improvements. The new and improved features include:

  • Flexible layout flexbox implementation of MyFlexLayout
  • The most value restrictions
  • Compression of view size and position
  • Wrap and stretch docking support
  • The Drag and drop class MyLayoutDragger implements the drag and drop of views within the layout
  • IOS13 supports black and white mode adaptation
  • Custom inline alignment for streaming layout
  • Baseline alignment support for streaming and floating layouts
  • Refactoring and adding animation support for layout views
  • Improved and expanded support for adaptive layout and view size Settings
  • Refactoring the implementation of streaming and relative layouts improves the performance of all layouts
  • Fixed some online bugs

Below is a detailed introduction of the above features of the new version:

1. MyFlexLayout

Flexbox is a popular layout framework for Web frontend. It provides the ability to arrange the subviews in sequence within a box and to wrap them and stretch and compress them. There are also a number of solutions for porting Flexbox to native clients. Of course, flexbox has its drawbacks: no overlap, no relative spacing, no uniform setting of row and column spacing, no irregular alignment, and so on.

In previous releases, the streaming layout MyFlowLayout implemented most of the flexbox features and extended it with more complex functionality. Because the syntax and Settings are not compatible with flexbox, it is more expensive for flexbox lovers to learn and use. The new version provides a new layout class: MyFlexLayout:

/* * Flexible layout is a layout that is derived from MyFlowLayout to be compatible with Flexbox syntax. MyFlowLayout also supports flexbox-like features * because its properties are incompatible with Flexbox. Therefore provides a new kind of MyFlexLayout to fully support flexbox. * / @ interface MyFlexLayout: MyFlowLayout / * * used box layout view their own layout Settings * / @ property (nonatomic, strong,readonly) id<MyFlexBox> myFlex;

@end
Copy the code

From the above class definition, we can see that the layout class is derived from the flow layout class MyFlowLayout. We can set the properties of the elastic layout view by using the myFlex property in the class. MyFlex provides both chained and property-setting syntax, and you can use the flexible layout in whichever way you like. Here is a detailed definition of the MyFlexBox interface for the property myFlex:

@protocol MyFlexBox <MyFlexItem> @property(nonatomic, strong) id<MyFlexBoxAttrs> attrs; /** Set or retrieve the location of the children of the flex box object in the parent container. Default value: MyFlexDirection_Row */ -(id<MyFlexBox> (^)(MyFlexDirection))flex_direction; /** Sets or retrieves whether a stretchbox object's children are newlines when they exceed the parent container. Default: MyFlexWrap_NoWrap */ -(id<MyFlexBox> (^)(MyFlexWrap))flex_wrap; /** Sets the location of the children of the stretchbox object in the parent container and whether the children of the stretchbox object are newlines when they exceed the parent container. The two combination operation conducted by | * / - (id < MyFlexBox > (^) (int)) flex_flow; /** Sets or retrieves the alignment of elastic box elements along the main axis (horizontal axis). The optional values are: MyFlexGravity_Flex_Start | MyFlexGravity_Flex_End | MyFlexGravity_Center | MyFlexGravity_Space_Between | MyFlexGravity_Space_Around, the default value is MyFlexGravity_Flex_Start */ -(id<MyFlexBox> (^)(MyFlexGravity)) conty_content; /** Sets or retrieves the alignment of elastic box elements along the lateral (vertical) axis. The optional values are: MyFlexGravity_Flex_Start | MyFlexGravity_Flex_End | MyFlexGravity_Center | MyFlexGravity_Baseline | MyFlexGravity_Flex_Start */ -(id<MyFlexBox> (^)(MyFlexGravity))align_items; /** Set or retrieve the alignment of elastic box stack flex rows. The optional values are: MyFlexGravity_Flex_Start | MyFlexGravity_Flex_End | MyFlexGravity_Center | MyFlexGravity_Between | MyFlexGravity_Around One of | MyFlexGravity_Stretch, the default value is MyFlexGravity_Stretch * / - (id < MyFlexBox > (^) (MyFlexGravity)) align_content; /** specifies the number of children for the main axis. This parameter is valid only if flex_wrap is set to wrap. The default value is 0, which means that the line feeds automatically depending on the size of the item. */ -(id<MyFlexBox> (^)(NSInteger))item_size; /** Specifies the number of entries per page in the layout view. This value must be a multiple of item_size. */ -(id<MyFlexBox> (^)(NSInteger))page_size; /** specifies that the layout is automatically arranged according to the size of the entries. The default value is NO. */ -(id<MyFlexBox> (^)(BOOL))auto_arrange; /** Set the padding of the elastic box */ -(id<MyFlexBox> (^)(UIEdgeInsets))padding; /** Set the vertical spacing between the views of all items in the elastic box */ -(id<MyFlexBox> (^)(CGFloat))vert_space; */ -(id<MyFlexBox> (^)(CGFloat))horz_space; @endCopy the code

The properties of the item subview (item) in the elastic box view can be set via myFlex, which is provided by a UIView classification extension:

@interface UIView(MyFlexLayout) /** Used to set the layout of subviews in the popbox view. */ @property(nonatomic, strong,readonly) id<MyFlexItem> myFlex;

@end
Copy the code

The myFlex attribute of the item view is defined as follows:

@protocol MyFlexItem

@property(nonatomic, strong, readonly) id<MyFlexItemAttrs> attrs;
@property(nonatomic, weak, readonly) __kindof UIView *view; Mylayoutsize.wrap indicates that the width is adaptive, myLayoutsize.fill indicates that the width is equal to the superview's width, and myLayoutsize.fill indicates that it is equal to the superview's width. Mylayoutsize.empty indicates that the width value is not set. Any other value is a fixed width value. */ -(id<MyFlexItem> (^)(CGFloat))width; /** Set the width of the view, where percent indicates the percentage of the width occupied by the superview, and inc indicates the increment from the percentage. */ -(id<MyFlexItem> (^)(CGFloat percent, CGFloat inc))width_percent; */ -(id<MyFlexItem> (^)(CGFloat))min_width; */ -(id<MyFlexItem> (^)(CGFloat))max_width; Mylayoutsize.wrap indicates that the height is adaptive, myLayoutsize.fill indicates that the height is equal to the height of the superview, and myLayoutsize.fill indicates that the height is equal to the height of the superview. Mylayoutsize. empty indicates that the height value is not set, and all other values are fixed. */ -(id<MyFlexItem> (^)(CGFloat))height; /** Set the height of the view, where percent indicates the percentage of the height occupied by the superview, and inc indicates the increment based on the percentage. */ -(id<MyFlexItem> (^)(CGFloat percent, CGFloat inc))height_percent; */ -(id<MyFlexItem> (^)(CGFloat))min_height; /** max_height limit */ -(id<MyFlexItem> (^)(CGFloat))max_height; // Set the outer spacing of the view. */ -(id<MyFlexItem> (^)(CGFloat))margin_top; */ -(id<MyFlexItem> (^)(CGFloat))margin_top; */ -(id<MyFlexItem> (^)(CGFloat))margin_bottom; */ -(id<MyFlexItem> (^)(CGFloat))margin_bottom; */ -(id<MyFlexItem> (^)(CGFloat))margin_left; */ -(id<MyFlexItem> (^)(CGFloat))margin_left; */ -(id<MyFlexItem> (^)(CGFloat))margin_right; */ -(id<MyFlexItem> (^)(CGFloat))margin_right; */ -(id<MyFlexItem> (^)(CGFloat))margin; */ -(id<MyFlexItem> (^)(MyVisibility))visibility; // addTo superview -(__kindof UIView* (^)(UIView*))addTo; // Add subview -(id<MyFlexItem> (^)(UIView*))add; /** The list of items in the cartridge is arranged in order, the higher the value, the more back. */ -(id<MyFlexItem> (^)(NSInteger))order; /** Sets or retrieves the expansion ratio of the elastic box. The default value of 0 means no extension */ -(id<MyFlexItem> (^)(CGFloat))flex_grow; /** Sets or retrieves the shrinkage ratio of the elastic box. The default value of 1 indicates that the item size will be compressed when it exceeds the elastic box size. */ -(id<MyFlexItem> (^)(CGFloat))flex_shrink; /** Set or retrieve the elastic box expansion reference value. The default value is MyFlex_Auto, which means that it is determined by other attributes. If the value is greater than 0 or less than 1, it is relative, and the rest is a fixed size value. */ -(id<MyFlexItem> (^)(CGFloat))flex_basis; /** Sets or retrieves the alignment of the elastic box element itself along the lateral (vertical) axis. The optional values are: MyFlexGravity_Flex_Start | MyFlexGravity_Flex_End | MyFlexGravity_Center | MyFlexGravity_Baseline | MyFlexGravity_Stretch, default is MyFlex_Auto */ -(id<MyFlexItem> (^)(MyFlexGravity))align_self; @endCopy the code

As you can see from the above definition, since it is set up and used almost exactly as the Flexbox protocol, it will cost almost nothing to use for those familiar with Flexbox. For example, let’s use MyFlexLayout to implement the following interface:

Code implementation is as follows:

-(void)viewDidLoad{ [super viewDidLoad]; // Create a flexible layout with chained syntax, MyFlexLayout * Layout = MyFlexLayout.new.myFlex. Flex_direction (MyFlexDirection_Row) .flex_wrap(MyFlexWrap_Wrap) .align_content(MyFlexGravity_Center) .align_items(MyFlexGravity_Flex_End) .vert_space(10) .horz_space(10) .padding(UIEdgeInsetsMake(10, 10, 10, 10)) .marign_top(50) .width(MyLayoutSize.fill) .height(MyLayoutSize.wrap) .addTo(self.view); UILabel *itemA = UILabel.new.myFlex .width(MyLayoutSize.fill) .height(30) .addTo(layout); UILabel *itemB = UILabel.new.myFlex .flex_grow(1) .align_self(MyFlexGravity_Flex_Start) .height(30) .addTo(layout); UILabel *itemC = UILabel.new.myFlex .flex_grow(1) .height(40) .addTo(layout); UILabel *itemD = UILabel.new.myFlex .flex_grow(1) .height(50) .addTo(layout); layout.backgroundColor = [UIColor grayColor]; itemA.text = @"A";
itemA.backgroundColor = [UIColor redColor];
itemB.text = @"B";
itemB.backgroundColor = [UIColor greenColor];
itemC.text = @"C";
itemC.backgroundColor = [UIColor blueColor];
itemD.text = @"D";
itemD.backgroundColor = [UIColor yellowColor];
}

Copy the code

In addition to using chained syntax for layout and item styling, styling can be done directly through attribute assignment. You can use attrs in MyFlexBox and ATTRs in MyFlexItem to style layouts and items in the form of attribute values. In order to better demonstrate the use of MyFlexLayout, I set up a Flex layout (FlexLayout) in the Demo project of MyLayout. You can see all the operations related to the elastic layout there.

2. The maximum value constraint

👉 Imagine a scenario where the width of a view is half the width of the screen under portrait and half the height of the screen under landscape. In other words, the width of the view is half the minimum in the width and height of the screen. 👉 Imagine another scenario in which the right position of one view wants to be aligned with the right-most position of the other two views. In other words, the right position of the view is the maximum of the right position of the other two views.

We call the constraint that the position or the size of a particular view is a set of positions or a set of dimensions the maximum or minimum value of the constraint the maximum value constraint. Use the expression as follows:

Position = MAX(position 1, position 2, position 3...) Or position = MIN(position 1, position 2, position 3...) Size = MAX(size 1, size 2, size 3...) Or size = MIN(size 1, size 2, size 3...)Copy the code

Position maximum constraint

MyLayout to support position maxima, we create an extended class on the array class NSArray:

@interface NSArray(MyLayoutMostPos) It requires that the elements of the array be either MyLayoutPos or NSNumber at sign property(nonatomic,readonly) MyLayoutMostPos *myMinPos; // Get the minimum position value from the array. It requires that the elements of the array be either MyLayoutPos or NSNumber at sign property(nonatomic,readonly) MyLayoutMostPos *myMaxPos;

@end

Copy the code

We can use the myMinPos and myMaxPos read-only properties in the array to get the minimum and maximum minimums, respectively. To get the positional minimums, the array must be NSNumber and MyLayoutPos instance objects. It indicates that the maximum value is the maximum or minimum value in these specific numeric or positional objects. For example, the following code:

EqualTo (@[b.leftpos, c.righpos, @100].mym); // The left of view A is the left of view B, and the right of view C is the smallest of the three values a.leftposinPos); // The vertical center of view A is the largest of the three values: top of view B, 100, and bottom of view C. A.centerYPos.equalTo(@[B.topPos, @100, C.bottomPos].myMaxPos); // The left position of view A is the largest of the two positions: the left position of view B +20, and the right position of view C -20. A.leftPos.equalTo(@[B.leftPos.clone(20), C.rightPos.clone(20)].myMaxPos);Copy the code

In the last example above we saw the use of the Clone method of the MyLayoutPos object, which is used to clone a new object with a certain offset. The Clone method in MyLayoutPos is specifically used for maximum constraints, in cases where you want an offset at a certain location when getting the maximum value.

Currently, only subviews in a relative layout support location maximum constraint setting. Subviews in other layouts do not support location maximum constraint setting. At the same time, when setting the position maximum constraint, it requires that the position constraint calculation of the elements in the array must be completed before the position constraint calculation of the current view, otherwise the result will be unknown.

Size the most value

In order to support the maximum size, MyLayout creates an extended class on the array class NSArray:

@interface NSArray(MyLayoutMostSize) // Get the minimum size value from the array. It requires that the elements of the array be MyLayoutSize or NSNumber at sign property(nonatomic,readonly) MyLayoutMostSize *myMinSize; // Get the maximum size value from the array. It requires that the elements of the array be MyLayoutSize or NSNumber at sign property(nonatomic,readonly) MyLayoutMostSize *myMaxSize;

@end

Copy the code

We can use the myMinSize and myMaxSize read-only properties in the array to get the minimum and maximum Max objects, respectively. When we get a size minima object, we require that the elements in the array be NSNumber and an instance of MyLayoutSize, which indicates that the minima is either the maximum or minimum value of one of these specific numbers or size objects. Take the following example:

// The width of view A is the width of view B, and the height of view C is 100. The smallest of the three values a. idthsize.equalto (@[b.idthsize, C. eightSize, @100].myminSize); // the height of view A is the height of view A, half the height of view B plus 20,100. A.h eightSize. EqualTo (@ [@ (MyLayoutSize. Wrap), B.h eightSize. Clone (20, 0.5), @ 100]. MyMaxSize);Copy the code

In the last example above we saw the use of the Clone method of the MyLayoutSize object, which is used to clone a new size object with a number of multiples and increments. We can also use a special size value, myLayoutsize.wrap, in the maximum array to indicate that its own size is involved in the maximum comparison.

The maximum size constraint setting can be applied to all views under the layout as well as the layout itself. However, when using the maximum value constraint, the size constraint of the elements in the array must be calculated before the size constraint of the current view is calculated, otherwise the result is unknown.

3. Compression of view size and position

In some scenarios where the size of all the subviews is larger than the size of the layout view in order for all the subviews to be fully displayed, we want to compress the size of the subviews appropriately, and the same is true for the position. This is where compression techniques are applied to view size and position. For example, if the width of A horizontal linear layout is 120, the width and spacing of the three subviews A,B, and C are: A left spacing 20, A width 30,B left spacing 10,B width 60,C left spacing 20, and C width 40. Without compression, the interface display effect is as follows:

To implement the compression capability, a new attribute shrink is provided in MyLayoutSize and MyLayoutPos classes, respectively. The value of this attribute indicates the value of compression gravity when the position and size exceed the layout view. The larger the value is, the larger the compressed proportion is, and the value of 0 indicates that it will not be compressed. The default value of compression gravity is set to 0. For the example above, suppose we set the width and spacing of views A,B, and C to the following values:

A.leftPos.equalTo(@20).shrink = 1;
A.widthSize.equalTo(@30).shrink = 1;
B.leftPos.equalTo(@10);
B.widthSize.equalTo(@50).shrink = 2;
C.leftPos.equalTo(@20).shrink = 1;
C.widthSize.equalTo(@40);
Copy the code

So the sum of the spacing and width of all the subviews without compression is :20+30+10+50+20+40 = 170, minus the layout view’s width of 120 which exceeds 50. The sum of the compression specific gravity values set above is: 1+1+2+1 = 5. Therefore, the final result values of each position and size after compression are:

A's left spacing = 20-50 * (1/5.0) = 10 A's width = 30-50 * (1/5.0) = 20 B's left spacing = 10 Not compressed B's width = 50-50 * (2/5.0) = 30 C's left spacing = 20 - 50 * (1/5.0) = 10 C width = 40 will not be compressedCopy the code

The final interface display effect is as follows:

Currently, only the width and size of subviews in linear, frame, streaming, table, and elastic layouts support compression. Subviews in other layouts do not support compression. And the compression feature only works if all the subviews are out of size otherwise it doesn’t work.

It is important to note that subviews in elastic layouts are compressed not by setting the shrink property directly, but by setting flex_shrink.

The difference between the compression property of a view and the weight property of a view is that the former is used to compress the view size, while the latter is used to stretch the view size. For details on how to use the weight attribute, refer to the related documents and DEMO.

4. Wrap and stretch to dock

We can set the overall docking and alignment properties of the subviews within the layout by setting the gravity property of the layout view. In order to implement some of the capabilities found in Flexbox, four docking properties have been added in the new version:

MyGravity_Horz_Around
MyGravity_Horz_Stretch
MyGravity_Vert_Around
MyGravity_Vert_Stretch
Copy the code

Position stretching and wrapping

In previous versions, MyGravity_Horz_Between or MyGravity_Vert_Between was used if we wanted to stretch the spacing between subviews. When stretching spacing, the spacing between the first and last subviews from the parent layout view will be 0, and the spacing between the subviews will bisects the remaining space. MyGravity_Horz_Around and MyGravity_Vert_Around mean that the spacing between the first and last child views and the parent layout view is half the spacing between the children. The following interface shows the difference Between Between and Around:

Size of stretch and surround

In previous versions, if we wanted to fill and stretch the size between all the subviews to fill the size of the layout view we could do that with either MyGravity_Horz_Fill or MyGravity_Vert_Fill. These two docking properties will evenly distribute the remaining space in the layout view to the size of all the subviews (except the layout view with size adaptive setting), regardless of whether the view has size constraints set or not, thus achieving the size stretching effect between the subviews. MyGravity_Horz_Stretch and MyGravity_Vert_Stretch have the same effect as filling, except that they only stretch subviews that have no size constraints and subviews that have size adaptation set (except for layout views that have size adaptation set). The following interface shows the difference between Fill and Stretch:

At present, only linear layout, flow layout, floating layout, frame layout, flexible layout has the effect of overall docking and alignment Settings, other layouts are not supported.

5. Layout neutron view drag and drop

In some applications you can use drag-and-drop to adjust the position of the subview or do some other things. A previous version of MyLayout implemented such a DEMO. In the new version, we abstracted the drag and drop capabilities of the DEMO into a new drag and drop class: MyLayoutDragger. The following steps are required to implement drag-and-drop functionality using drag-and-drop classes:

  1. Create a drag and drop class instance object from the layout view class using the createLayoutDragger method and save it.

  2. Add the following events to each of the sub-views added to the layout view:

[can be drag and drop the child views addTarget: self action: @ the selector (handleTouchDrag: withEvent:)forControlEvents:UIControlEventTouchDragInside]; // Register drag events. [can be drag and drop the child views addTarget: self action: @ the selector (handleTouchDrag: withEvent:)forControlEvents:UIControlEventTouchDragOutside]; // Register external drag events. [can be drag and drop the child views addTarget: self action: @ the selector (handleTouchDown: withEvent:)forControlEvents:UIControlEventTouchDown]; // Register the press event [subview that can be dragged and dropped addTarget:self Action :@selector(handleTouchUp:withEvent)forControlEvents:UIControlEventTouchUpInside]; // Register the Lift event [subview that can be dragged and dropped] addTarget:self Action :@selector(handleTouchUp:withEvent)forControlEvents:UIControlEventTouchCancel]; // Register the termination eventCopy the code
  1. Call the relevant methods of the drag-and-drop object in their respective event handling methods:
- (IBAction)handleTouchDown:(id)sender withEvent:(UIEvent*)event {// drag the child view to start processing. [self.dragger dragView:sender withEvent:event]; } - (IBAction)handleTouchUp (ID) Sender withEvent (UIEvent*)event {// Stop the drag processing of the child view. [self.dragger dropView:sender withEvent:event]; } - (IBAction)handleTouchDrag (id) Sender withEvent (UIEvent*)event {// Subview drag to handle. [self.dragger dragginView:sender withEvent:event]; }Copy the code

This allows you to automatically drag and drop the subviews. The drag-and-drop object can also be used to set some of the characteristics, such as the duration of the drag-and-drop animation, which subviews can be set to not move during drag-and-drop, and whether the hover effect can be implemented during drag-and-drop. Specific DEMO code please refer to the DEMO project: FLLTest3ViewController

6. Black and white mode adaptation in iOS13

Since iOS13, we’ve been able to do this in black and white. For MyLayout, because it has the ability to support the border, the internal implementation of the border is implemented by CALayer, and the input of the color of the CALayer is CGColorRef object. Therefore, in order to support the black-and-white mode adaptation, the version is upgraded, so that the border can also achieve the ability of the black-and-white mode adaptation.

7. Inline alignment control for streaming layout

In a streaming layout, we can set the gravity property and arrangedGravity property to set the overall docking property of subviews in the layout and the alignment property between subviews in the row. In practice, however, you might want to be able to customize the alignment properties of some rows differently than others. This allows us to achieve our interface requirements without inserting placeholder views or requiring multiple layers of nesting by using the row alignment property. (If you use linear layout to achieve multiple rows and columns, you need to do multiple layout layers of nesting processing). Here’s an example:

To support inline alignment docking custom processing, streaming layout provides a new property:

By default, the gravity and arrangedGravity of the layout view apply to all rows and dock alignment within rows. If you want to customize the alignment of a row separately, you can set this block property. LineGravity takes four parameters: the layout object, the index of the current row (starting at 0), the number of entry views for the current row, and whether it is the last row. If MyGravity_None is returned, then the layout's default gravity and arrangedGravity are used to dock alignment. */ @property(nonatomic, copy) MyGravity (^lineGravity)(MyFlowLayout *layout, NSInteger lineIndex, NSInteger itemCount, BOOL isLastLine);Copy the code

We can use this property in the form of a block to do custom processing of inline docking alignment. For details on the use of inline docking, see FLLTest4ViewController and FLLTest9ViewController in DEMO projects

8. Baseline alignment support for streaming and floating layouts

New support for baseline alignment between each row of subviews in vertical streaming and vertical floating layouts has been added. You can set the value of flow layout arrangement gravity to MyGravity_Vert_Baseline. And set the gravity of the floating layout to MyGravity_Vert_Baseline for inline baseline alignment. The standard view of the baseline is the first text view within the line. In this way, the whole layout system of horizontal linear layout, relative layout, vertical flow layout, vertical floating layout, elastic layout can realize the ability of inline baseline alignment.

9. Support and extension of layout animation

The proper use of animation will enhance the user experience. In MyLayout, if we want to animate a child view after adjusting its constraints, we can call the layout view method:

/** * Set the animation when the layout. And specifying the time, options, and completion processing, this animation will only be executed once on the next layout after the call. @ param duration specified time interval * / animation - (void) layoutAnimationWithDuration (NSTimeInterval) duration; -(void)layoutAnimationWithDuration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;Copy the code

After the above method is called, the system automatically animates the next layout cycle when it occurs. When using the animation method we can specify the duration of the animation and some options as well as the callback processing after the animation is completed.

10. Improved and expanded support for adaptive Settings of view sizes

The so-called size adaptation is that the size of the view dynamically determines its own size according to its own content and the size of the subviews within the view, thus forming the so-called wrapped effect. The purpose of size adaptation is to fully display everything in the view.

Old version size adaptive Settings

The adaptive size of a view is also a special size. In older versions, you can make the width of a view adaptive by setting the wrapContentWidth property to YES, and the height of a view adaptive by setting the wrapContentHeight property to YES. To set the actual size of the view, use widthSize or heightSize. It is not reasonable to use two properties separately to set the size. Instead of using wrapContentWidth, wrapContentHeight, and wrapContentSize to set size adaptation, the new version recommends using a new setting.

New version of size adaptive Settings

The new version incorporates the size adaptive setting into widthSize and heightSize. Because adaptive is also a size value, just a special value. The following code is how to set the old and new versions:

// The old method a.wrapcontentWidth = YES; EqualTo (@(myLayoutsize.wrap)); // new method 2 a.mywidth = myLayoutsize.wrap; // The old method: B.wrapcontentSize = YES; // New method: b.mysize = CGSizeMake(myLayoutsize.wrap, myLayoutsize.wrap); // New method: b.mysize = CGSizeMake(myLayoutsize.wrap, myLayoutsize.wrap); // The old read and judge methodif(a.wrapContentWidth) {} // New judge and read method 1if(a.idthsize.iswrap){} // New method 2 for judging and readingif (A.myWidth == MyLayoutSize.wrap){}

Copy the code

In addition to setting myLayoutsize.wrap to be size adaptive in the new version, we define two other class properties in the MyLayoutSize class: myLayoutsize.fill and myLayoutsize.empty. They can also be used to simplify size Settings.

  • Mylayoutsize.wrap: represents size adaptation
  • Mylayoutsize.fill: indicates that the size takes up the remaining space in the superview
  • Mylayoutsize. empty: clears the size constraint

For example, the following code is equivalent:

A.widthSize.equalTo(@(MyLayoutSize.wrap)) <==> A.myWidth = MyLayoutSize.wrap;
A.widthSize.equalTo(A.superview.widthSize) <==> A.myWidth = MyLayoutSize.fill;
A.widthSize.equalTo(nil) <==> A.myWidth = MyLayoutSize.empty;
Copy the code

conclusion


Since many functions in MyLayout are not introduced in the syntax space, if you want to learn more, you can download the corresponding project demo on Github to understand in detail.

👉 MyLayout: github.com/youngsoft/M…

👉 TangramKit: github.com/youngsoft/T…

👉 my nuggets home page: juejin. Im /user/852876…