From 1d512663b8bedb96d4c65f3e7e97ff198f7dd7e2 Mon Sep 17 00:00:00 2001 From: Eric Hyche Date: Tue, 1 Aug 2017 14:17:44 -0400 Subject: [PATCH] Enable changing of pinning and layoutMargin options --- .../project.pbxproj | 12 ++ .../UserInterfaceState.xcuserstate | Bin 28342 -> 29301 bytes .../Bool+Extensions.swift | 46 ++++++ .../CGFloat+Extensions.swift | 48 +++++++ .../EHPinningOptions.swift | 114 +++++++++++++++ .../EHStackViewSettingsModel.swift | 21 +-- .../EHStackViewSettingsViewController.swift | 135 ++++++++++++++++-- 7 files changed, 346 insertions(+), 30 deletions(-) create mode 100644 LearnAboutStackViews/LearnAboutStackViews/Bool+Extensions.swift create mode 100644 LearnAboutStackViews/LearnAboutStackViews/CGFloat+Extensions.swift create mode 100644 LearnAboutStackViews/LearnAboutStackViews/EHPinningOptions.swift diff --git a/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.pbxproj b/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.pbxproj index 729a151..6d27213 100644 --- a/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.pbxproj +++ b/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ FD07155F1F300A6300F7CB7A /* UILayoutConstraintAxis+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07155E1F300A6300F7CB7A /* UILayoutConstraintAxis+Extensions.swift */; }; FD0715611F300F4100F7CB7A /* UIStackViewDistribution+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0715601F300F4100F7CB7A /* UIStackViewDistribution+Extensions.swift */; }; FD0715631F3011F100F7CB7A /* UIStackViewAlignment+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0715621F3011F100F7CB7A /* UIStackViewAlignment+Extensions.swift */; }; + FD0715651F3027D400F7CB7A /* CGFloat+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0715641F3027D400F7CB7A /* CGFloat+Extensions.swift */; }; + FD96E4201F30DF810008DEE0 /* Bool+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD96E41F1F30DF810008DEE0 /* Bool+Extensions.swift */; }; + FD96E4221F30F3450008DEE0 /* EHPinningOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD96E4211F30F3450008DEE0 /* EHPinningOptions.swift */; }; FDD291411F2E18C2009CC565 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD291401F2E18C2009CC565 /* AppDelegate.swift */; }; FDD291431F2E18C2009CC565 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD291421F2E18C2009CC565 /* ViewController.swift */; }; FDD291461F2E18C2009CC565 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FDD291441F2E18C2009CC565 /* Main.storyboard */; }; @@ -38,6 +41,9 @@ FD07155E1F300A6300F7CB7A /* UILayoutConstraintAxis+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILayoutConstraintAxis+Extensions.swift"; sourceTree = ""; }; FD0715601F300F4100F7CB7A /* UIStackViewDistribution+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStackViewDistribution+Extensions.swift"; sourceTree = ""; }; FD0715621F3011F100F7CB7A /* UIStackViewAlignment+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStackViewAlignment+Extensions.swift"; sourceTree = ""; }; + FD0715641F3027D400F7CB7A /* CGFloat+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extensions.swift"; sourceTree = ""; }; + FD96E41F1F30DF810008DEE0 /* Bool+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bool+Extensions.swift"; sourceTree = ""; }; + FD96E4211F30F3450008DEE0 /* EHPinningOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EHPinningOptions.swift; sourceTree = ""; }; FDD2913D1F2E18C2009CC565 /* LearnAboutStackViews.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LearnAboutStackViews.app; sourceTree = BUILT_PRODUCTS_DIR; }; FDD291401F2E18C2009CC565 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; FDD291421F2E18C2009CC565 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -104,6 +110,7 @@ FDD2916F1F2E3656009CC565 /* EHStackViewSettingsViewController.swift */, FDD291741F2E7060009CC565 /* EHStackViewSettingsModel.swift */, FD07155C1F2FF3AD00F7CB7A /* EHSelectionViewController.swift */, + FD96E4211F30F3450008DEE0 /* EHPinningOptions.swift */, ); path = LearnAboutStackViews; sourceTree = ""; @@ -149,6 +156,8 @@ FD07155E1F300A6300F7CB7A /* UILayoutConstraintAxis+Extensions.swift */, FD0715601F300F4100F7CB7A /* UIStackViewDistribution+Extensions.swift */, FD0715621F3011F100F7CB7A /* UIStackViewAlignment+Extensions.swift */, + FD0715641F3027D400F7CB7A /* CGFloat+Extensions.swift */, + FD96E41F1F30DF810008DEE0 /* Bool+Extensions.swift */, ); name = Extensions; sourceTree = ""; @@ -237,7 +246,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + FD0715651F3027D400F7CB7A /* CGFloat+Extensions.swift in Sources */, FDD291431F2E18C2009CC565 /* ViewController.swift in Sources */, + FD96E4221F30F3450008DEE0 /* EHPinningOptions.swift in Sources */, FDD291701F2E3656009CC565 /* EHStackViewSettingsViewController.swift in Sources */, FDD291411F2E18C2009CC565 /* AppDelegate.swift in Sources */, FD07155D1F2FF3AD00F7CB7A /* EHSelectionViewController.swift in Sources */, @@ -247,6 +258,7 @@ FD0715611F300F4100F7CB7A /* UIStackViewDistribution+Extensions.swift in Sources */, FD07155F1F300A6300F7CB7A /* UILayoutConstraintAxis+Extensions.swift in Sources */, FDD291751F2E7060009CC565 /* EHStackViewSettingsModel.swift in Sources */, + FD96E4201F30DF810008DEE0 /* Bool+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.xcworkspace/xcuserdata/ehyche.xcuserdatad/UserInterfaceState.xcuserstate b/LearnAboutStackViews/LearnAboutStackViews.xcodeproj/project.xcworkspace/xcuserdata/ehyche.xcuserdatad/UserInterfaceState.xcuserstate index f32142b9d05ad79a0f87948c7673faa8b7d0987b..db66648564e03d22af3d9ec3ea927fc81d9a06bf 100644 GIT binary patch delta 13782 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 EKbfGPDgXcg delta 12712 zcmZ{J2Ut|c_x7E+jb&j4L=;fiMz6ceHi&?T(qUl>yOc##L=;6SHq^aiH+HWr#s=6m z(b!@%ru>qa#1>mj>>5ohNi0c>nne9(7g3YHpU0$>0pUmy3;+YcU{C{^ zz$h>pi~(c8IM58ng9%_JcoWP5v%wrN7t90m!3wa_0ak(4U<=p^-U07|ePBQM5F7ws zgG1mjI0C*0XTdpe9^3#o!7Xqb{0Sa{N8mA}Ap=?H27O@{=m(`x2IVjWDxeaoUtr7w7_+6J=_epz-@3l+y!^T z58yud5&Rf_20w>i!LQ*_cnqF~-@>!-GQ0w>!XMxb_$#~*|AY_WBlwhrBul!H0~av`~lTtTiRw~^b)_sAXOPI4Eyo7_Y0BlnXZlb?{El3$RA z$s^=(@&tK`JWYO2ULr4(SI9re2jrjRL-G;%nEZ?UoBW4-LOvy*Q3M4jmJ(8(DPO7! zKt{RxV}ME7Wxd^$+!gdP+T`2^!FlCTWVMX@+L$9&`{LOp9p=Ev03& zoDQKw=~!Avr_sIXEV_U;(1o;_w$UZDovxq<&;#kgbS*uSZlcH16X?nG6#7ki7QL8W zLNBG4(JSb8>236O`aOCFy_4QW@22Ypx-nu#!blkzBWI$S7)He;FghlgNnz5NTqcjn zXDm!HV`c2j0A?st%M4?hm{APJAZ8LXnc!4|Lvwva7m%h@V+5L?aGu_M@#>{xajJBbC8 z`MXpKsORJ8sa`S!LJ>$nAPE6G0u?(yr#*qNFZTfgLN27jD~wNNyYGC&><1v2-{ls< z|K%p(zr%k61yX*WAi&{H2#I0Dh*n}aQOAinDJMTkIQ!~}hBchzBw-{>L=!Q}o^Q-+ zYOL&ETh*(+zH)3E?yDh++eOC^4K2i2PR2<}%vrrgjObf8ys@Eu<^*D5*^8ORs>U{A z0^uNv&G|;$aEkC}1P?(U{+RnMkA_xaBe987a9U2ned55LD#9>ZmD zSzHd6#}#meoRKqg#hi^R<;uAVu96$TRdLl^4VESTA)XLV`A(uBJvWqVLxH-($Q z&F1EFi@0Un3T`#m#;xZzbMJ8Pal4(1sb;c8_wkiz>X{ z=Z{A!`4O4D`2B$f_jp&gslw|`{=QFteqxsdq1x4D!OP9S%XQ@)L2f%&c5VXhiLL=_ zh1WQjtY;6oFvZnXf@Mdzs7>)60Nm4Eon;kXGhK2kd#KnfSC^e%<3Gzi-}Sp+g;#@X zxSzPQ_sfkNU4xiNpQS=zbu|W7cnxz&E)D3)mb7S))=$i{mFew>q!}ta~lq zdawcGZQ>9&3FA#}$CEp{r3ez7*QIH#;xrPVnZYV;}$n4r@B3-BZGSqH`L|5E7Z;0uiSB{!3M6C=*z z_lAasgQMVNhxEUMPl3}|_zX9Pn~R0#@kkcpxB#xcmg*1S8kYT$Tfi;EvV1$$DUEaH zZ+B94ZdVzva_(KN)M0JvUug4ZaPPH?-v_^8z(2Uf+!749v|XD%ygf|p0DpmJubTr2 z2tYj~xwp9Gc+T7HbKLbk=6zA#tW@ch@mOK;dfkN5W@SQxN`pBmJ9t0=6ulO+6ZCQ^ zVI{Z9sRWG4Zwd=^bcNktrw7;r24MNArU5FPCdB|+(rzt zsa-9hLr!fzR_-LCQ(;A@;u9v6G%J+K1pTYLdc(}u@-k+@Y!|UD+}4-GdK}M9I^*J{ zROxgtcojm+Yk3tzE9OK zI`yEBcWG6ld-WQ?I@tJH_DygU1{=fe;oiq!d)p5QnVU~Mb(A(M^!Q{HYPH6BQFRzw zsd=%JiSSJ#d<%3y4k9=SPKHz9R5%Szhcn{?gf$9!t!R5!TE)%cV@8oAsJzUyjyhGWeXH@MT) z_<~m?jPZLVq`|$e{x2)M#`2Pgq5PUyiXWnOcOttVa1DK3;nnCGnjGURg#UB(9d<^E zcJa<`@Jm07$@fyqy2CR> zbqoBCJH_=lO&o&fh{J>so`)CUMRrWM$;fGm80RKz{%Kr%a# zEZpN)k!%>L6eInOk^XWbwOgV>6Oi1G?EeB~0QaN=Wsno4ntS>x$`FiF3oju+V3=o4 zm=5E0joyAwv>B-L?Y#F0F?7$cF35b$UrmmnbemscR)c3v?A zJS)6Lx-u-SzH8npay=2gfm}_lAzR2+vW;9zu0x;`0$vDsBjAHTX9Ro^=(2&_KyD;A zk(1pE-_hCl!Ufe3U*K!Sjje_M|{$oGj6E#zJVx^i;fmMHdi-6`@zXYT<7 z{9U~n4)T8_&NW`i%E^P|S5Ed{BG99S{2GBEXMNMDYRrhr;RCA%W;Ip~%Sy*(2QFU7 zqvSU&QZOPPUi`q7V;bd z@)q&}0wH{CQmm1@O5P@XHj+P(*U0PSkK|9}4e};=3xO~M!V!o-AQFKn1fmg$K_GS` z`72Z6qPx8z+RJ*i%=lT4#}JD1KxAj`S*{p7%qY%2eCk_D83 zDnuX`fjk8Ac|}T0YB5#%I>|DsoWd2a0Rb#ugkx>WJ!hFn5CaHt2qeTOsR4wL8c0>` zT$NG>9Y&WGP}S7n@)reZdSzo}8}7oDtR>&*Y<28-C{<5{ug5zcMh&OpsS(sj*S^gN zSn$>nC`Q1#9xI@cYNAHre;ZwDupv-_Kp6t~hs|l7(ya78y#_SajH=;hr!8@Cm=K~S z73Ujc8*7GDIqQOuw{Cnf3xU#hc2lUS?L?|tsVPKpg_pOfZeZnDab+V;@DkNpu_4dv zw#&q+na-kH#F5S#9h*EghiKSL&86m1^Qi^YLW-vrQHzN?)KUccAuc<@SVd@BVl*0GE0Rem>O$dxaU^D{Q*N)vl9j8uECkYXC$ayId7>7VJ z0^{-5JJ963m2ID90f%36vo2b!Nth5VZdN2HacQMfC?`y4SMgQsaH&I1@g5y^@*{<- zjLp5a19%xTHj2G6GW&z&?E1W(vCl>UZi7 z>H+m9^^kgm^G57uGN*H%2+Tm>CIWX6j7BgHK|RhT&u}57*p^I{{c|h(SJhT{dEu6E zaNX$q%274dm5p`v<+!8Iz#9C^>Dl0qsr;X%E_y z7SWw(FWMV{nFzdz0Jg)~2+ToXE&}rqn2*4MO>}44mk{IJ<^tV~_NN1!PHZ6p8?eUC zI3vv02;g9I88<^pYAeUqH8q;*tFV#yy`YoFpU#~r$BdnH)2sS7RaaNJIG(1%=x{oM z5YmxEJ{?WR@ag7UX&Xl%z$38!3>`JRx5NJhUF?WWaW6-^UGm19458ao>9uD7%w-H#0 z&ymiibMX9JI*-mT$r@NSys>6bO;x=)3&#{}Hp>ur3xVbQ<%&q5m%w#N=_1<5Cl&^i zt+a{P6-v5vU|6t@@)20!RLgQc-rmjkIe2ONz^aY`|IRoWB@WU3=t=@lSc3q*YWU90 ze!f5zJ&1P{b|b5CD(WcoCWD12yAYlv8`_5LQHv;HN!j1Y&Jcg@M)vx z&~s^QMOzVg2Z49n=ml5{_*}O+weThXFmGVLx17|LBe4C&eWF*=_#4OudKJBzUPHIg zt#li`7J>H=*nz-K1a={?8-YCtyuX27Pj8?%(wp$nZK3fZIHC9e0h~a5?mD$E5ID&1 z%U|f|Jff+8ZOwq#hS4>H8eDtG0NM{<7T`YY_MhfsZ;YvHeVrI8E^=eT@DFfsYZu3w`<@Q+#20 zuQjfY&U5XC^}iQ}75y5+!gsO0ZnUX##E7ba;q_Gm>Z*s=jH{|ojNp5+5!g4paQ}3_ zc0aqOo#ZX&>D)%(E3QX{SC?jIH5~79iwfr#Cygq8LPz;Z-=TlU^)P*xzDM7ue?tKK z$ioO6LEz|G`Vaa6)kr@?0K4T=uE=IPQXifXC{yGA?C?I}Y#*L%hg3}7GvSdGUKIDx>)wN5`u*a@-IXY$d;sW~FX z3tKDE!o{^P*wdYUo;@?ZL_;gnh4Dk+TLjL%$aNThraMlqm;eT+PS{evYh`*cK?r=0 zz*+tWp^Q&41*C*9;s23|aLSy=GMwiB&}CwocuawbL*QZy#PuQnsWC{ZW;FlGIT<~Z z5w?gDjOB^Dp?}%*a>8`(phMW*S`bckm@l9e(9s z;-i^noEtJ@n6b<_1nwblAA#T6nDNX6W+DQ=BPc*HiVNW@tRZ}wHMrE)W(G5pc@u#@5O{#Vp9o;{eT2Z{^~`K$4l@_jGxMDp#9s*F z&ov}=5Rm2S`J8fpi5=_DQqxd_-${z_I_(PWSkoC9`5on<{Gjq&|BiK+Gb?bV!QgQ8 zcMG!;fq!^l5Ax zg%~<8-(&E1U*`~ZnRo~|e{OP3c!tAtpD~S9!y9VqhBs7r`M$i@N;UpMr&VZQTx(`O zbKoVlj}W9BoTg)mPZ?aDb@2NfLE2fdxKc9aOXh1lXlV&)ce+j&NvaK_?^U?hSe*dhko#Jsz$fWK=EOzwdFjd_Uu3iCVj2lIgW z6G1Noy%F?5u=85x5%U;B{f(e6f?b?AU0u&>_`La+QeXa*Et3DZB!Pco3klR~6O>Ag zLSGf{@}w+@OIwyg&<~fk@%CV?8!IAw);X79h0FsMW3?~T&9#>QI<^z*MTiM8+Zn+C z1Ost$g=Kp1d`UF_dx>23UwnW3e8&bjSLp6qq{7ReNAA9SeyLCqjLQU8j9?Hac_ls( z`K+8yVMEz4oGU=FGdjUw1S2ZE6#RUHAHSwl;)o=w*RoM;G#kUlA}B#nhF~ayVJ{*T zt8j%MD0PLO3a_Ggai7e*rrO4u5w%sl2iMgMsB*ga-uN}JzOJ^msy_C0aY&pfHfLp2 zH8eKWJFm?1=oBF~#3YNuBc4Y(R>R!JxfPV-v%|@i)ifA~h=F2-7u6v^wR7=vap~y9 zxuA1axT}-jQ>N+iT6@RdLDu0|*-SPE-yJrK%|8}>8@JCmKo&SmGb3)$7|26iXAn|+`Cz%ATO z;r51GAGaJggPYB5klQe~I=7K-4Q}Jy#=A{)wYeR1yWw`v?Y`UZZvO}tQIy4rwC^XX9?#B=LuH`TZC=Gb;8ZUt-^PO+l3zqPY53fpL(z!9v=Q4 zK^|fcsYjScgh!M|j7O}8)+5)$?C`L9lz5bR4D%T6fjs7T%=1{_!Fw$BBt1Pm{XK&` z#hy~nFwY3jD9;$r1kWT-gJ-qp2+#SROFiHBJnDJQ^StK;&r6;^i+n`BB0o_#QGlqs zC`cq0Nkwu|s3=?%DT)@wisD5|QG!S#Di>9VDn$cCRibK9jcBN7n8;Bl8YyZJHHk)x z#)_In6GRRX5=|D(7cCSm5-sua^^$nWyh6OfyjOZ}_TK9KuJ?8yl~1Zqnoqh-_LxH`=0bY?R&&|yy+%%JR`+@SoRnxOeXtAY*&eG_yc=wi^#pa(%ugNa}mOa(K+j!wbe!JUJ< z1a}Sg4^9X!4Xz1Z5WGBiL-6+C1HlJ_zY0DSd?ff-@OQyygU<(F489zEHTZV$Lwu(^ z#eU*$;s9}XagaDn93hSp$B5&^3hcr%#D!wJxLRBz9x5Itt`mJiB)%tpB4H$M5_gG*L?r1d@s|Wj zdPssL5=o>)EqOzdB`K1aBo>KPQX&~3sghJnY9vD?!z805lO=N`%O!1+b&?H|O_D8= zU6MVLy^?*B4<#Q-zLcDlT#($7{3iKB@~7mHD)lTpBO!DeWuG zlx9nFrTNlgsZClcEtghEE2TrEP0~ryS<*SudC~<^Ub;fMO1ehcDqSmGFWn~HC;eP{ zLV8YmL3&AgMf!vEXX&rfyVCp8-=znrw#bP1$VOV%cihR@rXZ`?3#Y`(+1Y2W4N$4#|$l zj>(S8&dPp}{VaPV2XazQ%UQWV?j!e=`^me>1LWQ1A@W$cPTohJFE_}GMtK~KFdig~84EbXDR{6W~?Q+Ks`7Ze$`Cj=x`G@k4Lw-yCv;2)#13oi{H96ltxHhg&a?eK@;kHh~Ce-hCcfg&b5BBn-6 zk9ZR49_bM&iu8({AGtDeb!1CqTa-8|CMrHk8KsWWM(Lx>QTC|Hr~y$`QKO>fMJ&4H+pC^ik=(2AexU}61^;Xd30O!`sj_(o1^zfABg@q`qSvo zV$x&sVoGAlV=7|$#|(@a6jK*dALD3@85J`Y}|#oOL14@uEqTrcPH+C-0yJ@;+c52c=vdZcv1Yc_<8Xw;#bGFIO5mF zuaDmt|6csA_&xD^fvO;tSmjuw+N9c}`arc`^^xjR)n}?Bs&7;$Ri{-ys&1-otA178 zO{h(1N|=-|HDN}=tc1A<^AlDktWIc2SgY=)4pAqlwdzE5Pj#xgx4N%7OKnw`s_p7Z z^+0vCdWd?Mx=uY)y;!|by+{4E`n>v<`Zx6h^&|CPngESV6RL^OL^(7$nxUF8nz5R3 zn(>;Mn%SCpnuVIhnx&denjMK7%e6bThqRZq zf9O1PA-W{pc%5UiZia5YZl!LGu1&XIw@J4}w^z4M_o411-C^Bv-6`D}-Fe+5-BsN+ z-7Vcc-D5q}chdXm{q^1T!TL~rgg#myr&s6)>K*!J`WF3G{Wkp${cinU{eJxc{UQAc z{b~Jo`g8iL`s?}|`rGhLo z#}bbxo=Loxcsude#CwUqC;pZAB#B5OljtN-l6O*gk~-;)q?Dwzq&`WxNd-woN#>;D zq<%@&Nh6ZR^t{;fO3zz8ANG8jOegy!2PaFDLz2UjqmpBj70JoTy^_tMy52T zj7}MsG9iUanUpd$WqQh@lqD(4Qr=DtOHD}Cr0Pf2ns=IS+S0VOY3tKArfuo1?w!^?C{sy@|y zYWmdnz0&vBzW?-nmH{*947UtnhA6{3L!2SY2+fGdh{}k~h|f@FBxLl?sLt4!@mb?t{>c^Q203yQb9?5d=Jw9* zo12+CE_ZV7o4Ipx=jZadi*s9Z-^tyXyC?U9+z)eq%DtI;KhG<#OI|`=ue|iUzIj=B z{qlz8jmWFdYs#CQ_g3DDyw!Ov`7!yL{M`J){ObG>`ETd1$v>QbJ^x1jt^8l|@8mzs z|11AV{<8wN0%d`=pt4{{!TbWp;)4AJUlklKI970?;B>*6f~N+dL1geY_!_zz{0%{d zD1*|VHs}mVhBQMTLxv&SkZTxYm~Yr`@p|m|kctY%E+@xTXD?IKfJXv_Y@KWK` z!fS;;72YhoU-+!Zy(qXyS`<CS(IATyQptbW|6tbT2xwOFB)1jyl6yG zLlIXrxoB$9jH1;=TZ^_8?I_w+bhPMCBWa|KtkK=r+308VHwGG2##CdLG1pjNEHavn zc4MV+pt0IG#8_)=GCJlMml<1)+l+gS`;8wNKQ(@CJZk*Lc*1zf_^t6f;{%hANo~qE zm746Pex?DYL8if`k)~0mv8M5+iKbbm`6k}9#Pqglm8r$lW_r)`x#_6sjOm)`rs-$X z9noHI?=^pFK4v~;K4U&>zGS{?zHa`>{Kx_EfJPzOPobvNw)O1^tEJJ@-2lHlf_~ww)C?Mv(#IfEMqJaESzPsWvXSa&E{_F zY74OSu!(IlTZm0*Q`>a5BwMmA)s|;7*o-!d&1NgL4Yt+ThS+LtV{OxHGi|eN^K1)k zi*3tn>ueirn{8Wd@7mt8?XvB$ow403aW4reNiE4Mv6R?K%1SCq`j-qXaSSgRS<+B4 zs$@(_YstQnJEdNw!KLA)QKhk^@ueB1rqYVi{-sr=gG+~&4lf;BI=<9Vib^M!PAi>J zy1n#7>6Ox3rFTm2m;O=uXPHk~U|CR^q)b+(D@!cvS(aMXyR2{7xU$J*v&-g{Ei7AH zwybP<*@m*sWn0U(l~d*3<-X-z9pwS#vht8}Wx2XsTb@{+QJ!6%TV7B;u6%O&^6~@a zhswVxKUw~5`ML57<(JB@ls~cu*u(6R_Go*YU1?9S_q3PZ_9OPQ_DlAw_Urar_FwENckTBps0!~2 szY70~?iG>>Sw%=iSVdMvb;a0 String { + return "Boolean Selection" + } + + func choiceCount() -> Int { + return 2 + } + + func choiceText(atIndex: Int) -> String { + let indexChoice: Bool = (atIndex == 0 ? true : false) + return "\(indexChoice)" + } + + func isChoiceSelected(atIndex: Int) -> Bool { + let indexChoice: Bool = (atIndex == 0 ? true : false) + return self == indexChoice + } + + func canSelectMultipleChoices() -> Bool { + return false + } + + func canSelectChoice(atIndex: Int) -> Bool { + return true + } + + mutating func setChoice(selected: Bool, atIndex: Int) { + if atIndex < choiceCount() && selected { + let indexChoice: Bool = (atIndex == 0 ? true : false) + self = indexChoice + } + } + +} diff --git a/LearnAboutStackViews/LearnAboutStackViews/CGFloat+Extensions.swift b/LearnAboutStackViews/LearnAboutStackViews/CGFloat+Extensions.swift new file mode 100644 index 0000000..c93f074 --- /dev/null +++ b/LearnAboutStackViews/LearnAboutStackViews/CGFloat+Extensions.swift @@ -0,0 +1,48 @@ +// +// CGFloat+Extensions.swift +// LearnAboutStackViews +// +// Created by Eric Hyche on 7/31/17. +// Copyright © 2017 HeirPlay Software. All rights reserved. +// + +import UIKit + +extension CGFloat: EHMultipleChoiceDataSource { + + static let numberOfChoices = 25 + static let choiceDelta: CGFloat = 5.0 + + func title() -> String { + return "CGFloat Selection" + } + + func choiceCount() -> Int { + return CGFloat.numberOfChoices + } + + func choiceText(atIndex: Int) -> String { + return "\(CGFloat(atIndex) * CGFloat.choiceDelta)" + } + + func isChoiceSelected(atIndex: Int) -> Bool { + let indexValue = CGFloat(atIndex) * CGFloat.choiceDelta + return indexValue == self + } + + func canSelectMultipleChoices() -> Bool { + return false + } + + func canSelectChoice(atIndex: Int) -> Bool { + return true + } + + mutating func setChoice(selected: Bool, atIndex: Int) { + if atIndex < choiceCount() && selected { + let indexValue = CGFloat(atIndex) * CGFloat.choiceDelta + self = indexValue + } + } + +} diff --git a/LearnAboutStackViews/LearnAboutStackViews/EHPinningOptions.swift b/LearnAboutStackViews/LearnAboutStackViews/EHPinningOptions.swift new file mode 100644 index 0000000..3f450b4 --- /dev/null +++ b/LearnAboutStackViews/LearnAboutStackViews/EHPinningOptions.swift @@ -0,0 +1,114 @@ +// +// EHPinningOptions.swift +// LearnAboutStackViews +// +// Created by Eric Hyche on 8/1/17. +// Copyright © 2017 HeirPlay Software. All rights reserved. +// + +import UIKit + +struct EHPinningOptions: OptionSet { + let rawValue: Int + + static let none = EHPinningOptions(rawValue: 0) + static let leading = EHPinningOptions(rawValue: 1 << 0) + static let centerX = EHPinningOptions(rawValue: 1 << 1) + static let trailing = EHPinningOptions(rawValue: 1 << 2) + static let top = EHPinningOptions(rawValue: 1 << 3) + static let centerY = EHPinningOptions(rawValue: 1 << 4) + static let bottom = EHPinningOptions(rawValue: 1 << 5) + + var textDescription: String { + get { + return EHPinningOptions.toString(options: self) + } + } + + static func toString(options: EHPinningOptions) -> String { + var optionStrings = [String]() + + if options.contains(.leading) { + optionStrings.append("leading") + } + if options.contains(.centerX) { + optionStrings.append("centerX") + } + if options.contains(.trailing) { + optionStrings.append("trailing") + } + if options.contains(.top) { + optionStrings.append("top") + } + if options.contains(.centerY) { + optionStrings.append("centerY") + } + if options.contains(.bottom) { + optionStrings.append("bottom") + } + + var desc = "" + if optionStrings.isEmpty { + desc = "none" + } else if optionStrings.count == 1 { + desc = optionStrings[0] + } else { + desc = "\(optionStrings)" + } + + return desc + } + +} + +extension EHPinningOptions: EHMultipleChoiceDataSource { + + func title() -> String { + return "Pinning Options" + } + + func choiceCount() -> Int { + return 6 + } + + func choiceText(atIndex: Int) -> String { + var text = "unknown" + + if atIndex < choiceCount() { + let option = EHPinningOptions(rawValue: (1 << atIndex)) + text = option.textDescription + } + + return text + } + + func isChoiceSelected(atIndex: Int) -> Bool { + var selected = false + + if atIndex < choiceCount() { + selected = contains(EHPinningOptions(rawValue: (1 << atIndex))) + } + + return selected + } + + func canSelectMultipleChoices() -> Bool { + return true + } + + func canSelectChoice(atIndex: Int) -> Bool { + return true + } + + mutating func setChoice(selected: Bool, atIndex: Int) { + if atIndex < choiceCount() { + let option = EHPinningOptions(rawValue: (1 << atIndex)) + if selected { + insert(option) + } else { + remove(option) + } + } + } + +} diff --git a/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsModel.swift b/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsModel.swift index 5db8969..b2cff09 100644 --- a/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsModel.swift +++ b/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsModel.swift @@ -11,18 +11,6 @@ import UIKit typealias EHStackViewSettingsAnimationBlock = () -> Void typealias EHStackViewSettingsCompletionBlock = (_ finished: Bool) -> Void -struct EHPinningOptions: OptionSet { - let rawValue: Int - - static let none = EHPinningOptions(rawValue: 0) - static let top = EHPinningOptions(rawValue: 1 << 0) - static let centerY = EHPinningOptions(rawValue: 1 << 1) - static let bottom = EHPinningOptions(rawValue: 1 << 2) - static let leading = EHPinningOptions(rawValue: 1 << 3) - static let centerX = EHPinningOptions(rawValue: 1 << 4) - static let trailing = EHPinningOptions(rawValue: 1 << 5) -} - struct EHStackViewSettingsModel { var axis: UILayoutConstraintAxis var distribution: UIStackViewDistribution @@ -114,8 +102,9 @@ extension EHStackViewSettingsModel { static func computePinning(forStackView stackView: UIStackView, inContainerView containerView: UIView) -> EHPinningOptions { // Get all the contraints on the stackView var pinning: EHPinningOptions = EHPinningOptions.none - let constraints = stackView.constraints + let constraints = containerView.constraints for constraint in constraints { + print("constraint=\(constraint)") // This has to be a constraint between two views if let firstView = constraint.firstItem as? UIView, let secondView = constraint.secondItem as? UIView { @@ -129,8 +118,10 @@ extension EHStackViewSettingsModel { stackViewAttribute = constraint.secondAttribute containerViewAttribute = constraint.firstAttribute } - let pinOption = pinningOption(stackViewAttribute: stackViewAttribute, containerViewAttribute: containerViewAttribute) - pinning.update(with: pinOption) + if stackViewAttribute != .notAnAttribute && containerViewAttribute != .notAnAttribute { + let pinOption = pinningOption(stackViewAttribute: stackViewAttribute, containerViewAttribute: containerViewAttribute) + pinning.insert(pinOption) + } } } return pinning diff --git a/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsViewController.swift b/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsViewController.swift index 7a6ed9d..5bdb959 100644 --- a/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsViewController.swift +++ b/LearnAboutStackViews/LearnAboutStackViews/EHStackViewSettingsViewController.swift @@ -39,13 +39,20 @@ class EHStackViewSettingsViewController: UIViewController { // MARK: - Internal properties enum RowContent: Int { - case header + case paramsHeader case axis case distribution case alignment case spacing case isBaselineRelativeArrangement case isLayoutMarginsRelativeArrangement + case layoutMarginsHeader + case layoutMarginsLeft + case layoutMarginsTop + case layoutMarginsRight + case layoutMarginsBottom + case pinningHeader + case pinningValue } private let initialSettings: EHStackViewSettingsModel @@ -73,7 +80,7 @@ class EHStackViewSettingsViewController: UIViewController { displayStackView.distribution = .fill displayStackView.alignment = .fill displayStackView.isLayoutMarginsRelativeArrangement = true - displayStackView.layoutMargins = UIEdgeInsetsMake(0.0, 10.0, 0.0, 10.0) + displayStackView.layoutMargins = UIEdgeInsetsMake(20.0, 10.0, 20.0, 10.0) displayStackView.spacing = 8.0 scrollView.addSubview(displayStackView) @@ -96,23 +103,34 @@ class EHStackViewSettingsViewController: UIViewController { view.removeFromSuperview() } - displayStackView.addArrangedSubview(headerLabel(withText: "UIStackView parameters", content: .header)) + displayStackView.addArrangedSubview(headerLabel(withText: "Parameters", content: .paramsHeader)) displayStackView.addArrangedSubview(nameValueView(withName: "axis", andValue: currentSettings.axis.textDescription, content: .axis)) displayStackView.addArrangedSubview(nameValueView(withName: "distribution", andValue: currentSettings.distribution.textDescription, content: .distribution)) displayStackView.addArrangedSubview(nameValueView(withName: "alignment", andValue: currentSettings.alignment.textDescription, content: .alignment)) displayStackView.addArrangedSubview(nameValueView(withName: "spacing", andValue: "\(currentSettings.spacing)", content: .spacing)) displayStackView.addArrangedSubview(nameBooleanValueView(withName: "isBaselineRelativeArrangement", andValue: currentSettings.isBaselineRelativeArrangement, content: .isBaselineRelativeArrangement)) displayStackView.addArrangedSubview(nameBooleanValueView(withName: "isLayoutMarginsRelativeArrangement", andValue: currentSettings.isLayoutMarginsRelativeArrangement, content: .isLayoutMarginsRelativeArrangement)) + displayStackView.addArrangedSubview(headerLabel(withText: "layoutMargins", content: .layoutMarginsHeader)) + displayStackView.addArrangedSubview(nameValueView(withName: "left", andValue: "\(currentSettings.layoutMargins.left)", content: .layoutMarginsLeft)) + displayStackView.addArrangedSubview(nameValueView(withName: "top", andValue: "\(currentSettings.layoutMargins.top)", content: .layoutMarginsTop)) + displayStackView.addArrangedSubview(nameValueView(withName: "right", andValue: "\(currentSettings.layoutMargins.right)", content: .layoutMarginsRight)) + displayStackView.addArrangedSubview(nameValueView(withName: "bottom", andValue: "\(currentSettings.layoutMargins.bottom)", content: .layoutMarginsBottom)) + displayStackView.addArrangedSubview(headerLabel(withText: "Pinning", content: .pinningHeader)) + displayStackView.addArrangedSubview(nameValueView(withName: "Anchors", andValue: currentSettings.pinning.textDescription, content: .pinningValue)) } private func updateViewState() { - updateRow(content: .header) + // Headers are not updated since they don't change updateRow(content: .axis) updateRow(content: .distribution) updateRow(content: .alignment) updateRow(content: .spacing) updateRow(content: .isBaselineRelativeArrangement) updateRow(content: .isLayoutMarginsRelativeArrangement) + updateRow(content: .layoutMarginsLeft) + updateRow(content: .layoutMarginsTop) + updateRow(content: .layoutMarginsRight) + updateRow(content: .layoutMarginsBottom) } private func updateRow(content: RowContent) { @@ -126,7 +144,6 @@ class EHStackViewSettingsViewController: UIViewController { rowValueLabel.text = currentSettings.axis.textDescription rowValueLabel.textColor = textColor } - break case .distribution: if rowStackView.arrangedSubviews.count >= 2, let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { @@ -134,7 +151,6 @@ class EHStackViewSettingsViewController: UIViewController { rowValueLabel.text = currentSettings.distribution.textDescription rowValueLabel.textColor = textColor } - break case .alignment: if rowStackView.arrangedSubviews.count >= 2, let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { @@ -142,7 +158,6 @@ class EHStackViewSettingsViewController: UIViewController { rowValueLabel.text = currentSettings.alignment.textDescription rowValueLabel.textColor = textColor } - break case .spacing: if rowStackView.arrangedSubviews.count >= 2, let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { @@ -150,18 +165,51 @@ class EHStackViewSettingsViewController: UIViewController { rowValueLabel.text = "\(currentSettings.spacing)" rowValueLabel.textColor = textColor } - break case .isBaselineRelativeArrangement: if rowStackView.arrangedSubviews.count >= 2, let rowSwitch = rowStackView.arrangedSubviews[1] as? UISwitch { rowSwitch.isOn = currentSettings.isBaselineRelativeArrangement } - break case .isLayoutMarginsRelativeArrangement: if rowStackView.arrangedSubviews.count >= 2, let rowSwitch = rowStackView.arrangedSubviews[1] as? UISwitch { rowSwitch.isOn = currentSettings.isLayoutMarginsRelativeArrangement } + case .layoutMarginsLeft: + if rowStackView.arrangedSubviews.count >= 2, + let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { + let textColor = (currentSettings.layoutMargins.left == initialSettings.layoutMargins.left ? UIColor.blue : UIColor.red) + rowValueLabel.text = "\(currentSettings.layoutMargins.left)" + rowValueLabel.textColor = textColor + } + case .layoutMarginsTop: + if rowStackView.arrangedSubviews.count >= 2, + let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { + let textColor = (currentSettings.layoutMargins.top == initialSettings.layoutMargins.top ? UIColor.blue : UIColor.red) + rowValueLabel.text = "\(currentSettings.layoutMargins.top)" + rowValueLabel.textColor = textColor + } + case .layoutMarginsRight: + if rowStackView.arrangedSubviews.count >= 2, + let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { + let textColor = (currentSettings.layoutMargins.right == initialSettings.layoutMargins.right ? UIColor.blue : UIColor.red) + rowValueLabel.text = "\(currentSettings.layoutMargins.right)" + rowValueLabel.textColor = textColor + } + case .layoutMarginsBottom: + if rowStackView.arrangedSubviews.count >= 2, + let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { + let textColor = (currentSettings.layoutMargins.bottom == initialSettings.layoutMargins.bottom ? UIColor.blue : UIColor.red) + rowValueLabel.text = "\(currentSettings.layoutMargins.bottom)" + rowValueLabel.textColor = textColor + } + case .pinningValue: + if rowStackView.arrangedSubviews.count >= 2, + let rowValueLabel = rowStackView.arrangedSubviews[1] as? UILabel { + let textColor = (currentSettings.pinning == initialSettings.pinning ? UIColor.blue : UIColor.red) + rowValueLabel.text = currentSettings.pinning.textDescription + rowValueLabel.textColor = textColor + } break default: break @@ -256,7 +304,6 @@ class EHStackViewSettingsViewController: UIViewController { self?.navigationController?.popViewController(animated: true) } navigationController?.pushViewController(axisController, animated: true) - break case .distribution: let distController = EHMultipleChoiceViewController(withDataSource: currentSettings.distribution) distController.updateBlock = { [weak self] (dataSource) in @@ -267,7 +314,6 @@ class EHStackViewSettingsViewController: UIViewController { self?.navigationController?.popViewController(animated: true) } navigationController?.pushViewController(distController, animated: true) - break case .alignment: let alignController = EHMultipleChoiceViewController(withDataSource: currentSettings.alignment) alignController.updateBlock = { [weak self] (dataSource) in @@ -278,13 +324,72 @@ class EHStackViewSettingsViewController: UIViewController { self?.navigationController?.popViewController(animated: true) } navigationController?.pushViewController(alignController, animated: true) - break case .spacing: - break + let spacingController = EHMultipleChoiceViewController(withDataSource: currentSettings.spacing) + spacingController.updateBlock = { [weak self] (dataSource) in + if let updatedSpacing = dataSource as? CGFloat { + self?.currentSettings.spacing = updatedSpacing + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(spacingController, animated: true) case .isLayoutMarginsRelativeArrangement: - break + currentSettings.isLayoutMarginsRelativeArrangement = !currentSettings.isLayoutMarginsRelativeArrangement + updateRow(content: rowEnum) case .isBaselineRelativeArrangement: - break + currentSettings.isBaselineRelativeArrangement = !currentSettings.isBaselineRelativeArrangement + updateRow(content: rowEnum) + case .layoutMarginsLeft: + let marginController = EHMultipleChoiceViewController(withDataSource: currentSettings.layoutMargins.left) + marginController.updateBlock = { [weak self] (dataSource) in + if let updatedMargin = dataSource as? CGFloat { + self?.currentSettings.layoutMargins.left = updatedMargin + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(marginController, animated: true) + case .layoutMarginsTop: + let marginController = EHMultipleChoiceViewController(withDataSource: currentSettings.layoutMargins.top) + marginController.updateBlock = { [weak self] (dataSource) in + if let updatedMargin = dataSource as? CGFloat { + self?.currentSettings.layoutMargins.top = updatedMargin + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(marginController, animated: true) + case .layoutMarginsRight: + let marginController = EHMultipleChoiceViewController(withDataSource: currentSettings.layoutMargins.right) + marginController.updateBlock = { [weak self] (dataSource) in + if let updatedMargin = dataSource as? CGFloat { + self?.currentSettings.layoutMargins.right = updatedMargin + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(marginController, animated: true) + case .layoutMarginsBottom: + let marginController = EHMultipleChoiceViewController(withDataSource: currentSettings.layoutMargins.bottom) + marginController.updateBlock = { [weak self] (dataSource) in + if let updatedMargin = dataSource as? CGFloat { + self?.currentSettings.layoutMargins.bottom = updatedMargin + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(marginController, animated: true) + case .pinningValue: + let pinningController = EHMultipleChoiceViewController(withDataSource: currentSettings.pinning) + pinningController.updateBlock = { [weak self] (dataSource) in + if let updatedPinning = dataSource as? EHPinningOptions { + self?.currentSettings.pinning = updatedPinning + } + self?.updateRow(content: rowEnum) + self?.navigationController?.popViewController(animated: true) + } + navigationController?.pushViewController(pinningController, animated: true) default: break }