oc 使用 MyLayoutopen in new window 布局

添加依赖

#提供类似Android中更高层级的布局框架
#https://github.com/youngsoft/MyLinearLayout
pod 'MyLayout'

导入头文件

//提供类似Android中更高层级的布局框架
#import <MyLayout/MyLayout.h>

ViewController.m

//
//  ViewController.m
//  TestMyLayout
//
//  Created by xu menglong on 2023/8/18.
//

//提供类似Android中更高层级的布局框架
#import <MyLayout/MyLayout.h>
#import "ViewController.h"
#import "SettingController.h"

@interface ViewController ()

@property(nonatomic, strong) UIView *container;
@property(nonatomic, strong) UIButton *phoneLoginButton;
@property(nonatomic, strong) UIButton *primaryButton;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一个相对布局
    MyRelativeLayout *container = [MyRelativeLayout new];
    // 添加背景色
    container.backgroundColor = [UIColor whiteColor];

    // 安全区域
    container.leadingPos.equalTo(@(MyLayoutPos.safeAreaMargin)).offset(16);
    container.trailingPos.equalTo(@(MyLayoutPos.safeAreaMargin)).offset(16);
    container.topPos.equalTo(@(MyLayoutPos.safeAreaMargin)).offset(16);
    container.bottomPos.equalTo(@(MyLayoutPos.safeAreaMargin)).offset(16);
    // 添加到view
    [self.view addSubview:container];

    // logo
    UIImageView *logo = [UIImageView new];
    logo.image = [UIImage imageNamed:@"Logo"];
    [container addSubview:logo];
    // 宽高
    logo.myWidth = 100;
    logo.heightSize.equalTo(@(100));
    // 距离顶部
    logo.myTop = 100;
    // 水平居中
    logo.myCenterX = 0;

    #pragma mark - 底部容器
    // 创建一个垂直方向容器,类似android 线性布局控件
    MyLinearLayout *bottomContainer = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
    // 宽度和父布局一样
    bottomContainer.myWidth = MyLayoutSize.fill;
    // 高度包裹内容
    bottomContainer.myHeight = MyLayoutSize.wrap;
    bottomContainer.myBottom = 0;
    // 内容水平居中
    bottomContainer.gravity = MyGravity_Horz_Center;
    //子控件间距
    bottomContainer.subviewSpace = 30;
    [container addSubview:bottomContainer];


    #pragma mark - 底部容器
    // 手机号登录按钮
    self.phoneLoginButton = [UIButton buttonWithType:UIButtonTypeSystem];
    // 设置标题
    [self.phoneLoginButton setTitle:@"手机号登录" forState:UIControlStateNormal];
    // 设置点击事件
    [self.phoneLoginButton addTarget:self action:@selector(phoneLoginClick:) forControlEvents:UIControlEventTouchUpInside];
    // 背景颜色
    self.phoneLoginButton.backgroundColor = [UIColor redColor];
    // 圆角
    self.phoneLoginButton.layer.cornerRadius = 5;
    // 设置标题颜色
    [self.phoneLoginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    // 高亮颜色
    [self.phoneLoginButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
    // 添加到容器
    [bottomContainer addSubview:self.phoneLoginButton];

    // 设置宽高
    self.phoneLoginButton.myWidth = MyLayoutSize.fill;
    self.phoneLoginButton.myHeight = 42;

    #pragma mark - 主登录按钮
    // 登录按钮
    self.primaryButton = [UIButton buttonWithType:UIButtonTypeSystem];
    // 设置标题
    [self.primaryButton setTitle:@"用户名和密码登录" forState:UIControlStateNormal];
    // 字体颜色
    [self.primaryButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    // 设置点击
    [self.primaryButton addTarget:self action:@selector(primaryButtonClick:) forControlEvents:UIControlEventTouchUpInside];

    // 背景颜色
    self.primaryButton.backgroundColor = [UIColor clearColor];
    // 圆角
    self.primaryButton.layer.cornerRadius = 21;
    // 边框宽度
    self.primaryButton.layer.borderWidth = 1;
    // 边框颜色
    self.primaryButton.layer.borderColor = [UIColor redColor].CGColor;
    // 添加到容器
    [bottomContainer addSubview:self.primaryButton];

    // 设置宽高
    self.primaryButton.myWidth = MyLayoutSize.fill;
    self.primaryButton.myHeight = 42;

    #pragma mark - 登录按钮
    // 第三方登录容器
    MyBaseLayout *otherLoginContainer = [[MyLinearLayout alloc] initWithOrientation:MyOrientation_Horz];

    // 宽高
    otherLoginContainer.myWidth = MyLayoutSize.fill;
    otherLoginContainer.myHeight = MyLayoutSize.wrap;
    // 垂直居中
    otherLoginContainer.gravity = MyGravity_Vert_Center;
    otherLoginContainer.subviewSpace=10;

    // 添加到容器
    [bottomContainer addSubview:otherLoginContainer];

    // 第三方按钮
    //第三方登录按钮
    for (NSInteger i=0; i<4; i++) {
        UIButton *buttonView=[UIButton new];
        [buttonView setImage:[UIImage imageNamed:@"LoginQqSelected"] forState:UIControlStateNormal];
        [otherLoginContainer addSubview:buttonView];
//        buttonView.backgroundColor=[UIColor greenColor];

        buttonView.myHeight=50;

        //权重,如果相同就是平分
        buttonView.weight=1;
    }

    #pragma mark - 协议
    // 协议
    UILabel *agrementLabelView = [[UILabel alloc] init];
    // 标题
    agrementLabelView.text = @"登录即表示你同意《用户协议》和《隐私政策》oc 布局";
    // 字体大小
    agrementLabelView.font = [UIFont systemFontOfSize: 12];
    // 字体颜色
    agrementLabelView.textColor = [UIColor grayColor];
    // 添加容器
    [bottomContainer addSubview:agrementLabelView];
    // 设置宽高
    agrementLabelView.myWidth = MyLayoutSize.wrap;
    agrementLabelView.myHeight = MyLayoutSize.wrap;
}

// 手机号登录点击
-(void)phoneLoginClick:(UIButton *) sender {
    NSLog(@"ViewController phoneLoginClick %@",sender);
    // 跳转到 SettingController
    SettingController *settingController = [[SettingController alloc] init];
    [self.navigationController pushViewController:settingController animated:YES];
}

// 主按钮点击
-(void)primaryButtonClick:(UIButton *) sender {
    NSLog(@"ViewController primaryClick %@",sender);
}
@end

图片

自定义 View

// View/SettingView.h
//
//  SettingView.h
//  TestMyLayout
//
//  Created by xu menglong on 2023/8/19.
//

#import <MyLayout/MyLayout.h>

NS_ASSUME_NONNULL_BEGIN

@interface SettingView : MyLinearLayout

// 左侧图标
@property(nonatomic, strong) UIImageView *iconView;

// 标题
@property(nonatomic, strong) UILabel *titleView;

// 右侧图标
@property(nonatomic, strong) UIImageView *moreIconView;
@end

NS_ASSUME_NONNULL_END
// View/SettingView.m
//
//  SettingView.m
//  TestMyLayout
//
//  Created by xu menglong on 2023/8/19.
//

#import "SettingView.h"

@implementation SettingView


/// 初始化
- (instancetype)init
{
    self = [super initWithOrientation:MyOrientation_Horz];
    if (self) {
        [self innerInit];
    }
    return self;
}


/// 内部容器初始化
- (void)innerInit {
    self.myWidth = MyLayoutSize.fill;
    self.myHeight = 55;
    self.padding = UIEdgeInsetsMake(0, 16, 0, 16);
    self.subviewSpace = 10;

    self.gravity = MyGravity_Vert_Center;

    self.backgroundColor = [UIColor whiteColor];
    [self addSubview:self.iconView];
    [self addSubview:self.titleView];
    [self addSubview:self.moreIconView];
}

#pragma mark - 创建控件

/// 左侧图标
- (UIImageView *)iconView{
    if (!_iconView) {
        _iconView=[UIImageView new];
        _iconView.image=[UIImage imageNamed:@"Setting"];

        _iconView.myWidth=20;
        _iconView.myHeight=20;
    }
    return _iconView;
}


/// 标题
- (UILabel *)titleView{
    if (!_titleView) {
        _titleView=[UILabel new];
        _titleView.text=@"设置";

        _titleView.myWidth=MyLayoutSize.fill;
        _titleView.myHeight=MyLayoutSize.wrap;
        _titleView.weight=1;
    }
    return _titleView;
}


/// 右侧图标
- (UIImageView *)moreIconView{
    if (!_moreIconView) {
        _moreIconView=[UIImageView new];
        _moreIconView.image=[UIImage imageNamed:@"Arrow"];

        _moreIconView.myWidth=20;
        _moreIconView.myHeight=20;
    }
    return _moreIconView;
}

@end
// Controller/SettingController.h
//
//  SettingController.h
//  TestMyLayout
//
//  Created by xu menglong on 2023/8/19.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SettingController : UIViewController

@end

NS_ASSUME_NONNULL_END
// Controller/SettingController.m
//
//  SettingController.m
//  TestMyLayout
//
//  Created by xu menglong on 2023/8/19.
//

#import "SettingController.h"
#import "SettingView.h"

@interface SettingController ()

@property(nonatomic, strong) SettingView *settingView;
@property(nonatomic, strong) SettingView *collectView;


@end

@implementation SettingController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    // 设置标题
    self.title = @"设置";

    // 背景颜色
    self.view.backgroundColor = [UIColor systemGroupedBackgroundColor];

    //创建一个容器
    MyBaseLayout *container = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];

    //从安全区开始
    container.leadingPos.equalTo(@(MyLayoutPos.safeAreaMargin));
    container.trailingPos.equalTo(@(MyLayoutPos.safeAreaMargin));
    container.topPos.equalTo(@(MyLayoutPos.safeAreaMargin)).offset(16);
    container.myHeight = MyLayoutSize.wrap;

    container.subviewSpace = 0.5;

    [self.view addSubview:container];

    // 添加子控件
    [container addSubview:self.settingView];
    [container addSubview:self.collectView];

}


#pragma mark - 事件
-(void)settingTapGestureRecognizer:(UITapGestureRecognizer *)recognizer{
    NSLog(@"SettingController settingTapGestureRecognizer");
}

#pragma mark - 控件
/// 设置Item
- (SettingView *)settingView{
    if (!_settingView) {
        _settingView=[SettingView new];
        _settingView.titleView.text=@"设置";

        //设置点击事件
        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(settingTapGestureRecognizer:)];
        [_settingView addGestureRecognizer:tapGestureRecognizer];
    }

    return _settingView;
}

/// 收藏Item
- (SettingView *)collectView{
    if (!_collectView) {
        _collectView=[SettingView new];
        _collectView.titleView.text=@"收藏";
    }

    return _collectView;
}
@end

图片

swift 使用 TangramKitopen in new window 布局

添加依赖

#提供类似Android中更高层级的布局框架
#https://github.com/youngsoft/TangramKit
pod 'TangramKit'

ViewController.swift 文件

//
//  ViewController.swift
//  MyTestSnapKit
//
//  Created by xu menglong on 2023/8/22.
//

import UIKit

//自动布局框架
import TangramKit

class ViewController: UIViewController {
    // 根容器
    var container:UIView!

    override func viewDidLoad() {

        super.viewDidLoad()
        // Do any additional setup after loading the view.
        // 设置背景色
        view.backgroundColor = .white

        // 创建一个根容器
        self.container = TGRelativeLayout()
        // 从安全区开始
        container.tg_top.equal(TGLayoutPos.tg_safeAreaMargin).offset(16)
        container.tg_leading.equal(TGLayoutPos.tg_safeAreaMargin).offset(16)
        container.tg_trailing.equal(TGLayoutPos.tg_safeAreaMargin).offset(16)
        container.tg_bottom.equal(TGLayoutPos.tg_safeAreaMargin).offset(16)

        view.addSubview(container)

        // logo
        let logoView = UIImageView()
        // 设置宽高
        logoView.tg_width.equal(100)
        logoView.tg_height ~= 100
        logoView.tg_top ~= 100
        // 水平居中
        logoView.tg_centerX.equal(0)

        logoView.image = UIImage(named: "Logo")
        container.addSubview(logoView)


        // MARK: - 底部容器
        let bottomContainer = TGLinearLayout(.vert)
        bottomContainer.tg_height.equal(.wrap)
        bottomContainer.tg_width.equal(.fill)
        bottomContainer.tg_bottom.equal(0)
        bottomContainer.tg_gravity = TGGravity.horz.center
        bottomContainer.tg_space = 30
        container.addSubview(bottomContainer)

        // 手机的登录按钮
        bottomContainer.addSubview(phoneLoginButton)

        // 用户名和密码登录按钮
        bottomContainer.addSubview(primaryLoginButton)

        // MARK: - 第三方登录容器
        let otherLoginContainer = TGLinearLayout(.horz)
        otherLoginContainer.tg_height.equal(.wrap)
        otherLoginContainer.tg_width.equal(.fill)
        otherLoginContainer.tg_gravity = TGGravity.horz.between
        bottomContainer.addSubview(otherLoginContainer)

        // 第三方登录按钮
        for _ in 0..<4 {
            let buttonView = UIButton(type: .custom)
            buttonView.setImage(UIImage(named: "LoginQqSelected"), for: .normal)
            //  buttonView.backgroundColor = .green
            buttonView.tg_width.equal(.wrap)
            buttonView.tg_height.equal(50)
            otherLoginContainer.addSubview(buttonView)
        }

        // 协议
        let agreementLabelView = UILabel()
        // 标题
        agreementLabelView.text = "登录即代表您同意 swift 布局"
        // 字体大小
        agreementLabelView.font = UIFont.systemFont(ofSize: 12)
        // 字体颜色
        agreementLabelView.textColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
        agreementLabelView.tg_width.equal(.wrap)
        agreementLabelView.tg_height.equal(.wrap)
        bottomContainer.addSubview(agreementLabelView)
    }

    @objc func phoneLoginAction(_ sender: UIButton) {
        print("点击了手机登录按钮")
        let t = SettingController()
        navigationController!.pushViewController(t, animated: true)
    }

    @objc func primaryLoginAction(_ sender: UIButton) {
        print("点击了用户名和密码登录按钮")
    }




    // 手机登录按钮
    // 这是swift 懒加载
    lazy var phoneLoginButton: UIButton = {
        let r = UIButton(type: .system)
        // 设置标题
        r.setTitle("手机登录", for: .normal)
        // 设置点击事件
        r.addTarget(self, action: #selector(phoneLoginAction(_:)), for: .touchUpInside)
        // 设置背景颜色
        r.backgroundColor = .red
        // 圆角大小
        r.layer.cornerRadius = 5
        // 设置默认标题颜色
        r.setTitleColor(.white, for: .normal)
        // 设置按下时的标题颜色
        r.setTitleColor(UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1), for: .highlighted)

        // 设置宽高
        r.tg_width.equal(.fill)
        r.tg_height.equal(42)

        return r

    }()


    // 用户名和密码登录按钮
    // 这是swift 懒加载
    lazy var primaryLoginButton: UIButton = {
        let r = UIButton(type: .system)
        // 设置标题
        r.setTitle("用户名和密码登录", for: .normal)
        // 设置点击事件
        r.addTarget(self, action: #selector(primaryLoginAction(_:)), for: .touchUpInside)
        // 设置背景颜色
        r.backgroundColor = .clear
        // 圆角大小
        r.layer.cornerRadius = 21
        // 边框颜色
        r.layer.borderColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1).cgColor
        r.layer.borderWidth = 1
        // 设置默认标题颜色
        r.setTitleColor(.red, for: .normal)
        // 设置按下时的标题颜色
        r.setTitleColor(UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1), for: .highlighted)

        // 设置宽高
        r.tg_width.equal(.fill)
        r.tg_height.equal(42)

        return r

    }()


}

图片

自定义 View

// View/SettingView.swift
//
//  SettingView.swift
//  MyTestSnapKit
//
//  Created by xu menglong on 2023/8/28.
//

import UIKit
import TangramKit

class SettingView: TGRelativeLayout {

    init() {
        super.init(frame: CGRect.zero)
        innerInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        innerInit()
    }

    func innerInit() {
        tg_width.equal(.fill)
        tg_height.equal(55)


        backgroundColor = .white
        addSubview(iconView)
        addSubview(titleView)
        addSubview(moreIconView)
    }

    /// 左侧图标
    lazy var iconView: UIImageView = {
        let result = UIImageView()
        result.image = UIImage(named: "Setting")

        result.tg_width.equal(20)
        result.tg_height.equal(20)
        result.tg_centerY.equal(0)
        result.tg_leading.equal(16)
        return result
    }()

    /// 标题
    lazy var titleView: UILabel = {
        let result = UILabel()
        result.text = "设置"
        result.tg_width.equal(.wrap)
        result.tg_height.equal(.wrap)
        result.tg_centerY.equal(0)
        result.tg_leading.equal(iconView.tg_trailing).offset(16)
        return result
    }()

    /// 右侧图标
    lazy var moreIconView: UIImageView = {
        let result = UIImageView()
        result.image = UIImage(named: "Arrow")
        result.tg_width.equal(20)
        result.tg_height.equal(20)
        result.tg_centerY.equal(0)
        result.tg_right.equal(16)
        return result
    }()

}
// Controller/SettingController.swift
//
//  SettingController.swift
//  MyTestSnapKit
//
//  Created by xu menglong on 2023/8/28.
//

import UIKit
import TangramKit

class SettingController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // 设置背景颜色
        view.backgroundColor = .systemGroupedBackground

        // 设置标题
        title = "设置界面"

        let container = TGLinearLayout(.vert)
        container.tg_width.equal(.fill)
        container.tg_height.equal(.wrap)
        container.tg_top.equal(TGLayoutPos.tg_safeAreaMargin).offset(16)
        container.tg_space = 1

        container.addSubview(settingView)
        container.addSubview(collectView)

        view.addSubview(container)

    }

    @objc func onSettingClick(recognizer:UITapGestureRecognizer) {
        print("onSettingClick")
    }

    /// 设置Item
    lazy var settingView: SettingView = {
        let r = SettingView()

        //设置点击事件
        r.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onSettingClick(recognizer:))))

        return r
    }()

    /// 收藏Item
    lazy var collectView: SettingView = {
        let r = SettingView()
        r.titleView.text = "收藏"
        r.iconView.image = UIImage(named: "Setting")
        return r
    }()
    /*
     // MARK: - Navigation

     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destination.
     // Pass the selected object to the new view controller.
     }
     */

}

图片

参考资料