From 0d5493ff2936e9532feef1ae3775eaeefbb35754 Mon Sep 17 00:00:00 2001 From: youngsoft Date: Tue, 29 Oct 2019 00:38:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8D=87=E7=BA=A7=EF=BC=8CBU?= =?UTF-8?q?G=E4=BF=AE=E5=A4=8D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyLayout.xcodeproj/project.pbxproj | 6 + MyLayout/Lib/MyFlexLayout.h | 9 +- MyLayout/Lib/MyFlowLayout.h | 11 +- MyLayout/Lib/MyFlowLayout.m | 85 ++++++-- MyLayout/Lib/MyLayoutPos.h | 4 +- MyLayout/Lib/MyLayoutSize.h | 2 +- MyLayoutDemo/AllTestExampleViewController.m | 53 ++++- MyLayoutDemo/FLLTest4ViewController.m | 2 +- MyLayoutDemo/FLLTest9ViewController.h | 14 ++ MyLayoutDemo/FLLTest9ViewController.m | 184 ++++++++++++++++++ MyLayoutDemo/RLTest6ViewController.m | 4 +- MyLayoutDemo/ViewController.m | 4 + .../zh-Hans.lproj/Localizable.strings | 1 + 13 files changed, 349 insertions(+), 30 deletions(-) create mode 100644 MyLayoutDemo/FLLTest9ViewController.h create mode 100644 MyLayoutDemo/FLLTest9ViewController.m diff --git a/MyLayout.xcodeproj/project.pbxproj b/MyLayout.xcodeproj/project.pbxproj index d45c2c0..ce750b5 100644 --- a/MyLayout.xcodeproj/project.pbxproj +++ b/MyLayout.xcodeproj/project.pbxproj @@ -181,6 +181,7 @@ 4689881D23430A8400BFE829 /* MyPathLayoutTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4689881C23430A8400BFE829 /* MyPathLayoutTestCase.m */; }; 4689881F23430AA000BFE829 /* MyGridLayoutTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4689881E23430AA000BFE829 /* MyGridLayoutTestCase.m */; }; 4689882223449E8300BFE829 /* RLTest6ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4689882123449E8300BFE829 /* RLTest6ViewController.m */; }; + 46898847236733AC00BFE829 /* FLLTest9ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 46898846236733AC00BFE829 /* FLLTest9ViewController.m */; }; 6740E1F820A52D9E00AFBC5A /* AllTest10ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6740E1F620A52D9E00AFBC5A /* AllTest10ViewController.m */; }; 6740E1FB20A52DA900AFBC5A /* AllTest10Model.m in Sources */ = {isa = PBXBuildFile; fileRef = 6740E1F920A52DA900AFBC5A /* AllTest10Model.m */; }; 6740E1FE20A52DB100AFBC5A /* AllTest10HeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6740E1FC20A52DB000AFBC5A /* AllTest10HeaderView.m */; }; @@ -441,6 +442,8 @@ 4689881E23430AA000BFE829 /* MyGridLayoutTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyGridLayoutTestCase.m; sourceTree = ""; }; 4689882023449E7900BFE829 /* RLTest6ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RLTest6ViewController.h; sourceTree = ""; }; 4689882123449E8300BFE829 /* RLTest6ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RLTest6ViewController.m; sourceTree = ""; }; + 468988452367339C00BFE829 /* FLLTest9ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLLTest9ViewController.h; sourceTree = ""; }; + 46898846236733AC00BFE829 /* FLLTest9ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLLTest9ViewController.m; sourceTree = ""; }; 6740E1F520A52D9D00AFBC5A /* AllTest10ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllTest10ViewController.h; sourceTree = ""; }; 6740E1F620A52D9E00AFBC5A /* AllTest10ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AllTest10ViewController.m; sourceTree = ""; }; 6740E1F920A52DA900AFBC5A /* AllTest10Model.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AllTest10Model.m; sourceTree = ""; }; @@ -616,6 +619,8 @@ 2075CC3120A0B2A400BA6F65 /* FLLTest7ViewController.m */, 20F0DFFE21120A8D00CFCE8C /* FLLTest8ViewController.h */, 20F0DFFF21120A8D00CFCE8C /* FLLTest8ViewController.m */, + 468988452367339C00BFE829 /* FLLTest9ViewController.h */, + 46898846236733AC00BFE829 /* FLLTest9ViewController.m */, ); name = FlowLayoutDemo; sourceTree = ""; @@ -1204,6 +1209,7 @@ 18D3C9941EDF08F800D3DE43 /* YYFPSLabel.m in Sources */, 18D3C91D1EDF078200D3DE43 /* FLTest2ViewController.m in Sources */, 18D3C9661EDF080800D3DE43 /* TLTest1ViewController.m in Sources */, + 46898847236733AC00BFE829 /* FLLTest9ViewController.m in Sources */, 467E63CC228C4D6F0065D080 /* AllTest12ViewController.m in Sources */, 6740E1FE20A52DB100AFBC5A /* AllTest10HeaderView.m in Sources */, 18D3C94A1EDF07E700D3DE43 /* PLTest2ViewController.m in Sources */, diff --git a/MyLayout/Lib/MyFlexLayout.h b/MyLayout/Lib/MyFlexLayout.h index 7068385..7ec041f 100644 --- a/MyLayout/Lib/MyFlexLayout.h +++ b/MyLayout/Lib/MyFlexLayout.h @@ -58,14 +58,13 @@ extern const int MyFlex_Auto; @property(nonatomic, assign) MyVisibility visibility_val; - //条目的顺序设置 -(MyFlexItem* (^)(NSInteger))order; //条目的尺寸比重设置,默认为0表示不按比重 -(MyFlexItem* (^)(CGFloat))flex_grow; //条目的压缩比重设置,默认为1,表示当会进行压缩 -(MyFlexItem* (^)(CGFloat))flex_shrink; -//条目的尺寸设置,可以设置为_auto,固定值,相对值。你可以使用这个属性也可以通过width/height来设置。 +//条目的尺寸设置,可以设置为MyFlex_Auto,固定值,相对值。你可以使用这个属性也可以通过width/height来设置。 -(MyFlexItem* (^)(CGFloat))flex_basis; //行内条目自身的对齐方式。 -(MyFlexItem* (^)(MyFlexGravity))align_self; @@ -125,17 +124,17 @@ extern const int MyFlex_Auto; @end -//视图在flexbox中的分类扩展,只有MyFlexLayout中的子视图才有用。 +//条目视图在应用flexbox时的分类扩展,只有MyFlexLayout中的子视图才有用。 @interface UIView(MyFlexLayout) -//我们可以借助视图的flexItem来设置当视图在flexbox中的一些属性。 +//我们可以借助视图的flexItem来设置条目视图在弹性布局视图中的一些属性。 @property(nonatomic, readonly, strong) MyFlexItem *flexItem; @end /* - * FlexLayout布局是为了兼容flexbox语法而建立了一个布局,它是从MyFlowLayout派生。在MyFlowLayout中也是支持类似flexbox的一些特性的 + * 弹性布局是为了兼容flexbox语法而建立了一个布局,它是从MyFlowLayout派生。在MyFlowLayout中也是支持类似flexbox的一些特性的 * 但是它的属性和flexbox不兼容和一致,因此提供一个新的类MyFlexLayout来完全支持flexbox. */ @interface MyFlexLayout:MyFlowLayout diff --git a/MyLayout/Lib/MyFlowLayout.h b/MyLayout/Lib/MyFlowLayout.h index cf56f5a..03d6749 100644 --- a/MyLayout/Lib/MyFlowLayout.h +++ b/MyLayout/Lib/MyFlowLayout.h @@ -137,7 +137,7 @@ /** - 为流式布局提供分页展示的能力,默认是0表不支持分页展示。当设置为非0时则要求必须是arrangedCount的整数倍数,表示每页的子视图的数量。而arrangedCount则表示每排内的子视图的数量。当启用pagedCount时要求将流式布局加入到UIScrollView或者其派生类中才能生效。只有数量约束流式布局才支持分页展示的功能,通过pagedCount和设置尺寸的高度或者宽度自适应配合使用能实现不同的分页展示能力: + 为流式布局提供分页展示的能力,默认是0表不支持分页展示。当设置为非0时则要求必须是arrangedCount的整数倍数,表示每页的子视图的数量。而arrangedCount则表示每排内的子视图的数量。当启用pagedCount时如果流式布局的父视图是UIScrollView或者其派生类就会有分页滚动的效果。只有数量约束流式布局才支持分页展示的功能,通过pagedCount和设置尺寸的高度或者宽度自适应配合使用能实现不同的分页展示能力: @note 1. 垂直数量约束流式布局的高度设置为自适应时则以UIScrollView的尺寸作为一页展示的大小,因为指定了一页的子视图数量,以及指定了一排的子视图数量,因此默认也会自动计算出子视图的宽度和高度,而不需要单独指出高度和宽度(子视图的宽度你也可以自定义),整体的分页滚动是从上到下滚动。(每页布局时从左到右再从上到下排列,新页往下滚动继续排列): @code @@ -232,11 +232,12 @@ /** - 单独为某一行或者一列定制gravity停靠对齐属性,默认情况下布局视图的gravity作用于所有行或者列的停靠对齐。如果你想单独定制某一行或者某一列的停靠对齐方式时 - 可以通过设置这个block属性。lineGravity的入参是布局对象和当前行列的索引值,索引值以0开始,返回的是此行的停靠对齐方式,如果返回MyGravity_None则表示使用 - 布局默认的gravity停靠对齐属性。如果您的gravity属性设置的是Fill的话则有可能通过这个进行定制化会出现一些异常。 + 单独为某一行或者一列定制的水平和垂直停靠对齐属性,默认情况下布局视图的gravity和arrangedGravity作用于所有行或者列的停靠对齐。如果你想单独定制某一行或者某一列的停靠对齐方式时 + 可以通过设置这个block属性。 + lineGravity的入参分别是布局对象、当前行的索引(0开始)、当前行的条目视图数量、是否是最后一行四个参数。 + 函数返回的是此行的停靠对齐方式,如果返回MyGravity_None则表示使用布局默认的gravity和arrangedGravity停靠对齐属性。 */ -@property(nonatomic, copy) MyGravity (^lineGravity)(MyFlowLayout *layout, NSInteger lineIndex); +@property(nonatomic, copy) MyGravity (^lineGravity)(MyFlowLayout *layout, NSInteger lineIndex, NSInteger itemCount, BOOL isLastLine); diff --git a/MyLayout/Lib/MyFlowLayout.m b/MyLayout/Lib/MyFlowLayout.m index b4def57..e1f1760 100644 --- a/MyLayout/Lib/MyFlowLayout.m +++ b/MyLayout/Lib/MyFlowLayout.m @@ -290,7 +290,7 @@ - (void)myAdjustVertLayoutSinglelineWidth:(CGSize)selfSize lineIndex:(NSInteger) MyGravity lineHorzGravity = horzGravity; if (self.lineGravity != nil) { - lineHorzGravity = self.lineGravity(self, lineIndex); + lineHorzGravity = self.lineGravity(self, lineIndex, count, startIndex == sbs.count) & MyGravity_Vert_Mask; if (lineHorzGravity == MyGravity_None) lineHorzGravity = horzGravity; } @@ -339,7 +339,7 @@ - (void)myAdjustHorzLayoutSinglelineHeight:(CGSize)selfSize lineIndex:(NSInteger MyGravity lineVertGravity = vertGravity; if (self.lineGravity != nil) { - lineVertGravity = self.lineGravity(self, lineIndex); + lineVertGravity = self.lineGravity(self, lineIndex, count, startIndex == sbs.count) & MyGravity_Horz_Mask; if (lineVertGravity == MyGravity_None) lineVertGravity = vertGravity; } @@ -456,13 +456,19 @@ - (void)myCalcVertLayoutSinglelineAlignment:(CGSize)selfSize rowIndex:(NSInteger CGFloat addXFill = 0; //多出来的平均区域,用于拉伸间距或者尺寸 MyGravity lineHorzGravity = horzGravity; + MyGravity lineVertAlignment = vertAlignment; if (self.lineGravity != nil) { - lineHorzGravity = self.lineGravity(self, rowIndex); + MyGravity lineGravity = self.lineGravity(self, rowIndex, count, startIndex == sbs.count); + lineHorzGravity = lineGravity & MyGravity_Vert_Mask; if (lineHorzGravity == MyGravity_None) lineHorzGravity = horzGravity; else lineHorzGravity = [self myConvertLeftRightGravityToLeadingTrailing:lineHorzGravity]; + + lineVertAlignment = lineGravity & MyGravity_Horz_Mask; + if (lineVertAlignment == MyGravity_None) + lineVertAlignment = vertAlignment; } switch (lineHorzGravity) @@ -553,9 +559,10 @@ - (void)myCalcVertLayoutSinglelineAlignment:(CGSize)selfSize rowIndex:(NSInteger MyGravity sbvVertAlignment = sbvsc.alignment & MyGravity_Horz_Mask; if (sbvVertAlignment == MyGravity_None) - sbvVertAlignment = vertAlignment; + sbvVertAlignment = lineVertAlignment; + //因为单行内的垂直间距拉伸被赋予紧凑排列,所以这里的定制化将不起作用。 if (vertAlignment == MyGravity_Vert_Between) - sbvVertAlignment = MyGravity_Vert_Between; + sbvVertAlignment = MyGravity_None; UIFont *sbvFont = nil; if (sbvVertAlignment == MyGravity_Vert_Baseline) @@ -649,10 +656,18 @@ - (void)myCalcHorzLayoutSinglelineAlignment:(CGSize)selfSize colIndex:(NSInteger //计算每行的gravity情况。 CGFloat addYPos = 0; CGFloat addYFill = 0; + MyGravity lineHorzAlignment = horzAlignment; MyGravity lineVertGravity = vertGravity; if (self.lineGravity != nil) { - lineVertGravity = self.lineGravity(self, colIndex); + MyGravity lineGravity = self.lineGravity(self, colIndex, count, startIndex == sbs.count); + lineHorzAlignment = lineGravity & MyGravity_Vert_Mask; + if (lineHorzAlignment == MyGravity_None) + lineHorzAlignment = horzAlignment; + else + lineHorzAlignment = [self myConvertLeftRightGravityToLeadingTrailing:lineHorzAlignment]; + + lineVertGravity = lineGravity & MyGravity_Horz_Mask; if (lineVertGravity == MyGravity_None) lineVertGravity = vertGravity; } @@ -745,9 +760,10 @@ - (void)myCalcHorzLayoutSinglelineAlignment:(CGSize)selfSize colIndex:(NSInteger MyGravity sbvHorzAlignment = [self myConvertLeftRightGravityToLeadingTrailing:sbvsc.alignment & MyGravity_Vert_Mask]; if (sbvHorzAlignment == MyGravity_None) - sbvHorzAlignment = horzAlignment; + sbvHorzAlignment = lineHorzAlignment; + //因为单行内的水平间距拉伸被赋予紧凑排列,所以这里的定制化将不起作用。 if (horzAlignment == MyGravity_Horz_Between) - sbvHorzAlignment = MyGravity_Horz_Between; + sbvHorzAlignment = MyGravity_None; if ((sbvHorzAlignment != MyGravity_None && sbvHorzAlignment != MyGravity_Horz_Leading) || _myCGFloatNotEqual(addYPos, 0.0) || _myCGFloatNotEqual(addYFill, 0.0) || colTotalShrink != 0.0) { @@ -1147,7 +1163,17 @@ -(CGSize)myCalcLayoutSizeForVertOrientationContent:(CGSize)selfSize sbs:(NSMutab rect.size.width = [self myValidMeasure:sbvsc.widthSizeInner sbv:sbv calcSize:rect.size.width sbvSize:rect.size selfLayoutSize:selfSize]; //计算子视图的高度。 - rect.size.height = [self myGetSubviewHeightSizeValue:sbv sbvsc:sbvsc lsc:lsc selfSize:selfSize paddingTop:paddingTop paddingLeading:paddingLeading paddingBottom:paddingBottom paddingTrailing:paddingTrailing sbvSize:rect.size]; + if (sbvsc.heightSizeInner.dimeVal != nil) + { + rect.size.height = [self myGetSubviewHeightSizeValue:sbv sbvsc:sbvsc lsc:lsc selfSize:selfSize paddingTop:paddingTop paddingLeading:paddingLeading paddingBottom:paddingBottom paddingTrailing:paddingTrailing sbvSize:rect.size]; + } + else if (vertGravity == MyGravity_Vert_Fill || vertGravity == MyGravity_Vert_Stretch) + { + rect.size.height = 0; + } + + + rect.size.height = [self myValidMeasure:sbvsc.heightSizeInner sbv:sbv calcSize:rect.size.height sbvSize:rect.size selfLayoutSize:selfSize]; if (sbvsc.heightSizeInner.dimeRelaVal != nil && sbvsc.heightSizeInner.dimeRelaVal == sbvsc.widthSizeInner) @@ -1375,9 +1401,16 @@ -(CGSize)myCalcLayoutSizeForVertOrientation:(CGSize)selfSize sbs:(NSMutableArray pagingItemWidth = (selfSize.width - paddingHorz - (arrangedCount - 1) * horzSpace) / arrangedCount; //分页滚动时和非分页滚动时的高度计算是不一样的。 if (isPagingScroll) + { pagingItemHeight = (CGRectGetHeight(self.superview.bounds) - paddingVert - (rows - 1) * vertSpace) / rows; + } else - pagingItemHeight = (CGRectGetHeight(self.superview.bounds) - paddingTop - rows * vertSpace) / rows; + { + if ([self.superview isKindOfClass:[UIScrollView class]]) + pagingItemHeight = (CGRectGetHeight(self.superview.bounds) - paddingTop - rows * vertSpace) / rows; + else + pagingItemHeight = (selfSize.height - paddingVert - (rows - 1) * vertSpace) / rows; + } } @@ -1571,9 +1604,18 @@ -(CGSize)myCalcLayoutSizeForVertOrientation:(CGSize)selfSize sbs:(NSMutableArray CGRect rect = sbvmyFrame.frame; if (pagingItemHeight != 0) + { rect.size.height = pagingItemHeight - topSpace - bottomSpace; - else + } + else if (sbvsc.heightSizeInner.dimeVal != nil) + { rect.size.height = [self myGetSubviewHeightSizeValue:sbv sbvsc:sbvsc lsc:lsc selfSize:selfSize paddingTop:paddingTop paddingLeading:paddingLeading paddingBottom:paddingBottom paddingTrailing:paddingTrailing sbvSize:rect.size]; + } + else if (vertGravity == MyGravity_Vert_Fill || vertGravity == MyGravity_Vert_Stretch) + {//如果没有设置高度约束但是又是垂直拉伸则将高度设置为0. + rect.size.height = 0; + } + rect.size.height = [self myValidMeasure:sbvsc.heightSizeInner sbv:sbv calcSize:rect.size.height sbvSize:rect.size selfLayoutSize:selfSize]; @@ -1890,6 +1932,10 @@ -(CGSize)myCalcLayoutSizeForHorzOrientationContent:(CGSize)selfSize sbs:(NSMutab rect.size.width = [self myGetSubviewWidthSizeValue:sbv sbvsc:sbvsc lsc:lsc selfSize:selfSize paddingTop:paddingTop paddingLeading:paddingLeading paddingBottom:paddingBottom paddingTrailing:paddingTrailing sbvSize:rect.size]; rect.size.width = [self myValidMeasure:sbvsc.widthSizeInner sbv:sbv calcSize:rect.size.width sbvSize:rect.size selfLayoutSize:selfSize]; } + else if (horzGravity == MyGravity_Horz_Fill || horzGravity == MyGravity_Horz_Stretch) + { + rect.size.width = 0.0; + } if (subviewSize != 0.0) { @@ -2228,9 +2274,16 @@ -(CGSize)myCalcLayoutSizeForHorzOrientation:(CGSize)selfSize sbs:(NSMutableArray pagingItemHeight = (selfSize.height - paddingVert - (arrangedCount - 1) * vertSpace) / arrangedCount; //分页滚动时和非分页滚动时的宽度计算是不一样的。 if (isPagingScroll) + { pagingItemWidth = (CGRectGetWidth(self.superview.bounds) - paddingHorz - (cols - 1) * horzSpace) / cols; + } else - pagingItemWidth = (CGRectGetWidth(self.superview.bounds) - paddingLeading - cols * horzSpace) / cols; + { + if ([self.superview isKindOfClass:[UIScrollView class]]) + pagingItemWidth = (CGRectGetWidth(self.superview.bounds) - paddingLeading - cols * horzSpace) / cols; + else + pagingItemWidth = (selfSize.width - paddingHorz - (cols - 1) * horzSpace) / cols; + } } @@ -2281,8 +2334,14 @@ -(CGSize)myCalcLayoutSizeForHorzOrientation:(CGSize)selfSize sbs:(NSMutableArray //水平流式布局因为高度依赖宽度自适应的情况比较少,所以这里直接先计算宽度 if (pagingItemWidth != 0.0) rect.size.width = pagingItemWidth - leadingSpace - trailingSpace; - else + else if (sbvsc.widthSizeInner.dimeVal != nil) + { rect.size.width = [self myGetSubviewWidthSizeValue:sbv sbvsc:sbvsc lsc:lsc selfSize:selfSize paddingTop:paddingTop paddingLeading:paddingLeading paddingBottom:paddingBottom paddingTrailing:paddingTrailing sbvSize:rect.size]; + } + else if (horzGravity == MyGravity_Horz_Fill || horzGravity == MyGravity_Horz_Stretch) + { + rect.size.width = 0; + } rect.size.width = [self myValidMeasure:sbvsc.widthSizeInner sbv:sbv calcSize:rect.size.width sbvSize:rect.size selfLayoutSize:selfSize]; diff --git a/MyLayout/Lib/MyLayoutPos.h b/MyLayout/Lib/MyLayoutPos.h index 3f5a7c9..512b55e 100644 --- a/MyLayout/Lib/MyLayoutPos.h +++ b/MyLayout/Lib/MyLayoutPos.h @@ -271,9 +271,9 @@ */ @interface NSArray(MyLayoutMostPos) -//从数组中得到最小的尺寸值。要求数组的元素必须是MyLayoutPos或者NSNumber类型 +//从数组中得到最大的位置值。要求数组的元素必须是MyLayoutPos或者NSNumber类型 @property(nonatomic, readonly) MyLayoutMostPos *myMinPos; -//从数组中得到最小的尺寸值。要求数组的元素必须是MyLayoutPos或者NSNumber类型 +//从数组中得到最小的位置值。要求数组的元素必须是MyLayoutPos或者NSNumber类型 @property(nonatomic, readonly) MyLayoutMostPos *myMaxPos; @end diff --git a/MyLayout/Lib/MyLayoutSize.h b/MyLayout/Lib/MyLayoutSize.h index 748eba2..b9ceac6 100644 --- a/MyLayout/Lib/MyLayoutSize.h +++ b/MyLayout/Lib/MyLayoutSize.h @@ -238,7 +238,7 @@ //从数组中得到最小的尺寸值。要求数组的元素必须是MyLayoutSize类型 @property(nonatomic, readonly) MyLayoutMostSize *myMinSize; -//从数组中得到最小的尺寸值。要求数组的元素必须是MyLayoutSize类型 +//从数组中得到最大的尺寸值。要求数组的元素必须是MyLayoutSize类型 @property(nonatomic, readonly) MyLayoutMostSize *myMaxSize; @end diff --git a/MyLayoutDemo/AllTestExampleViewController.m b/MyLayoutDemo/AllTestExampleViewController.m index 4330f15..53f8f62 100644 --- a/MyLayoutDemo/AllTestExampleViewController.m +++ b/MyLayoutDemo/AllTestExampleViewController.m @@ -24,7 +24,8 @@ - (void)viewDidLoad { self.view.backgroundColor = [UIColor whiteColor]; // [self example1]; - [self example2]; + // [self example2]; + [self example3]; } - (void)didReceiveMemoryWarning { @@ -126,5 +127,55 @@ -(void)example2 } +-(void)example3 +{ + //用链式语法创建一个弹性布局,宽度和父视图一致,高度为100 + MyFlexLayout *layout = MyFlexLayout.new.flex + .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)) + .margin_top(50) + .width(MyLayoutSize.fill) + .height(MyLayoutSize.wrap) + .addTo(self.view); + + + UILabel *itemA = UILabel.new.flexItem + .width(MyLayoutSize.fill) + .height(30) + .addTo(layout); + + UILabel *itemB = UILabel.new.flexItem + .flex_grow(1) + .align_self(MyFlexGravity_Flex_Start) + .height(30) + .addTo(layout); + + UILabel *itemC = UILabel.new.flexItem + .flex_grow(1) + .height(40) + .addTo(layout); + + UILabel *itemD = UILabel.new.flexItem + .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]; + +} @end diff --git a/MyLayoutDemo/FLLTest4ViewController.m b/MyLayoutDemo/FLLTest4ViewController.m index 4632e27..e3a27b3 100644 --- a/MyLayoutDemo/FLLTest4ViewController.m +++ b/MyLayoutDemo/FLLTest4ViewController.m @@ -166,7 +166,7 @@ -(void)createFlowLayout1:(MyLinearLayout*)rootLayout //第六行因为最后只有一个按钮,所以这里不需要建立占位视图。 //我们可以通过lineGravity属性来实现为每一行进行不同的对齐方式定制,如果返回MyGravity_None则表示用gravity属性设置的对齐方式来进行处理。 - flowLayout.lineGravity = ^MyGravity(MyFlowLayout *layout, NSInteger lineIndex) { + flowLayout.lineGravity = ^MyGravity(MyFlowLayout *layout, NSInteger lineIndex, NSInteger itemCount, BOOL isLastLine) { switch (lineIndex) { case 3: diff --git a/MyLayoutDemo/FLLTest9ViewController.h b/MyLayoutDemo/FLLTest9ViewController.h new file mode 100644 index 0000000..5582105 --- /dev/null +++ b/MyLayoutDemo/FLLTest9ViewController.h @@ -0,0 +1,14 @@ +// +// FLLTest9ViewController.h +// MyLayoutDemo +// +// Created by oubaiquan on 2018/8/1. +// Copyright © 2018年 YoungSoft. All rights reserved. +// + +#import + +/*9.FlowLayout - line gravity*/ +@interface FLLTest9ViewController : UIViewController + +@end diff --git a/MyLayoutDemo/FLLTest9ViewController.m b/MyLayoutDemo/FLLTest9ViewController.m new file mode 100644 index 0000000..5557b92 --- /dev/null +++ b/MyLayoutDemo/FLLTest9ViewController.m @@ -0,0 +1,184 @@ +// +// FLLTest9ViewController.m +// MyLayoutDemo +// +// Created by oubaiquan on 2018/8/1. +// Copyright © 2018年 YoungSoft. All rights reserved. +// + +#import "FLLTest9ViewController.h" +#import "MyLayout.h" +#import "CFTool.h" + +@interface FLLTest9ViewController () + +@property(nonatomic, strong) MyFlowLayout *vertContentLayout; +@property(nonatomic, strong) MyFlowLayout *horzContentLayout; + +@end + +@implementation FLLTest9ViewController + +-(void)loadView +{ + /* + 这个例子主要演示流式布局中进行行内的自定义停靠对齐属性lineGravity的使用方法。一般情况下我们可以通过gravity来设置布局内所有行的停靠特性,而通过arrangedGravity来设置行内的对齐特性。而如果我们想自定义某行的停靠和对齐特性时则需要实现lineGravity这个block。 + + */ + + self.edgesForExtendedLayout = UIRectEdgeNone; //设置视图控制器中的视图尺寸不延伸到导航条或者工具条下面。您可以注释这句代码看看效果。 + MyFlowLayout *rootLayout = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Vert arrangedCount:0]; + rootLayout.isFlex = YES; + rootLayout.padding = UIEdgeInsetsMake(5, 5, 5, 5); + rootLayout.subviewSpace = 5; + self.view = rootLayout; + + [self createVertContentLayout:rootLayout]; + + [self createHorzContentLayout:rootLayout]; + +} + +-(void)createVertContentLayout:(MyFlowLayout*)rootLayout +{ + UIButton *vertLayoutItemAddButon = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [vertLayoutItemAddButon addTarget:self action:@selector(handleVertLayoutItemAdd:) forControlEvents:UIControlEventTouchUpInside]; + [vertLayoutItemAddButon setTitle:@"Add" forState:UIControlStateNormal]; + [rootLayout addSubview:vertLayoutItemAddButon]; + vertLayoutItemAddButon.weight = 1.0; + vertLayoutItemAddButon.heightSize.equalTo(@(40)); + + UIButton *vertLayoutItemRemoveButon = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [vertLayoutItemRemoveButon addTarget:self action:@selector(handleVertLayoutItemRemove:) forControlEvents:UIControlEventTouchUpInside]; + [vertLayoutItemRemoveButon setTitle:@"Remove" forState:UIControlStateNormal]; + [rootLayout addSubview:vertLayoutItemRemoveButon]; + vertLayoutItemRemoveButon.weight = 1.0; + vertLayoutItemRemoveButon.heightSize.equalTo(@(40)); + + MyFlowLayout *vertContentLayout = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Vert arrangedCount:1]; + [rootLayout addSubview:vertContentLayout]; + vertContentLayout.widthSize.equalTo(rootLayout.widthSize); + vertContentLayout.heightSize.equalTo(vertContentLayout.widthSize).multiply(3.0/5); + vertContentLayout.gravity = MyGravity_Horz_Fill | MyGravity_Vert_Center; + //单独设置行内的停靠方向。 + vertContentLayout.lineGravity = ^MyGravity(MyFlowLayout *layout, NSInteger lineIndex, NSInteger itemCount, BOOL isLastLine) { + + //只有当布局视图的子视图数量为3个,并且是最后一行时才水平居中,否则其他返回默认的停靠值 + if (layout.subviews.count == 3 && isLastLine) + return MyGravity_Horz_Center; + else + return MyGravity_None; + }; + + self.vertContentLayout = vertContentLayout; + self.vertContentLayout.backgroundColor = [UIColor lightGrayColor]; +} + +-(void)createHorzContentLayout:(MyFlowLayout*)rootLayout +{ + UIButton *horzLayoutItemAddButon = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [horzLayoutItemAddButon addTarget:self action:@selector(handleHorzLayoutItemAdd:) forControlEvents:UIControlEventTouchUpInside]; + [horzLayoutItemAddButon setTitle:@"Add" forState:UIControlStateNormal]; + [rootLayout addSubview:horzLayoutItemAddButon]; + horzLayoutItemAddButon.weight = 1.0; + horzLayoutItemAddButon.heightSize.equalTo(@(40)); + + UIButton *horzLayoutItemRemoveButon = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [horzLayoutItemRemoveButon addTarget:self action:@selector(handleHorzLayoutItemRemove:) forControlEvents:UIControlEventTouchUpInside]; + [horzLayoutItemRemoveButon setTitle:@"Remove" forState:UIControlStateNormal]; + [rootLayout addSubview:horzLayoutItemRemoveButon]; + horzLayoutItemRemoveButon.weight = 1.0; + horzLayoutItemRemoveButon.heightSize.equalTo(@(40)); + + MyFlowLayout *horzContentLayout = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Horz arrangedCount:1]; + [rootLayout addSubview:horzContentLayout]; + horzContentLayout.widthSize.equalTo(rootLayout.widthSize); + horzContentLayout.heightSize.equalTo(horzContentLayout.widthSize).multiply(3.0/5); + horzContentLayout.gravity = MyGravity_Vert_Fill | MyGravity_Horz_Center; + horzContentLayout.lineGravity = ^MyGravity(MyFlowLayout *layout, NSInteger lineIndex, NSInteger itemCount, BOOL isLastLine) { + + //只有当布局视图的子视图数量为3个,并且是最后一行时才水平居中,否则其他返回默认的停靠值 + if (layout.subviews.count == 3 && isLastLine) + return MyGravity_Vert_Center; + else + return MyGravity_None; + }; + + self.horzContentLayout = horzContentLayout; + self.horzContentLayout.backgroundColor = [UIColor lightGrayColor]; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +#pragma mark -- Handler + +-(void)handleVertLayoutItemAdd:(id)sender +{ + UILabel *itemView = [UILabel new]; + itemView.backgroundColor = [CFTool color:arc4random_uniform(14) + 1]; + itemView.text = [NSString stringWithFormat:@"%ld", self.vertContentLayout.subviews.count]; + itemView.textAlignment = NSTextAlignmentCenter; + [self.vertContentLayout addSubview:itemView]; + + + //1个就1,小于等于4个就2, 小于等于9个就3, 小于等于16个就4 + //也就是每行的数量是大于子视图数量开根的最小整数。 + self.vertContentLayout.arrangedCount = ceil(sqrt(self.vertContentLayout.subviews.count)); + //这里启用分页功能,这样子视图的高度将会被自动计算出来。 + self.vertContentLayout.pagedCount = self.vertContentLayout.arrangedCount * self.vertContentLayout.arrangedCount; +} + +-(void)handleVertLayoutItemRemove:(id)sender +{ + [self.vertContentLayout.subviews.lastObject removeFromSuperview]; + //1个就1,小于等于4个就2, 小于等于9个就3, 小于等于16个就4 + //也就是每行的数量是大于子视图数量开根的最小整数。 + self.vertContentLayout.arrangedCount = ceil(sqrt(self.vertContentLayout.subviews.count)); + self.vertContentLayout.pagedCount = self.vertContentLayout.arrangedCount * self.vertContentLayout.arrangedCount; +} + +-(void)handleHorzLayoutItemAdd:(id)sender +{ + UILabel *itemView = [UILabel new]; + itemView.backgroundColor = [CFTool color:arc4random_uniform(14) + 1]; + itemView.text = [NSString stringWithFormat:@"%ld", self.horzContentLayout.subviews.count]; + itemView.textAlignment = NSTextAlignmentCenter; + [self.horzContentLayout addSubview:itemView]; + + + //1个就1,小于等于4个就2, 小于等于9个就3, 小于等于16个就4 + //也就是每行的数量是大于子视图数量开根的最小整数。 + self.horzContentLayout.arrangedCount = ceil(sqrt(self.horzContentLayout.subviews.count)); + //这里启用分页功能,这样子视图的高度将会被自动计算出来。 + self.horzContentLayout.pagedCount = self.horzContentLayout.arrangedCount * self.horzContentLayout.arrangedCount; +} + +-(void)handleHorzLayoutItemRemove:(id)sender +{ + [self.horzContentLayout.subviews.lastObject removeFromSuperview]; + //1个就1,小于等于4个就2, 小于等于9个就3, 小于等于16个就4 + //也就是每行的数量是大于子视图数量开根的最小整数。 + self.horzContentLayout.arrangedCount = ceil(sqrt(self.horzContentLayout.subviews.count)); + self.horzContentLayout.pagedCount = self.horzContentLayout.arrangedCount * self.horzContentLayout.arrangedCount; +} + +@end diff --git a/MyLayoutDemo/RLTest6ViewController.m b/MyLayoutDemo/RLTest6ViewController.m index 300d5bc..1712510 100644 --- a/MyLayoutDemo/RLTest6ViewController.m +++ b/MyLayoutDemo/RLTest6ViewController.m @@ -96,11 +96,11 @@ -(MyRelativeLayout*)createLayout1 UIButton *clickButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [clickButton setTitle:@"Click me" forState:UIControlStateNormal]; clickButton.backgroundColor = [CFTool color:10]; - [clickButton sizeToFit]; //这里直接计算出date的size是自适应的 + [clickButton sizeToFit]; //这里直接计算出clickButton的size是自适应的 clickButton.topPos.equalTo(nameLabel.topPos); //最新版本的相对布局可以让子视图的位置设置为某些视图位置中的最大或者最小值,也就是极限值,我们可以对一个数组调用扩展分类的方法myMaxPos或者myMinPos来获取 //到数组中元素的最大或者最小位置值。使用最大最小值的前提是在计算当前位置的约束时,要求数组中的元素的约束都是已经计算好了的,否则得到的结果是未可知,就如本例中 - //在计算dateLabel的右边距时,detailLabel以及nameLabel的右边距都是已经计算好了的。 + //在计算clickButton的右边距时,detailLabel以及nameLabel的右边距都是已经计算好了的。 clickButton.rightPos.equalTo(@[detailLabel.rightPos, nameLabel.rightPos.clone(-1 *(40+clickButton.frame.size.width))].myMaxPos); [rootLayout addSubview:clickButton]; diff --git a/MyLayoutDemo/ViewController.m b/MyLayoutDemo/ViewController.m index 5f85902..39eb301 100644 --- a/MyLayoutDemo/ViewController.m +++ b/MyLayoutDemo/ViewController.m @@ -43,6 +43,7 @@ #import "FLLTest6ViewController.h" #import "FLLTest7ViewController.h" #import "FLLTest8ViewController.h" +#import "FLLTest9ViewController.h" #import "FLXTest1ViewController.h" @@ -199,6 +200,9 @@ -(NSArray*)demoTypeList }, @{@"title":NSLocalizedString(@"8.FlowLayout - Flex space", @""), @"class":[FLLTest8ViewController class] + }, + @{@"title":NSLocalizedString(@"9.FlowLayout - Line gravity", @""), + @"class":[FLLTest9ViewController class] } ] }, diff --git a/MyLayoutDemo/zh-Hans.lproj/Localizable.strings b/MyLayoutDemo/zh-Hans.lproj/Localizable.strings index 47cf8b2..2cd2669 100644 --- a/MyLayoutDemo/zh-Hans.lproj/Localizable.strings +++ b/MyLayoutDemo/zh-Hans.lproj/Localizable.strings @@ -36,6 +36,7 @@ "6.FlowLayout - Scroll" = "6.流式布局-不同方向的滚动"; "7.FlowLayout - Auto Arrange" = "7.流式布局-自动布局和对瀑布流的支持"; "8.FlowLayout - Flex space" = "8.流式布局-浮动间距"; +"9.FlowLayout - Line gravity" = "9.流式布局-自定义行停靠对齐"; "1.FloatLayout - Float" = "1.浮动布局-浮动效果的演示"; "2.FloatLayout - Jagged" = "2.浮动布局-仿天猫淘宝首页实现" ; "3.FloatLayout - Card news" = "3.浮动布局-仿ZAKER今日头条实现";