PLXFrameLayout 是一个小框架,用于定位、尺寸和布局视图,而无需使用 CGRects。 PLXFrameLayout 还提供了一组方便的读写属性,可以从视图的框架中提取/设置离散值,如:宽度、高度、minX/Y、maxX/Y。
它不支持 Autolayout。在需要时,您可以与 Autolayout 一起使用。
PLXFrameLayout 定义为 UIView
类的一个分类。它包含了一组方法来配置视图的尺寸和位置,与其父视图或其他视图相关。在底层,所有的 PLXFrameLayout 方法都计算并设置 view.frame
属性。
让我们看看以下典型的基于框架的布局。
- (void)layoutSubviews {
[super layoutSubviews];
[self.titleLabel sizeToFit];
CGRect titleLabelFrame = self.titleLabel.frame;
titleLabelFrame.origin.x = CGRectGetMidX(self.bounds) - (CGRectGetWidth(titleLabelFrame) * 0.5f);
titleLabelFrame.origin.y = CGRectGetMidY(self.bounds) - (CGRectGetHeight(titleLabelFrame) * 0.5f);
self.titleLabel.frame = titleLabelFrame;
[self.captionLabel sizeToFit];
CGRect captionLabelFrame = self.captionLabel.frame;
captionLabelFrame.origin.y = CGRectGetMaxY(self.titleLabel.frame) + 10.f;
captionLabelFrame.origin.x = CGRectGetMinX(self.titleLabel.frame);
self.captionLabel.frame = captionLabelFrame;
CGRect otherViewFrame = self.otherView.frame;
otherViewFrame.origin.x = CGRectGetMaxX(self.titleLabel.frame) + 10.f;
otherViewFrame.origin.y = CGRectGetMidY(self.titleLabel.frame) - (CGRectGetHeight(otherViewFrame) * 0.5f);
otherViewFrame.size.width = CGRectGetWidth(self.bounds) - CGRectGetMinX(otherViewFrame) - 10.f;
self.otherView.frame = otherViewFrame;
}
现在,让我们看看使用 PLXFrameLayout
的实现。
- (void)layoutSubviews {
[super layoutSubviews];
[self plx_sizeToFitSubviews];
[self.titleLabel plx_centerInSuperView];
[self.captionLabel plx_placeUnderAligningToLeft:self.titleLabel withMargin:10.f];
[self.otherView plx_placeOnRightOf:self.titleLabel withMargin:10.f];
[self.otherView plx_expandToSuperViewEdge:NSLayoutAttributeRight withInset:10.f];
[self.otherView plx_alignToAttribute:NSLayoutAttributeCenterY ofView:self.titleLabel offset:0];
}
这是使用 PLXFrameLayout
实现的一种方法。它看起来比使用大量 CGRect
函数和结构体复制的方式进行得更好、更易读。
在第一行中,我们通过一个方法调用将视图居中在父视图上。然后我们将 captionLabel
放在 titleLabel
下方,并通过一个方法将它的 x
对齐到 titleView
的相同属性值。 otherView
被放在 titleLabel
的右侧,然后它的宽度被扩展,使得 maxX
等于父视图的 maxX
减去内边距(10.f
),最后它相对于 titleLabel
的中心 y
进行居中。
将 pod PLXFrameLayout 添加到您的 Podfile 中
pod 'PLXFrameLayout'
从 Terminal 中运行 pod install
,然后打开您的 app 的 .xcworkspace 文件以启动您的 IDE。
导入头文件
#import "UIView+PLXFrameLayout.h"
UIView+PLXFrameLayout.h
和 UIView+PLXFrameLayout.m
拖放到您的项目中;UIView+PLXFrameLayout.m
属于您的 app 目标;#import UIView+PLXFrameLayout.h
添加到您的文件中。有一些最常用的属性,您可能想要更改以实现视图所需布局。
@property(nonatomic, assign, setter=pl_setMinY:) CGFloat plx_minY;
@property(nonatomic, assign, setter=pl_setMidY:) CGFloat plx_midY;
@property(nonatomic, assign, setter=pl_setMaxY:) CGFloat plx_maxY;
@property(nonatomic, assign, setter=pl_setMinX:) CGFloat plx_minX;
@property(nonatomic, assign, setter=pl_setMidX:) CGFloat plx_midX;
@property(nonatomic, assign, setter=pl_setMaxX:) CGFloat plx_maxX;
@property(nonatomic, assign, setter=pl_setWidth:) CGFloat plx_width;
@property(nonatomic, assign, setter=pl_setHeight:) CGFloat plx_height;
@property(nonatomic, assign, setter=pl_setSize:) CGSize plx_size;
@property(nonatomic, assign, setter=pl_setFrame:) CGRect plx_frame;
每个属性都是可分配的。这意味着不再有必要复制一个CGRect
,然后修改它并重新分配。例如,修改plx_midX
会考虑其宽度改变视图的x
值,因此可以将其视为视图的中心x。
有几个方法使得容易将视图相对于其superview或其兄弟视图居中。
- (void)plx_centerInSuperView;
- (void)plx_centerXInSuperView;
- (void)plx_centerYInSuperView;
- (void)plx_alignToCenterOfView:(UIView *)view;
- (void)plx_alignToCenterXOfView:(UIView *)view;
- (void)plx_alignToCenterYOfView:(UIView *)view;
有许多方法使得视图的对齐变得简单。
最基本的允许两种给定视图的任何属性对齐。然而,不是所有的属性组合都是有意义的或受到支持的。
- (void)plx_alignAttribute:(NSLayoutAttribute)attribute toAttribute:(NSLayoutAttribute)outerAttribute ofView:(UIView *)view;
- (void)plx_alignAttribute:(NSLayoutAttribute)attribute toAttribute:(NSLayoutAttribute)outerAttribute ofView:(UIView *)view offset:(CGFloat)offset;
- (void)plx_alignAttribute:(NSLayoutAttribute)attribute toAttribute:(NSLayoutAttribute)outerAttribute ofView:(UIView *)view multiplier:(CGFloat)multiplier;
- (void)plx_alignAttribute:(NSLayoutAttribute)attribute toAttribute:(NSLayoutAttribute)outerAttribute ofView:(UIView *)view multiplier:(CGFloat)multiplier offset:(CGFloat)offset;
最后一个基本的方法是所有其他方法的语法糖。它看起来与其Autolayout等效,表现也相似。
如果想要对齐两个视图的相同属性,可以使用额外的方法。
- (void)plx_alignToAttribute:(NSLayoutAttribute)edgeAttribute ofView:(UIView *)view withOffset:(CGFloat)offset;
最后有一个允许将视图的给定属性与其superview的相同属性对齐的方法。
- (void)plx_alignToSuperViewAttribute:(NSLayoutAttribute)edgeAttribute withOffset:(CGFloat)offset;
以下方法易于使用和理解。它们帮助在给定视图的下方/上方/左侧/右侧定位视图:两个具有X轴额外对齐的额外变化。
注意:margin
始终具有正值(与上面的offset
参数相反)。例如,使用plx_placeOnLeftOf:withMargin:
,正的margin
值将使视图更靠近左侧(而不是右侧,在X轴方向)。
- (void)plx_placeUnder:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeAbove:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeOnLeftOf:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeOnRightOf:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeAboveAligningCenterX:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeAboveAligningToLeft:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeAboveAligningToRight:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeUnderAligningCenterX:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeUnderAligningToLeft:(UIView *)view withMargin:(CGFloat)margin;
- (void)plx_placeUnderAligningToRight:(UIView *)view withMargin:(CGFloat)margin;
有两个核心方法plx_alignViewsVertically
和plx_alignViewsHorizontally:
,以及它们的变体,允许批量视图对齐。它们接受一个视图数组和数字(作为视图之间的间距)。
注意:每个方法返回所有对齐视图的总量和间距的高度。
- (CGFloat)plx_alignViewsVertically:(NSArray *)viewsAndSpacings;
- (CGFloat)plx_alignViewsVerticallyCentering:(NSArray *)viewsAndSpacings;
- (CGFloat)plx_alignViewsVertically:(NSArray *)viewsAndSpacings centeringWithMargin:(CGFloat)spaceFromCenter;
- (CGFloat)plx_alignViewsVertically:(NSArray *)viewsAndSpacings additionallyAligningTo:(NSLayoutAttribute)attribute withMargin:(CGFloat)marginFromAttribute;
- (CGFloat)plx_alignViewsHorizontally:(NSArray *)viewsAndSpacings;
- (CGFloat)plx_alignViewsHorizontallyCentering:(NSArray *)viewsAndSpacings;
- (CGFloat)plx_alignViewsHorizontally:(NSArray *)viewsAndSpacings centeringWithMargin:(CGFloat)spaceFromCenter;
- (CGFloat)plx_alignViewsHorizontally:(NSArray *)viewsAndSpacings additionallyAligningTo:(NSLayoutAttribute)attribute withMargin:(CGFloat)marginFromAttribute;
以下是一个示例。
[self plx_alignViewsVertically:@[
self.titleLabel,
@20,
self.captionLabel,
]];
这段代码意味着titleLabel
将相对于superview的上边对齐,然后在它下方20点位置放置captionLabel
。在这个例子中,x
属性值将不会修改。
有一些方法可以帮助扩展视图(而不仅仅是对齐它们的边缘)。
- (void)plx_expandToSuperViewEdges;
- (void)plx_expandToSuperViewEdgesWithInsets:(UIEdgeInsets)insets;
- (void)plx_expandToSuperViewHorizontalEdgesWithInsets:(UIEdgeInsets)insets;
- (void)plx_expandToSuperViewVerticalEdgesWithInsets:(UIEdgeInsets)insets;
- (void)plx_expandToSuperViewEdge:(NSLayoutAttribute)edge withInset:(CGFloat)inset;
前两种方法将视图大小调整到superview的边界。它类似于self.titleLabel.frame = self.bounds;
,但是可以根据需要传递内边距。
接下来两个方法允许在希望的轴(水平(X)或垂直(Y))上扩展视图。这意味着例如,如果self.titleLabel
应该填充superview的所有宽度(从0到superview的bounds maxX),但不更改y
和height
属性 - 应使用plx_expandToSuperViewVerticalEdgesWithInsets:
。
最后一个方法允许扩展只有一个边缘到superview的同一边缘,被NSLayoutAttributeTop/Bottom/Left/Right
标识。
有时有一些视图没有固有的内容大小(例如,滚动视图),它们的宽度(或高度)必须动态计算并设置。在这些情况下,以下两个方法可能有助于。
- (void)plx_fillSuperViewVertically:(NSArray *)viewsAndSpacings expandableViews:(NSArray *)expandableViews;
- (void)plx_fillSuperViewHorizontally:(NSArray *)viewsAndSpacing expandableViews:(NSArray *)expandableViews;
它们与plx_alignViewsVertically/Horizontally:
方法类似,但有一个额外的参数。这是一个视图数组(还应列表在第一个参数中)允许扩展(不仅仅是对齐)。
以下是一个示例。
[self plx_fillSuperViewVertically:@[
self.titleLabel,
self.tableView,
self.footerLabel,
] expandableViews:@[self.tableView]];
这意味着视图将在垂直轴上对齐,但表格视图将扩展以填充可用的superview空间(高度)。
有时需要在超视图中等距分配视图(它们之间有相等的边距)。以下方法可以实现这一点。
- (void)plx_distributeSubviewsVerticallyInSuperView:(NSArray *)subviews withTopAndBottomMargin:(BOOL)shouldAddTopAndBottomMargins;
- (void)plx_distributeSubviewsHorizontallyInSuperView:(NSArray *)subviews withLeftAndRightMargin:(BOOL)shouldAddLeftAndRightMargin;
注意:每种方法的第二个参数确定是否在计算中考虑超视图边缘与第一个和最后一个视图之间的边距。
请随时通过拉取请求或创建问题进行贡献。
PLXFrameLayout 在MIT许可证下发布。有关详细信息,请参阅LICENSE文件。