MyLayout Framework

repository·master·Indexed 26 days ago

https://github.com/youngsoft/mylinearlayout

An Objective-C framework for iOS view layout that provides high-level abstractions inspired by Android layouts and CSS models. It offers a frame-based alternative to AutoLayout with specialized layout containers including MyLinearLayout, MyRelativeLayout, MyFrameLayout, MyTableLayout, MyFlowLayout, MyFloatLayout, MyPathLayout, MyGridLayout, and MyFlexLayout. It features a declarative syntax for positioning and sizing via MyLayoutPos and MyLayoutSize, and supports multi-screen adaptation through MySizeClass.

Tokens
8K
Snippets
24
Records
36
Agent score
38%

What's inside MyLayout

  1. Overview of MyLayout

    master

    MyLayout is an Objective-C framework for iOS view layout. It provides simplified functions to build complex interfaces by integrating concepts from Autolayout, iOS SizeClass, Android layout classes, HTML/CSS (float, flex-box, and bootstrap), and more.

    Note: For Swift projects, use TangramKit instead.

  2. Overview of MyLayout

    master

    MyLayout is an iOS interface view layout framework. Unlike AutoLayout, which relies on constraints, MyLayout is built by overriding layoutSubviews and setting the bounds and center properties of subviews using frames. This approach offers several advantages:

    • Performance: Faster than AutoLayout and Masonry, especially as the number of subviews increases.
    • Compatibility: Since it is frame-based, it is not restricted by specific iOS versions.
    • Versatility: Integrates multiple layout paradigms including Linear, Relative, Frame, Table, Flow, Float, and Path layouts, similar to Android, HTML/CSS, and Flexbox.
    • Ease of Use: Supports automatic constraint establishment based on subview addition order and provides solutions for multi-screen size adaptation (Size Classes).
    • Advanced Features: Supports dynamic height auto-adaptation (e.g., for UITableViewCell), tag clouds, width auto-adaptation, proportional sizing, and automatic layout triggering when views are hidden or shown.
  3. Install MyLayout via Carthage

    master

    Follow these steps to use Carthage for dependency management:

    1. Create a Cartfile with the following content:
    github "youngsoft/MyLinearLayout"
    1. Run the update command:
    carthage update
    1. In Xcode, go to your application target's General settings, find Linked Frameworks and Libraries, and drag/drop the MyLayout framework from the Carthage/Build folder.
    2. In the Build Phases tab, add a New Run Script Phase with the following shell script:
    /usr/local/bin/carthage copy-frameworks
    1. Add the framework path to the Input Files section:
    $(SRCROOT)/Carthage/Build/iOS/MyLayout.framework
  4. Understand relative spacing in MyLinearLayout

    master

    In MyLinearLayout, if a subview's MyLayoutPos property is set to a decimal between 0 and 1, it represents a relative spacing/margin rather than an absolute value.

    Example: In a vertical layout with subviews a, b, c, d, if you want c and d to be positioned at the bottom of the layout instead of following b, you can set c.myTop to a decimal between 0 and 1.

    Recommended Approach: For better readability, instead of using fractional myTop values, you can use:

    • b.myBottom = 0.5
    • c.myTop = 0.5
  5. Retrieve view dimensions after layout

    master

    Because MyLayout uses a constraint-based system similar to AutoLayout, layout is not performed immediately. To get the correct size or frame after setting constraints, use one of these four methods:

    1. Size Estimation: Call sizeThatFits: passing CGSizeMake(explicitWidth, 0). The returned size contains the evaluated height. You can also use the estimatedRect property to get evaluated sizes and positions of subviews.
    2. Immediate Layout: Call layoutIfNeeded on the layout view to force immediate calculation, then read the frame property. Note: You must set an explicit width on the layout view's frame before calling this, otherwise calculations may be incorrect.
    3. KVO Monitoring: Monitor the isMyLayouting property via KVO to receive notifications when the layout view and its subviews have finished updating their frames.
    4. Completion Blocks: Set an endLayoutBlock on the layout view or a viewLayoutCompleteBlock on subviews. Note that these blocks may return slightly inaccurate frames as they represent the result of the first layout pass.
  6. Install MyLayout via CocoaPods

    master

    To integrate MyLayout into your Xcode project using CocoaPods, add the following to your Podfile:

    source 'https://github.com/CocoaPods/Specs.git'
    platform :ios, '11.0'
    
    pod 'MyLayout'

    Then, run the following command in your terminal:

    $ pod install
    source 'https://github.com/CocoaPods/Specs.git'
    platform :ios, '11.0'
    
    pod 'MyLayout'
  7. Use MyLayout for view positioning and sizing

    master

    MyLayout uses a declarative syntax to define the position and size of subviews. You can use properties like leftPos, rightPos, widthSize, and heightSize combined with equalTo: and multiply: to define constraints relative to parent containers or other views.

    Key concepts:

    • Positioning: Use leftPos and rightPos to set margins/offsets.
    • Sizing: Use widthSize and heightSize to define dimensions.
    • Relative Sizing: Use .multiply() to set dimensions as a percentage of another value.
    • Spacing: Use subviewSpacing on container layouts to manage gaps between children.
    // Example: Creating a vertical linear layout with subviews
    MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
    S.subviewSpacing = 10;
    S.widthSize.equalTo(@100);
    
    UIView *A = UIView.new;
    A.leftPos.equalTo(@0.2); // 20% of parent width
    A.rightPos.equalTo(@0.3); // 30% of parent width
    A.heightSize.equalTo(A.widthSize);
    [S addSubview:A];
    
    UIView *B = UIView.new;
    B.leftPos.equalTo(@40);
    B.widthSize.equalTo(@60);
    B.heightSize.equalTo(@40);
    [S addSubview:B];
    
    UIView *C = UIView.new;
    C.leftPos.equalTo(@0);
    C.rightPos.equalTo(@0);
    C.heightSize.equalTo(@40);
    [S addSubview:C];
    
    UIView *D = UIView.new;
    D.rightPos.equalTo(@@20);
    D.widthSize.equalTo(S.widthSize).multiply(0.5); // 50% of parent width
    D.heightSize.equalTo(@40);
    [S addSubview:D];
  8. Troubleshoot 100% CPU usage and crashes in layoutSubviews

    master

    If your app experiences 100% CPU usage and crashes in layoutSubviews, it is caused by constraint conflicts. This typically happens when a layout view depends on a subview's size, while that subview simultaneously depends on the parent view's size, creating a circular dependency.

    Solution: Inspect the constraints between parent and child views to ensure there are no mutual dependencies.

  9. Troubleshoot MyLayout common issues

    master

    CPU Usage and Constraint Conflicts

    If you experience 100% CPU usage, it is likely caused by constraint conflicts. Check the subview's constraint set.

    Layout View Constraints

    • Root Views: If you set a layout view as a UIViewController's root view, you must set wrapContentWidth and wrapContentHeight to NO.
    • Conflicting Sizes: Setting wrapContentWidth or wrapContentHeight simultaneously with widthSize or heightSize may cause constraint conflicts.

    Subview Behavior

    • Relative Margin: Only MyLinearLayout and MyFrameLayout subviews support relative margins.
    • setFrame Method: When adding a subview to a layout view, the setFrame method can only be used to set the size, not the origin.

    Exceptions

    • If an exception occurs in the MyBaseLayout *willMoveToSuperview method, it can be ignored by disabling the exception breakpoint in Xcode (CMD+7).
  10. Example: Implementing a Vertical Linear Layout

    master

    The following example demonstrates how to use MyLinearLayout to create a vertical container with specific subview positioning and sizing using the MyLayoutPos and MyLayoutSize logic (via leftPos, rightPos, widthSize, etc.).

    In this scenario:

    • A container S is created with vertical orientation and 10px spacing.
    • Subview A uses percentage-based positioning (0.2 left, 0.3 right) and maintains a square aspect ratio.
    • Subview B uses absolute positioning and fixed dimensions.
    • Subview C spans the full width.
    • Subview D uses a proportional width (50% of parent) and absolute right positioning.
         MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
        S.subviewSpacing = 10;
        S.widthSize.equalTo(@100);
        
        UIView *A = UIView.new;
        A.leftPos.equalTo(@0.2);
        A.rightPos.equalTo(@0.3);
        A.heightSize.equalTo(A.widthSize);
        [S addSubview:A];
        
        UIView *B = UIView.new;
        B.leftPos.equalTo(@40);
        B.widthSize.equalTo(@60);
        B.heightSize.equalTo(@40);
        [S addSubview:B];
        
        UIView *C = UIView.new;
        C.leftPos.equalTo(@0);
        C.rightPos.equalTo(@0);
        C.heightSize.equalTo(@40);
        [S addSubview:C];
        
        UIView *D = UIView.new;
        D.rightPos.equalTo(@20);
        D.widthSize.equalTo(S.widthSize).multiply(0.5);
        D.heightSize.equalTo(@40);
        [S addSubview:D];
        
        ```
  11. Use MyPathLayout for path-based layouts

    master

    A unique layout where subviews are arranged along a specific mathematical curve.

    To use it, you must provide:

    1. A curve function (polarEquation).
    2. A coordinate system (coordinateSetting).
    3. Distance settings for subviews on the curve.
    MyPathLayout *S = [MyPathLayout new];
    S.mySize = CGSizeMake(320,320);
    S.coordinateSetting.isReverse = YES;
    S.coordinateSetting.origin = CGPointMake(0.5, 0.2);
    
    S.polarEquation = ^(CGFloat angle) {
        return 80 * (1 + cos(angle));
    };
    
    for (int i = 0; i < 4; i++) {
        UIView *A = [UIView new];
        A.mySize = CGSizeMake(40,40);
        [S addSubview:A];
    }