From ed46490c259c04e592f45624ba8f4ee8864d07ce Mon Sep 17 00:00:00 2001 From: fzy Date: Sat, 4 Aug 2018 20:17:55 +0800 Subject: [PATCH] Release V1.2.0 fix #issue25 --- CHANGELOG.md | 12 +- TangramKit.podspec | 2 +- TangramKit.xcodeproj/project.pbxproj | 8 + TangramKit/TGBaseLayout.swift | 61 +++++- TangramKit/TGFloatLayout.swift | 2 +- TangramKit/TGFlowLayout.swift | 95 +++++++-- TangramKit/TGFrameLayout.swift | 1 + TangramKit/TGLayoutSizeClass.swift | 4 + TangramKit/TGLinearLayout.swift | 2 +- TangramKit/TGPathLayout.swift | 1 + TangramKit/TGRelativeLayout.swift | 2 +- TangramKit/TangramKit.swift | 2 +- .../FLLTest8ViewController.swift | 92 ++++++++ .../AllTest9ViewController.swift | 201 ++++++++++++++++++ .../zh-Hans.lproj/Localizable.strings | 10 + TangramKitDemo/ViewController.swift | 6 + 16 files changed, 480 insertions(+), 21 deletions(-) create mode 100644 TangramKitDemo/FlowLayoutDemo/FLLTest8ViewController.swift create mode 100644 TangramKitDemo/IntegratedDemo/AllTest9ViewController.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c6f67..c2a4a7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,17 @@ # Change Log **TangramKit**中的所有历史版本变化将会在这个文件中列出。 ---- +--- + +## [V1.2.0](https://github.com/youngsoft/TangramKit/releases/tag/1.2.0)(2018/08/04) + +#### Added +1. 添加布局属性`tg_layoutTransform`,用来实现对布局内子视图的整体位置变换,可以通过这个属性来实现一般常见的平移,缩放,水平翻转,垂直翻转等功能。具体的DEMO在新增加的[AllTest9ViewController](https://github.com/youngsoft/TangramKit/blob/master/TangramKitDemo/IntegratedDemo/AllTest9ViewController.swift)中可以查看。 +2. 为流式布局`MyFlowLayout`支持子视图固定尺寸并且间距动态拉伸调整的能力,你可以通过设置流式布局的方法:`tg_setSubviews`来实现,这个方法原先只支持内容约束流式布局,现在新版本对数量约束流式布局也同样支持了。具体的DEMO在新增加的[FLLTest8ViewController](https://github.com/youngsoft/TangramKit/blob/master/TangramKitDemo/FlowLayoutDemo/FLLTest8ViewController.swift)中可以查看。 + +#### Fixed +1. 修复了UILabel等控件的尺寸设置了.wrap并且同时又设置了最大最小尺寸时,在相对布局内进行尺寸计算内可能会出现的问题。[#issue25](https://github.com/youngsoft/TangramKit/issues/25) + ## [V1.1.6](https://github.com/youngsoft/TangramKit/releases/tag/1.1.6)(2018/05/10) diff --git a/TangramKit.podspec b/TangramKit.podspec index 9e67791..e65ba9a 100644 --- a/TangramKit.podspec +++ b/TangramKit.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "TangramKit" - s.version = "1.1.6" + s.version = "1.2.0" s.summary = "TangramKit is A powerful iOS UI framework. It integrated the Android layout,AutoLayout,SizeClass, HTML/CSS float and flexbox functions." s.description = <<-DESC diff --git a/TangramKit.xcodeproj/project.pbxproj b/TangramKit.xcodeproj/project.pbxproj index 34fd18b..43e1d9d 100644 --- a/TangramKit.xcodeproj/project.pbxproj +++ b/TangramKit.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 20B6C6E71FA40AEC001D51C7 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20B6C6E61FA40AEC001D51C7 /* DetailViewController.swift */; }; 20DCF335208CD022007A879B /* FOLTest7ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20DCF334208CD022007A879B /* FOLTest7ViewController.swift */; }; 20FC8FE220A4241D0029DE31 /* FLLTest7ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20FC8FE120A4241D0029DE31 /* FLLTest7ViewController.swift */; }; + 4680F8FD211583FF00BFB765 /* FLLTest8ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4680F8FC211583FF00BFB765 /* FLLTest8ViewController.swift */; }; + 4680F8FF2115891600BFB765 /* AllTest9ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4680F8FE2115891600BFB765 /* AllTest9ViewController.swift */; }; 681BD8DF1E0B91A500403A1F /* TangramKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 681BD8DD1E0B91A500403A1F /* TangramKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 681BD90F1E0B92E100403A1F /* TangramKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 681BD9011E0B92E100403A1F /* TangramKit.swift */; }; 681BD9111E0B92E100403A1F /* TGBaseLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 681BD9021E0B92E100403A1F /* TGBaseLayout.swift */; }; @@ -108,6 +110,8 @@ 20B6C6E61FA40AEC001D51C7 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 20DCF334208CD022007A879B /* FOLTest7ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FOLTest7ViewController.swift; sourceTree = ""; }; 20FC8FE120A4241D0029DE31 /* FLLTest7ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FLLTest7ViewController.swift; sourceTree = ""; }; + 4680F8FC211583FF00BFB765 /* FLLTest8ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FLLTest8ViewController.swift; sourceTree = ""; }; + 4680F8FE2115891600BFB765 /* AllTest9ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllTest9ViewController.swift; sourceTree = ""; }; 681BD8DB1E0B91A500403A1F /* TangramKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TangramKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 681BD8DD1E0B91A500403A1F /* TangramKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TangramKit.h; sourceTree = ""; }; 681BD8DE1E0B91A500403A1F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -292,6 +296,7 @@ 184243071E327F0800E2CCE1 /* FLLTest5ViewController.swift */, 18058AAE1E63B4EA00EAECDC /* FLLTest6ViewController.swift */, 20FC8FE120A4241D0029DE31 /* FLLTest7ViewController.swift */, + 4680F8FC211583FF00BFB765 /* FLLTest8ViewController.swift */, ); path = FlowLayoutDemo; sourceTree = ""; @@ -316,6 +321,7 @@ 68F036041E0B7D2700CEBAEF /* AllTest6ViewController.swift */, 68F036051E0B7D2700CEBAEF /* AllTest7ViewController.swift */, 18BCBD451E1336D900AC7766 /* AllTest8ViewController.swift */, + 4680F8FE2115891600BFB765 /* AllTest9ViewController.swift */, 68F036061E0B7D2700CEBAEF /* AllTestModel&View */, ); path = IntegratedDemo; @@ -544,6 +550,7 @@ 18058AAF1E63B4EA00EAECDC /* FLLTest6ViewController.swift in Sources */, 68F036501E0B7D2700CEBAEF /* AllTest2ViewController.swift in Sources */, 20B6C6E71FA40AEC001D51C7 /* DetailViewController.swift in Sources */, + 4680F8FD211583FF00BFB765 /* FLLTest8ViewController.swift in Sources */, 184243081E327F0800E2CCE1 /* FLLTest5ViewController.swift in Sources */, 68F0363D1E0B7D2700CEBAEF /* CFTool.swift in Sources */, 68F036581E0B7D2700CEBAEF /* AllTest2TableViewCell.swift in Sources */, @@ -580,6 +587,7 @@ 68F0364C1E0B7D2700CEBAEF /* FLTest2ViewController.swift in Sources */, 68F036471E0B7D2700CEBAEF /* FLLTest1ViewController.swift in Sources */, 68F036691E0B7D2700CEBAEF /* LLTest3ViewController.swift in Sources */, + 4680F8FF2115891600BFB765 /* AllTest9ViewController.swift in Sources */, 68F036511E0B7D2700CEBAEF /* AllTest3ViewController.swift in Sources */, 68F0364B1E0B7D2700CEBAEF /* FLTest1ViewController.swift in Sources */, 68F0363C1E0B7D2700CEBAEF /* AppDelegate.swift in Sources */, diff --git a/TangramKit/TGBaseLayout.swift b/TangramKit/TGBaseLayout.swift index 07e1402..8d69766 100644 --- a/TangramKit/TGBaseLayout.swift +++ b/TangramKit/TGBaseLayout.swift @@ -1031,6 +1031,24 @@ open class TGBaseLayout: UIView,TGLayoutViewSizeClass { } + public var tg_layoutTransform: CGAffineTransform + { + get + { + return (self.tgCurrentSizeClass as! TGLayoutViewSizeClass).tg_layoutTransform + } + set + { + let lsc = self.tgCurrentSizeClass as! TGLayoutViewSizeClass + if lsc.tg_layoutTransform != newValue + { + lsc.tg_layoutTransform = newValue + setNeedsLayout() + } + + } + } + /** 把一个布局视图放入到UIScrollView(UITableView和UICollectionView除外)内时是否自动调整UIScrollView的contentSize值。默认是.auto表示布局视图会自动接管UIScrollView的contentSize的值。 你可以将这个属性设置.no而不调整和控制contentSize的值,设置为.yes则一定会调整contentSize. @@ -3285,7 +3303,19 @@ extension TGBaseLayout //最终的结果是非布局视图的宽度是wrap的情况下适用。 if (sbv as? TGBaseLayout) == nil && sbvsc.width.isWrap { - let fitSize = sbv.sizeThatFits(CGSize.zero) + var fits = CGSize.zero + + if let t = sbvsc.width.maxVal?.numberVal + { + fits.width = t + } + + if let t = sbvsc.height.maxVal?.numberVal + { + fits.height = t + } + + let fitSize = sbv.sizeThatFits(fits) sbvtgFrame.width = sbvsc.width.measure(fitSize.width) if sbvsc.height.isWrap { @@ -3344,6 +3374,35 @@ extension TGBaseLayout } } } + + internal func tgAdjustSubviewsLayoutTransform(sbs:[UIView], lsc:TGLayoutViewSizeClassImpl, selfSize:CGSize) + { + let layoutTransform = lsc.tg_layoutTransform + if !layoutTransform.isIdentity + { + for sbv in sbs + { + let sbvtgFrame = sbv.tgFrame + + //取子视图中心点坐标。因为这个坐标系的原点是布局视图的左上角,所以要转化为数学坐标系的原点坐标, 才能应用坐标变换。 + var centerPoint = CGPoint(x:sbvtgFrame.leading + sbvtgFrame.width / 2.0 - selfSize.width / 2.0, + y:sbvtgFrame.top + sbvtgFrame.height / 2.0 - selfSize.height / 2.0) + + //应用坐标变换 + centerPoint = centerPoint.applying(layoutTransform) + + //还原为左上角坐标系。 + centerPoint.x += selfSize.width / 2.0 + centerPoint.y += selfSize.height / 2.0 + + //根据中心点的变化调整开始和结束位置。 + sbvtgFrame.leading = centerPoint.x - sbvtgFrame.width / 2.0 + sbvtgFrame.trailing = sbvtgFrame.leading + sbvtgFrame.width + sbvtgFrame.top = centerPoint.y - sbvtgFrame.height / 2.0 + sbvtgFrame.bottom = sbvtgFrame.top + sbvtgFrame.height + } + } + } internal func tgGetSubviewFrameAndSizeClass(_ subview:UIView) -> (TGFrame, TGViewSizeClassImpl) { diff --git a/TangramKit/TGFloatLayout.swift b/TangramKit/TGFloatLayout.swift index 6e3e989..9748941 100644 --- a/TangramKit/TGFloatLayout.swift +++ b/TangramKit/TGFloatLayout.swift @@ -254,7 +254,7 @@ open class TGFloatLayout: TGBaseLayout,TGFloatLayoutViewSizeClass { tgAdjustLayoutSelfSize(selfSize: &selfSize, lsc: lsc) - + tgAdjustSubviewsLayoutTransform(sbs: sbs, lsc: lsc, selfSize: selfSize) tgAdjustSubviewsRTLPos(sbs: sbs, selfWidth: selfSize.width) diff --git a/TangramKit/TGFlowLayout.swift b/TangramKit/TGFlowLayout.swift index e3fd099..bc6f623 100644 --- a/TangramKit/TGFlowLayout.swift +++ b/TangramKit/TGFlowLayout.swift @@ -241,11 +241,11 @@ open class TGFlowLayout:TGBaseLayout,TGFlowLayoutViewSizeClass { /** - *在内容约束流式布局的一些应用场景中我们有时候希望某些子视图的宽度是固定的情况下,子视图的间距是浮动的而不是固定的,这样就可以尽可能的容纳更多的子视图。比如每个子视图的宽度是固定80,那么在小屏幕下每行只能放3个,而我们希望大屏幕每行能放4个或者5个子视图。 因此您可以通过如下方法来设置浮动间距,这个方法会根据您当前布局的orientation方向不同而意义不同: + *在流式布局的一些应用场景中我们有时候希望某些子视图的宽度或者高度是固定的情况下,子视图的间距是浮动的而不是固定的。比如每个子视图的宽度是固定80,那么在小屏幕下每行只能放3个,而我们希望大屏幕每行能放4个或者5个子视图。 因此您可以通过如下方法来设置浮动间距,这个方法会根据您当前布局的orientation方向不同而意义不同: 1.如果您的布局方向是.vert表示设置的是子视图的水平间距,其中的size指定的是子视图的宽度,minSpace指定的是最小的水平间距,maxSpace指定的是最大的水平间距,如果指定的subviewSize计算出的间距大于这个值则会调整subviewSize的宽度。 2.如果您的布局方向是.horz表示设置的是子视图的垂直间距,其中的size指定的是子视图的高度,minSpace指定的是最小的垂直间距,maxSpace指定的是最大的垂直间距,如果指定的subviewSize计算出的间距大于这个值则会调整subviewSize的高度。 3.如果您不想使用浮动间距则请将subviewSize设置为0就可以了。 - 4.这个方法只在内容约束流式布局里面设置才有意义。 + 4.对于数量约束流式布局来说,因为每行和每列的数量的固定的,因此不存在根据屏幕的大小自动换行的能力以及进行最佳数量的排列,但是可以使用这个方法来实现所有子视图尺寸固定但是间距是浮动的功能需求。 */ public func tg_setSubviews(size:CGFloat, minSpace:CGFloat, maxSpace:CGFloat = CGFloat.greatestFiniteMagnitude, inSizeClass type:TGSizeClassType = TGSizeClassType.default) { @@ -424,7 +424,7 @@ open class TGFlowLayout:TGBaseLayout,TGFlowLayoutViewSizeClass { } tgAdjustLayoutSelfSize(selfSize: &selfSize, lsc: lsc) - + tgAdjustSubviewsLayoutTransform(sbs: sbs, lsc: lsc, selfSize: selfSize) tgAdjustSubviewsRTLPos(sbs: sbs, selfWidth: selfSize.width) return self.tgAdjustSizeWhenNoSubviews(size: selfSize, sbs: sbs, lsc:lsc) @@ -888,9 +888,36 @@ extension TGFlowLayout let horzGravity:TGGravity = self.tgConvertLeftRightGravityToLeadingTrailing(lsc.tg_gravity & TGGravity.vert.mask) let vertAlignment:TGGravity = lsc.tg_arrangedGravity & TGGravity.horz.mask - let horzSpace = lsc.tg_hspace + var horzSpace = lsc.tg_hspace let vertSpace = lsc.tg_vspace - + var subviewSize = lsc.subviewSize + if (subviewSize != 0) + { + + let minSpace = lsc.minSpace + let maxSpace = lsc.maxSpace + + if arrangedCount > 1 + { + horzSpace = (selfSize.width - lsc.tgLeadingPadding - lsc.tgTrailingPadding - subviewSize * CGFloat(arrangedCount))/CGFloat(arrangedCount - 1) + + if _tgCGFloatGreat(horzSpace , maxSpace) || _tgCGFloatLess(horzSpace, minSpace) + { + if _tgCGFloatGreat(horzSpace , maxSpace) + { + horzSpace = maxSpace + } + + if _tgCGFloatLess(horzSpace, minSpace) + { + horzSpace = minSpace + } + + subviewSize = (selfSize.width - lsc.tgLeadingPadding - lsc.tgTrailingPadding - horzSpace * CGFloat(arrangedCount - 1)) / CGFloat(arrangedCount) + + } + } + } //判断父滚动视图是否分页滚动 var isPagingScroll = false @@ -984,12 +1011,17 @@ extension TGFlowLayout } else { - if (pagingItemWidth != 0) + if subviewSize != 0 + { + rect.size.width = subviewSize + } + + if pagingItemWidth != 0 { rect.size.width = pagingItemWidth } - if (sbvsc.width.numberVal != nil && !averageArrange) + if sbvsc.width.numberVal != nil && !averageArrange { rect.size.width = sbvsc.width.measure; } @@ -1553,9 +1585,38 @@ extension TGFlowLayout let horzGravity:TGGravity = self.tgConvertLeftRightGravityToLeadingTrailing(lsc.tg_gravity & TGGravity.vert.mask) let horzAlignment:TGGravity = self.tgConvertLeftRightGravityToLeadingTrailing(lsc.tg_arrangedGravity & TGGravity.vert.mask) - let vertSpace = lsc.tg_vspace let horzSpace = lsc.tg_hspace - + var vertSpace = lsc.tg_vspace + var subviewSize = lsc.subviewSize; + if (subviewSize != 0) + { + + let minSpace = lsc.minSpace + let maxSpace = lsc.maxSpace + + if (arrangedCount > 1) + { + vertSpace = (selfSize.height - lsc.tgTopPadding - lsc.tgBottomPadding - subviewSize * CGFloat(arrangedCount))/CGFloat(arrangedCount - 1) + + if _tgCGFloatGreat(vertSpace , maxSpace) || _tgCGFloatLess(vertSpace, minSpace) + { + if _tgCGFloatGreat(vertSpace , maxSpace) + { + vertSpace = maxSpace + } + + if _tgCGFloatLess(vertSpace , minSpace) + { + vertSpace = minSpace + } + + + subviewSize = (selfSize.height - lsc.tgTopPadding - lsc.tgBottomPadding - vertSpace * CGFloat(arrangedCount - 1)) / CGFloat(arrangedCount) + + } + + } + } //判断父滚动视图是否分页滚动 var isPagingScroll = false @@ -1659,6 +1720,12 @@ extension TGFlowLayout } else { + + if subviewSize != 0 + { + rect.size.height = subviewSize + } + if (pagingItemHeight != 0) { rect.size.height = pagingItemHeight @@ -2039,16 +2106,16 @@ extension TGFlowLayout rect.size.width = sbvsc.width.numberSize(rect.size.width) - rect.size.height = sbvsc.height.numberSize(rect.size.height) - - - rect = tgSetSubviewRelativeSize(sbvsc.height, selfSize: selfSize, sbvsc:sbvsc, lsc:lsc, rect: rect) - if subviewSize != 0 { rect.size.height = subviewSize } + rect.size.height = sbvsc.height.numberSize(rect.size.height) + + + rect = tgSetSubviewRelativeSize(sbvsc.height, selfSize: selfSize, sbvsc:sbvsc, lsc:lsc, rect: rect) + rect = tgSetSubviewRelativeSize(sbvsc.width, selfSize: selfSize, sbvsc:sbvsc, lsc:lsc, rect: rect) if sbvsc.height.weightVal != nil || sbvsc.height.isFill diff --git a/TangramKit/TGFrameLayout.swift b/TangramKit/TGFrameLayout.swift index 0c20e92..9b319c6 100644 --- a/TangramKit/TGFrameLayout.swift +++ b/TangramKit/TGFrameLayout.swift @@ -150,6 +150,7 @@ open class TGFrameLayout: TGBaseLayout,TGFrameLayoutViewSizeClass { } } + tgAdjustSubviewsLayoutTransform(sbs: sbs, lsc: lsc, selfSize: selfSize) tgAdjustSubviewsRTLPos(sbs: sbs, selfWidth: selfSize.width) return self.tgAdjustSizeWhenNoSubviews(size: selfSize, sbs: sbs, lsc:lsc) diff --git a/TangramKit/TGLayoutSizeClass.swift b/TangramKit/TGLayoutSizeClass.swift index 030528e..e88eb73 100644 --- a/TangramKit/TGLayoutSizeClass.swift +++ b/TangramKit/TGLayoutSizeClass.swift @@ -157,6 +157,8 @@ public protocol TGLayoutViewSizeClass:TGViewSizeClass var tg_reverseLayout: Bool{get set} var tg_gravity:TGGravity{get set} + + var tg_layoutTransform:CGAffineTransform{get set} } @@ -611,6 +613,7 @@ internal class TGLayoutViewSizeClassImpl:TGViewSizeClassImpl,TGLayoutViewSizeCla var tg_reverseLayout: Bool = false var tg_gravity: TGGravity = TGGravity.none + var tg_layoutTransform: CGAffineTransform = CGAffineTransform.identity internal var tgTopPadding:CGFloat { @@ -827,6 +830,7 @@ internal class TGLayoutViewSizeClassImpl:TGViewSizeClassImpl,TGLayoutViewSizeCla tsc.tg_hspace = self.tg_hspace tsc.tg_reverseLayout = self.tg_reverseLayout tsc.tg_gravity = self.tg_gravity + tsc.tg_layoutTransform = self.tg_layoutTransform return tsc } diff --git a/TangramKit/TGLinearLayout.swift b/TangramKit/TGLinearLayout.swift index f45e210..634cc83 100644 --- a/TangramKit/TGLinearLayout.swift +++ b/TangramKit/TGLinearLayout.swift @@ -335,7 +335,7 @@ open class TGLinearLayout: TGBaseLayout,TGLinearLayoutViewSizeClass { tgAdjustLayoutSelfSize(selfSize: &selfSize, lsc: lsc) - + tgAdjustSubviewsLayoutTransform(sbs: sbs, lsc: lsc, selfSize: selfSize) tgAdjustSubviewsRTLPos(sbs: sbs, selfWidth: selfSize.width) return self.tgAdjustSizeWhenNoSubviews(size: selfSize, sbs: sbs, lsc:lsc) diff --git a/TangramKit/TGPathLayout.swift b/TangramKit/TGPathLayout.swift index d8d012d..4bea0fe 100644 --- a/TangramKit/TGPathLayout.swift +++ b/TangramKit/TGPathLayout.swift @@ -642,6 +642,7 @@ open class TGPathLayout : TGBaseLayout,TGPathLayoutViewSizeClass { tgAdjustLayoutSelfSize(selfSize: &selfSize, lsc: lsc) + tgAdjustSubviewsLayoutTransform(sbs: sbs, lsc: lsc, selfSize: selfSize) return self.tgAdjustSizeWhenNoSubviews(size: selfSize, sbs: sbs2, lsc:lsc) } diff --git a/TangramKit/TGRelativeLayout.swift b/TangramKit/TGRelativeLayout.swift index eede451..7f01d51 100644 --- a/TangramKit/TGRelativeLayout.swift +++ b/TangramKit/TGRelativeLayout.swift @@ -119,7 +119,7 @@ open class TGRelativeLayout: TGBaseLayout,TGRelativeLayoutViewSizeClass { let sbs2 = self.tgGetLayoutSubviews() tgAdjustLayoutSelfSize(selfSize: &selfSize, lsc: lsc) - + tgAdjustSubviewsLayoutTransform(sbs: sbs2, lsc: lsc, selfSize: selfSize) tgAdjustSubviewsRTLPos(sbs: sbs2, selfWidth: selfSize.width) return self.tgAdjustSizeWhenNoSubviews(size: selfSize, sbs: sbs2, lsc:lsc) diff --git a/TangramKit/TangramKit.swift b/TangramKit/TangramKit.swift index bfa1877..da82a55 100644 --- a/TangramKit/TangramKit.swift +++ b/TangramKit/TangramKit.swift @@ -53,7 +53,7 @@ */ -//Current version is 1.1.6, please open: https://github.com/youngsoft/TangramKit/blob/master/CHANGELOG.md to show the changes. +//Current version is 1.2.0, please open: https://github.com/youngsoft/TangramKit/blob/master/CHANGELOG.md to show the changes. diff --git a/TangramKitDemo/FlowLayoutDemo/FLLTest8ViewController.swift b/TangramKitDemo/FlowLayoutDemo/FLLTest8ViewController.swift new file mode 100644 index 0000000..2f15e79 --- /dev/null +++ b/TangramKitDemo/FlowLayoutDemo/FLLTest8ViewController.swift @@ -0,0 +1,92 @@ +// +// FLLTest8ViewController.swift +// TangramKit +// +// Created by apple on 16/7/18. +// Copyright © 2016年 youngsoft. All rights reserved. +// + +import UIKit + + + +/** + *8.FlowLayout - Flex space + */ +class FLLTest8ViewController: UIViewController { + + override func loadView() { + + /* + 这个例子主要用于展示流式布局的间距的可伸缩性。当我们布局视图中的子视图的宽度或者高度为固定值,但是其中的间距又希望是可以伸缩的,那么就可以借助流式布局提供的方法 + + -(void)setSubviewsSize:(CGFloat)subviewSize minSpace:(CGFloat)minSpace maxSpace:(CGFloat)maxSpace; + + 来设置子视图的尺寸,以及最小和最大的间距值。并且当布局视图中子视图的间距小于最小值时会自动调整子视图的尺寸来满足这个最小的间距。 + + 对于垂直流式布局来说,这个方法只用于设置子视图的宽度和水平间距。 + 对于水平流式布局来说,这个方法只用于设置子视图的高度和垂直间距。 + + + 你可以在这个界面中尝试一下屏幕的旋转,看看布局为了支持横屏和竖屏而进行的布局调整,以便达到最完美的布局效果。 + + */ + + self.edgesForExtendedLayout = UIRectEdge(rawValue:0) //设置视图控制器中的视图尺寸不延伸到导航条或者工具条下面。您可以注释这句代码看看效果。 + + //这里的根视图是一个每列只有一个子视图的垂直流式布局,效果就相当于垂直线性布局了。 + let rootLayout = TGFlowLayout(.vert, arrangedCount: 1) + rootLayout.tg_gravity = .fill //这里将tg_gravity设置为.fill表明子视图的宽度和高度都将平分这个流式布局,可见一个简单的属性设置就可以很容易的实现子视图的尺寸的设置,而不需要编写太复杂的约束。 + rootLayout.tg_space = 10 + rootLayout.backgroundColor = .white + self.view = rootLayout + + + let vertLayout = TGFlowLayout(.vert, arrangedCount: 4) + //这个垂直流式布局中,每个子视图之间的水平间距是浮动的,并且子视图的宽度是固定为60。间距最小为10,最大不限制。 + vertLayout.tg_setSubviews(size:60, minSpace:10, maxSpace:CGFloat.greatestFiniteMagnitude) + vertLayout.tg_padding = UIEdgeInsetsMake(5, 5, 5, 5) + vertLayout.backgroundColor = CFTool.color(5) + vertLayout.tg_vspace = 20 + vertLayout.tg_gravity = TGGravity.vert.fill //因为上面tg_setSubviews设置了固定宽度,这个属性设置子视图的高度是填充满子布局视图,因此系统内部会自动设置每个子视图的高度,如果你不设置这个属性,那么你就需要在下面分别为每个子视图设置高度。 + rootLayout.addSubview(vertLayout) + + for i in 0 ..< 14 + { + let label = UILabel() + //label.tg_height.equal(60) 因为子视图的宽度在布局视图的tg_setSubviews中设置了,你也可以在这里单独为每个子视图设置高度,当然如果你的父布局视图使用了tg_gravity来设置填充属性的话,那么子视图是不需要单独设置高度尺寸的。 + label.text = "\(i)" //[NSString stringWithFormat:@"%d", i]; + label.textAlignment = .center + label.backgroundColor = CFTool.color(2) + vertLayout.addSubview(label) + } + + + + let horzLayout = TGFlowLayout(.horz, arrangedCount: 4) + //这个水平流式布局中,每个子视图之间的垂直间距是浮动的,并且子视图的高度是固定为60。间距最小为10,最大不限制。 + horzLayout.tg_setSubviews(size:60, minSpace:10, maxSpace:CGFloat.greatestFiniteMagnitude) + horzLayout.tg_padding = UIEdgeInsetsMake(5, 5, 5, 5) + horzLayout.backgroundColor = CFTool.color(6) + horzLayout.tg_hspace = 20 + horzLayout.tg_gravity = TGGravity.horz.fill //因为上面tg_setSubviews设置了固定高度,这个属性设置子视图的宽度是填充满子布局视图,因此系统内部会自动设置每个子视图的宽度,如果你不设置这个属性,那么你就需要在下面分别为每个子视图设置宽度。 + rootLayout.addSubview(horzLayout) + + for i in 0 ..< 14 + { + let label = UILabel() + //label.tg_height.equal(60) 因为子视图的高度在布局视图的setSubviewsSize:minSpace:maxSpace:中设置了,你也可以在这里单独为每个子视图设置宽度,当然如果你的父布局视图使用了gravity来设置填充属性的话,那么子视图是不需要单独设置宽度尺寸的。 + label.text = "\(i)" //[NSString stringWithFormat:@"%d", i]; + label.textAlignment = .center + label.backgroundColor = CFTool.color(3) + horzLayout.addSubview(label) + } + + } + + + override func viewDidLoad() { + super.viewDidLoad() + + } +} diff --git a/TangramKitDemo/IntegratedDemo/AllTest9ViewController.swift b/TangramKitDemo/IntegratedDemo/AllTest9ViewController.swift new file mode 100644 index 0000000..ad07e0e --- /dev/null +++ b/TangramKitDemo/IntegratedDemo/AllTest9ViewController.swift @@ -0,0 +1,201 @@ +// +// AllTest9ViewController.swift +// TangramKitDemo +// +// Created by fzy on 2018/8/4. +// Copyright © 2018年 youngsoft. All rights reserved. +// + +import UIKit + +/** + *❁3.Subviews layout transform + */ +class AllTest9ViewController: UIViewController { + + var contentLayout:TGBaseLayout! + + override func loadView() { + + /* + + 这个DEMO主要用来演示布局视图的tg_layoutTransform属性的使用和设置方法,这个属性用来对布局视图内所有子视图的位置进行坐标变换。只要你了解CGAffineTransform的设置和使用 + 方法,就可以用他来进行各种布局视图内子视图的整体的坐标变换,比如:平移、缩放、水平反转、垂直反转、旋转等以及一些复合的坐标变换。在下面的例子里面我分别列举了一些常见的布局位置 + 坐标变换的设置方法以及参数。 + + + 当你的布局内所有视图都需要有统一的变换的动画时,你可以借助tg_layoutTransform属性并且配合tg_layoutAnimationWithDuration方法来实现动画效果。 + + */ + + self.edgesForExtendedLayout = UIRectEdge(rawValue:0) //设置视图控制器中的视图尺寸不延伸到导航条或者工具条下面。您可以注释这句代码看看效果。 + + let rootLayout = TGLinearLayout(.vert) + rootLayout.tg_gravity = TGGravity.horz.fill //里面所有子视图的宽度都填充为和父视图一样宽。 + rootLayout.backgroundColor = .white + self.view = rootLayout + + + //添加操作按钮。 + let actionLayout = TGFlowLayout(.vert, arrangedCount: 2) + actionLayout.tg_height.equal(.wrap) + actionLayout.tg_gravity = TGGravity.horz.fill //所有子视图水平填充,也就是所有子视图的宽度相等。 + actionLayout.tg_padding = UIEdgeInsetsMake(5, 5, 5, 5) + actionLayout.tg_hspace = 5 + actionLayout.tg_vspace = 5 + rootLayout.addSubview(actionLayout) + + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Identity", comment:""), action:#selector(handleIdentityTransform))) + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Translation", comment:""),action:#selector(handleTranslationTransform))) + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Scale", comment:""), + action:#selector(handleScaleTransform))) + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Horz Reflection", comment:""), + action:#selector(handleHorzReflectionTransform))) + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Vert Reflection", comment:""), + action:#selector(handleVertReflectionTransform))) + actionLayout.addSubview(self.createActionButton(NSLocalizedString("Reverse", comment:""), + action:#selector(handleReverseTransform))) + + + + //下面是用于测试的layoutTransform属性的布局视图,本系统中的所有布局视图都支持layoutTransform属性。 + let contentLayout = TGFlowLayout(.vert, arrangedCount: 4) + contentLayout.backgroundColor = CFTool.color(5) + contentLayout.tg_height.equal(.fill) + contentLayout.tg_space = 10 + rootLayout.addSubview(contentLayout) + self.contentLayout = contentLayout + + for i in 0 ..< 14 + { + let label = UILabel() + label.text = "\(i)" + label.backgroundColor = .red + label.tg_size(CGSize(width:40,height:40)) + label.textAlignment = .center + contentLayout.addSubview(label) + } + + } + + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + + /* + // 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.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} + +//MAKR: -Layout Construction +extension AllTest9ViewController +{ + //创建动作操作按钮。 + func createActionButton(_ title:String,action:Selector) ->UIButton + { + let button = UIButton(type:.system) + button.setTitle(title, for: UIControlState()) + button.titleLabel?.font = CFTool.font(14) + button.layer.borderColor = UIColor.lightGray.cgColor + button.layer.borderWidth = 0.5 + button.addTarget(self,action:action, for:.touchUpInside) + button.tg_height.equal(30) + return button + + } + + +} + +//MARK: -Handle Method +extension AllTest9ViewController +{ + @objc func handleIdentityTransform(_ sender:AnyObject?) + { + //还原位置的坐标变换,这也是默认值。 + self.contentLayout.tg_layoutTransform = .identity + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + + } + + @objc func handleTranslationTransform(_ sender:AnyObject?) + { + if self.contentLayout.tg_layoutTransform.isIdentity + { + self.contentLayout.tg_layoutTransform = CGAffineTransform(translationX: 100, y: 0) + } + else if self.contentLayout.tg_layoutTransform == CGAffineTransform(translationX: 100, y: 0) + { + self.contentLayout.tg_layoutTransform = CGAffineTransform(translationX: 100, y: 100) + } + else + { + self.contentLayout.tg_layoutTransform = CGAffineTransform.identity + } + + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + + } + + @objc func handleScaleTransform(_ sender:AnyObject?) + { + + //布局内子视图位置的放大和缩小的位置变换。因为缩放是以布局视图的中心点为中心进行缩放的,所以如果是想要以某个点为中心进行缩放。所以在缩放的同时还需要进行位移的调整。 + //下面的例子里面,因为缩放默认是以布局视图的中心点为中心进行缩放,但这里是想以第一个子视图保持不变而进行缩放,所以除了要进行缩放外,还需要调整所有子视图的偏移,因为第一个 + //子视图的中心点的位置按照布局视图中心点原点坐标的话位置是: (20 - 布局视图的宽度/2, 20 - 布局视图的高度/2), 这里的20是因为视图的高度都是40。 + //所以只要保证第一个子视图的中心点在放大后的位置还是一样,就会实现以第一个子视图为中心进行放大的效果。 + + + let size = self.contentLayout.frame.size + + //缩放因子。 + let factor:CGFloat = 2.0 //你可以试试0.9看看效果。 + + self.contentLayout.tg_layoutTransform = CGAffineTransform(a:factor, b:0, c:0, d:factor, tx:(1 - factor) * (20 - size.width / 2.0), ty:(1 - factor) * (20 - size.height / 2)); //这里因为要让第一个子视图的位置保持不变,所以tx,ty参数需要进行特殊设置。 + + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + + + } + + + + @objc func handleHorzReflectionTransform(_ sender:AnyObject?) + { + //布局内所有子视图都进行水平翻转排列,也就是水平镜像的效果。 + self.contentLayout.tg_layoutTransform = CGAffineTransform(a:-1,b:0,c:0,d:1,tx:0,ty:0) + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + } + + @objc func handleVertReflectionTransform(_ sender:AnyObject?) + { + //布局内所有子视图都进行垂直翻转排列,也就是垂直镜像的效果。 + self.contentLayout.tg_layoutTransform = CGAffineTransform(a:1,b:0,c:0,d:-1,tx:0,ty:0) + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + } + + @objc func handleReverseTransform(_ sender:AnyObject?) + { + + //布局内所有子视图整体翻转180度的效果。 + self.contentLayout.tg_layoutTransform = CGAffineTransform(a:-1,b:0,c:0,d:-1,tx:0,ty:0) + self.contentLayout.tg_layoutAnimationWithDuration(0.3) + } + +} diff --git a/TangramKitDemo/Support Files/zh-Hans.lproj/Localizable.strings b/TangramKitDemo/Support Files/zh-Hans.lproj/Localizable.strings index 4c4e416..d3f28cd 100644 --- a/TangramKitDemo/Support Files/zh-Hans.lproj/Localizable.strings +++ b/TangramKitDemo/Support Files/zh-Hans.lproj/Localizable.strings @@ -33,6 +33,7 @@ "5.FlowLayout - Paging" = "5.流式布局-对分页滚动的支持"; "6.FlowLayout - Scroll" = "6.流式布局-不同方向的滚动"; "7.FlowLayout - Auto Arrange" = "7.流式布局-自动布局和对瀑布流的支持"; +"8.FlowLayout - Flex space" = "8.流式布局-浮动间距"; "1.FloatLayout - Float" = "1.浮动布局-浮动效果的演示"; "2.FloatLayout - Jagged" = "2.浮动布局-仿天猫淘宝首页实现" ; "3.FloatLayout - Card news" = "3.浮动布局-仿ZAKER今日头条实现"; @@ -52,6 +53,7 @@ "2.SizeClass - Demo2" = "2.SizeClass-不同屏幕下的布局样式2"; "❁1.Screen perfect fit - Demo1" = "❁1.界面的完美适配DEMO"; "❁2.Screen perfect fit - Demo2" = "❁2.界面的完美适配DEMO2"; +"❁3.Subviews layout transform" = "❁3.布局内子视图的整体变换"; //LLTest1ViewController "vertical(from top to bottom)" = "垂直布局(从上到下)"; @@ -259,3 +261,11 @@ //AllTest8ViewController "Pop layoutview at center"="居中弹出布局视图"; "Title"="标题"; + +//AllTest9ViewController +"Identity"="正常"; +"Translation" = "平移"; +"Scale" = "缩放"; +"Horz Reflection" = "水平翻转"; +"Vert Reflection" = "垂直翻转"; +"Reverse" = "对角翻转"; diff --git a/TangramKitDemo/ViewController.swift b/TangramKitDemo/ViewController.swift index ef56d87..f028975 100644 --- a/TangramKitDemo/ViewController.swift +++ b/TangramKitDemo/ViewController.swift @@ -128,6 +128,9 @@ class ViewController: UITableViewController { demoVCList5.append(["title":NSLocalizedString("7.FlowLayout - Auto Arrange",comment:""), "class":FLLTest7ViewController.self] ) + demoVCList5.append(["title":NSLocalizedString("8.FlowLayout - Flex space",comment:""), + "class":FLLTest8ViewController.self] + ) //float layout list var demoVCList6 = [[String:Any]]() @@ -196,6 +199,9 @@ class ViewController: UITableViewController { demoVCList8.append(["title":NSLocalizedString("❁2.Screen perfect fit - Demo2",comment:""), "class":AllTest8ViewController.self] ) + demoVCList8.append(["title":NSLocalizedString("❁3.Subviews layout transform",comment:""), + "class":AllTest9ViewController.self] + ) //type list