2019-12-04 13:29:26 +08:00
|
|
|
/*
|
|
|
|
* Copyright [2019] [Doric.Pub]
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
//
|
|
|
|
// Created by pengfei.zhou on 2019/10/23.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "DoricLayouts.h"
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
#import "UIView+Doric.h"
|
2020-04-03 16:36:43 +08:00
|
|
|
#import "DoricExtensions.h"
|
2021-11-17 10:23:21 +08:00
|
|
|
#import <QuartzCore/QuartzCore.h>
|
2019-12-04 13:29:26 +08:00
|
|
|
|
2021-04-07 17:24:33 +08:00
|
|
|
void DoricAddEllipticArcPath(CGMutablePathRef path,
|
|
|
|
CGPoint origin,
|
|
|
|
CGFloat radius,
|
|
|
|
CGFloat startAngle,
|
|
|
|
CGFloat endAngle) {
|
|
|
|
CGAffineTransform t = CGAffineTransformMakeTranslation(origin.x, origin.y);
|
|
|
|
CGPathAddArc(path, &t, 0, 0, radius, startAngle, endAngle, NO);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CGPathRef DoricCreateRoundedRectPath(CGRect bounds,
|
|
|
|
CGFloat leftTop,
|
|
|
|
CGFloat rightTop,
|
|
|
|
CGFloat rightBottom,
|
|
|
|
CGFloat leftBottom) {
|
|
|
|
const CGFloat minX = CGRectGetMinX(bounds);
|
|
|
|
const CGFloat minY = CGRectGetMinY(bounds);
|
|
|
|
const CGFloat maxX = CGRectGetMaxX(bounds);
|
|
|
|
const CGFloat maxY = CGRectGetMaxY(bounds);
|
|
|
|
|
|
|
|
CGMutablePathRef path = CGPathCreateMutable();
|
|
|
|
DoricAddEllipticArcPath(path, (CGPoint) {
|
|
|
|
minX + leftTop, minY + leftTop
|
|
|
|
}, leftTop, M_PI, 3 * M_PI_2);
|
|
|
|
DoricAddEllipticArcPath(path, (CGPoint) {
|
|
|
|
maxX - rightTop, minY + rightTop
|
|
|
|
}, rightTop, 3 * M_PI_2, 0);
|
|
|
|
DoricAddEllipticArcPath(path, (CGPoint) {
|
|
|
|
maxX - rightBottom, maxY - rightBottom
|
|
|
|
}, rightBottom, 0, M_PI_2);
|
|
|
|
DoricAddEllipticArcPath(path, (CGPoint) {
|
|
|
|
minX + leftBottom, maxY - leftBottom
|
|
|
|
}, leftBottom, M_PI_2, M_PI);
|
|
|
|
CGPathCloseSubpath(path);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2019-12-04 13:29:26 +08:00
|
|
|
static const void *kLayoutConfig = &kLayoutConfig;
|
|
|
|
|
2021-11-17 10:23:21 +08:00
|
|
|
@interface DoricShapeLayer : CAShapeLayer
|
|
|
|
@property CGRect viewBounds;
|
|
|
|
@property UIEdgeInsets corners;
|
|
|
|
@end
|
2021-11-16 20:47:18 +08:00
|
|
|
|
2021-11-17 10:23:21 +08:00
|
|
|
@implementation DoricShapeLayer
|
2021-11-16 20:47:18 +08:00
|
|
|
@end
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
@implementation UIView (DoricLayout)
|
|
|
|
@dynamic doricLayout;
|
2019-12-04 13:29:26 +08:00
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)setDoricLayout:(DoricLayout *)doricLayout {
|
|
|
|
objc_setAssociatedObject(self, kLayoutConfig, doricLayout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (DoricLayout *)doricLayout {
|
|
|
|
DoricLayout *layout = objc_getAssociatedObject(self, kLayoutConfig);
|
|
|
|
if (!layout) {
|
|
|
|
layout = [DoricLayout new];
|
|
|
|
layout.width = self.width;
|
|
|
|
layout.height = self.height;
|
|
|
|
layout.view = self;
|
|
|
|
self.doricLayout = layout;
|
|
|
|
}
|
|
|
|
return layout;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
@interface DoricLayout ()
|
2022-08-19 14:52:43 +08:00
|
|
|
@property(nonatomic, assign) BOOL needRemeasure;
|
|
|
|
@property(nonatomic, assign) BOOL remeasuring;
|
2019-12-04 19:02:15 +08:00
|
|
|
@end
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
@implementation DoricLayout
|
|
|
|
- (instancetype)init {
|
|
|
|
if (self = [super init]) {
|
|
|
|
_widthSpec = DoricLayoutJust;
|
|
|
|
_heightSpec = DoricLayoutJust;
|
2020-04-11 09:38:27 +08:00
|
|
|
_maxWidth = CGFLOAT_MAX;
|
|
|
|
_maxHeight = CGFLOAT_MAX;
|
2022-08-18 19:57:22 +08:00
|
|
|
_minWidth = -1;
|
|
|
|
_minHeight = -1;
|
2022-08-19 12:04:22 +08:00
|
|
|
_needRemeasure = NO;
|
|
|
|
_remeasuring = NO;
|
2020-04-03 16:36:43 +08:00
|
|
|
}
|
|
|
|
return self;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2021-07-29 11:36:49 +08:00
|
|
|
- (void)setMeasuredWidth:(CGFloat)measuredWidth {
|
|
|
|
_measuredWidth = MAX(0, measuredWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setMeasuredHeight:(CGFloat)measuredHeight {
|
|
|
|
_measuredHeight = MAX(0, measuredHeight);
|
|
|
|
}
|
|
|
|
|
2020-04-03 18:15:43 +08:00
|
|
|
- (void)apply:(CGSize)frameSize {
|
2020-04-03 16:36:43 +08:00
|
|
|
self.resolved = NO;
|
2020-04-03 18:15:43 +08:00
|
|
|
[self measure:frameSize];
|
2020-04-03 16:36:43 +08:00
|
|
|
[self setFrame];
|
2020-04-08 19:30:08 +08:00
|
|
|
self.resolved = YES;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:15:43 +08:00
|
|
|
- (void)apply {
|
|
|
|
[self apply:self.view.frame.size];
|
|
|
|
}
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)measure:(CGSize)targetSize {
|
2020-04-13 11:57:31 +08:00
|
|
|
[self measureSelf:targetSize];
|
|
|
|
[self layout];
|
|
|
|
}
|
|
|
|
|
2022-08-17 17:54:10 +08:00
|
|
|
#pragma helper
|
|
|
|
|
2022-08-23 17:50:46 +08:00
|
|
|
- (BOOL)remeasuring {
|
|
|
|
return _remeasuring || [self.superLayout remeasuring];
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)hasWidthWeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.inHLayout && self.weight > 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)hasHeightWeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.inVLayout && self.weight > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)fitWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.widthSpec == DoricLayoutFit;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)fitHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.heightSpec == DoricLayoutFit;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)justWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.widthSpec == DoricLayoutJust;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)justHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.heightSpec == DoricLayoutJust;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)mostWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.widthSpec == DoricLayoutMost;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)mostHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.heightSpec == DoricLayoutMost;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (DoricLayout *)superLayout {
|
|
|
|
return self.view.superview.doricLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superFitWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.fitWidth;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superFitHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.fitHeight;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superJustWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.justWidth;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superJustHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.justHeight;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superMostWidth {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.mostWidth;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)superMostHeight {
|
2022-08-17 17:54:10 +08:00
|
|
|
return self.superLayout.mostHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (BOOL)inScrollable {
|
|
|
|
return [self.view.superview isKindOfClass:UIScrollView.class];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)inVLayout {
|
|
|
|
return self.superLayout.layoutType == DoricVLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)inHLayout {
|
|
|
|
return self.superLayout.layoutType == DoricHLayout;
|
|
|
|
}
|
|
|
|
|
2022-08-23 17:50:46 +08:00
|
|
|
- (BOOL)inStack {
|
|
|
|
return self.superLayout.layoutType == DoricStack;
|
|
|
|
}
|
|
|
|
|
2022-08-17 17:54:10 +08:00
|
|
|
- (CGFloat)takenWidth {
|
|
|
|
return self.measuredWidth + self.marginLeft + self.marginRight;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)takenHeight {
|
|
|
|
return self.measuredHeight + self.marginTop + self.marginBottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGSize)removeMargin:(CGSize)targetSize {
|
|
|
|
return CGSizeMake(
|
|
|
|
targetSize.width - self.marginLeft - self.marginRight,
|
|
|
|
targetSize.height - self.marginTop - self.marginBottom);
|
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (BOOL)restrain:(CGSize)limit {
|
2022-08-17 17:54:10 +08:00
|
|
|
BOOL needRemeasure = NO;
|
|
|
|
if (self.measuredWidth > self.maxWidth) {
|
|
|
|
self.measuredWidth = self.maxWidth;
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
|
|
|
if (self.measuredHeight > self.maxHeight) {
|
|
|
|
self.measuredHeight = self.maxHeight;
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
|
|
|
if (self.measuredWidth < self.minWidth) {
|
|
|
|
self.measuredWidth = self.minWidth;
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
|
|
|
if (self.measuredHeight < self.minHeight) {
|
|
|
|
self.measuredHeight = self.minHeight;
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
2022-08-18 19:57:22 +08:00
|
|
|
|
|
|
|
if (self.measuredWidth > limit.width && !self.hasWidthWeight && !self.inScrollable) {
|
|
|
|
self.measuredWidth = MIN(limit.width, self.measuredWidth);
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.measuredHeight > limit.height && !self.hasHeightWeight && !self.inScrollable) {
|
|
|
|
self.measuredHeight = MIN(limit.height, self.measuredHeight);
|
|
|
|
needRemeasure = YES;
|
|
|
|
}
|
|
|
|
|
2022-08-17 17:54:10 +08:00
|
|
|
return needRemeasure;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)rect:(CGRect)rect1 equalTo:(CGRect)rect2 {
|
|
|
|
return ABS(rect1.origin.x - rect2.origin.x) < 0.00001f
|
|
|
|
&& ABS(rect1.origin.y - rect2.origin.y) < 0.00001f
|
|
|
|
&& ABS(rect1.size.width - rect2.size.width) < 0.00001f
|
|
|
|
&& ABS(rect1.size.height - rect2.size.height) < 0.00001f;
|
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (CGSize)removeSizePadding:(CGSize)size {
|
|
|
|
return CGSizeMake([self removeWidthPadding:size.width],
|
|
|
|
[self removeHeightPadding:size.height]);
|
|
|
|
}
|
2022-08-17 17:54:10 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (CGFloat)removeWidthPadding:(CGFloat)size {
|
|
|
|
return size - self.paddingLeft - self.paddingRight;
|
|
|
|
}
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (CGFloat)removeHeightPadding:(CGFloat)size {
|
|
|
|
return size - self.paddingTop - self.paddingBottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)addWidthPadding:(CGFloat)size {
|
|
|
|
return size + self.paddingLeft + self.paddingRight;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)addHeightPadding:(CGFloat)size {
|
|
|
|
return size + self.paddingTop + self.paddingBottom;
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)needFitWidth {
|
2022-08-23 17:50:46 +08:00
|
|
|
if (self.widthSpec == DoricLayoutFit) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.widthSpec == DoricLayoutJust) {
|
|
|
|
return self.hasWidthWeight;
|
|
|
|
}
|
|
|
|
if (self.widthSpec == DoricLayoutMost) {
|
|
|
|
if (self.superLayout.needFitWidth) {
|
|
|
|
if (!self.remeasuring) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.inHLayout) {
|
|
|
|
if (self.superLayout.fitWidth) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (!self.superLayout.inHLayout) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.superLayout.superLayout.inStack) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.superLayout.superLayout.superMostHeight) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
2022-08-18 19:57:22 +08:00
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (BOOL)needFitHeight {
|
2022-08-23 17:50:46 +08:00
|
|
|
if (self.heightSpec == DoricLayoutFit) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.heightSpec == DoricLayoutJust) {
|
|
|
|
return self.hasHeightWeight;
|
|
|
|
}
|
|
|
|
if (self.heightSpec == DoricLayoutMost) {
|
|
|
|
if (self.superLayout.needFitHeight) {
|
|
|
|
if (!self.remeasuring) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.inVLayout) {
|
|
|
|
if (self.superLayout.fitHeight) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (!self.superLayout.inVLayout) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.superLayout.superLayout.inStack) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if (self.superLayout.superLayout.superMostWidth) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
2022-08-18 19:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (NSString *)getLayoutType {
|
|
|
|
switch (self.layoutType) {
|
|
|
|
case DoricVLayout:
|
|
|
|
return @"VLayout";
|
|
|
|
case DoricHLayout:
|
|
|
|
return @"HLayout";
|
|
|
|
case DoricStack:
|
|
|
|
return @"Stack";
|
|
|
|
default:
|
|
|
|
return [NSString stringWithFormat:@"Undefined:%@", self.view.class];
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2022-08-18 19:57:22 +08:00
|
|
|
}
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
|
|
|
|
- (NSString *)getSpecType:(DoricLayoutSpec)spec {
|
|
|
|
switch (spec) {
|
|
|
|
case DoricLayoutJust:
|
|
|
|
return @"JUST";
|
|
|
|
case DoricLayoutMost:
|
|
|
|
return @"MOST";
|
|
|
|
default:
|
|
|
|
return @"FIT";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)toString {
|
|
|
|
return [NSString stringWithFormat:@"%@[width:%@,height:%@]",
|
|
|
|
[self getLayoutType],
|
|
|
|
[self getSpecType:self.widthSpec],
|
|
|
|
[self getSpecType:self.heightSpec]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma measureSelf
|
|
|
|
|
|
|
|
- (void)measureSelf:(CGSize)remainingSize {
|
|
|
|
CGFloat limitWidth = remainingSize.width;
|
|
|
|
CGFloat limitHeight = remainingSize.height;
|
|
|
|
|
|
|
|
if (self.inScrollable) {
|
|
|
|
if (self.fitWidth) {
|
|
|
|
limitWidth = CGFLOAT_MAX;
|
2022-08-17 17:10:25 +08:00
|
|
|
}
|
2022-08-18 19:57:22 +08:00
|
|
|
if (self.fitHeight) {
|
|
|
|
limitHeight = CGFLOAT_MAX;
|
2022-08-17 17:10:25 +08:00
|
|
|
}
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureSelf:remainingSize
|
|
|
|
limitTo:CGSizeMake(limitWidth, limitHeight)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)measureSelf:(CGSize)remainingSize limitTo:(CGSize)limitSize {
|
|
|
|
|
|
|
|
CGFloat remainingWidth = remainingSize.width;
|
|
|
|
CGFloat remainingHeight = remainingSize.height;
|
|
|
|
|
|
|
|
CGFloat limitWidth = limitSize.width;
|
|
|
|
CGFloat limitHeight = limitSize.height;
|
2020-04-03 17:28:55 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
if (self.justWidth && !self.hasWidthWeight) {
|
|
|
|
remainingWidth = limitWidth = self.width;
|
|
|
|
}
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
if (self.justHeight && !self.hasHeightWeight) {
|
|
|
|
remainingHeight = limitHeight = self.height;
|
2020-04-11 12:20:43 +08:00
|
|
|
}
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureSelf:CGSizeMake(remainingWidth, remainingHeight)
|
|
|
|
limitTo:CGSizeMake(limitWidth, limitHeight)
|
|
|
|
restrain:YES];
|
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
- (void)measureSelf:(CGSize)remainingSize limitTo:(CGSize)limitSize restrain:(BOOL)needRestrain {
|
2022-08-19 12:04:22 +08:00
|
|
|
self.needRemeasure = NO;
|
|
|
|
self.remeasuring = NO;
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureContent:[self removeSizePadding:remainingSize]
|
|
|
|
limitTo:[self removeSizePadding:limitSize]];
|
|
|
|
|
|
|
|
if (self.needFitWidth) {
|
2022-08-19 14:52:43 +08:00
|
|
|
self.measuredWidth = self.contentWidth
|
|
|
|
+ self.paddingLeft + self.paddingRight
|
|
|
|
+ (self.justWidth ? self.width : 0);
|
2022-08-18 19:57:22 +08:00
|
|
|
} else if (self.mostWidth) {
|
|
|
|
self.measuredWidth = remainingSize.width;
|
|
|
|
} else {
|
|
|
|
self.measuredWidth = self.width;
|
2022-08-17 17:10:25 +08:00
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
if (self.needFitHeight) {
|
2022-08-19 14:52:43 +08:00
|
|
|
self.measuredHeight = self.contentHeight
|
|
|
|
+ self.paddingTop + self.paddingBottom
|
|
|
|
+ (self.justHeight ? self.height : 0);
|
2022-08-18 19:57:22 +08:00
|
|
|
} else if (self.mostHeight) {
|
|
|
|
self.measuredHeight = remainingSize.height;
|
|
|
|
} else {
|
|
|
|
self.measuredHeight = self.height;
|
2022-08-17 17:10:25 +08:00
|
|
|
}
|
|
|
|
|
2022-08-19 14:52:43 +08:00
|
|
|
if ([self.view isKindOfClass:[UIImageView class]]) {
|
|
|
|
if (self.needFitWidth && self.heightSpec != DoricLayoutFit && self.contentWidth > 0) {
|
|
|
|
self.measuredWidth = self.contentWidth / self.contentHeight * self.measuredHeight
|
|
|
|
+ self.paddingLeft + self.paddingRight;
|
|
|
|
}
|
|
|
|
if (self.needFitHeight && self.widthSpec != DoricLayoutFit && self.contentHeight > 0) {
|
|
|
|
self.measuredHeight = self.contentHeight / self.contentWidth * self.measuredWidth
|
|
|
|
+ self.paddingLeft + self.paddingRight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-19 12:04:22 +08:00
|
|
|
if (needRestrain
|
|
|
|
&& [self restrain:limitSize]
|
|
|
|
&& self.layoutType != DoricUndefined
|
|
|
|
) {
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize size = [self removeSizePadding:CGSizeMake(
|
|
|
|
self.measuredWidth,
|
|
|
|
self.measuredHeight)];
|
|
|
|
[self measureSelf:size limitTo:size restrain:NO];
|
|
|
|
}
|
2022-08-19 12:04:22 +08:00
|
|
|
|
|
|
|
if (self.needRemeasure) {
|
|
|
|
self.remeasuring = YES;
|
2022-08-19 14:52:43 +08:00
|
|
|
CGFloat width, limitWidth;
|
|
|
|
width = limitWidth = [self removeWidthPadding:self.measuredWidth];
|
|
|
|
CGFloat height, limitHeight;
|
|
|
|
height = limitHeight = [self removeHeightPadding:self.measuredHeight];
|
|
|
|
if (self.needFitWidth) {
|
|
|
|
limitWidth = limitSize.width;
|
|
|
|
}
|
|
|
|
if (self.needFitHeight) {
|
|
|
|
limitHeight = limitSize.height;
|
|
|
|
}
|
|
|
|
[self measureContent:CGSizeMake(width, height)
|
|
|
|
limitTo:CGSizeMake(limitWidth, limitHeight)];
|
|
|
|
|
|
|
|
if (self.needFitWidth) {
|
|
|
|
if ([self.view isKindOfClass:[UIImageView class]]
|
|
|
|
&& self.heightSpec != DoricLayoutFit && self.contentHeight > 0) {
|
|
|
|
self.measuredWidth = self.contentWidth / self.contentHeight * self.measuredHeight
|
|
|
|
+ self.paddingLeft + self.paddingRight;
|
|
|
|
} else {
|
|
|
|
self.measuredWidth = self.contentWidth
|
|
|
|
+ self.paddingLeft + self.paddingRight
|
|
|
|
+ (self.justWidth ? self.width : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.needFitHeight) {
|
|
|
|
if ([self.view isKindOfClass:[UIImageView class]]
|
|
|
|
&& self.widthSpec != DoricLayoutFit && self.contentHeight > 0) {
|
|
|
|
self.measuredHeight = self.contentHeight / self.contentWidth * self.measuredWidth
|
|
|
|
+ self.paddingLeft + self.paddingRight;
|
|
|
|
} else {
|
|
|
|
self.measuredHeight = self.contentHeight
|
|
|
|
+ self.paddingTop + self.paddingBottom
|
|
|
|
+ (self.justHeight ? self.height : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-19 12:04:22 +08:00
|
|
|
self.remeasuring = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((self.mostWidth && self.superLayout.needFitWidth)
|
|
|
|
|| (self.mostHeight && self.superLayout.needFitHeight)) {
|
|
|
|
self.superLayout.needRemeasure = YES;
|
|
|
|
}
|
2020-04-11 12:20:43 +08:00
|
|
|
}
|
|
|
|
|
2022-08-17 17:54:10 +08:00
|
|
|
#pragma measureContent
|
2022-08-17 17:10:25 +08:00
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (void)measureContent:(CGSize)remaining limitTo:(CGSize)limit {
|
2020-04-03 16:36:43 +08:00
|
|
|
switch (self.layoutType) {
|
|
|
|
case DoricStack: {
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureStackContent:remaining limitTo:limit];
|
2020-04-03 16:36:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DoricVLayout: {
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureVLayoutContent:remaining limitTo:limit];
|
2020-04-03 16:36:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DoricHLayout: {
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureHLayoutContent:remaining limitTo:limit];
|
2020-04-03 16:36:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
2022-08-18 19:57:22 +08:00
|
|
|
[self measureUndefinedContent:remaining];
|
2020-04-03 16:36:43 +08:00
|
|
|
break;
|
2020-03-20 15:27:09 +08:00
|
|
|
}
|
|
|
|
}
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2021-11-16 20:47:18 +08:00
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)measureUndefinedContent:(CGSize)targetSize {
|
|
|
|
CGSize measuredSize = [self.view sizeThatFits:targetSize];
|
2021-05-13 16:18:21 +08:00
|
|
|
|
|
|
|
self.contentWidth = measuredSize.width;
|
|
|
|
self.contentHeight = measuredSize.height;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (void)measureStackContent:(CGSize)remaining limitTo:(CGSize)limit {
|
2020-04-03 16:36:43 +08:00
|
|
|
CGFloat contentWidth = 0, contentHeight = 0;
|
2022-08-19 14:52:43 +08:00
|
|
|
BOOL existsWidthContent = NO, existsHeightContent = NO;
|
2020-04-03 16:36:43 +08:00
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childRemaining = [layout removeMargin:remaining];
|
|
|
|
CGSize childLimit = [layout removeMargin:limit];
|
|
|
|
[layout measureSelf:childRemaining limitTo:childLimit];
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!(layout.mostWidth && self.fitWidth)) {
|
|
|
|
existsWidthContent = YES;
|
|
|
|
contentWidth = MAX(contentWidth, layout.takenWidth);
|
|
|
|
}
|
|
|
|
if (!(layout.mostHeight && self.fitHeight)) {
|
|
|
|
existsHeightContent = YES;
|
|
|
|
contentHeight = MAX(contentHeight, layout.takenHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!existsWidthContent) {
|
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
contentWidth = MAX(contentWidth, layout.takenWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!existsHeightContent) {
|
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
contentHeight = MAX(contentHeight, layout.takenHeight);
|
|
|
|
}
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
self.contentWidth = contentWidth;
|
2019-12-04 13:29:26 +08:00
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
self.contentHeight = contentHeight;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (void)measureVLayoutContent:(CGSize)remaining limitTo:(CGSize)limit {
|
2020-04-03 17:17:40 +08:00
|
|
|
CGFloat contentWidth = 0, contentHeight = 0, contentWeight = 0;
|
2020-04-03 16:36:43 +08:00
|
|
|
BOOL had = NO;
|
2022-08-19 14:52:43 +08:00
|
|
|
BOOL existsContent = NO;
|
2020-04-03 16:36:43 +08:00
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
had = YES;
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childRemaining = [layout removeMargin:CGSizeMake(
|
|
|
|
remaining.width,
|
2022-08-23 17:50:46 +08:00
|
|
|
(self.contentWeight > 0 || layout.hasHeightWeight) ? remaining.height : remaining.height - contentHeight)];
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childLimit = [layout removeMargin:CGSizeMake(
|
|
|
|
limit.width,
|
2022-08-23 17:50:46 +08:00
|
|
|
(self.contentWeight > 0 || layout.hasHeightWeight) ? limit.height : limit.height - contentHeight)];
|
2022-08-18 19:57:22 +08:00
|
|
|
[layout measureSelf:childRemaining limitTo:childLimit];
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!(layout.mostWidth && self.fitWidth)) {
|
|
|
|
existsContent = YES;
|
|
|
|
contentWidth = MAX(contentWidth, layout.takenWidth);
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
contentHeight += layout.takenHeight + self.spacing;
|
2020-04-03 17:17:40 +08:00
|
|
|
contentWeight += layout.weight;
|
2020-04-03 16:36:43 +08:00
|
|
|
}
|
2022-08-23 17:50:46 +08:00
|
|
|
self.contentWeight = contentWeight;
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!existsContent) {
|
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
contentWidth = MAX(contentWidth, layout.takenWidth);
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (had) {
|
|
|
|
contentHeight -= self.spacing;
|
|
|
|
}
|
2022-08-23 17:50:46 +08:00
|
|
|
BOOL reassign = NO;
|
|
|
|
if (contentWeight > 0) {
|
|
|
|
if (self.needFitHeight && self.inVLayout) {
|
|
|
|
if (self.remeasuring) {
|
|
|
|
reassign = YES;
|
|
|
|
} else {
|
|
|
|
self.superLayout.needRemeasure = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!self.needFitHeight && !self.hasHeightWeight) {
|
|
|
|
reassign = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reassign) {
|
2022-08-18 19:57:22 +08:00
|
|
|
CGFloat extra = remaining.height - contentHeight;
|
2020-04-03 17:17:40 +08:00
|
|
|
contentWidth = 0;
|
2021-07-29 11:36:49 +08:00
|
|
|
contentHeight = 0;
|
|
|
|
had = NO;
|
2020-04-03 17:17:40 +08:00
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-29 11:36:49 +08:00
|
|
|
had = YES;
|
2022-08-18 19:57:22 +08:00
|
|
|
CGFloat measuredHeight = layout.measuredHeight + extra / contentWeight * layout.weight;
|
2020-04-09 10:54:38 +08:00
|
|
|
layout.measuredHeight = measuredHeight;
|
2022-08-18 19:57:22 +08:00
|
|
|
|
2020-04-03 17:17:40 +08:00
|
|
|
//Need Remeasure
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childRemaining = CGSizeMake(
|
|
|
|
[layout removeWidthPadding:layout.measuredWidth],
|
|
|
|
[layout removeHeightPadding:measuredHeight]);
|
|
|
|
[layout measureContent:childRemaining limitTo:childRemaining];
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!(layout.mostWidth && self.fitWidth)) {
|
|
|
|
contentWidth = MAX(contentWidth, layout.takenWidth);
|
|
|
|
}
|
2021-07-29 11:36:49 +08:00
|
|
|
contentHeight += layout.takenHeight + self.spacing;
|
|
|
|
}
|
|
|
|
if (had) {
|
|
|
|
contentHeight -= self.spacing;
|
2020-04-03 17:17:40 +08:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
self.contentWidth = contentWidth;
|
|
|
|
|
|
|
|
self.contentHeight = contentHeight;
|
|
|
|
}
|
|
|
|
|
2022-08-18 19:57:22 +08:00
|
|
|
- (void)measureHLayoutContent:(CGSize)remaining limitTo:(CGSize)limit {
|
2020-04-03 17:17:40 +08:00
|
|
|
CGFloat contentWidth = 0, contentHeight = 0, contentWeight = 0;;
|
2020-04-03 16:36:43 +08:00
|
|
|
BOOL had = NO;
|
2022-08-19 14:52:43 +08:00
|
|
|
BOOL existsContent = NO;
|
2020-04-03 16:36:43 +08:00
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
2019-12-04 13:29:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
had = YES;
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childRemaining = [layout removeMargin:CGSizeMake(
|
2022-08-23 17:50:46 +08:00
|
|
|
(self.contentWeight > 0 || layout.hasWidthWeight) ? remaining.width : remaining.width - contentWidth,
|
2022-08-18 19:57:22 +08:00
|
|
|
remaining.height)];
|
|
|
|
CGSize childLimit = [layout removeMargin:CGSizeMake(
|
2022-08-23 17:50:46 +08:00
|
|
|
(self.contentWeight > 0 || layout.hasWidthWeight) ? limit.width : limit.width - contentWidth,
|
2022-08-18 19:57:22 +08:00
|
|
|
limit.height)];
|
|
|
|
[layout measureSelf:childRemaining limitTo:childLimit];
|
2020-04-03 16:36:43 +08:00
|
|
|
contentWidth += layout.takenWidth + self.spacing;
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!(layout.mostHeight && self.fitHeight)) {
|
|
|
|
existsContent = YES;
|
|
|
|
contentHeight = MAX(contentHeight, layout.takenHeight);
|
|
|
|
}
|
2020-04-03 17:17:40 +08:00
|
|
|
contentWeight += layout.weight;
|
2020-04-03 16:36:43 +08:00
|
|
|
}
|
2022-08-23 17:50:46 +08:00
|
|
|
self.contentWeight = contentWeight;
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!existsContent) {
|
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
contentHeight = MAX(contentHeight, layout.takenHeight);
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (had) {
|
|
|
|
contentWidth -= self.spacing;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2022-08-23 17:50:46 +08:00
|
|
|
BOOL reassign = NO;
|
|
|
|
if (contentWeight > 0) {
|
|
|
|
if (self.needFitWidth && self.inHLayout) {
|
|
|
|
if (self.remeasuring) {
|
|
|
|
reassign = YES;
|
|
|
|
} else {
|
|
|
|
self.superLayout.needRemeasure = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!self.needFitWidth && !self.hasWidthWeight) {
|
|
|
|
reassign = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (reassign) {
|
2022-08-18 19:57:22 +08:00
|
|
|
CGFloat extra = remaining.width - contentWidth;
|
2021-07-29 11:36:49 +08:00
|
|
|
contentWidth = 0;
|
2020-04-03 17:17:40 +08:00
|
|
|
contentHeight = 0;
|
2021-07-29 11:36:49 +08:00
|
|
|
had = NO;
|
2020-04-03 17:17:40 +08:00
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-29 11:36:49 +08:00
|
|
|
had = YES;
|
2022-08-18 19:57:22 +08:00
|
|
|
CGFloat measuredWidth = layout.measuredWidth + extra / contentWeight * layout.weight;
|
2020-04-09 10:54:38 +08:00
|
|
|
layout.measuredWidth = measuredWidth;
|
2020-04-03 17:17:40 +08:00
|
|
|
//Need Remeasure
|
2022-08-18 19:57:22 +08:00
|
|
|
CGSize childRemaining = CGSizeMake(
|
|
|
|
[layout removeWidthPadding:measuredWidth],
|
|
|
|
[layout removeHeightPadding:layout.measuredHeight]);
|
|
|
|
[layout measureContent:childRemaining limitTo:childRemaining];
|
2021-07-29 11:36:49 +08:00
|
|
|
contentWidth += layout.takenWidth + self.spacing;
|
2022-08-19 14:52:43 +08:00
|
|
|
if (!(layout.mostHeight && self.fitHeight)) {
|
|
|
|
contentHeight = MAX(contentHeight, layout.takenHeight);
|
|
|
|
}
|
2020-04-03 17:17:40 +08:00
|
|
|
}
|
2021-07-29 11:36:49 +08:00
|
|
|
if (had) {
|
|
|
|
contentWidth -= self.spacing;
|
|
|
|
}
|
2020-04-03 17:17:40 +08:00
|
|
|
}
|
|
|
|
|
2019-12-04 13:29:26 +08:00
|
|
|
self.contentWidth = contentWidth;
|
|
|
|
self.contentHeight = contentHeight;
|
|
|
|
}
|
|
|
|
|
2022-08-17 17:54:10 +08:00
|
|
|
#pragma layout
|
|
|
|
|
|
|
|
- (void)layout {
|
|
|
|
switch (self.layoutType) {
|
|
|
|
case DoricStack: {
|
|
|
|
[self layoutStack];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DoricVLayout: {
|
|
|
|
[self layoutVLayout];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DoricHLayout: {
|
|
|
|
[self layoutHLayout];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma setFrame
|
|
|
|
|
|
|
|
- (void)setFrame {
|
|
|
|
if (self.layoutType != DoricUndefined) {
|
|
|
|
[self.view.subviews forEach:^(__kindof UIView *obj) {
|
|
|
|
[obj.doricLayout setFrame];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
CGRect originFrame = CGRectMake(self.measuredX, self.measuredY, self.measuredWidth, self.measuredHeight);
|
|
|
|
if (!CGAffineTransformEqualToTransform(self.view.transform, CGAffineTransformIdentity)) {
|
|
|
|
CGPoint anchor = self.view.layer.anchorPoint;
|
|
|
|
originFrame = CGRectOffset(originFrame, -anchor.x * self.measuredWidth - self.measuredX, -anchor.y * self.measuredHeight - self.measuredY);
|
|
|
|
originFrame = CGRectApplyAffineTransform(originFrame, self.view.transform);
|
|
|
|
originFrame = CGRectOffset(originFrame, anchor.x * self.measuredWidth + self.measuredX, anchor.y * self.measuredHeight + self.measuredY);
|
|
|
|
}
|
|
|
|
BOOL isFrameChange = ![self rect:originFrame equalTo:self.view.frame];
|
|
|
|
if (isFrameChange) {
|
|
|
|
if (isnan(originFrame.origin.x) || isinf(originFrame.origin.x)
|
|
|
|
|| isnan(originFrame.origin.y) || isinf(originFrame.origin.y)
|
|
|
|
|| isnan(originFrame.size.width) || isinf(originFrame.size.width)
|
|
|
|
|| isnan(originFrame.size.height) || isinf(originFrame.size.height)
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
self.view.frame = originFrame;
|
|
|
|
}
|
|
|
|
if (!UIEdgeInsetsEqualToEdgeInsets(self.corners, UIEdgeInsetsZero)) {
|
|
|
|
if (self.view.layer.mask) {
|
|
|
|
if ([self.view.layer.mask isKindOfClass:[DoricShapeLayer class]]) {
|
|
|
|
DoricShapeLayer *shapeLayer = (DoricShapeLayer *) self.view.layer.mask;
|
|
|
|
if (!UIEdgeInsetsEqualToEdgeInsets(self.corners, shapeLayer.corners)
|
|
|
|
|| !CGRectEqualToRect(self.view.bounds, shapeLayer.viewBounds)) {
|
|
|
|
shapeLayer.corners = self.corners;
|
|
|
|
shapeLayer.viewBounds = self.view.bounds;
|
|
|
|
[self configMaskWithLayer:shapeLayer];
|
|
|
|
}
|
|
|
|
} else if (isFrameChange) {
|
|
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
|
|
|
[self configMaskWithLayer:shapeLayer];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DoricShapeLayer *shapeLayer = [DoricShapeLayer layer];
|
|
|
|
shapeLayer.corners = self.corners;
|
|
|
|
shapeLayer.viewBounds = self.view.bounds;
|
|
|
|
[self configMaskWithLayer:shapeLayer];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)configMaskWithLayer:(CAShapeLayer *)shapeLayer {
|
|
|
|
CGPathRef path = DoricCreateRoundedRectPath(self.view.bounds,
|
|
|
|
self.corners.top, self.corners.left, self.corners.bottom, self.corners.right);
|
|
|
|
shapeLayer.path = path;
|
|
|
|
if ((self.corners.left != self.corners.right
|
|
|
|
|| self.corners.left != self.corners.top
|
|
|
|
|| self.corners.left != self.corners.bottom)
|
|
|
|
&& self.view.layer.borderWidth > CGFLOAT_MIN) {
|
|
|
|
CAShapeLayer *lineLayer = [CAShapeLayer layer];
|
|
|
|
lineLayer.lineWidth = self.view.layer.borderWidth * 2;
|
|
|
|
lineLayer.strokeColor = self.view.layer.borderColor;
|
|
|
|
lineLayer.path = path;
|
|
|
|
lineLayer.fillColor = nil;
|
|
|
|
[[self.view.layer sublayers] forEach:^(__kindof CALayer *obj) {
|
|
|
|
if ([obj isKindOfClass:CAShapeLayer.class] && ((CAShapeLayer *) obj).lineWidth > CGFLOAT_MIN) {
|
|
|
|
[obj removeFromSuperlayer];
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
[self.view.layer addSublayer:lineLayer];
|
|
|
|
}
|
|
|
|
CGPathRelease(path);
|
|
|
|
self.view.layer.mask = shapeLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)layoutStack {
|
|
|
|
for (__kindof UIView *subview in self.view.subviews) {
|
|
|
|
DoricLayout *layout = subview.doricLayout;
|
|
|
|
if (layout.disabled) {
|
2019-12-04 13:29:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
[layout layout];
|
|
|
|
DoricGravity gravity = layout.alignment;
|
2020-03-27 10:07:53 +08:00
|
|
|
if ((gravity & DoricGravityLeft) == DoricGravityLeft) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.paddingLeft;
|
2020-03-27 10:07:53 +08:00
|
|
|
} else if ((gravity & DoricGravityRight) == DoricGravityRight) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.measuredWidth - self.paddingRight - layout.measuredWidth;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.measuredWidth / 2 - layout.measuredWidth / 2;
|
2019-12-04 13:29:26 +08:00
|
|
|
} else {
|
2021-05-07 18:47:33 +08:00
|
|
|
layout.measuredX = self.paddingLeft;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if ((gravity & DoricGravityTop) == DoricGravityTop) {
|
|
|
|
layout.measuredY = self.paddingTop;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityBottom) == DoricGravityBottom) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredY = self.measuredHeight - self.paddingBottom - layout.measuredHeight;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredY = self.measuredHeight / 2 - layout.measuredHeight / 2;
|
2019-12-04 13:29:26 +08:00
|
|
|
} else {
|
2021-05-07 18:47:33 +08:00
|
|
|
layout.measuredY = self.paddingTop;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-03-21 16:03:03 +08:00
|
|
|
|
|
|
|
if (!gravity) {
|
2020-04-03 16:36:43 +08:00
|
|
|
gravity = DoricGravityLeft | DoricGravityTop;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginLeft && !((gravity & DoricGravityRight) == DoricGravityRight)) {
|
|
|
|
layout.measuredX += layout.marginLeft;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginRight && !((gravity & DoricGravityLeft) == DoricGravityLeft)) {
|
|
|
|
layout.measuredX -= layout.marginRight;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginTop && !((gravity & DoricGravityBottom) == DoricGravityBottom)) {
|
|
|
|
layout.measuredY += layout.marginTop;
|
2020-03-21 17:03:52 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginBottom && !((gravity & DoricGravityTop) == DoricGravityTop)) {
|
|
|
|
layout.measuredY -= layout.marginBottom;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)layoutVLayout {
|
|
|
|
CGFloat yStart = self.paddingTop;
|
|
|
|
if ((self.gravity & DoricGravityTop) == DoricGravityTop) {
|
|
|
|
yStart = self.paddingTop;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((self.gravity & DoricGravityBottom) == DoricGravityBottom) {
|
2020-04-03 16:36:43 +08:00
|
|
|
yStart = self.measuredHeight - self.contentHeight - self.paddingBottom;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((self.gravity & DoricGravityCenterY) == DoricGravityCenterY) {
|
2020-04-03 16:36:43 +08:00
|
|
|
yStart = (self.measuredHeight - self.contentHeight - self.paddingTop - self.paddingBottom) / 2 + self.paddingTop;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
for (UIView *child in self.view.subviews) {
|
|
|
|
DoricLayout *layout = child.doricLayout;
|
|
|
|
if (layout.disabled) {
|
2019-12-04 13:29:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
[layout layout];
|
|
|
|
DoricGravity gravity = layout.alignment | self.gravity;
|
2020-03-27 10:07:53 +08:00
|
|
|
if ((gravity & DoricGravityLeft) == DoricGravityLeft) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.paddingLeft;
|
2020-03-27 10:07:53 +08:00
|
|
|
} else if ((gravity & DoricGravityRight) == DoricGravityRight) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.measuredWidth - self.paddingRight - layout.measuredWidth;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.measuredWidth / 2 - layout.measuredWidth / 2;
|
2019-12-04 13:29:26 +08:00
|
|
|
} else {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = self.paddingLeft;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-03-21 16:03:03 +08:00
|
|
|
if (!gravity) {
|
2020-03-27 10:07:53 +08:00
|
|
|
gravity = DoricGravityLeft;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginLeft && !((gravity & DoricGravityRight) == DoricGravityRight)) {
|
|
|
|
layout.measuredX += layout.marginLeft;
|
2020-03-21 17:03:52 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginRight && !((gravity & DoricGravityLeft) == DoricGravityLeft)) {
|
|
|
|
layout.measuredX -= layout.marginRight;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredY = yStart + layout.marginTop;
|
|
|
|
yStart += self.spacing + layout.takenHeight;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
- (void)layoutHLayout {
|
|
|
|
CGFloat xStart = self.paddingLeft;
|
2020-03-27 10:07:53 +08:00
|
|
|
if ((self.gravity & DoricGravityLeft) == DoricGravityLeft) {
|
2020-04-03 16:36:43 +08:00
|
|
|
xStart = self.paddingLeft;
|
2020-03-27 10:07:53 +08:00
|
|
|
} else if ((self.gravity & DoricGravityRight) == DoricGravityRight) {
|
2020-04-03 16:36:43 +08:00
|
|
|
xStart = self.measuredWidth - self.contentWidth - self.paddingRight;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((self.gravity & DoricGravityCenterX) == DoricGravityCenterX) {
|
2020-04-03 16:36:43 +08:00
|
|
|
xStart = (self.measuredWidth - self.contentWidth - self.paddingLeft - self.paddingRight) / 2 + self.paddingLeft;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
for (UIView *child in self.view.subviews) {
|
|
|
|
DoricLayout *layout = child.doricLayout;
|
|
|
|
if (layout.disabled) {
|
2019-12-04 13:29:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
2021-04-07 17:24:33 +08:00
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
[layout layout];
|
2019-12-14 15:04:34 +08:00
|
|
|
|
2020-04-03 16:36:43 +08:00
|
|
|
DoricGravity gravity = layout.alignment | self.gravity;
|
|
|
|
if ((gravity & DoricGravityTop) == DoricGravityTop) {
|
|
|
|
layout.measuredY = self.paddingTop;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityBottom) == DoricGravityBottom) {
|
2020-04-03 18:15:43 +08:00
|
|
|
layout.measuredY = self.measuredHeight - self.paddingBottom - layout.measuredHeight;
|
2020-04-03 10:19:13 +08:00
|
|
|
} else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredY = self.measuredHeight / 2 - layout.measuredHeight / 2;
|
2019-12-04 13:29:26 +08:00
|
|
|
} else {
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredY = self.paddingTop;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-03-21 16:03:03 +08:00
|
|
|
if (!gravity) {
|
2020-04-03 16:36:43 +08:00
|
|
|
gravity = DoricGravityTop;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginTop && !((gravity & DoricGravityBottom) == DoricGravityBottom)) {
|
|
|
|
layout.measuredY += layout.marginTop;
|
2020-03-21 16:03:03 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
if (layout.marginBottom && !((gravity & DoricGravityTop) == DoricGravityTop)) {
|
|
|
|
layout.measuredY -= layout.marginBottom;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
layout.measuredX = xStart + layout.marginLeft;
|
|
|
|
xStart += self.spacing + layout.takenWidth;
|
2019-12-04 13:29:26 +08:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 16:36:43 +08:00
|
|
|
|
2019-12-04 13:29:26 +08:00
|
|
|
@end
|
2021-11-17 10:23:21 +08:00
|
|
|
|