├── .swift-version
├── JustUiKitDemo
├── JustUiKit.framework
│ ├── .swift-version
│ ├── JustUiKit
│ ├── Info.plist
│ ├── Modules
│ │ ├── JustUiKit.swiftmodule
│ │ │ ├── i386.swiftdoc
│ │ │ └── i386.swiftmodule
│ │ └── module.modulemap
│ ├── Headers
│ │ ├── JustUiKit.h
│ │ └── JustUiKit-Swift.h
│ ├── JustUiKit.podspec
│ └── _CodeSignature
│ │ └── CodeResources
├── ViewController.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
└── AppDelegate.swift
├── art
├── framelayout1.png
├── framelayout2.png
├── relativelayout1.png
├── vertical_layout.png
└── horizontal_layout.png
├── JustUiKit
├── JustUiKit.xcodeproj.xcworkspace
│ └── contents.xcworkspacedata
├── utils
│ ├── ReleasePool.swift
│ ├── Orientation.swift
│ ├── ColorExtension.swift
│ ├── Queue.swift
│ └── Gravity.swift
├── JustUiKit.h
├── Info.plist
├── layout
│ ├── JustViewManager.swift
│ ├── JustViewParent.swift
│ ├── JustViewGroup.swift
│ └── JustExtensionView.swift
├── params
│ └── JustLayoutParams.swift
└── widget
│ ├── JustFrameLayout.swift
│ ├── JustLinearLayout.swift
│ └── JustRelativeLayout.swift
├── JustUiKitTests
├── Info.plist
├── JustUiKitTests.swift
└── ViewController.swift
├── LICENSE
├── JustUiKitSample
└── JustUiKitSample
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Info.plist
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ └── ViewController.swift
├── .gitignore
├── JustUiKit.podspec
├── README_ZH.md
├── README.md
└── JustUiKit.xcodeproj
└── project.pbxproj
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
--------------------------------------------------------------------------------
/art/framelayout1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/art/framelayout1.png
--------------------------------------------------------------------------------
/art/framelayout2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/art/framelayout2.png
--------------------------------------------------------------------------------
/art/relativelayout1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/art/relativelayout1.png
--------------------------------------------------------------------------------
/art/vertical_layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/art/vertical_layout.png
--------------------------------------------------------------------------------
/art/horizontal_layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/art/horizontal_layout.png
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/JustUiKit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/JustUiKitDemo/JustUiKit.framework/JustUiKit
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/JustUiKitDemo/JustUiKit.framework/Info.plist
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Modules/JustUiKit.swiftmodule/i386.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/JustUiKitDemo/JustUiKit.framework/Modules/JustUiKit.swiftmodule/i386.swiftdoc
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Modules/JustUiKit.swiftmodule/i386.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfkdsk/JustUiKit/HEAD/JustUiKitDemo/JustUiKit.framework/Modules/JustUiKit.swiftmodule/i386.swiftmodule
--------------------------------------------------------------------------------
/JustUiKit/JustUiKit.xcodeproj.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module JustUiKit {
2 | umbrella header "JustUiKit.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
8 | module JustUiKit.Swift {
9 | header "JustUiKit-Swift.h"
10 | }
11 |
--------------------------------------------------------------------------------
/JustUiKit/utils/ReleasePool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 刘丰恺 on 2017/1/24.
3 | // Copyright (c) 2017 ___FULL___. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public class ReleasePool {
9 | var releasePool: Array = Array()
10 |
11 | public func acquire() -> T? {
12 | if releasePool.count > 0 {
13 | let obj = releasePool.removeLast()
14 | return obj
15 | }
16 | return nil
17 | }
18 |
19 | public func release(instance: T) {
20 | releasePool.append(instance)
21 | }
22 | }
--------------------------------------------------------------------------------
/JustUiKit/JustUiKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // JustUiKit.h
3 | // JustUiKit
4 | //
5 | // Created by 刘丰恺 on 2017/1/17.
6 | // Copyright (c) 2017 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | //! Project version number for JustUiKit.
13 | FOUNDATION_EXPORT double JustUiKitVersionNumber;
14 |
15 | //! Project version string for JustUiKit.
16 | FOUNDATION_EXPORT const unsigned char JustUiKitVersionString[];
17 |
18 | // In this header, you should import all the public headers of your framework using statements like #import
19 |
20 |
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Headers/JustUiKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // JustUiKit.h
3 | // JustUiKit
4 | //
5 | // Created by 刘丰恺 on 2017/1/17.
6 | // Copyright (c) 2017 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | //! Project version number for JustUiKit.
13 | FOUNDATION_EXPORT double JustUiKitVersionNumber;
14 |
15 | //! Project version string for JustUiKit.
16 | FOUNDATION_EXPORT const unsigned char JustUiKitVersionString[];
17 |
18 | // In this header, you should import all the public headers of your framework using statements like #import
19 |
20 |
--------------------------------------------------------------------------------
/JustUiKitDemo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // JustUiKitDemo
4 | //
5 | // Created by 刘丰恺 on 2017/1/18.
6 | // Copyright © 2017年 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view, typically from a nib.
16 | }
17 |
18 | override func didReceiveMemoryWarning() {
19 | super.didReceiveMemoryWarning()
20 | // Dispose of any resources that can be recreated.
21 | }
22 |
23 |
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/JustUiKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/JustUiKit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 JustWe
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/JustUiKitTests/JustUiKitTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JustUiKitTests.swift
3 | // JustUiKitTests
4 | //
5 | // Created by 刘丰恺 on 2017/1/17.
6 | // Copyright (c) 2017 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import JustUiKit
11 |
12 | class JustUiKitTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | var controller = ViewController(coder: NSCoder())
26 | // This is an example of a functional test case.
27 | // Use XCTAssert and related functions to verify your tests produce the correct results.
28 | }
29 |
30 | func testPerformanceExample() {
31 | // This is an example of a performance test case.
32 | self.measure {
33 | // Put the code you want to measure the time of here.
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/JustUiKit/utils/Orientation.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 |
24 | public enum Orientation {
25 | case Vertical
26 | case Horizontal
27 | }
--------------------------------------------------------------------------------
/JustUiKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/JustUiKitSample/JustUiKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/JustUiKit/layout/JustViewManager.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 |
24 | import UIKit
25 |
26 | public protocol JustViewManager {
27 |
28 | func addView(view: UIView)
29 |
30 | func updateView(view: UIView,
31 | params: LayoutParams)
32 |
33 | func removeView(view: UIView)
34 | }
--------------------------------------------------------------------------------
/JustUiKit/layout/JustViewParent.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import Foundation
24 | import UIKit
25 |
26 | public protocol JustViewParent {
27 | func getParent() -> JustViewParent
28 |
29 | func requestLayout()
30 |
31 | func setParent(viewGroup: JustViewParent)
32 |
33 | func hasParent() -> Bool
34 | }
35 |
--------------------------------------------------------------------------------
/JustUiKitSample/JustUiKitSample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/JustUiKitDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/JustUiKit/utils/ColorExtension.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import UIKit
24 |
25 | extension UIColor {
26 | public convenience init(rgb: UInt, alphaVal: CGFloat? = 1.0) {
27 | self.init(
28 | red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
29 | green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
30 | blue: CGFloat(rgb & 0x0000FF) / 255.0,
31 | alpha: CGFloat(alphaVal!)
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | .idea/
6 | idea/
7 |
8 | ## Build generated
9 | build/
10 | DerivedData/
11 |
12 | ## Various settings
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata/
22 |
23 | ## Other
24 | *.moved-aside
25 | *.xcuserstate
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/JustUiKitDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/JustUiKitDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/JustUiKitDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // JustUiKitDemo
4 | //
5 | // Created by 刘丰恺 on 2017/1/18.
6 | // Copyright © 2017年 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/JustUiKit/utils/Queue.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | public struct Queue {
24 | fileprivate var array = [T?]()
25 | fileprivate var head = 0
26 |
27 | public var isEmpty: Bool {
28 | return count == 0
29 | }
30 |
31 | public var count: Int {
32 | return array.count - head
33 | }
34 |
35 | public mutating func enqueue(_ element: T) {
36 | array.append(element)
37 | }
38 |
39 | public mutating func dequeue() -> T? {
40 | guard head < array.count, let element = array[head] else {
41 | return nil
42 | }
43 |
44 | array[head] = nil
45 | head += 1
46 |
47 | let percentage = Double(head) / Double(array.count)
48 | if array.count > 50 && percentage > 0.25 {
49 | array.removeFirst(head)
50 | head = 0
51 | }
52 |
53 | return element
54 | }
55 |
56 | public var front: T? {
57 | if isEmpty {
58 | return nil
59 | } else {
60 | return array[head]
61 | }
62 | }
63 |
64 | public mutating func clear() {
65 | array.removeAll()
66 | head = 0
67 | }
68 | }
--------------------------------------------------------------------------------
/JustUiKitSample/JustUiKitSample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // JustUiKitSample
4 | //
5 | // Created by 刘丰恺 on 2017/2/6.
6 | // Copyright (c) 2017 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | self.window = UIWindow(frame: UIScreen.main.bounds)
20 |
21 | let mainViewController = ViewController()
22 | self.window?.rootViewController = mainViewController
23 | self.window?.makeKeyAndVisible()
24 | return true
25 | }
26 |
27 |
28 | func applicationWillResignActive(_ application: UIApplication) {
29 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
30 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
31 |
32 | }
33 |
34 |
35 | func applicationDidEnterBackground(_ application: UIApplication) {
36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
38 |
39 | }
40 |
41 |
42 | func applicationWillEnterForeground(_ application: UIApplication) {
43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
44 | }
45 |
46 |
47 | func applicationDidBecomeActive(_ application: UIApplication) {
48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
49 | }
50 |
51 |
52 | func applicationWillTerminate(_ application: UIApplication) {
53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
54 | }
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/JustUiKit/utils/Gravity.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 |
24 | public class Gravity {
25 | static let VERTICAL_GRAVITY_MASK = 112
26 | static let HORIZONTAL_GRAVITY_MASK = 7
27 |
28 | private static let NO_GRAVITY_V = 0
29 | private static let TOP_V = 48
30 | private static let BOTTOM_V = 80
31 | private static let LEFT_V = 3
32 | private static let RIGHT_V = 5
33 | private static let CENTER_VERTICAL_V = 16
34 | private static let CENTER_HORIZONTAL_V = 1
35 | private static let CENTER_V = 17
36 |
37 | public static let NO_GRAVITY = Gravity(value: NO_GRAVITY_V)
38 | public static let TOP = Gravity(value: TOP_V)
39 | public static let BOTTOM = Gravity(value: BOTTOM_V)
40 | public static let LEFT = Gravity(value: LEFT_V)
41 | public static let RIGHT = Gravity(value: RIGHT_V)
42 | public static let CENTER_VERTICAL = Gravity(value: CENTER_VERTICAL_V)
43 | public static let CENTER_HORIZONTAL = Gravity(value: CENTER_HORIZONTAL_V)
44 | public static let CENTER = Gravity(value: CENTER_V)
45 |
46 | private let innerValue: Int
47 |
48 | private init(value: Int) {
49 | self.innerValue = value
50 | }
51 |
52 | public static func |(left: Gravity, right: Gravity) -> Gravity {
53 | return Gravity(value: left.getValue() | right.getValue())
54 | }
55 |
56 | public static func getHorizontalGravity(gravity: Gravity) -> Int {
57 | return gravity.getValue() & HORIZONTAL_GRAVITY_MASK
58 | }
59 |
60 | public static func getVerticalGravity(gravity: Gravity) -> Int {
61 | return gravity.getValue() & VERTICAL_GRAVITY_MASK
62 | }
63 |
64 | public func getValue() -> Int {
65 | return innerValue
66 | }
67 | }
--------------------------------------------------------------------------------
/JustUiKitSample/JustUiKitSample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/JustUiKit/params/JustLayoutParams.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 |
24 | import UIKit
25 |
26 | public class LayoutParams {
27 |
28 | public static let MATCH_PARENT: CGFloat = -1
29 | public static let WRAP_CONTENT: CGFloat = -2
30 |
31 | public var width: CGFloat = 0
32 | public var height: CGFloat = 0
33 |
34 | public var bindView: UIView? = nil
35 |
36 | public init(width: CGFloat, height: CGFloat) {
37 | self.width = width
38 | self.height = height
39 | }
40 |
41 | public func bindWith(view: UIView?) {
42 | self.bindView = view
43 | }
44 |
45 | public init(_ params: LayoutParams) {
46 | self.width = params.width
47 | self.height = params.height
48 | }
49 |
50 | public static func generateDefaultLayoutParams() -> LayoutParams {
51 | return LayoutParams(width: 0, height: 0)
52 | }
53 | }
54 |
55 | public class MarginLayoutParams: LayoutParams {
56 | private static let DEFAULT_MARGIN: Int = 0;
57 |
58 | public var leftMargin = DEFAULT_MARGIN
59 | public var rightMargin = DEFAULT_MARGIN
60 | public var topMargin = DEFAULT_MARGIN
61 | public var bottomMargin = DEFAULT_MARGIN
62 |
63 | public var startMargin = DEFAULT_MARGIN
64 | public var endMargin = DEFAULT_MARGIN
65 |
66 | override public init(_ source: LayoutParams) {
67 | super.init(source)
68 | }
69 |
70 | override public init(width: CGFloat, height: CGFloat) {
71 | super.init(width: width, height: height)
72 | }
73 |
74 | public init(source: MarginLayoutParams) {
75 | super.init(width: source.width, height: source.height)
76 | self.leftMargin = source.leftMargin
77 | self.rightMargin = source.rightMargin
78 | self.topMargin = source.topMargin
79 | self.bottomMargin = source.bottomMargin
80 | }
81 |
82 | public func setMargins(left: Int, top: Int, right: Int, bottom: Int) {
83 | leftMargin = left;
84 | topMargin = top;
85 | rightMargin = right;
86 | bottomMargin = bottom;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/JustUiKit/layout/JustViewGroup.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import Foundation
24 | import UIKit
25 |
26 | open class JustViewGroup: UIView, JustViewParent, JustViewManager {
27 |
28 | private var parentView: JustViewParent? = nil;
29 |
30 | private var isChanged: Bool = false
31 |
32 | public init() {
33 | super.init(frame: CGRect.zero)
34 | isChanged = false
35 | }
36 |
37 | public override init(frame groupFrame: CGRect) {
38 | super.init(frame: groupFrame)
39 | isChanged = false
40 | }
41 |
42 | public init(frame groupFrame: CGRect,
43 | parentView: JustViewParent) {
44 | super.init(frame: groupFrame)
45 | self.parentView = parentView
46 | }
47 |
48 | public required init?(coder aDecoder: NSCoder) {
49 | super.init(coder: aDecoder)
50 | }
51 |
52 | public func onLayout(_ changed: Bool = false,
53 | _ top: CGFloat,
54 | _ left: CGFloat,
55 | _ right: CGFloat,
56 | _ bottom: CGFloat) {
57 |
58 | }
59 |
60 | public func onMeasure(_ size: CGSize) {
61 |
62 | }
63 |
64 | override open func layoutSubviews() {
65 |
66 | let top = frame.origin.y
67 | let left = frame.origin.x
68 | let right = frame.size.width + left
69 | let bottom = frame.size.height + top
70 |
71 | onMeasure(frame.size)
72 |
73 | onLayout(isChanged, top, left, right, bottom)
74 | }
75 |
76 | public func getParent() -> JustViewParent {
77 | return parentView!
78 | }
79 |
80 | public func requestLayout() {
81 |
82 | }
83 |
84 | public func setParent(viewGroup: JustViewParent) {
85 | self.parentView = viewGroup
86 | }
87 |
88 |
89 | public func hasParent() -> Bool {
90 | return parentView != nil
91 | }
92 |
93 | public func updateView(view: UIView, params: LayoutParams) {
94 |
95 | }
96 |
97 | public func removeView(view: UIView) {
98 | // self.willRemoveSubview(view)
99 | }
100 |
101 | public func addView(view: UIView) {
102 |
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/JustUiKitTests/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // JustUiKitTest
4 | //
5 | // Created by 刘丰恺 on 2017/1/2.
6 | // Copyright (c) 2017 ___FULL___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | class ViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | // Do any additional setup after loading the view, typically from a nib.
17 | }
18 |
19 |
20 | override func didReceiveMemoryWarning() {
21 | super.didReceiveMemoryWarning()
22 | // Dispose of any resources that can be recreated.
23 | }
24 |
25 | func createSectionLabel(_ title: String) -> UILabel {
26 | let sectionLabel = UILabel()
27 | sectionLabel.text = title;
28 | sectionLabel.font = UIFont.systemFont(ofSize: 17)
29 | sectionLabel.sizeToFit()
30 | // sizeToFit函数的意思是让视图的尺寸刚好包裹其内容。
31 | // 注意sizeToFit方法必要在设置字体、文字后调用才正确。
32 | return sectionLabel
33 | }
34 |
35 |
36 | override func loadView() {
37 | super.loadView()
38 |
39 | self.view = UIView(frame: UIScreen.main.bounds)
40 | view.backgroundColor = UIColor(rgb: 0xFF8C00)
41 |
42 | let lfkdsk = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Horizontal)
43 |
44 | view.addSubview(lfkdsk)
45 |
46 | let linearLayout: JustLinearLayout = lfkdsk
47 |
48 | let params: LinearLayoutParams = LinearLayoutParams(
49 | width: LayoutParams.WRAP_CONTENT,
50 | height: LayoutParams.WRAP_CONTENT)
51 | params.weight = 1
52 | // params.leftMargin = 100
53 | // params.rightMargin = 10
54 |
55 | let fuckView = createSectionLabel("FUCK")
56 |
57 | print(fuckView.frame.origin)
58 | print(fuckView.frame.size)
59 |
60 | print("Before Layout")
61 |
62 | let centerParams = LinearLayoutParams(linear: params)
63 | // centerParams.weight = 1
64 | centerParams.layoutGravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL
65 |
66 | let rightParams = LinearLayoutParams(linear: params)
67 | rightParams.layoutGravity = Gravity.BOTTOM.getValue()
68 |
69 | let rightAndBottomParams = LinearLayoutParams(params)
70 | // rightAndBottomParams.weight = 1
71 | rightAndBottomParams.layoutGravity = Gravity.BOTTOM | Gravity.RIGHT
72 |
73 | let rightAndTopParams = LinearLayoutParams(linear: params)
74 | // rightAndTopParams.rightMargin = 12
75 | // rightAndTopParams.weight = 1
76 | rightAndTopParams.layoutGravity = Gravity.TOP | Gravity.RIGHT
77 |
78 | linearLayout.addView(view: createSectionLabel("苟"), params: rightAndTopParams)
79 | linearLayout.addView(view: createSectionLabel("利"), params: params)
80 | linearLayout.addView(view: createSectionLabel("国"), params: params)
81 | // linearLayout.addView(view: createSectionLabel("家"), params: centerParams)
82 | // linearLayout.addView(view: createSectionLabel("生"), params: params)
83 | // linearLayout.addView(view: createSectionLabel("死"), params: rightAndBottomParams)
84 | // linearLayout.addView(view: createSectionLabel("以"), params: params)
85 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
86 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
87 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
88 | // linearLayout.addView(view: createSectionLabel("以"), params: params)
89 |
90 | var fuck2View = JustLinearLayout(orientation: .Horizontal)
91 | // fuck2View.linearExtension.padding.paddingBottom = 10
92 | var Fuck2Params = LinearLayoutParams(width: LayoutParams.MATCH_PARENT,
93 | height: LayoutParams.WRAP_CONTENT)
94 | // Fuck2Params.topMargin = 80
95 | Fuck2Params.leftMargin = 20
96 | Fuck2Params.weight = 1
97 | Fuck2Params.layoutGravity = Gravity.CENTER_VERTICAL.getValue()
98 | // fuck2View.setPadding(top: 10, left: 0, right: 10, bottom: 0)
99 | lfkdsk.addView(view: fuck2View, params: Fuck2Params)
100 |
101 | let firstInnerItem = createSectionLabel("以")
102 | // rightAndTopParams.bottomMargin = 10
103 |
104 | fuck2View.addView(view: firstInnerItem, params: params)
105 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
106 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
107 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
108 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: rightParams)
109 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
110 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: centerParams)
111 | // fuck2View.linearExtension.padding.paddingRight = 80
112 |
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/JustUiKit.podspec:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Be sure to run `pod spec lint TangramKit.podspec' to ensure this is a
4 | # valid spec and to remove all comments including this before submitting the spec.
5 | #
6 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
7 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
8 | #
9 |
10 | Pod::Spec.new do |s|
11 |
12 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
13 | #
14 | # These will help people to find your library, and whilst it
15 | # can feel like a chore to fill in it's definitely to your advantage. The
16 | # summary should be tweet-length, and the description more in depth.
17 | #
18 |
19 | s.name = "JustUiKit"
20 | s.version = "0.2.1"
21 | s.summary = "iOS UI Kit With Android-Style Tools"
22 |
23 | s.description = <<-DESC
24 | *iOS UI Kit With Android-Style Tools.
25 | DESC
26 |
27 | s.homepage = "https://github.com/lfkdsk/JustUiKit"
28 |
29 |
30 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
31 | #
32 | # Licensing your code is important. See http://choosealicense.com for more info.
33 | # CocoaPods will detect a license file if there is a named LICENSE*
34 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
35 | #
36 |
37 | s.license = "MIT"
38 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
39 |
40 |
41 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
42 | #
43 | # Specify the authors of the library, with email addresses. Email addresses
44 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
45 | # accepts just a name if you'd rather not provide an email address.
46 | #
47 | # Specify a social_media_url where others can refer to, for example a twitter
48 | # profile URL.
49 | #
50 |
51 | s.author = { "lfkdsk" => "lfk_dsk@hotmail.com" }
52 | # Or just: s.author = "lfkdsk"
53 |
54 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
55 | #
56 | # If this Pod runs only on iOS or OS X, then specify the platform and
57 | # the deployment target. You can optionally include the target after the platform.
58 | #
59 |
60 | # s.platform = :ios
61 | s.platform = :ios, "8.0"
62 |
63 | # When using multiple platforms
64 | # s.ios.deployment_target = "5.0"
65 | # s.osx.deployment_target = "10.7"
66 | # s.watchos.deployment_target = "2.0"
67 |
68 |
69 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
70 | #
71 | # Specify the location from where the source should be retrieved.
72 | # Supports git, hg, bzr, svn and HTTP.
73 | #
74 |
75 | s.source = { :git => "https://github.com/lfkdsk/JustUiKit.git", :tag => "0.2.1" }
76 |
77 |
78 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
79 | #
80 | # CocoaPods is smart about how it includes source code. For source files
81 | # giving a folder will include any swift, h, m, mm, c & cpp files.
82 | # For header files it will include any header in the folder.
83 | # Not including the public_header_files will make all headers public.
84 | #
85 |
86 | s.source_files = "JustUiKit/**/*.swift"
87 | #s.exclude_files = "Classes/Exclude"
88 |
89 | #s.public_header_files = "JustUiKit/Lib/*.h"
90 |
91 |
92 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
93 | #
94 | # A list of resources included with the Pod. These are copied into the
95 | # target bundle with a build phase script. Anything else will be cleaned.
96 | # You can preserve files from being cleaned, please don't preserve
97 | # non-essential files like tests, examples and documentation.
98 | #
99 |
100 | # s.resource = "icon.png"
101 | # s.resources = "Resources/*.png"
102 |
103 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
104 |
105 |
106 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
107 | #
108 | # Link your library with frameworks, or libraries. Libraries do not include
109 | # the lib prefix of their name.
110 | #
111 |
112 | # s.framework = "SomeFramework"
113 | # s.frameworks = "SomeFramework", "AnotherFramework"
114 |
115 | # s.library = "iconv"
116 | # s.libraries = "iconv", "xml2"
117 |
118 |
119 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
120 | #
121 | # If your library depends on compiler flags you can set them in the xcconfig hash
122 | # where they will only apply to your library. If you depend on other Podspecs
123 | # you can include multiple dependencies to ensure it works.
124 |
125 | # s.requires_arc = true
126 |
127 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
128 | # s.dependency "JSONKit", "~> 1.4"
129 |
130 | end
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/JustUiKit.podspec:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Be sure to run `pod spec lint TangramKit.podspec' to ensure this is a
4 | # valid spec and to remove all comments including this before submitting the spec.
5 | #
6 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
7 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
8 | #
9 |
10 | Pod::Spec.new do |s|
11 |
12 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
13 | #
14 | # These will help people to find your library, and whilst it
15 | # can feel like a chore to fill in it's definitely to your advantage. The
16 | # summary should be tweet-length, and the description more in depth.
17 | #
18 |
19 | s.name = "JustUiKit"
20 | s.version = "0.1.3"
21 | s.summary = "iOS UI Kit With Android-Style Tools"
22 |
23 | s.description = <<-DESC
24 | *iOS UI Kit With Android-Style Tools.
25 | DESC
26 |
27 | s.homepage = "https://github.com/lfkdsk/JustUiKit"
28 |
29 |
30 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
31 | #
32 | # Licensing your code is important. See http://choosealicense.com for more info.
33 | # CocoaPods will detect a license file if there is a named LICENSE*
34 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
35 | #
36 |
37 | s.license = "MIT"
38 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
39 |
40 |
41 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
42 | #
43 | # Specify the authors of the library, with email addresses. Email addresses
44 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
45 | # accepts just a name if you'd rather not provide an email address.
46 | #
47 | # Specify a social_media_url where others can refer to, for example a twitter
48 | # profile URL.
49 | #
50 |
51 | s.author = { "lfkdsk" => "lfk_dsk@hotmail.com" }
52 | # Or just: s.author = "lfkdsk"
53 |
54 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
55 | #
56 | # If this Pod runs only on iOS or OS X, then specify the platform and
57 | # the deployment target. You can optionally include the target after the platform.
58 | #
59 |
60 | # s.platform = :ios
61 | s.platform = :ios, "8.0"
62 |
63 | # When using multiple platforms
64 | # s.ios.deployment_target = "5.0"
65 | # s.osx.deployment_target = "10.7"
66 | # s.watchos.deployment_target = "2.0"
67 |
68 |
69 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
70 | #
71 | # Specify the location from where the source should be retrieved.
72 | # Supports git, hg, bzr, svn and HTTP.
73 | #
74 |
75 | s.source = { :git => "https://github.com/lfkdsk/JustUiKit.git", :tag => "0.1.3" }
76 |
77 |
78 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
79 | #
80 | # CocoaPods is smart about how it includes source code. For source files
81 | # giving a folder will include any swift, h, m, mm, c & cpp files.
82 | # For header files it will include any header in the folder.
83 | # Not including the public_header_files will make all headers public.
84 | #
85 |
86 | s.source_files = "JustUiKit/**/*.swift"
87 | #s.exclude_files = "Classes/Exclude"
88 |
89 | #s.public_header_files = "JustUiKit/Lib/*.h"
90 |
91 |
92 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
93 | #
94 | # A list of resources included with the Pod. These are copied into the
95 | # target bundle with a build phase script. Anything else will be cleaned.
96 | # You can preserve files from being cleaned, please don't preserve
97 | # non-essential files like tests, examples and documentation.
98 | #
99 |
100 | # s.resource = "icon.png"
101 | # s.resources = "Resources/*.png"
102 |
103 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
104 |
105 |
106 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
107 | #
108 | # Link your library with frameworks, or libraries. Libraries do not include
109 | # the lib prefix of their name.
110 | #
111 |
112 | # s.framework = "SomeFramework"
113 | # s.frameworks = "SomeFramework", "AnotherFramework"
114 |
115 | # s.library = "iconv"
116 | # s.libraries = "iconv", "xml2"
117 |
118 |
119 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
120 | #
121 | # If your library depends on compiler flags you can set them in the xcconfig hash
122 | # where they will only apply to your library. If you depend on other Podspecs
123 | # you can include multiple dependencies to ensure it works.
124 |
125 | # s.requires_arc = true
126 |
127 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
128 | # s.dependency "JSONKit", "~> 1.4"
129 |
130 | end
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/Headers/JustUiKit-Swift.h:
--------------------------------------------------------------------------------
1 | // Generated by Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
2 | #pragma clang diagnostic push
3 |
4 | #if defined(__has_include) && __has_include()
5 | # include
6 | #endif
7 |
8 | #pragma clang diagnostic ignored "-Wauto-import"
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #if !defined(SWIFT_TYPEDEFS)
15 | # define SWIFT_TYPEDEFS 1
16 | # if defined(__has_include) && __has_include()
17 | # include
18 | # elif !defined(__cplusplus) || __cplusplus < 201103L
19 | typedef uint_least16_t char16_t;
20 | typedef uint_least32_t char32_t;
21 | # endif
22 | typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
23 | typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
24 | typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
25 | typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
26 | typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
27 | typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
28 | typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
29 | typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
30 | typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
31 | typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
32 | typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
33 | typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
34 | #endif
35 |
36 | #if !defined(SWIFT_PASTE)
37 | # define SWIFT_PASTE_HELPER(x, y) x##y
38 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
39 | #endif
40 | #if !defined(SWIFT_METATYPE)
41 | # define SWIFT_METATYPE(X) Class
42 | #endif
43 | #if !defined(SWIFT_CLASS_PROPERTY)
44 | # if __has_feature(objc_class_property)
45 | # define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
46 | # else
47 | # define SWIFT_CLASS_PROPERTY(...)
48 | # endif
49 | #endif
50 |
51 | #if defined(__has_attribute) && __has_attribute(objc_runtime_name)
52 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
53 | #else
54 | # define SWIFT_RUNTIME_NAME(X)
55 | #endif
56 | #if defined(__has_attribute) && __has_attribute(swift_name)
57 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
58 | #else
59 | # define SWIFT_COMPILE_NAME(X)
60 | #endif
61 | #if defined(__has_attribute) && __has_attribute(objc_method_family)
62 | # define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
63 | #else
64 | # define SWIFT_METHOD_FAMILY(X)
65 | #endif
66 | #if defined(__has_attribute) && __has_attribute(noescape)
67 | # define SWIFT_NOESCAPE __attribute__((noescape))
68 | #else
69 | # define SWIFT_NOESCAPE
70 | #endif
71 | #if !defined(SWIFT_CLASS_EXTRA)
72 | # define SWIFT_CLASS_EXTRA
73 | #endif
74 | #if !defined(SWIFT_PROTOCOL_EXTRA)
75 | # define SWIFT_PROTOCOL_EXTRA
76 | #endif
77 | #if !defined(SWIFT_ENUM_EXTRA)
78 | # define SWIFT_ENUM_EXTRA
79 | #endif
80 | #if !defined(SWIFT_CLASS)
81 | # if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
82 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
83 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
84 | # else
85 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
86 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
87 | # endif
88 | #endif
89 |
90 | #if !defined(SWIFT_PROTOCOL)
91 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
92 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
93 | #endif
94 |
95 | #if !defined(SWIFT_EXTENSION)
96 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
97 | #endif
98 |
99 | #if !defined(OBJC_DESIGNATED_INITIALIZER)
100 | # if defined(__has_attribute) && __has_attribute(objc_designated_initializer)
101 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
102 | # else
103 | # define OBJC_DESIGNATED_INITIALIZER
104 | # endif
105 | #endif
106 | #if !defined(SWIFT_ENUM)
107 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type
108 | # if defined(__has_feature) && __has_feature(generalized_swift_name)
109 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type
110 | # else
111 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
112 | # endif
113 | #endif
114 | #if !defined(SWIFT_UNAVAILABLE)
115 | # define SWIFT_UNAVAILABLE __attribute__((unavailable))
116 | #endif
117 | #if defined(__has_feature) && __has_feature(modules)
118 | @import UIKit;
119 | @import CoreGraphics;
120 | #endif
121 |
122 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
123 | #pragma clang diagnostic ignored "-Wduplicate-method-arg"
124 |
125 | @interface UIColor (SWIFT_EXTENSION(JustUiKit))
126 | @end
127 |
128 |
129 | @interface UIView (SWIFT_EXTENSION(JustUiKit))
130 | - (void)setPaddingWithTop:(CGFloat)top left:(CGFloat)left right:(CGFloat)right bottom:(CGFloat)bottom;
131 | @end
132 |
133 | #pragma clang diagnostic pop
134 |
--------------------------------------------------------------------------------
/JustUiKitDemo/JustUiKit.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | .swift-version
8 |
9 | vcFAipHxYdq1qYk9I9s8cJUgDh0=
10 |
11 | Headers/JustUiKit-Swift.h
12 |
13 | q5hJZ57zzllNSYHIjOATlcfsXFs=
14 |
15 | Headers/JustUiKit.h
16 |
17 | apLsWgBOz9JiVcsrWzwvrrqC9XU=
18 |
19 | Info.plist
20 |
21 | mZ4UlJEfyq2tbF1gx22v9BzKwFs=
22 |
23 | JustUiKit.podspec
24 |
25 | qJPsV4CFBCXLzYR3vCswXUV+2BY=
26 |
27 | Modules/JustUiKit.swiftmodule/i386.swiftdoc
28 |
29 | ZTFzosRQNCvoMb+N8t9NagOEFQU=
30 |
31 | Modules/JustUiKit.swiftmodule/i386.swiftmodule
32 |
33 | GMNXqo2CjoVrE5FunhzeIn+26mI=
34 |
35 | Modules/module.modulemap
36 |
37 | 0umYKMV8GM7GL3trRseWFBq1sEY=
38 |
39 |
40 | files2
41 |
42 | .swift-version
43 |
44 | hash
45 |
46 | vcFAipHxYdq1qYk9I9s8cJUgDh0=
47 |
48 | hash2
49 |
50 | pBbqhEIfp+E1FYLaSCNbrIg4CjN+xctakjncfVeQi0s=
51 |
52 |
53 | Headers/JustUiKit-Swift.h
54 |
55 | hash
56 |
57 | q5hJZ57zzllNSYHIjOATlcfsXFs=
58 |
59 | hash2
60 |
61 | RA9hbKcF0wiIGgsvNh4wUGBbDXxOXN+m8U+JxuQxjuw=
62 |
63 |
64 | Headers/JustUiKit.h
65 |
66 | hash
67 |
68 | apLsWgBOz9JiVcsrWzwvrrqC9XU=
69 |
70 | hash2
71 |
72 | mIrKNajKGQsTZbWll9iTK8JhwIqUqMEHM+TxSQ7P/t0=
73 |
74 |
75 | JustUiKit.podspec
76 |
77 | hash
78 |
79 | qJPsV4CFBCXLzYR3vCswXUV+2BY=
80 |
81 | hash2
82 |
83 | w9ekR9hDQ4QGPEm17VN0AMV60mY0xoOjLuKIV/AjWCw=
84 |
85 |
86 | Modules/JustUiKit.swiftmodule/i386.swiftdoc
87 |
88 | hash
89 |
90 | ZTFzosRQNCvoMb+N8t9NagOEFQU=
91 |
92 | hash2
93 |
94 | GIknIJ6tMhevxSgRQl7CZV2dIAA03FGQNbyf9MXziEU=
95 |
96 |
97 | Modules/JustUiKit.swiftmodule/i386.swiftmodule
98 |
99 | hash
100 |
101 | GMNXqo2CjoVrE5FunhzeIn+26mI=
102 |
103 | hash2
104 |
105 | 0xg4fKJmND/wSMyPTmTBFI37nDPvw6qqC+ewegWoDaU=
106 |
107 |
108 | Modules/module.modulemap
109 |
110 | hash
111 |
112 | 0umYKMV8GM7GL3trRseWFBq1sEY=
113 |
114 | hash2
115 |
116 | pPWL6choMH7wLjDLG2VBJ9kSkd5LCwJOiiUTtTvoPtM=
117 |
118 |
119 |
120 | rules
121 |
122 | ^
123 |
124 | ^.*\.lproj/
125 |
126 | optional
127 |
128 | weight
129 | 1000
130 |
131 | ^.*\.lproj/locversion.plist$
132 |
133 | omit
134 |
135 | weight
136 | 1100
137 |
138 | ^Base\.lproj/
139 |
140 | weight
141 | 1010
142 |
143 | ^version.plist$
144 |
145 |
146 | rules2
147 |
148 | .*\.dSYM($|/)
149 |
150 | weight
151 | 11
152 |
153 | ^
154 |
155 | weight
156 | 20
157 |
158 | ^(.*/)?\.DS_Store$
159 |
160 | omit
161 |
162 | weight
163 | 2000
164 |
165 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
166 |
167 | nested
168 |
169 | weight
170 | 10
171 |
172 | ^.*
173 |
174 | ^.*\.lproj/
175 |
176 | optional
177 |
178 | weight
179 | 1000
180 |
181 | ^.*\.lproj/locversion.plist$
182 |
183 | omit
184 |
185 | weight
186 | 1100
187 |
188 | ^Base\.lproj/
189 |
190 | weight
191 | 1010
192 |
193 | ^Info\.plist$
194 |
195 | omit
196 |
197 | weight
198 | 20
199 |
200 | ^PkgInfo$
201 |
202 | omit
203 |
204 | weight
205 | 20
206 |
207 | ^[^/]+$
208 |
209 | nested
210 |
211 | weight
212 | 10
213 |
214 | ^embedded\.provisionprofile$
215 |
216 | weight
217 | 20
218 |
219 | ^version\.plist$
220 |
221 | weight
222 | 20
223 |
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/JustUiKit/layout/JustExtensionView.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 |
24 | import UIKit
25 |
26 | public protocol ExtensionParams {
27 | func setLayoutParams(params: LayoutParams)
28 |
29 | func getLayoutParams() -> LayoutParams
30 | }
31 |
32 | public struct Padding {
33 | var paddingLeft: CGFloat = 0
34 | var paddingRight: CGFloat = 0
35 | var paddingBottom: CGFloat = 0
36 | var paddingTop: CGFloat = 0
37 |
38 | public init() {
39 |
40 | }
41 |
42 | public init(top: CGFloat, left: CGFloat, right: CGFloat, bottom: CGFloat) {
43 | self.paddingTop = top
44 | self.paddingLeft = left
45 | self.paddingRight = right
46 | self.paddingBottom = bottom
47 | }
48 | /**
49 | ** delete when size - padding < 0 (isHidden)
50 | */
51 | public func getMinSize(size: CGSize) -> CGSize {
52 | return CGSize(width: max(size.width - paddingLeft - paddingRight, 0),
53 | height: max(size.height - paddingTop - paddingBottom, 0))
54 | }
55 |
56 | public func getMaxSize(size: CGSize) -> CGSize {
57 | return CGSize(width: max(size.width + paddingLeft + paddingRight, 0),
58 | height: max(size.height + paddingTop + paddingBottom, 0))
59 | }
60 | }
61 |
62 | public struct UIViewExtension {
63 | public var padding: Padding
64 | internal var layoutParams: LayoutParams
65 | internal init(padding: Padding, params: LayoutParams) {
66 | self.padding = padding
67 | self.layoutParams = params
68 | }
69 |
70 | internal init() {
71 | self.padding = Padding()
72 | self.layoutParams = LayoutParams.generateDefaultLayoutParams()
73 | }
74 |
75 | public mutating func setLayoutParams(params: LayoutParams) {
76 | params.bindWith(view:layoutParams.bindView)
77 | self.layoutParams = params
78 | }
79 | }
80 |
81 | extension UIView: ExtensionParams {
82 |
83 | private struct Key {
84 | static var ExtensionKey = "ExtensionKey"
85 | }
86 |
87 | public var uiViewExtension: UIViewExtension {
88 | set {
89 | objc_setAssociatedObject(self, &Key.ExtensionKey,
90 | newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
91 | }
92 |
93 | get {
94 | if let el = objc_getAssociatedObject(self, &Key.ExtensionKey) as? UIViewExtension {
95 | return el
96 | }
97 | let el = UIViewExtension()
98 | objc_setAssociatedObject(self, &Key.ExtensionKey,
99 | el, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
100 | return el
101 | }
102 | }
103 |
104 | public func setLayoutParams(params: LayoutParams) {
105 | uiViewExtension.layoutParams = params
106 | }
107 |
108 | public func getLayoutParams() -> LayoutParams {
109 | return uiViewExtension.layoutParams
110 | }
111 |
112 | public func setPadding(top: CGFloat, left: CGFloat, right: CGFloat, bottom: CGFloat) {
113 | self.uiViewExtension.padding = Padding(top: top, left: left, right: right, bottom: bottom)
114 | }
115 | }
116 |
117 | extension UIView {
118 |
119 | private struct IdKey {
120 | static var ExtensionKey = "IdExtensionKey"
121 | }
122 |
123 | private static var atomicInteger = 1
124 |
125 | public class InnerInteger {
126 | let viewId: Int
127 |
128 | init(_ id: Int) {
129 | viewId = id
130 | }
131 |
132 | public static func ==(_ a: InnerInteger, _ b: InnerInteger) -> Bool {
133 | if a.viewId == b.viewId {
134 | return true
135 | }
136 | return false
137 | }
138 | }
139 |
140 | private var viewId: InnerInteger {
141 | set {
142 | objc_setAssociatedObject(self, &IdKey.ExtensionKey,
143 | newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
144 | }
145 |
146 | get {
147 | if let el = objc_getAssociatedObject(self, &IdKey.ExtensionKey) as? InnerInteger {
148 | return el
149 | }
150 | let el = InnerInteger(-1)
151 | objc_setAssociatedObject(self, &IdKey.ExtensionKey,
152 | el, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
153 | return el
154 | }
155 | }
156 |
157 | public static func generateViewId() -> Int {
158 | objc_sync_enter(atomicInteger)
159 | atomicInteger += 1
160 | objc_sync_exit(atomicInteger)
161 | return Int(atomicInteger)
162 | }
163 |
164 | public func setViewId(id: Int) {
165 | viewId = InnerInteger(id)
166 | }
167 |
168 | public func getViewId() -> InnerInteger {
169 | return viewId
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/JustUiKitSample/JustUiKitSample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // JustUiKitSample
4 | //
5 | // Created by 刘丰恺 on 2017/2/6.
6 | // Copyright (c) 2017 ___lfkdsk___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import JustUiKit
11 |
12 | class ViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | // Do any additional setup after loading the view, typically from a nib.
17 |
18 | }
19 |
20 |
21 | override func didReceiveMemoryWarning() {
22 | super.didReceiveMemoryWarning()
23 | // Dispose of any resources that can be recreated.
24 | }
25 |
26 | func createSectionLabel(_ title: String) -> UILabel {
27 | let sectionLabel = UILabel()
28 | sectionLabel.text = title;
29 | sectionLabel.font = UIFont.systemFont(ofSize: 17)
30 | sectionLabel.sizeToFit()
31 | sectionLabel.backgroundColor = UIColor.brown
32 | return sectionLabel
33 | }
34 |
35 | func loadLinearLayout() {
36 | self.view = UIView(frame: UIScreen.main.bounds)
37 | view.backgroundColor = UIColor(rgb: 0xFF8C00)
38 |
39 | let lfkdsk = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Horizontal)
40 |
41 | view.addSubview(lfkdsk)
42 |
43 | let linearLayout: JustLinearLayout = lfkdsk
44 |
45 | let params: LinearLayoutParams = LinearLayoutParams(
46 | width: LayoutParams.WRAP_CONTENT,
47 | height: LayoutParams.WRAP_CONTENT)
48 | params.weight = 1
49 | // params.leftMargin = 100
50 | // params.rightMargin = 10
51 |
52 | let fuckView = createSectionLabel("FUCK")
53 |
54 | print(fuckView.frame.origin)
55 | print(fuckView.frame.size)
56 |
57 | print("Before Layout")
58 |
59 | let centerParams = LinearLayoutParams(linear: params)
60 | // centerParams.weight = 1
61 | centerParams.layoutGravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL
62 |
63 | let rightParams = LinearLayoutParams(linear: params)
64 | rightParams.layoutGravity = Gravity.BOTTOM
65 |
66 | let rightAndBottomParams = LinearLayoutParams(params)
67 | // rightAndBottomParams.weight = 1
68 | rightAndBottomParams.layoutGravity = Gravity.BOTTOM | Gravity.RIGHT
69 |
70 | let rightAndTopParams = LinearLayoutParams(linear: params)
71 | // rightAndTopParams.rightMargin = 12
72 | // rightAndTopParams.weight = 1
73 | rightAndTopParams.layoutGravity = Gravity.TOP | Gravity.RIGHT
74 |
75 | linearLayout.addView(view: createSectionLabel("苟"), params: rightAndTopParams)
76 | linearLayout.addView(view: createSectionLabel("利"), params: params)
77 | linearLayout.addView(view: createSectionLabel("国"), params: params)
78 | // linearLayout.addView(view: createSectionLabel("家"), params: centerParams)
79 | // linearLayout.addView(view: createSectionLabel("生"), params: params)
80 | // linearLayout.addView(view: createSectionLabel("死"), params: rightAndBottomParams)
81 | // linearLayout.addView(view: createSectionLabel("以"), params: params)
82 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
83 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
84 | // linearLayout.addView(view: createSectionLabel("岂因祸福"), params: params)
85 | // linearLayout.addView(view: createSectionLabel("以"), params: params)
86 |
87 | let fuck2View = JustLinearLayout(orientation: .Horizontal)
88 | // fuck2View.linearExtension.padding.paddingBottom = 10
89 | let Fuck2Params = LinearLayoutParams(width: LayoutParams.MATCH_PARENT,
90 | height: LayoutParams.WRAP_CONTENT)
91 | // Fuck2Params.topMargin = 80
92 | Fuck2Params.leftMargin = 20
93 | Fuck2Params.weight = 1
94 | Fuck2Params.layoutGravity = Gravity.CENTER_VERTICAL
95 | // fuck2View.setPadding(top: 10, left: 0, right: 10, bottom: 0)
96 | lfkdsk.addView(view: fuck2View, params: Fuck2Params)
97 |
98 | let firstInnerItem = createSectionLabel("以")
99 | // rightAndTopParams.bottomMargin = 10
100 |
101 | fuck2View.addView(view: firstInnerItem, params: params)
102 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
103 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
104 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
105 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: rightParams)
106 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: params)
107 | fuck2View.addView(view: createSectionLabel("岂因祸福"), params: centerParams)
108 | // fuck2View.linearExtension.padding.paddingRight = 80
109 |
110 | }
111 |
112 | func loadFrameLayout() {
113 | self.view = JustFrameLayout(frame: UIScreen.main.bounds)
114 | view.backgroundColor = UIColor(rgb: 0xFF8C00)
115 |
116 | let lfkdsk: JustFrameLayout = view as! JustFrameLayout
117 | // (view as! JustFrameLayout).addView(view: lfkdsk, params: FrameLayoutParams(width:
118 | // LayoutParams.WRAP_CONTENT, height: LayoutParams.WRAP_CONTENT))
119 |
120 | let params = FrameLayoutParams(width: LayoutParams.WRAP_CONTENT,
121 | height: LayoutParams.WRAP_CONTENT)
122 |
123 | let CENTER_V = FrameLayoutParams(source: params)
124 | CENTER_V.layoutGravity = Gravity.CENTER_HORIZONTAL
125 |
126 | let CENTER_H = FrameLayoutParams(source: params)
127 | CENTER_H.layoutGravity = Gravity.CENTER_VERTICAL
128 |
129 | let bottom_left = FrameLayoutParams(source: params)
130 | bottom_left.layoutGravity = Gravity.BOTTOM | Gravity.LEFT
131 |
132 | let ver_right = FrameLayoutParams(source: params)
133 | ver_right.layoutGravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT
134 |
135 | let center = FrameLayoutParams(source: params)
136 | center.layoutGravity = Gravity.CENTER
137 |
138 | lfkdsk.addView(view: createSectionLabel("FFFFFFFFFF"), params: CENTER_V)
139 | lfkdsk.addView(view: createSectionLabel("ssssssss"), params: CENTER_H)
140 | lfkdsk.addView(view: createSectionLabel("aaaaa"), params: bottom_left)
141 | lfkdsk.addView(view: createSectionLabel("vvvv"), params: ver_right)
142 | lfkdsk.addView(view: createSectionLabel("ssss"), params: center)
143 | }
144 |
145 | func loadRelativeLayout() {
146 | self.view = JustRelativeLayout(frame: UIScreen.main.bounds)
147 | view.backgroundColor = UIColor(rgb: 0xFF8C00)
148 |
149 | let lfkdsk: JustRelativeLayout = view as! JustRelativeLayout
150 |
151 | let params = RelativeLayoutParams(width: LayoutParams.WRAP_CONTENT,
152 | height: LayoutParams.WRAP_CONTENT)
153 |
154 | let view1 = createSectionLabel("FFF")
155 |
156 |
157 | }
158 |
159 | func addViewToLayout() {
160 | self.view = JustRelativeLayout(frame: UIScreen.main.bounds)
161 | view.backgroundColor = UIColor(rgb: 0xFF8C00)
162 |
163 | let lfkdsk: JustRelativeLayout = view as! JustRelativeLayout
164 |
165 | let view1 = createSectionLabel("11111111111111111111")
166 | let view2 = createSectionLabel("22222222222222222222")
167 | let view3 = createSectionLabel("33333333333333333333")
168 |
169 | let params = RelativeLayoutParams.generateDefaultParams()
170 |
171 | params.leftOf(view2)
172 | // params.alignLeftTo(left: view3)
173 | params.bellowOf(view3)
174 | params.topMargin = 10
175 | // 2 <==== 1 ====> 3
176 |
177 | // 3
178 | // |
179 | // 1 ==== 2
180 | lfkdsk.addView(view: view1, params: params)
181 |
182 | let params2 = RelativeLayoutParams(params)
183 | params2.layoutGravity = Gravity.RIGHT
184 |
185 | lfkdsk.addView(view: view2, params: params2)
186 |
187 | let params_center = RelativeLayoutParams(params)
188 | params_center.layoutGravity = Gravity.CENTER
189 |
190 | lfkdsk.addView(view: view3, params: params_center)
191 | }
192 |
193 | override func loadView() {
194 | super.loadView()
195 |
196 | // loadFrameLayout()
197 | addViewToLayout()
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/README_ZH.md:
--------------------------------------------------------------------------------
1 | # JustUiKit
2 | JustUiKit是一套Android样式工具iOS UI套件。 JustUiKit包含JustLinearLayout,JustFrameLayout, JustRelativeLayout等。 它旨在使Android开发人员轻松构建iOS UI。 也为iOS开发人员提供了一种新的方式来构建UI。
3 |
4 | [](https://raw.githubusercontent.com/lfkdsk/JustUiKit/master/LICENSE)
5 | [](https://github.com/lfkdsk/JustUiKit)
6 | [](https://github.com/lfkdsk/JustUiKit)
7 | [](https://cocoapods.org/pods/JustUiKit)
8 |
9 | ## 如何使用?
10 |
11 | * 拷贝代码
12 |
13 | 拷贝Deomo中的JustUiKit代码到项目
14 |
15 | * 使用 CocoaPods 安装
16 |
17 | CocoaPods是Objective-C / Swift的依赖项管理器,它自动化和简化在项目中使用第三方库(JustUiKit)的过程。 您可以使用以下命令安装它:
18 |
19 | `$ sudo gem install cocoapods`
20 |
21 | 要使用CocoaPods将JustUiKit集成到您的Xcode项目中,请在Podfile中指定:
22 |
23 | ```ruby
24 | platform :ios, '8.0'
25 | pod 'JustUiKit', '~> 0.2.1'
26 | ```
27 |
28 | 之后运行如下命令:
29 |
30 | `$ pod install`
31 |
32 | ## 快捷开始
33 |
34 | ### JustLinearLayout
35 | 将其子代排列在单列或单行中的布局。 行的方向可以通过方向设置。 您还可以指定gravity,它通过设置重力指定所有子元素的对齐方式,或通过设置LinearLayoutParams的weight成员来指定特定子项增长以填充布局中的任何剩余空间。 默认方向为水平。
36 |
37 | #### Gravity & Margin & Orientation
38 | 
39 |
40 | 您可以设置重力以使视图布局在parentView的指定空间。 还设置Margin将在视图的四个方向保留空格。 在默认情况下,LinearLayout布局子项在水平方向,并且可以将其更改为Veritcal。
41 |
42 | ``` swift
43 | let parentView = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Vertical)
44 | let params = LinearLayoutParams(
45 | width: LayoutParams.WRAP_CONTENT,
46 | height: LayoutParams.WRAP_CONTENT)
47 | let centerParams = LinearLayoutParams(params)
48 | centerParams.layoutGravity = Gravity.Horizontal.getValue()
49 |
50 | let marginParams = LinearLayoutParams(params)
51 | marginParams.topMargin = 10
52 |
53 | parentView.addView(createView(), centerParams)
54 | parentView.addView(createView(), marginParams)
55 | ```
56 |
57 | #### Padding & weight
58 | 
59 |
60 | 使用Padding在四个方向,您可以保留视图的内部空间。 “权重”描述了子视图的位置。 默认为Gravity.TOP | Gravity.LEFT。 如果此布局具有VERTICAL方向,则控制在存在额外垂直空间时放置所有子视图的位置。 如果此布局具有HORIZONTAL方向,则控制子项的对齐方式。
61 |
62 | ``` swift
63 | let parentView = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Vertical)
64 | let params = LinearLayoutParams(
65 | width: LayoutParams.WRAP_CONTENT,
66 | height: LayoutParams.WRAP_CONTENT)
67 | params.weight = 1
68 | let paddingParams = LinearLayoutParams(params)
69 | paddingParams.paddingTop = 10
70 | parentView.addView(createView(), params)
71 | parentView.addView(createView(), paddingParams)
72 | ```
73 |
74 | ### JustFrameLayout
75 |
76 | FrameLayout设计用于屏蔽屏幕上的一个区域以显示单个项目。
77 |
78 | 通常,FrameLayout应该用于保存单个子视图,因为可能难以以可扩展到不同屏幕尺寸的方式组织子视图,而不会使子节点相互重叠。
79 |
80 | 然而,您可以添加多个孩子到一个FrameLayout,并通过分配重力给每个孩子,使用layoutGravity控制他们在FrameLayout中的位置。
81 |
82 | #### Overlap on left
83 | 
84 |
85 | 如果不使用任何边距或填充来更改视图的位置。 所有的视图将添加像堆栈和重叠在屏幕的左边|顶部。
86 |
87 | Example:
88 |
89 | ``` swift
90 | let parentView: JustFrameLayout = JustFrameLayout(width:MATCH_PARENT, height:MATCH_PARENT)
91 | let params: FrameLayoutParams = JustFrameLayoutParams(width: WRAP_CONTENT, height: WRAP_CONTENT)
92 | parentView.addView(createView(rgb:0xE4E1D8), params)
93 | parentView.addView(createView(rgb:0x89A49D), params)
94 | parentView.addView(createView(rgb:0x877B6B), params)
95 | ```
96 |
97 | #### Layout With Gravity
98 | 
99 |
100 | 您可以使用水平和垂直重力。 此外,您可以使用像left | bottom,center_horizontal | center_vertical来同时使用它们。
101 |
102 | Example:
103 |
104 | ``` swift
105 | let parentView: FrameLayout = FrameLayout(width:MATCH_PARENT, height:MATCH_PARENT)
106 | let params: FrameLayoutParams = FrameLayoutParams(width: WRAP_CONTENT, height: WRAP_CONTENT)
107 |
108 | let b_l = FrameLayoutParams(params)
109 | b_l.layoutGravity = Gravity.BOTTOM | Gravity.TOP
110 | let c_r = FrameLayoutParams(params)
111 | c_r.layoutGravity = Gravity.CENTER_HORIZONTAL | Gravity.RIGHT
112 | parentView.addView(createView(rgb:0xE4E1D8), b_l)
113 | parentView.addView(createView(rgb:0x89A49D), c_r)
114 | parentView.addView(createView(rgb:0x877B6B), params)
115 | ```
116 |
117 | ### JustRelativeLayout
118 | 一个布局,其中子节点的位置可以相对于彼此或相对于父节点来描述。
119 |
120 | 请注意,您不能在RelativeLayout的大小和其子项的位置之间具有循环依赖关系。 例如,您不能具有高度设置为WRAP_CONTENT的RelativeLayout和设置为ALIGN_PARENT_BOTTOM的子级。
121 |
122 | 
123 |
124 | 在RelativeLayout中,您可以使用所有边距,填充和重力。 此外,您可以使用一些对齐功能。 例如,如果视图是alignLeftTo,则其左边缘将被设置为等于锚视图。 您可以使用一组函数,如leftOf,rightOf,bottomOf将当前视图设置到锚视图的左侧。
125 |
126 | ``` swift
127 | // view1 view2 view3 view4 view5
128 | let params = RelativeLayoutParams.generateDefaultParams()
129 | let params1 = RelativeLayoutParams(params)
130 | params1.centerInHorizontal()
131 | let params2 = RelativeLayoutParams(params)
132 | params2.bottomTo(view4)
133 | params2.topMargin = xxx
134 | let params3 = RelativeLayoutParams(params)
135 | param3.alignRightTo(view1)
136 | let params4 = RelativeLayoutParams(params)
137 | params4.centerInParent()
138 | let params5 = RelativeLayoutParams(params)
139 | params5.alignParentBottom()
140 | // add view to parent
141 | ```
142 |
143 | #### RelativeLayout中的约束
144 |
145 | | Constants | Description |
146 | | ------------------- | -------------------------------------- |
147 | | ABOVE | 将孩子的底部边缘与另一个孩子的顶部边缘对齐的规则。 |
148 | | ALIGN_BASELINE | 将子项的基准与另一个子项的基准对齐的规则。 |
149 | | ALIGN_BOTTOM | 将儿童的底部边缘与另一个儿童的底部边缘对齐的规则。 |
150 | | ALIGN_LEFT | 将儿童的左边缘与另一个儿童的左边缘对齐的规则。 |
151 | | ALIGN_PARENT_BOTTOM | 将子元素的底边与其RelativeLayout父元素的底边对齐的规则。 |
152 | | ALIGN_PARENT_LEFT | 将子对象的左边缘与其RelativeLayout父对象的左边缘对齐的规则。 |
153 | | ALIGN_PARENT_RIGHT | 将子对象的右边缘与其RelativeLayout父对象的右边缘对齐的规则。 |
154 | | ALIGN_PARENT_TOP | 将子对象的顶边与其RelativeLayout父对象的顶边对齐的规则。 |
155 | | ALIGN_RIGHT | 将孩子的右边缘与另一个孩子的右边缘对齐的规则。 |
156 | | ALIGN_TOP | 将儿童的顶部边缘与另一个儿童的顶部边缘对齐的规则。 |
157 | | BELOW | 将儿童的顶部边缘与另一个儿童的底部边缘对齐的规则。 |
158 | | CENTER_HORIZONTAL | 将子元素相对于其RelativeLayout父元素的边界进行水平居中的规则。 |
159 | | CENTER_IN_PARENT | 使子对象相对于其RelativeLayout父对象的边界居中的规则。 |
160 | | CENTER_VERTICAL | 将子元素相对于其RelativeLayout父元素的边界垂直居中的规则。 |
161 | | END_OF | 将孩子的起始边缘与另一个孩子的边缘对齐的规则。 |
162 | | LEFT_OF | 将儿童的右边缘与另一个儿童的左边缘对齐的规则。 |
163 | | RIGHT_OF | 将儿童的左边缘与另一个儿童的右边缘对齐的规则。 |
164 |
165 | ## Gravity
166 |
167 | 必须是以下常量值中的一个或多个(由“|”分隔)。
168 |
169 | | Constant | Value | Description |
170 | | :---------------- | ----- | ---------------------------- |
171 | | 顶部 | 0x30 | 将对象推送到其容器的顶部,而不更改其大小。 |
172 | | 底部 | 0x50 | 将对象推送到其容器的底部,而不更改其大小。 |
173 | | 右 | 0x05 | 将对象推送到其容器的右侧,而不更改其大小。 |
174 | | center_vertical | 0x10 | 将对象放置在其容器的垂直中心,而不是更改其大小。 |
175 | | center_horizontal | 0x01 | 将对象放置在其容器的水平中心,而不改变其大小。 |
176 | | 中心 | 0x11 | 将对象放置在其容器的垂直和水平轴的中心,而不改变其大小。 |
177 |
178 |
179 | ## Feedback
180 | 只要发生问题,请发送您的反馈。 你可以与我联系:
181 | * Email: lfk_dsk@hotmail.com
182 | * Weibo: [@亦狂亦侠_亦温文](http://www.weibo.com/u/2443510260)
183 | * Blog: [刘丰恺](https://lfkdsk.github.io)
184 |
185 | ## License
186 |
187 | ```
188 |
189 | MIT License
190 |
191 | Copyright (c) 2017 JustWe
192 |
193 | Permission is hereby granted, free of charge, to any person obtaining a copy
194 | of this software and associated documentation files (the "Software"), to deal
195 | in the Software without restriction, including without limitation the rights
196 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
197 | copies of the Software, and to permit persons to whom the Software is
198 | furnished to do so, subject to the following conditions:
199 |
200 | The above copyright notice and this permission notice shall be included in all
201 | copies or substantial portions of the Software.
202 |
203 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
204 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
205 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
206 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
208 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
209 | SOFTWARE.
210 | ```
211 |
--------------------------------------------------------------------------------
/JustUiKit/widget/JustFrameLayout.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import UIKit
24 |
25 | /// FrameLayout Params
26 | /// Params For FrameLayout
27 | /// This params just has layoutGravity
28 |
29 | public class FrameLayoutParams: MarginLayoutParams {
30 | public var layoutGravity: Gravity = Gravity.NO_GRAVITY
31 |
32 | public init(width: CGFloat, height: CGFloat, layoutGravity: Gravity) {
33 | super.init(width: width, height: height)
34 | self.layoutGravity = layoutGravity
35 | }
36 |
37 | public override init(width: CGFloat, height: CGFloat) {
38 | super.init(width: width, height: height)
39 | }
40 |
41 | public init(source: FrameLayoutParams) {
42 | super.init(source: source)
43 | self.layoutGravity = source.layoutGravity
44 | }
45 |
46 | /// init
47 | /// - LayoutParams params base generate method
48 | override init(_ source: LayoutParams) {
49 | super.init(source)
50 | }
51 |
52 | public static func generateDefaultParams() -> FrameLayoutParams {
53 | return FrameLayoutParams(width: LayoutParams.WRAP_CONTENT, height: LayoutParams.WRAP_CONTENT)
54 | }
55 | }
56 |
57 | open class JustFrameLayout: JustViewGroup {
58 |
59 | private var childViewSizes: [CGSize] = []
60 |
61 | override open func sizeThatFits(_ size: CGSize) -> CGSize {
62 | let childSizes: [CGSize]
63 | var childLayoutSize = CGSize.zero
64 | var padding: Padding
65 | var index: Int = 0
66 |
67 | childSizes = measureChildren(size)
68 |
69 | for size in childSizes {
70 | padding = subviews[index].uiViewExtension.padding
71 | childLayoutSize.width = max(childLayoutSize.width, size.width + padding.paddingLeft + padding.paddingRight)
72 | childLayoutSize.height = max(childLayoutSize.height, size.height + padding.paddingTop + padding.paddingBottom)
73 | index += 1
74 | }
75 | return uiViewExtension.padding.getMaxSize(size: childLayoutSize)
76 | }
77 |
78 |
79 | override public func onLayout(_ changed: Bool, _ top: CGFloat, _ left: CGFloat, _ right: CGFloat, _ bottom: CGFloat) {
80 | super.onLayout(changed, top, left, right, bottom)
81 |
82 | let padding = uiViewExtension.padding
83 |
84 | let pTop = top + padding.paddingTop,
85 | pLeft = left + padding.paddingLeft,
86 | pRight = right - padding.paddingRight,
87 | pBottom = bottom - padding.paddingBottom
88 |
89 | layoutChildren(changed, pTop, pLeft, pRight, pBottom)
90 | }
91 |
92 | override public func onMeasure(_ size: CGSize) {
93 | super.onMeasure(size)
94 | childViewSizes = measureChildren(size)
95 | }
96 |
97 | private func measureChildren(_ size: CGSize) -> [CGSize] {
98 | let selfSize = uiViewExtension.padding.getMinSize(size: size)
99 |
100 | var childSizes = [CGSize](repeating: CGSize(width: -1, height: -1), count: subviews.count)
101 | let height = selfSize.height
102 | let width = selfSize.width
103 | let maxHeightSize: CGFloat = height
104 | let maxWidthSize: CGFloat = width
105 |
106 | for (index, child) in subviews.enumerated() {
107 | if child.isHidden {
108 | continue
109 | }
110 |
111 | let params: FrameLayoutParams = child.uiViewExtension.layoutParams as! FrameLayoutParams
112 |
113 | var childHeight: CGFloat = 0
114 | var childSize: CGSize = CGSize()
115 |
116 | switch params.height {
117 | case LayoutParams.MATCH_PARENT:
118 | childHeight = maxHeightSize
119 | case LayoutParams.WRAP_CONTENT:
120 | childSize = child.sizeThatFits(
121 | CGSize(width: maxWidthSize,
122 | height: maxHeightSize))
123 | childHeight = childSize.height
124 | default:
125 | childHeight = params.height
126 | }
127 |
128 | childHeight = min(childHeight, maxHeightSize)
129 | childSizes[index].height = childHeight
130 |
131 | if childSize.height == childHeight {
132 | childSizes[index].width = childSize.width
133 | }
134 |
135 | var childWidth: CGFloat = 0
136 | childSize = CGSize.zero
137 |
138 | switch (params.width) {
139 | case LayoutParams.MATCH_PARENT:
140 | childWidth = maxWidthSize
141 | case LayoutParams.WRAP_CONTENT:
142 | childSize = child.sizeThatFits(
143 | CGSize(width: maxWidthSize,
144 | height: maxHeightSize))
145 |
146 | childWidth = childSize.width
147 | default:
148 | childWidth = params.width
149 | }
150 |
151 | childWidth = min(childWidth, maxWidthSize)
152 |
153 | childSizes[index].width = childWidth
154 | }
155 | return childSizes
156 | }
157 |
158 | private func layoutChildren(_ changed: Bool,
159 | _ top: CGFloat,
160 | _ left: CGFloat,
161 | _ right: CGFloat,
162 | _ bottom: CGFloat) {
163 |
164 | let height = bottom - top
165 |
166 | for (index, size) in childViewSizes.enumerated() {
167 | let child = subviews[index]
168 |
169 | if child.isHidden {
170 | continue
171 | }
172 |
173 | let childParams: FrameLayoutParams = child.uiViewExtension.layoutParams as! FrameLayoutParams
174 | let childWidth = size.width
175 | let childHeight = size.height
176 | var childTop: CGFloat = 0
177 | var childLeft: CGFloat = 0
178 |
179 | let verticalGravity = Gravity.getVerticalGravity(gravity: childParams.layoutGravity)
180 | let horizontalGravity = Gravity.getHorizontalGravity(gravity: childParams.layoutGravity)
181 |
182 | switch verticalGravity {
183 | case Gravity.CENTER_VERTICAL.getValue():
184 | childTop = (height - childHeight) / 2
185 | childTop += CGFloat(childParams.topMargin - childParams.bottomMargin)
186 | case Gravity.BOTTOM.getValue():
187 | childTop = height - childHeight
188 | default:
189 | childTop = top + CGFloat(childParams.topMargin)
190 | }
191 |
192 | switch horizontalGravity {
193 | case Gravity.CENTER_HORIZONTAL.getValue():
194 | childLeft = (right - left - childWidth) / 2 + left
195 | childLeft += (CGFloat(childParams.leftMargin - childParams.rightMargin))
196 | case Gravity.RIGHT.getValue():
197 | childLeft = right - left - childWidth - CGFloat(childParams.rightMargin);
198 | default:
199 | childLeft = left + CGFloat(childParams.leftMargin)
200 | }
201 |
202 | child.frame = CGRect(
203 | x: childLeft,
204 | y: childTop,
205 | width: childWidth,
206 | height: childHeight)
207 | child.layoutSubviews()
208 | }
209 | }
210 |
211 | public func addView(view: UIView, params: FrameLayoutParams = FrameLayoutParams.generateDefaultParams()) {
212 | view.uiViewExtension.layoutParams = params
213 |
214 | if view.superview != nil {
215 | return
216 | }
217 |
218 | if view is JustViewGroup {
219 | (view as! JustViewGroup).setParent(viewGroup: self)
220 | }
221 |
222 | addSubview(view)
223 | params.bindWith(view: view)
224 | }
225 |
226 | override public func addView(view: UIView) {
227 | super.addView(view: view)
228 | self.addView(view: view, params: FrameLayoutParams.generateDefaultParams())
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JustUiKit
2 | iOS UI Kit With Android-Style Tools. JustUiKit contains `JustLinearLayout`, `JustFrameLayout` and so on. It is designed to make Android developers build iOS UI easily. Also for iOS developers, it provides a new way to build UI.
3 |
4 | [](https://raw.githubusercontent.com/lfkdsk/JustUiKit/master/LICENSE)
5 | [](https://github.com/lfkdsk/JustUiKit)
6 | [](https://github.com/lfkdsk/JustUiKit)
7 | [](https://cocoapods.org/pods/JustUiKit)
8 |
9 | [中文请参阅](README_ZH.md)
10 |
11 | ## How To Install?
12 |
13 | * Copy to your project
14 |
15 | Copy JustUiKit folder from the demo project to your project
16 |
17 | * Installation with CocoaPods
18 |
19 | CocoaPods is a dependency manager for Objective-C/Swift, which automates and simplifies the process of using 3rd-party libraries like JustUiKit in your projects. You can install it with the following command:
20 |
21 | `$ sudo gem install cocoapods`
22 |
23 | To integrate JustUiKit into your Xcode project using CocoaPods, specify it in your Podfile:
24 |
25 | ``` ruby
26 | platform :ios, '8.0'
27 | pod 'JustUiKit', '~> 0.2.1'
28 | ```
29 |
30 | Then, run the following command:
31 |
32 | `$ pod install`
33 |
34 | ## Quick Start
35 |
36 | ### JustLinearLayout
37 | A Layout that arranges its children in a single column or a single row. The direction of the row can be set by `orientation`. You can also specify gravity, which specifies the alignment of all the child elements by set `gravity` or specify that specific children grow to fill up any remaining space in the layout by setting the weight member of `LinearLayoutParams`. The default orientation is horizontal.
38 |
39 | #### Gravity & Margin & Orientation
40 | 
41 |
42 | You can set `Gravity` to make Views be layouted at a specify space of parentView. Also set `Margin` will remain spaces in the four directions of the View. In default, LinearLayout layout children in `Horizontal` direction, and you can change it to `Veritcal`.
43 |
44 | Example:
45 |
46 | ``` swift
47 | let parentView = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Vertical)
48 | let params = LinearLayoutParams(
49 | width: LayoutParams.WRAP_CONTENT,
50 | height: LayoutParams.WRAP_CONTENT)
51 | let centerParams = LinearLayoutParams(params)
52 | centerParams.layoutGravity = Gravity.Horizontal.getValue()
53 |
54 | let marginParams = LinearLayoutParams(params)
55 | marginParams.topMargin = 10
56 |
57 | parentView.addView(createView(), centerParams)
58 | parentView.addView(createView(), marginParams)
59 | ```
60 |
61 | #### Padding & weight
62 | 
63 |
64 | With the `Padding` in four directions, you can remain inner space of the view. And `Weight` describes how the child views are positioned. Defaults to Gravity.TOP | Gravity.LEFT. If this layout has a VERTICAL orientation, this controls where all the child views are placed if there is extra vertical space. If this layout has a HORIZONTAL orientation, this controls the alignment of the children.
65 |
66 | See [Gravity](##Gravity) to get more details.
67 |
68 | Example:
69 |
70 | ``` swift
71 | let parentView = JustLinearLayout(frame: UIScreen.main.bounds, orientation: .Vertical)
72 | let params = LinearLayoutParams(
73 | width: LayoutParams.WRAP_CONTENT,
74 | height: LayoutParams.WRAP_CONTENT)
75 | params.weight = 1
76 | let paddingParams = LinearLayoutParams(params)
77 | paddingParams.paddingTop = 10
78 | parentView.addView(createView(), params)
79 | parentView.addView(createView(), paddingParams)
80 | ```
81 |
82 | ### JustFrameLayout
83 |
84 | FrameLayout is designed to block out an area on the screen to display a single item.
85 | Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that's scalable to different screen sizes without the children overlapping each other.
86 | You can, however, add multiple children to a FrameLayout and control their position within the FrameLayout by assigning gravity to each child, using the layoutGravity.
87 |
88 | #### Overlap on left
89 | 
90 |
91 | if don't use any `Margin` or `Padding` to change view's position. All the Views will be add like stack and overlap on the `left|top` of the screen.
92 |
93 | Example:
94 |
95 | ``` swift
96 | let parentView: JustFrameLayout = JustFrameLayout(width:MATCH_PARENT, height:MATCH_PARENT)
97 | let params: FrameLayoutParams = JustFrameLayoutParams(width: WRAP_CONTENT, height: WRAP_CONTENT)
98 | parentView.addView(createView(rgb:0xE4E1D8), params)
99 | parentView.addView(createView(rgb:0x89A49D), params)
100 | parentView.addView(createView(rgb:0x877B6B), params)
101 | ```
102 |
103 | #### Layout With Gravity
104 | 
105 |
106 | You can use horizontal and vertical gravity. Also You can use like `left|bottom`, `center_horizontal|center_vertical` to use them at the same time.
107 |
108 | See [Gravity](##Gravity) to get more details.
109 |
110 | Example:
111 |
112 | ``` swift
113 | let parentView: FrameLayout = FrameLayout(width:MATCH_PARENT, height:MATCH_PARENT)
114 | let params: FrameLayoutParams = FrameLayoutParams(width: WRAP_CONTENT, height: WRAP_CONTENT)
115 |
116 | let b_l = FrameLayoutParams(params)
117 | b_l.layoutGravity = Gravity.BOTTOM | Gravity.TOP
118 | let c_r = FrameLayoutParams(params)
119 | c_r.layoutGravity = Gravity.CENTER_HORIZONTAL | Gravity.RIGHT
120 | parentView.addView(createView(rgb:0xE4E1D8), b_l)
121 | parentView.addView(createView(rgb:0x89A49D), c_r)
122 | parentView.addView(createView(rgb:0x877B6B), params)
123 | ```
124 |
125 | ### JustRelativeLayout
126 | A Layout where the positions of the children can be described in relation to each other or to the parent.
127 |
128 | Note that you cannot have a circular dependency between the size of the RelativeLayout and the position of its children. For example, you cannot have a RelativeLayout whose height is set to WRAP_CONTENT and a child set to ALIGN_PARENT_BOTTOM.
129 |
130 | 
131 |
132 | In RelativeLayout, you can use all the `Margin`,`Padding` and `Gravity`. Also You can use some `Align` functions. Such as, if a view is `alignLeftTo`, its left edge will be set equal to the anchor view. You can use a set of functions like `leftOf`, `rightOf`, `bottomOf` set the current view to the left of anchor view.
133 |
134 | ``` swift
135 | // view1 view2 view3 view4 view5
136 | let params = RelativeLayoutParams.generateDefaultParams()
137 | let params1 = RelativeLayoutParams(params)
138 | params1.centerInHorizontal()
139 | let params2 = RelativeLayoutParams(params)
140 | params2.bottomTo(view4)
141 | params2.topMargin = xxx
142 | let params3 = RelativeLayoutParams(params)
143 | param3.alignRightTo(view1)
144 | let params4 = RelativeLayoutParams(params)
145 | params4.centerInParent()
146 | let params5 = RelativeLayoutParams(params)
147 | params5.alignParentBottom()
148 | // add view to parent
149 | ```
150 |
151 | #### Rule in RelativeLayout
152 |
153 | | Constants | Description |
154 | | ------------------- | ---------------------------------------- |
155 | | ABOVE | Rule that aligns a child's bottom edge with another child's top edge. |
156 | | ALIGN_BASELINE | Rule that aligns a child's baseline with another child's baseline. |
157 | | ALIGN_BOTTOM | Rule that aligns a child's bottom edge with another child's bottom edge. |
158 | | ALIGN_LEFT | Rule that aligns a child's left edge with another child's left edge. |
159 | | ALIGN_PARENT_BOTTOM | Rule that aligns the child's bottom edge with its RelativeLayout parent's bottom edge. |
160 | | ALIGN_PARENT_LEFT | Rule that aligns the child's left edge with its RelativeLayout parent's left edge. |
161 | | ALIGN_PARENT_RIGHT | Rule that aligns the child's right edge with its RelativeLayout parent's right edge. |
162 | | ALIGN_PARENT_TOP | Rule that aligns the child's top edge with its RelativeLayout parent's top edge. |
163 | | ALIGN_RIGHT | Rule that aligns a child's right edge with another child's right edge. |
164 | | ALIGN_TOP | Rule that aligns a child's top edge with another child's top edge. |
165 | | BELOW | Rule that aligns a child's top edge with another child's bottom edge. |
166 | | CENTER_HORIZONTAL | Rule that centers the child horizontally with respect to the bounds of its RelativeLayout parent. |
167 | | CENTER_IN_PARENT | Rule that centers the child with respect to the bounds of its RelativeLayout parent. |
168 | | CENTER_VERTICAL | Rule that centers the child vertically with respect to the bounds of its RelativeLayout parent. |
169 | | END_OF | Rule that aligns a child's start edge with another child's end edge. |
170 | | LEFT_OF | Rule that aligns a child's right edge with another child's left edge. |
171 | | RIGHT_OF | Rule that aligns a child's left edge with another child's right edge. |
172 |
173 | ## Gravity
174 |
175 | Must be one or more (separated by '|') of the following constant values.
176 |
177 | | Constant | Value | Description |
178 | | :---------------- | ----- | ---------------------------------------- |
179 | | top | 0x30 | Push object to the top of its container, not changing its size. |
180 | | bottom | 0x50 | Push object to the bottom of its container, not changing its size. |
181 | | right | 0x05 | Push object to the right of its container, not changing its size. |
182 | | center_vertical | 0x10 | Place object in the vertical center of its container, not changing its size. |
183 | | center_horizontal | 0x01 | Place object in the horizontal center of its container, not changing its size. |
184 | | center | 0x11 | Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. |
185 |
186 | ## Feedback
187 |
188 | Please send your feedback as long as there occurs any inconvenience or problem. You can contact me with:
189 | * Email: lfk_dsk@hotmail.com
190 | * Weibo: [@亦狂亦侠_亦温文](http://www.weibo.com/u/2443510260)
191 | * Blog: [刘丰恺](https://lfkdsk.github.io)
192 |
193 | ## License
194 |
195 | ```
196 |
197 | MIT License
198 |
199 | Copyright (c) 2017 JustWe
200 |
201 | Permission is hereby granted, free of charge, to any person obtaining a copy
202 | of this software and associated documentation files (the "Software"), to deal
203 | in the Software without restriction, including without limitation the rights
204 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
205 | copies of the Software, and to permit persons to whom the Software is
206 | furnished to do so, subject to the following conditions:
207 |
208 | The above copyright notice and this permission notice shall be included in all
209 | copies or substantial portions of the Software.
210 |
211 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
212 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
213 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
214 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
215 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217 | SOFTWARE.
218 |
219 | ```
220 |
--------------------------------------------------------------------------------
/JustUiKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1F4A50AB70CA7FAA8452071D /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1F4A536A1248643E93F8A2CD /* Info.plist */; };
11 | 1F4A50DF28D4F4DB7E48B1F5 /* JustFrameLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5242F547BDDE9E85737F /* JustFrameLayout.swift */; };
12 | 1F4A52920CBEDAC4E8EBB468 /* JustExtensionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A53BFD8C6BC0B089C3A33 /* JustExtensionView.swift */; };
13 | 1F4A5478A2C2D99BD50069AC /* JustLinearLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5551A35FC077DE6B5B2F /* JustLinearLayout.swift */; };
14 | 1F4A56BE01BB7181D793C388 /* ReleasePool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5D2DDC60FD033F813BE6 /* ReleasePool.swift */; };
15 | 1F4A571634F8208E3BE1671F /* JustUiKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F4A505755AC835F3762D3A3 /* JustUiKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
16 | 1F4A57D0DE7EA6295AB293D2 /* JustViewParent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5456678972DE25244C98 /* JustViewParent.swift */; };
17 | 1F4A57E10237CAEE95A4650E /* Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5F9AF4A2DC76D4825118 /* Orientation.swift */; };
18 | 1F4A5944BBC556272F2CC3A8 /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A505849AD0FC368329099 /* ColorExtension.swift */; };
19 | 1F4A5989D9FC754C62434510 /* JustViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A51215B79447FBF05FD4E /* JustViewManager.swift */; };
20 | 1F4A59B149573A55F70F2B95 /* JustLayoutParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5AD76626AC9CFB1358EF /* JustLayoutParams.swift */; };
21 | 1F4A59E2B441CBC469D1081D /* JustViewGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5511BC326869D730F08C /* JustViewGroup.swift */; };
22 | 1F4A5BDA99E2B314D8F00C94 /* JustUiKit.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 1F4A5C468AA857CCB949BFEC /* JustUiKit.podspec */; };
23 | 1F4A5C1CD4E1B9684E62A2A1 /* .swift-version in Resources */ = {isa = PBXBuildFile; fileRef = 1F4A59ACE48077F39440C6CC /* .swift-version */; };
24 | 1F4A5CC393D38237C20F73B3 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A538A84DAF817FE7AABA2 /* Queue.swift */; };
25 | 1F4A5D248CDEBE9F7C9D87B3 /* Gravity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A5A9ACB27277D696F9F49 /* Gravity.swift */; };
26 | 529896541E374C1B00CA01B9 /* JustRelativeLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 529896531E374C1B00CA01B9 /* JustRelativeLayout.swift */; };
27 | /* End PBXBuildFile section */
28 |
29 | /* Begin PBXContainerItemProxy section */
30 | 1F4A520233E995710022CAB9 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 1F4A5EE6514429FA6E1E68F6 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 1F4A5E9B5B37635B5E156071;
35 | remoteInfo = JustUiKit;
36 | };
37 | /* End PBXContainerItemProxy section */
38 |
39 | /* Begin PBXFileReference section */
40 | 1F4A505755AC835F3762D3A3 /* JustUiKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JustUiKit.h; sourceTree = ""; };
41 | 1F4A505849AD0FC368329099 /* ColorExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = ""; };
42 | 1F4A51215B79447FBF05FD4E /* JustViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustViewManager.swift; sourceTree = ""; };
43 | 1F4A5242F547BDDE9E85737F /* JustFrameLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustFrameLayout.swift; sourceTree = ""; };
44 | 1F4A536A1248643E93F8A2CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.info; path = Info.plist; sourceTree = ""; };
45 | 1F4A538A84DAF817FE7AABA2 /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = ""; };
46 | 1F4A53BFD8C6BC0B089C3A33 /* JustExtensionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustExtensionView.swift; sourceTree = ""; };
47 | 1F4A5456678972DE25244C98 /* JustViewParent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustViewParent.swift; sourceTree = ""; };
48 | 1F4A5511BC326869D730F08C /* JustViewGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustViewGroup.swift; sourceTree = ""; };
49 | 1F4A5551A35FC077DE6B5B2F /* JustLinearLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustLinearLayout.swift; sourceTree = ""; };
50 | 1F4A59ACE48077F39440C6CC /* .swift-version */ = {isa = PBXFileReference; lastKnownFileType = "file.swift-version"; path = ".swift-version"; sourceTree = ""; };
51 | 1F4A5A9ACB27277D696F9F49 /* Gravity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gravity.swift; sourceTree = ""; };
52 | 1F4A5AD76626AC9CFB1358EF /* JustLayoutParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustLayoutParams.swift; sourceTree = ""; };
53 | 1F4A5C468AA857CCB949BFEC /* JustUiKit.podspec */ = {isa = PBXFileReference; lastKnownFileType = file.podspec; path = JustUiKit.podspec; sourceTree = ""; };
54 | 1F4A5D2DDC60FD033F813BE6 /* ReleasePool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReleasePool.swift; sourceTree = ""; };
55 | 1F4A5F9AF4A2DC76D4825118 /* Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Orientation.swift; sourceTree = ""; };
56 | 529896521E374C0E00CA01B9 /* JustUiKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JustUiKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 529896531E374C1B00CA01B9 /* JustRelativeLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustRelativeLayout.swift; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 1F4A5276196EA8B81244EF6D /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | 1F4A551154CCEE13D44F75EF /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 1F4A52985AAE5EBA23FEBDE2 /* utils */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 1F4A5A9ACB27277D696F9F49 /* Gravity.swift */,
82 | 1F4A5F9AF4A2DC76D4825118 /* Orientation.swift */,
83 | 1F4A505849AD0FC368329099 /* ColorExtension.swift */,
84 | 1F4A538A84DAF817FE7AABA2 /* Queue.swift */,
85 | 1F4A5D2DDC60FD033F813BE6 /* ReleasePool.swift */,
86 | );
87 | path = utils;
88 | sourceTree = "";
89 | };
90 | 1F4A53E4C54A6588A68324D1 /* layout */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 1F4A5511BC326869D730F08C /* JustViewGroup.swift */,
94 | 1F4A5456678972DE25244C98 /* JustViewParent.swift */,
95 | 1F4A51215B79447FBF05FD4E /* JustViewManager.swift */,
96 | 1F4A53BFD8C6BC0B089C3A33 /* JustExtensionView.swift */,
97 | );
98 | path = layout;
99 | sourceTree = "";
100 | };
101 | 1F4A54665BF1962B972E84B4 = {
102 | isa = PBXGroup;
103 | children = (
104 | 1F4A54AB7F9F57E5B9752BB4 /* JustUiKit */,
105 | 1F4A59ACE48077F39440C6CC /* .swift-version */,
106 | 1F4A5C468AA857CCB949BFEC /* JustUiKit.podspec */,
107 | 5241B5D31E2F906A00F96976 /* Frameworks */,
108 | 529896521E374C0E00CA01B9 /* JustUiKitTests.xctest */,
109 | );
110 | sourceTree = "";
111 | };
112 | 1F4A54AB7F9F57E5B9752BB4 /* JustUiKit */ = {
113 | isa = PBXGroup;
114 | children = (
115 | 1F4A536A1248643E93F8A2CD /* Info.plist */,
116 | 1F4A505755AC835F3762D3A3 /* JustUiKit.h */,
117 | 1F4A52985AAE5EBA23FEBDE2 /* utils */,
118 | 1F4A5CA795838BC2E7696DD9 /* widget */,
119 | 1F4A53E4C54A6588A68324D1 /* layout */,
120 | 1F4A5CD8DDD6C55800B38D5A /* params */,
121 | );
122 | path = JustUiKit;
123 | sourceTree = "";
124 | };
125 | 1F4A5CA795838BC2E7696DD9 /* widget */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 529896531E374C1B00CA01B9 /* JustRelativeLayout.swift */,
129 | 1F4A5551A35FC077DE6B5B2F /* JustLinearLayout.swift */,
130 | 1F4A5242F547BDDE9E85737F /* JustFrameLayout.swift */,
131 | );
132 | path = widget;
133 | sourceTree = "";
134 | };
135 | 1F4A5CD8DDD6C55800B38D5A /* params */ = {
136 | isa = PBXGroup;
137 | children = (
138 | 1F4A5AD76626AC9CFB1358EF /* JustLayoutParams.swift */,
139 | );
140 | path = params;
141 | sourceTree = "";
142 | };
143 | 5241B5D31E2F906A00F96976 /* Frameworks */ = {
144 | isa = PBXGroup;
145 | children = (
146 | );
147 | name = Frameworks;
148 | sourceTree = "";
149 | };
150 | /* End PBXGroup section */
151 |
152 | /* Begin PBXHeadersBuildPhase section */
153 | 1F4A5C7CE2B0DAC0AC08E864 /* Headers */ = {
154 | isa = PBXHeadersBuildPhase;
155 | buildActionMask = 2147483647;
156 | files = (
157 | 1F4A571634F8208E3BE1671F /* JustUiKit.h in Headers */,
158 | );
159 | runOnlyForDeploymentPostprocessing = 0;
160 | };
161 | /* End PBXHeadersBuildPhase section */
162 |
163 | /* Begin PBXNativeTarget section */
164 | 1F4A532CDD58114D087EB1A0 /* JustUiKitTests */ = {
165 | isa = PBXNativeTarget;
166 | buildConfigurationList = 1F4A5848BF7D5C2F06C1A7AD /* Build configuration list for PBXNativeTarget "JustUiKitTests" */;
167 | buildPhases = (
168 | 1F4A585DC44E65ADB54C9A3D /* Sources */,
169 | 1F4A551154CCEE13D44F75EF /* Frameworks */,
170 | 1F4A547AEA28315F6480C19C /* Resources */,
171 | );
172 | buildRules = (
173 | );
174 | dependencies = (
175 | 1F4A5DAB2D5F2E6BCEC9787E /* PBXTargetDependency */,
176 | );
177 | name = JustUiKitTests;
178 | productName = JustUiKitTests;
179 | productReference = 529896521E374C0E00CA01B9 /* JustUiKitTests.xctest */;
180 | productType = "com.apple.product-type.bundle.unit-test";
181 | };
182 | 1F4A5E9B5B37635B5E156071 /* JustUiKit */ = {
183 | isa = PBXNativeTarget;
184 | buildConfigurationList = 1F4A5597EED025BF554E4B3A /* Build configuration list for PBXNativeTarget "JustUiKit" */;
185 | buildPhases = (
186 | 1F4A5A2AFF6930AF7DF64C6D /* Sources */,
187 | 1F4A5276196EA8B81244EF6D /* Frameworks */,
188 | 1F4A5C7CE2B0DAC0AC08E864 /* Headers */,
189 | 1F4A5BD68EA21E0D9E3AC6F6 /* Resources */,
190 | );
191 | buildRules = (
192 | );
193 | dependencies = (
194 | );
195 | name = JustUiKit;
196 | productName = JustUiKit;
197 | productType = "com.apple.product-type.framework";
198 | };
199 | /* End PBXNativeTarget section */
200 |
201 | /* Begin PBXProject section */
202 | 1F4A5EE6514429FA6E1E68F6 /* Project object */ = {
203 | isa = PBXProject;
204 | attributes = {
205 | LastSwiftUpdateCheck = 0820;
206 | ORGANIZATIONNAME = "___lfkdsk___";
207 | };
208 | buildConfigurationList = 1F4A5518D6076A2787B201A4 /* Build configuration list for PBXProject "JustUiKit" */;
209 | compatibilityVersion = "Xcode 3.2";
210 | developmentRegion = English;
211 | hasScannedForEncodings = 0;
212 | knownRegions = (
213 | en,
214 | Base,
215 | );
216 | mainGroup = 1F4A54665BF1962B972E84B4;
217 | productRefGroup = 1F4A54665BF1962B972E84B4;
218 | projectDirPath = "";
219 | projectRoot = "";
220 | targets = (
221 | 1F4A5E9B5B37635B5E156071 /* JustUiKit */,
222 | 1F4A532CDD58114D087EB1A0 /* JustUiKitTests */,
223 | );
224 | };
225 | /* End PBXProject section */
226 |
227 | /* Begin PBXResourcesBuildPhase section */
228 | 1F4A547AEA28315F6480C19C /* Resources */ = {
229 | isa = PBXResourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | );
233 | runOnlyForDeploymentPostprocessing = 0;
234 | };
235 | 1F4A5BD68EA21E0D9E3AC6F6 /* Resources */ = {
236 | isa = PBXResourcesBuildPhase;
237 | buildActionMask = 2147483647;
238 | files = (
239 | 1F4A50AB70CA7FAA8452071D /* Info.plist in Resources */,
240 | 1F4A5C1CD4E1B9684E62A2A1 /* .swift-version in Resources */,
241 | 1F4A5BDA99E2B314D8F00C94 /* JustUiKit.podspec in Resources */,
242 | );
243 | runOnlyForDeploymentPostprocessing = 0;
244 | };
245 | /* End PBXResourcesBuildPhase section */
246 |
247 | /* Begin PBXSourcesBuildPhase section */
248 | 1F4A585DC44E65ADB54C9A3D /* Sources */ = {
249 | isa = PBXSourcesBuildPhase;
250 | buildActionMask = 2147483647;
251 | files = (
252 | );
253 | runOnlyForDeploymentPostprocessing = 0;
254 | };
255 | 1F4A5A2AFF6930AF7DF64C6D /* Sources */ = {
256 | isa = PBXSourcesBuildPhase;
257 | buildActionMask = 2147483647;
258 | files = (
259 | 1F4A5D248CDEBE9F7C9D87B3 /* Gravity.swift in Sources */,
260 | 1F4A57E10237CAEE95A4650E /* Orientation.swift in Sources */,
261 | 1F4A5944BBC556272F2CC3A8 /* ColorExtension.swift in Sources */,
262 | 1F4A5478A2C2D99BD50069AC /* JustLinearLayout.swift in Sources */,
263 | 1F4A59E2B441CBC469D1081D /* JustViewGroup.swift in Sources */,
264 | 529896541E374C1B00CA01B9 /* JustRelativeLayout.swift in Sources */,
265 | 1F4A57D0DE7EA6295AB293D2 /* JustViewParent.swift in Sources */,
266 | 1F4A5989D9FC754C62434510 /* JustViewManager.swift in Sources */,
267 | 1F4A52920CBEDAC4E8EBB468 /* JustExtensionView.swift in Sources */,
268 | 1F4A59B149573A55F70F2B95 /* JustLayoutParams.swift in Sources */,
269 | 1F4A50DF28D4F4DB7E48B1F5 /* JustFrameLayout.swift in Sources */,
270 | 1F4A5CC393D38237C20F73B3 /* Queue.swift in Sources */,
271 | 1F4A56BE01BB7181D793C388 /* ReleasePool.swift in Sources */,
272 | );
273 | runOnlyForDeploymentPostprocessing = 0;
274 | };
275 | /* End PBXSourcesBuildPhase section */
276 |
277 | /* Begin PBXTargetDependency section */
278 | 1F4A5DAB2D5F2E6BCEC9787E /* PBXTargetDependency */ = {
279 | isa = PBXTargetDependency;
280 | target = 1F4A5E9B5B37635B5E156071 /* JustUiKit */;
281 | targetProxy = 1F4A520233E995710022CAB9 /* PBXContainerItemProxy */;
282 | };
283 | /* End PBXTargetDependency section */
284 |
285 | /* Begin XCBuildConfiguration section */
286 | 1F4A561058B423F883C8864A /* Debug */ = {
287 | isa = XCBuildConfiguration;
288 | buildSettings = {
289 | INFOPLIST_FILE = JustUiKitTests/Info.plist;
290 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
291 | PRODUCT_BUNDLE_IDENTIFIER = lfkdsk.JustUiKitTests;
292 | PRODUCT_NAME = "$(TARGET_NAME)";
293 | SWIFT_VERSION = 3.0;
294 | };
295 | name = Debug;
296 | };
297 | 1F4A56538A5E892CBABE47CD /* Release */ = {
298 | isa = XCBuildConfiguration;
299 | buildSettings = {
300 | INFOPLIST_FILE = JustUiKitTests/Info.plist;
301 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
302 | PRODUCT_BUNDLE_IDENTIFIER = lfkdsk.JustUiKitTests;
303 | PRODUCT_NAME = "$(TARGET_NAME)";
304 | SWIFT_VERSION = 3.0;
305 | };
306 | name = Release;
307 | };
308 | 1F4A5816D29D78DADD747432 /* Release */ = {
309 | isa = XCBuildConfiguration;
310 | buildSettings = {
311 | ALWAYS_SEARCH_USER_PATHS = NO;
312 | CLANG_ANALYZER_NONNULL = YES;
313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
314 | CLANG_CXX_LIBRARY = "libc++";
315 | CLANG_ENABLE_MODULES = YES;
316 | CLANG_ENABLE_OBJC_ARC = YES;
317 | CLANG_WARN_BOOL_CONVERSION = YES;
318 | CLANG_WARN_CONSTANT_CONVERSION = YES;
319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
320 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
321 | CLANG_WARN_EMPTY_BODY = YES;
322 | CLANG_WARN_ENUM_CONVERSION = YES;
323 | CLANG_WARN_INFINITE_RECURSION = YES;
324 | CLANG_WARN_INT_CONVERSION = YES;
325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
326 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
327 | CLANG_WARN_UNREACHABLE_CODE = YES;
328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
330 | COPY_PHASE_STRIP = NO;
331 | CURRENT_PROJECT_VERSION = 1;
332 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
333 | ENABLE_NS_ASSERTIONS = NO;
334 | ENABLE_STRICT_OBJC_MSGSEND = YES;
335 | GCC_C_LANGUAGE_STANDARD = gnu99;
336 | GCC_NO_COMMON_BLOCKS = YES;
337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
339 | GCC_WARN_UNDECLARED_SELECTOR = YES;
340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
341 | GCC_WARN_UNUSED_FUNCTION = YES;
342 | GCC_WARN_UNUSED_VARIABLE = YES;
343 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
344 | MTL_ENABLE_DEBUG_INFO = NO;
345 | SDKROOT = iphoneos;
346 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
347 | TARGETED_DEVICE_FAMILY = "1,2";
348 | VALIDATE_PRODUCT = YES;
349 | VERSIONING_SYSTEM = "apple-generic";
350 | VERSION_INFO_PREFIX = "";
351 | };
352 | name = Release;
353 | };
354 | 1F4A585421BE7F40D94FA92B /* Debug */ = {
355 | isa = XCBuildConfiguration;
356 | buildSettings = {
357 | CODE_SIGN_IDENTITY = "";
358 | DEFINES_MODULE = YES;
359 | DYLIB_COMPATIBILITY_VERSION = 1;
360 | DYLIB_CURRENT_VERSION = 1;
361 | DYLIB_INSTALL_NAME_BASE = "@rpath";
362 | INFOPLIST_FILE = JustUiKit/Info.plist;
363 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
364 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
365 | PRODUCT_BUNDLE_IDENTIFIER = lfkdsk.JustUiKit;
366 | PRODUCT_NAME = "$(TARGET_NAME)";
367 | SKIP_INSTALL = YES;
368 | SWIFT_VERSION = 3.0;
369 | USER_HEADER_SEARCH_PATHS = "\"${PROJECT_DIR}/JustUiKitTest\"/** \"${PROJECT_DIR}/JustUiKitSample\"/**";
370 | };
371 | name = Debug;
372 | };
373 | 1F4A5A1F0B96416F341B8B1B /* Debug */ = {
374 | isa = XCBuildConfiguration;
375 | buildSettings = {
376 | ALWAYS_SEARCH_USER_PATHS = NO;
377 | CLANG_ANALYZER_NONNULL = YES;
378 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
379 | CLANG_CXX_LIBRARY = "libc++";
380 | CLANG_ENABLE_MODULES = YES;
381 | CLANG_ENABLE_OBJC_ARC = YES;
382 | CLANG_WARN_BOOL_CONVERSION = YES;
383 | CLANG_WARN_CONSTANT_CONVERSION = YES;
384 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
385 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
386 | CLANG_WARN_EMPTY_BODY = YES;
387 | CLANG_WARN_ENUM_CONVERSION = YES;
388 | CLANG_WARN_INFINITE_RECURSION = YES;
389 | CLANG_WARN_INT_CONVERSION = YES;
390 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
391 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
392 | CLANG_WARN_UNREACHABLE_CODE = YES;
393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
395 | COPY_PHASE_STRIP = NO;
396 | CURRENT_PROJECT_VERSION = 1;
397 | DEBUG_INFORMATION_FORMAT = dwarf;
398 | ENABLE_STRICT_OBJC_MSGSEND = YES;
399 | ENABLE_TESTABILITY = YES;
400 | GCC_C_LANGUAGE_STANDARD = gnu99;
401 | GCC_DYNAMIC_NO_PIC = NO;
402 | GCC_NO_COMMON_BLOCKS = YES;
403 | GCC_OPTIMIZATION_LEVEL = 0;
404 | GCC_PREPROCESSOR_DEFINITIONS = (
405 | "DEBUG=1",
406 | "$(inherited)",
407 | );
408 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
409 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
410 | GCC_WARN_UNDECLARED_SELECTOR = YES;
411 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
412 | GCC_WARN_UNUSED_FUNCTION = YES;
413 | GCC_WARN_UNUSED_VARIABLE = YES;
414 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
415 | MTL_ENABLE_DEBUG_INFO = YES;
416 | ONLY_ACTIVE_ARCH = YES;
417 | SDKROOT = iphoneos;
418 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
419 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
420 | TARGETED_DEVICE_FAMILY = "1,2";
421 | VERSIONING_SYSTEM = "apple-generic";
422 | VERSION_INFO_PREFIX = "";
423 | };
424 | name = Debug;
425 | };
426 | 1F4A5AE4FCB2948544206D6F /* Release */ = {
427 | isa = XCBuildConfiguration;
428 | buildSettings = {
429 | CODE_SIGN_IDENTITY = "";
430 | DEFINES_MODULE = YES;
431 | DYLIB_COMPATIBILITY_VERSION = 1;
432 | DYLIB_CURRENT_VERSION = 1;
433 | DYLIB_INSTALL_NAME_BASE = "@rpath";
434 | INFOPLIST_FILE = JustUiKit/Info.plist;
435 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
437 | PRODUCT_BUNDLE_IDENTIFIER = lfkdsk.JustUiKit;
438 | PRODUCT_NAME = "$(TARGET_NAME)";
439 | SKIP_INSTALL = YES;
440 | SWIFT_VERSION = 3.0;
441 | USER_HEADER_SEARCH_PATHS = "\"${PROJECT_DIR}/JustUiKitTest\"/** \"${PROJECT_DIR}/JustUiKitSample\"/**";
442 | };
443 | name = Release;
444 | };
445 | /* End XCBuildConfiguration section */
446 |
447 | /* Begin XCConfigurationList section */
448 | 1F4A5518D6076A2787B201A4 /* Build configuration list for PBXProject "JustUiKit" */ = {
449 | isa = XCConfigurationList;
450 | buildConfigurations = (
451 | 1F4A5A1F0B96416F341B8B1B /* Debug */,
452 | 1F4A5816D29D78DADD747432 /* Release */,
453 | );
454 | defaultConfigurationIsVisible = 0;
455 | defaultConfigurationName = Release;
456 | };
457 | 1F4A5597EED025BF554E4B3A /* Build configuration list for PBXNativeTarget "JustUiKit" */ = {
458 | isa = XCConfigurationList;
459 | buildConfigurations = (
460 | 1F4A585421BE7F40D94FA92B /* Debug */,
461 | 1F4A5AE4FCB2948544206D6F /* Release */,
462 | );
463 | defaultConfigurationIsVisible = 0;
464 | defaultConfigurationName = Release;
465 | };
466 | 1F4A5848BF7D5C2F06C1A7AD /* Build configuration list for PBXNativeTarget "JustUiKitTests" */ = {
467 | isa = XCConfigurationList;
468 | buildConfigurations = (
469 | 1F4A561058B423F883C8864A /* Debug */,
470 | 1F4A56538A5E892CBABE47CD /* Release */,
471 | );
472 | defaultConfigurationIsVisible = 0;
473 | defaultConfigurationName = Release;
474 | };
475 | /* End XCConfigurationList section */
476 | };
477 | rootObject = 1F4A5EE6514429FA6E1E68F6 /* Project object */;
478 | }
479 |
--------------------------------------------------------------------------------
/JustUiKit/widget/JustLinearLayout.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import UIKit
24 |
25 | public class LinearLayoutParams: MarginLayoutParams {
26 | public var weight: CGFloat = 0
27 | public var layoutGravity: Gravity = Gravity.NO_GRAVITY
28 | public var minHeight: CGFloat = 0
29 | public var minWidth: CGFloat = 0
30 | public var maxHeight: CGFloat = CGFloat.greatestFiniteMagnitude
31 | public var maxWidth: CGFloat = CGFloat.greatestFiniteMagnitude
32 |
33 | override public init(width: CGFloat, height: CGFloat) {
34 | super.init(width: width, height: height)
35 | self.layoutGravity = Gravity.NO_GRAVITY
36 | }
37 |
38 | public init(width: CGFloat, height: CGFloat, layoutGravity: Gravity) {
39 | super.init(width: width, height: height)
40 | self.layoutGravity = layoutGravity
41 | }
42 |
43 | public init(linear: LinearLayoutParams) {
44 | super.init(source: linear)
45 | self.weight = linear.weight
46 | self.layoutGravity = linear.layoutGravity
47 | self.minHeight = linear.minHeight
48 | self.maxHeight = linear.maxHeight
49 | self.minWidth = linear.minWidth
50 | self.maxWidth = linear.maxWidth
51 | }
52 |
53 | override public init(source: MarginLayoutParams) {
54 | super.init(source: source)
55 | }
56 |
57 | override public init(_ params: LayoutParams) {
58 | super.init(params)
59 | }
60 |
61 | public static func generateDefaultParams() -> LinearLayoutParams {
62 | return LinearLayoutParams(width: LayoutParams.WRAP_CONTENT,
63 | height: LayoutParams.WRAP_CONTENT)
64 | }
65 | }
66 |
67 | fileprivate struct Rect {
68 | public var width, height, x, y: CGFloat
69 |
70 | public init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
71 | self.x = x
72 | self.y = y
73 | self.width = width
74 | self.height = height
75 | }
76 |
77 | public init(rect: Rect) {
78 | self.x = rect.x
79 | self.y = rect.y
80 | self.width = rect.width
81 | self.height = rect.height
82 | }
83 |
84 | public func toCGRect() -> CGRect {
85 | return CGRect(x: x, y: y, width: width, height: height)
86 | }
87 | }
88 |
89 | fileprivate extension CGRect {
90 | fileprivate func toRect() -> Rect {
91 | return Rect(x: origin.x, y: origin.y, width: width, height: height)
92 | }
93 | }
94 |
95 | private struct BindViewWithRect {
96 | public var view: UIView
97 | public var rect: Rect
98 |
99 | public init(view: UIView, rect: Rect) {
100 | self.view = view
101 | self.rect = rect
102 | }
103 |
104 | public init(bind: BindViewWithRect) {
105 | self.view = bind.view
106 | self.rect = bind.rect
107 | }
108 | }
109 |
110 | open class JustLinearLayout: JustViewGroup {
111 | private var marginFlag: Gravity = Gravity.TOP | Gravity.LEFT
112 |
113 | private var currentChildLayoutTop: CGFloat = 0.0
114 | private var currentChildLayoutLeft: CGFloat = 0.0
115 |
116 | private var childViewSizes: [CGSize] = []
117 |
118 | private var orientation: Orientation = Orientation.Vertical {
119 | didSet {
120 | setNeedsLayout()
121 | }
122 | }
123 |
124 | public init(orientation: Orientation) {
125 | super.init()
126 | self.orientation = orientation
127 | }
128 |
129 | public init(frame groupFrame: CGRect, orientation: Orientation) {
130 | super.init(frame: groupFrame)
131 | self.orientation = orientation
132 | }
133 |
134 | public required init?(coder aDecoder: NSCoder) {
135 | super.init(coder: aDecoder)
136 | }
137 |
138 | override open func sizeThatFits(_ size: CGSize) -> CGSize {
139 | let childSizes: [CGSize]
140 | var childLayoutSize = CGSize.zero
141 |
142 | if orientation == .Horizontal {
143 | var padding: Padding
144 | var index: Int = 0
145 | childSizes = measureHorizontal(size)
146 | for size in childSizes {
147 | padding = subviews[index].uiViewExtension.padding
148 | childLayoutSize.width += size.width + padding.paddingLeft + padding.paddingRight
149 | childLayoutSize.height = max(childLayoutSize.height, size.height + padding.paddingTop + padding.paddingBottom)
150 | index += 1
151 | }
152 | } else {
153 | var padding: Padding
154 | var index: Int = 0
155 | childSizes = measureVertical(size)
156 | for size in childSizes {
157 | padding = subviews[index].uiViewExtension.padding
158 | childLayoutSize.width = max(childLayoutSize.width, size.width + padding.paddingLeft + padding.paddingRight)
159 | childLayoutSize.height += size.height + padding.paddingTop + padding.paddingBottom
160 | index += 1
161 | }
162 | }
163 | return uiViewExtension.padding.getMaxSize(size: childLayoutSize)
164 | }
165 |
166 |
167 | public func measureHorizontal(_ size: CGSize) -> [CGSize] {
168 | let selfSize = uiViewExtension.padding.getMinSize(size: size)
169 |
170 | let height = selfSize.height
171 | let width = selfSize.width
172 |
173 | let maxHeightSize: CGFloat = height
174 | var maxWidthSize: CGFloat = width
175 |
176 | var totalWeight: CGFloat = 0.0
177 |
178 | var childSizes = [CGSize](repeating: CGSize(width: -1, height: -1), count: subviews.count)
179 |
180 | for (index, child) in subviews.enumerated() {
181 | if child.isHidden {
182 | continue
183 | }
184 |
185 | let params: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
186 |
187 | totalWeight += params.weight
188 | var childHeight: CGFloat = 0
189 | var childSize: CGSize = CGSize()
190 |
191 | switch params.height {
192 | case LayoutParams.MATCH_PARENT:
193 | childHeight = maxHeightSize
194 | case LayoutParams.WRAP_CONTENT:
195 | childSize = child.sizeThatFits(
196 | CGSize(width: maxWidthSize,
197 | height: maxHeightSize))
198 |
199 | childHeight = childSize.height
200 | default:
201 | childHeight = params.height
202 | }
203 |
204 | childHeight = max(childHeight, params.minHeight)
205 | childHeight = min(childHeight, params.maxHeight)
206 | childHeight = min(childHeight, maxHeightSize)
207 |
208 | childSizes[index].height = childHeight
209 |
210 | if childSize.height == childHeight {
211 | childSizes[index].width = childSize.width
212 | }
213 |
214 | var childWidth: CGFloat = 0
215 | childSize = CGSize.zero
216 |
217 | switch (params.width) {
218 | case LayoutParams.MATCH_PARENT:
219 | childWidth = maxWidthSize
220 | case LayoutParams.WRAP_CONTENT:
221 | childSize = child.sizeThatFits(
222 | CGSize(width: maxWidthSize,
223 | height: maxHeightSize))
224 |
225 | childWidth = childSize.width
226 | default:
227 | childWidth = params.width
228 | }
229 |
230 | childWidth = max(childWidth, params.minWidth)
231 | childWidth = min(childWidth, params.maxWidth)
232 | childWidth = min(childWidth, maxWidthSize)
233 |
234 | childSizes[index].width = childWidth
235 |
236 | maxWidthSize -= (childWidth)
237 | }
238 |
239 | if totalWeight > 0.0 {
240 | let layoutEx = uiViewExtension.padding
241 | maxWidthSize = width - layoutEx.paddingLeft - layoutEx.paddingRight
242 | for (index, child) in subviews.enumerated() {
243 | if child.isHidden {
244 | continue
245 | }
246 |
247 | let params: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
248 |
249 | if params.weight > 0.0 && maxWidthSize > 0.0 {
250 | let childWidth: CGFloat = params.weight * maxWidthSize / totalWeight
251 | if childWidth > 0.0 {
252 | childSizes[index].width = childWidth
253 | continue
254 | }
255 | } else {
256 | childSizes[index].height = 0
257 | childSizes[index].width = 0
258 | }
259 | }
260 | }
261 |
262 | return childSizes
263 | }
264 |
265 | private func measureVertical(_ size: CGSize) -> [CGSize] {
266 | let selfSize = uiViewExtension.padding.getMinSize(size: size)
267 |
268 | let height = selfSize.height
269 | let width = selfSize.width
270 |
271 | let layoutEx = uiViewExtension.padding
272 |
273 | var maxHeightSize: CGFloat = height
274 | let maxWidthSize: CGFloat = width
275 |
276 | var totalWeight: CGFloat = 0.0
277 |
278 | // all sub view size
279 | var childSizes = [CGSize](repeating: CGSize(width: -1, height: -1), count: subviews.count)
280 |
281 | for (index, child) in subviews.enumerated() {
282 | if (child.isHidden) {
283 | continue
284 | }
285 |
286 | let params: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
287 |
288 | totalWeight += params.weight
289 |
290 | var childWidth: CGFloat = 0
291 | var childSize: CGSize = CGSize()
292 |
293 | switch (params.width) {
294 | case LayoutParams.MATCH_PARENT:
295 | childWidth = maxWidthSize
296 | case LayoutParams.WRAP_CONTENT:
297 | childSize = child.sizeThatFits(
298 | CGSize(width: maxWidthSize,
299 | height: maxHeightSize))
300 |
301 | childWidth = childSize.width
302 | default:
303 | childWidth = params.width
304 | }
305 |
306 | childWidth = max(childWidth, params.minWidth)
307 | childWidth = min(childWidth, params.maxWidth)
308 | childWidth = min(childWidth, maxWidthSize)
309 |
310 | childSizes[index].width = childWidth
311 |
312 | if childSize.width == childWidth {
313 | childSizes[index].height = childSize.height
314 | }
315 |
316 |
317 | // maxWidthSize -= (childWidth + marginWidth)
318 |
319 | ////////////////////////////////////////////
320 | var childHeight: CGFloat = 0
321 | childSize = CGSize()
322 |
323 | switch params.height {
324 | case LayoutParams.MATCH_PARENT:
325 | childHeight = maxHeightSize
326 | case LayoutParams.WRAP_CONTENT:
327 | childSize = child.sizeThatFits(
328 | CGSize(width: maxWidthSize,
329 | height: maxHeightSize))
330 |
331 | childHeight = childSize.height
332 | default:
333 | childHeight = params.height
334 | }
335 |
336 | childHeight = max(childHeight, params.minHeight)
337 | childHeight = min(childHeight, params.maxHeight)
338 | childHeight = min(childHeight, maxHeightSize)
339 |
340 | childSizes[index].height = childHeight
341 |
342 | maxHeightSize -= (childHeight)
343 | }
344 |
345 | if totalWeight > 0.0 {
346 |
347 | maxHeightSize = height - layoutEx.paddingTop - layoutEx.paddingBottom
348 |
349 | for (index, child) in subviews.enumerated() {
350 | if child.isHidden {
351 | continue
352 | }
353 |
354 | let params: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
355 |
356 | if params.weight > 0.0 && maxHeightSize > 0.0 {
357 | let childHeight: CGFloat = params.weight * maxHeightSize / totalWeight
358 | if childHeight > 0.0 {
359 | childSizes[index].height = childHeight
360 | continue
361 | }
362 | } else {
363 | childSizes[index].height = 0
364 | childSizes[index].width = 0
365 | }
366 | }
367 | }
368 |
369 | return childSizes
370 | }
371 |
372 | public func layoutVertical(_ top: CGFloat,
373 | _ left: CGFloat,
374 | _ right: CGFloat,
375 | _ bottom: CGFloat) {
376 | // let height = bottom - top
377 | // let padding = uiViewExtension.padding
378 |
379 | currentChildLayoutTop = top
380 |
381 | var childViewRect: [BindViewWithRect] = []
382 |
383 | for (index, size) in childViewSizes.enumerated() {
384 |
385 | let child = subviews[index]
386 |
387 | if child.isHidden {
388 | continue
389 | }
390 |
391 | let childParams: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
392 | let childWidth = size.width
393 | let childHeight = size.height
394 | var childTop: CGFloat = 0
395 | var childLeft: CGFloat = 0
396 |
397 | // let verticalGravity = childParams.layoutGravity & JustLinearLayout.VERTICAL_GRAVITY_MASK
398 | //
399 | // var specialComFlag = false
400 |
401 | // switch verticalGravity {
402 | // case Gravity.CENTER_VERTICAL.getValue():
403 | // childTop = (height - childHeight) / 2
404 | // childTop += CGFloat(childParams.topMargin - childParams.bottomMargin)
405 | // case Gravity.BOTTOM.getValue():
406 | // specialComFlag = true
407 | // childTop = height - childHeight
408 | // default:
409 | // childTop = currentChildLayoutTop + CGFloat(childParams.topMargin)
410 | // }
411 | childTop = currentChildLayoutTop + CGFloat(childParams.topMargin)
412 |
413 | let horizontalGravity = Gravity.getHorizontalGravity(gravity: childParams.layoutGravity)
414 |
415 | switch horizontalGravity {
416 | case Gravity.CENTER_HORIZONTAL.getValue():
417 | // if verticalGravity == Gravity.CENTER_VERTICAL.getValue()
418 | // || verticalGravity == Gravity.BOTTOM.getValue() {
419 | // specialComFlag = true
420 | // }
421 | childLeft = (right - left - childWidth) / 2 + left
422 | childLeft += (CGFloat(childParams.leftMargin - childParams.rightMargin))
423 | case Gravity.RIGHT.getValue():
424 | // if verticalGravity == Gravity.BOTTOM.getValue() {
425 | // specialComFlag = true
426 | // }
427 | childLeft = right - left - childWidth - CGFloat(childParams.rightMargin);
428 | default:
429 | childLeft = left + CGFloat(childParams.leftMargin)
430 | // if hasParent() && verticalGravity == Gravity.BOTTOM.getValue() {
431 | // childLeft -= left
432 | // }
433 | }
434 |
435 |
436 | if hasParent() {
437 | childTop -= top
438 | childLeft -= left
439 | }
440 |
441 | // if childViewRect.count == 0 {
442 | // childLeft += padding.paddingLeft
443 | // childTop += padding.paddingTop
444 | // }
445 |
446 | child.frame = CGRect(
447 | x: childLeft,
448 | y: childTop,
449 | width: childWidth,
450 | height: childHeight)
451 | child.layoutSubviews()
452 |
453 | childViewRect.append(BindViewWithRect(
454 | view: child,
455 | rect: child.frame.toRect()))
456 |
457 | // if !specialComFlag {
458 | currentChildLayoutTop += size.height
459 | // }
460 | }
461 |
462 | var localBinders: [BindViewWithRect] = childViewRect.sorted { (first, second) -> Bool in
463 | return first.rect.y < second.rect.y
464 | }
465 |
466 | var index: Int = 0
467 |
468 | for item in localBinders {
469 |
470 | if index == localBinders.endIndex - 1 {
471 | break
472 | }
473 |
474 | var nextView = localBinders[index + 1]
475 | let itemBottom = item.rect.y + item.rect.height
476 | let nextTop = nextView.rect.y
477 |
478 | if nextTop <= itemBottom {
479 | let oldFrame = nextView.rect
480 |
481 | nextView.rect = Rect(
482 | x: oldFrame.x,
483 | y: itemBottom,
484 | width: oldFrame.width,
485 | height: oldFrame.height
486 | )
487 | nextView.view.frame = nextView.rect.toCGRect()
488 | nextView.view.layoutSubviews()
489 | }
490 | index += 1
491 | }
492 | }
493 |
494 |
495 | public func layoutHorizontal(_ top: CGFloat,
496 | _ left: CGFloat,
497 | _ right: CGFloat,
498 | _ bottom: CGFloat) {
499 | // let width = right - left
500 | let height = bottom - top
501 | // let padding = uiViewExtension.padding
502 |
503 | currentChildLayoutLeft = left
504 |
505 | var childViewRect: [BindViewWithRect] = []
506 |
507 | for (index, size) in childViewSizes.enumerated() {
508 |
509 | let child = subviews[index]
510 |
511 | if child.isHidden {
512 | continue
513 | }
514 |
515 | let childParams: LinearLayoutParams = child.uiViewExtension.layoutParams as! LinearLayoutParams
516 | let childWidth = size.width
517 | let childHeight = size.height
518 | var childTop: CGFloat = 0
519 | var childLeft: CGFloat = 0
520 |
521 | // let horizontalGravity = childParams.layoutGravity & JustLinearLayout.HORIZONTAL_GRAVITY_MASK
522 | //
523 | // var specialComFlag = false
524 | //
525 | // switch horizontalGravity {
526 | // case Gravity.RIGHT.getValue():
527 | // childLeft = width - childWidth - CGFloat(childParams.rightMargin);
528 | // case Gravity.CENTER_HORIZONTAL.getValue():
529 | // childLeft = (right - left - childWidth) / 2
530 | // childLeft += (CGFloat(childParams.leftMargin - childParams.rightMargin))
531 | // default:
532 | // childLeft = currentChildLayoutLeft + CGFloat(childParams.leftMargin)
533 | // }
534 |
535 | childLeft = currentChildLayoutLeft + CGFloat(childParams.leftMargin)
536 |
537 | let verticalGravity = Gravity.getVerticalGravity(gravity: childParams.layoutGravity)
538 |
539 | switch verticalGravity {
540 | case Gravity.CENTER_VERTICAL.getValue():
541 | childTop = (height - childHeight) / 2 + top
542 | childTop += CGFloat(childParams.topMargin - childParams.bottomMargin)
543 | case Gravity.BOTTOM.getValue():
544 | childTop = bottom - childHeight
545 | default:
546 | childTop = top + CGFloat(childParams.topMargin)
547 | }
548 |
549 | if hasParent() {
550 | childTop -= top
551 | childLeft -= left
552 | }
553 | //
554 | // if childViewRect.count == 0 {
555 | // childLeft += padding.paddingLeft
556 | // childTop += padding.paddingTop
557 | // }
558 |
559 | child.frame = CGRect(
560 | x: childLeft,
561 | y: childTop,
562 | width: childWidth,
563 | height: childHeight)
564 | child.layoutSubviews()
565 |
566 | // if !specialComFlag {
567 | currentChildLayoutLeft += size.width
568 | // }
569 |
570 | childViewRect.append(BindViewWithRect(
571 | view: child,
572 | rect: child.frame.toRect()))
573 | }
574 |
575 | var localBinders: [BindViewWithRect] = childViewRect.sorted { (first, second) -> Bool in
576 | return first.rect.x < second.rect.x
577 | }
578 |
579 | var index: Int = 0
580 |
581 | for item in localBinders {
582 |
583 | if index == localBinders.endIndex - 1 {
584 | break
585 | }
586 |
587 | var nextView = localBinders[index + 1]
588 | let itemRight = item.rect.x + item.rect.width
589 | let nextLeft = nextView.rect.x
590 |
591 | if nextLeft <= itemRight {
592 | let oldFrame = nextView.rect
593 |
594 | nextView.rect = Rect(
595 | x: itemRight,
596 | y: oldFrame.y,
597 | width: oldFrame.width,
598 | height: oldFrame.height
599 | )
600 | nextView.view.frame = nextView.rect.toCGRect()
601 | nextView.view.layoutSubviews()
602 | }
603 | index += 1
604 | }
605 | }
606 |
607 | override public func onLayout(_ changed: Bool,
608 | _ top: CGFloat,
609 | _ left: CGFloat,
610 | _ right: CGFloat,
611 | _ bottom: CGFloat) {
612 | super.onLayout(changed, top, left, right, bottom)
613 | let padding = uiViewExtension.padding
614 |
615 | let pTop = top + padding.paddingTop,
616 | pLeft = left + padding.paddingLeft,
617 | pRight = right - padding.paddingRight,
618 | pBottom = bottom - padding.paddingBottom
619 |
620 | if orientation == Orientation.Horizontal {
621 | layoutHorizontal(
622 | pTop, pLeft, pRight, pBottom)
623 | } else {
624 | layoutVertical(
625 | pTop, pLeft, pRight, pBottom)
626 | }
627 | }
628 |
629 | override public func onMeasure(_ size: CGSize) {
630 | super.onMeasure(size)
631 |
632 | if orientation == Orientation.Horizontal {
633 | childViewSizes = measureHorizontal(size)
634 | } else {
635 | childViewSizes = measureVertical(size)
636 | }
637 | }
638 |
639 | public func addView(view: UIView, params: LinearLayoutParams = LinearLayoutParams.generateDefaultParams()) {
640 | view.uiViewExtension.layoutParams = params
641 |
642 | if view.superview != nil {
643 | return
644 | }
645 |
646 | if view is JustViewGroup {
647 | (view as! JustViewGroup).setParent(viewGroup: self)
648 | }
649 |
650 | addSubview(view)
651 | params.bindWith(view: view)
652 | }
653 |
654 | override public func addView(view: UIView) {
655 | super.addView(view: view)
656 | self.addView(view: view, params: LinearLayoutParams.generateDefaultParams())
657 | }
658 |
659 | }
660 |
--------------------------------------------------------------------------------
/JustUiKit/widget/JustRelativeLayout.swift:
--------------------------------------------------------------------------------
1 | /// MIT License
2 | ///
3 | /// Copyright (c) 2017 JustWe
4 | ///
5 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
6 | /// of this software and associated documentation files (the "Software"), to deal
7 | /// in the Software without restriction, including without limitation the rights
8 | /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | /// copies of the Software, and to permit persons to whom the Software is
10 | /// furnished to do so, subject to the following conditions:
11 | ///
12 | /// The above copyright notice and this permission notice shall be included in all
13 | /// copies or substantial portions of the Software.
14 | ///
15 | /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | /// SOFTWARE.
22 |
23 | import UIKit
24 | import Foundation
25 |
26 | public enum RelativeRule: Int {
27 | case NONE_RULE = -1
28 | /**
29 | * Rule that aligns a child's right edge with another child's left edge.
30 | */
31 | case LEFT_OF = 0;
32 | /**
33 | * Rule that aligns a child's left edge with another child's right edge.
34 | */
35 | case RIGHT_OF = 1;
36 | /**
37 | * Rule that aligns a child's bottom edge with another child's top edge.
38 | */
39 | case ABOVE = 2;
40 | /**
41 | * Rule that aligns a child's top edge with another child's bottom edge.
42 | */
43 | case BELOW = 3;
44 |
45 | /**
46 | * Rule that aligns a child's baseline with another child's baseline.
47 | */
48 | case ALIGN_BASELINE = 4;
49 | /**
50 | * Rule that aligns a child's left edge with another child's left edge.
51 | */
52 | case ALIGN_LEFT = 5;
53 | /**
54 | * Rule that aligns a child's top edge with another child's top edge.
55 | */
56 | case ALIGN_TOP = 6;
57 | /**
58 | * Rule that aligns a child's right edge with another child's right edge.
59 | */
60 | case ALIGN_RIGHT = 7;
61 | /**
62 | * Rule that aligns a child's bottom edge with another child's bottom edge.
63 | */
64 | case ALIGN_BOTTOM = 8;
65 |
66 | /**
67 | * Rule that aligns the child's left edge with its RelativeLayout
68 | * parent's left edge.
69 | */
70 | case ALIGN_PARENT_LEFT = 9;
71 | /**
72 | * Rule that aligns the child's top edge with its RelativeLayout
73 | * parent's top edge.
74 | */
75 | case ALIGN_PARENT_TOP = 10;
76 | /**
77 | * Rule that aligns the child's right edge with its RelativeLayout
78 | * parent's right edge.
79 | */
80 | case ALIGN_PARENT_RIGHT = 11;
81 | /**
82 | * Rule that aligns the child's bottom edge with its RelativeLayout
83 | * parent's bottom edge.
84 | */
85 | case ALIGN_PARENT_BOTTOM = 12;
86 |
87 | /**
88 | * Rule that centers the child with respect to the bounds of its
89 | * RelativeLayout parent.
90 | */
91 | case CENTER_IN_PARENT = 13;
92 | /**
93 | * Rule that centers the child horizontally with respect to the
94 | * bounds of its RelativeLayout parent.
95 | */
96 | case CENTER_HORIZONTAL = 14;
97 | /**
98 | * Rule that centers the child vertically with respect to the
99 | * bounds of its RelativeLayout parent.
100 | */
101 | case CENTER_VERTICAL = 15;
102 |
103 | fileprivate static let VERB_COUNT = 16;
104 |
105 | fileprivate static let RULES_VERTICAL = [
106 | ABOVE, BELOW, ALIGN_BASELINE, ALIGN_TOP, ALIGN_BOTTOM
107 | ]
108 |
109 | fileprivate static let RULES_HORIZONTAL = [
110 | LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT
111 | ]
112 |
113 | public func getValue() -> Int {
114 | return rawValue
115 | }
116 | }
117 |
118 | fileprivate enum BindType {
119 | case UNBIND
120 | case BIND
121 | }
122 |
123 |
124 | fileprivate struct BindViewWithRule {
125 | var RULE: RelativeRule = .NONE_RULE
126 | var VIEW: UIView?
127 | var TYPE: BindType = .UNBIND
128 |
129 | init(view: UIView, rule: RelativeRule) {
130 | RULE = rule
131 | VIEW = view
132 | TYPE = .BIND
133 | }
134 |
135 | private init() {
136 |
137 | }
138 |
139 | fileprivate static func generateDefaultBind() -> BindViewWithRule {
140 | return BindViewWithRule()
141 | }
142 | }
143 |
144 | public class RelativeLayoutParams: MarginLayoutParams {
145 |
146 | fileprivate var rules: [BindViewWithRule] =
147 | [BindViewWithRule](
148 | repeating: BindViewWithRule.generateDefaultBind(),
149 | count: RelativeRule.VERB_COUNT)
150 |
151 | public var layoutGravity: Gravity = Gravity.NO_GRAVITY
152 |
153 | public static let VALUE_NOT_SET: CGFloat = -1
154 |
155 | public var mLeft: CGFloat = VALUE_NOT_SET,
156 | mTop: CGFloat = VALUE_NOT_SET,
157 | mRight: CGFloat = VALUE_NOT_SET,
158 | mBottom: CGFloat = VALUE_NOT_SET
159 |
160 | public var alignWithParent: Bool = false
161 |
162 | override public init(_ source: LayoutParams) {
163 | super.init(source)
164 | }
165 |
166 | override public init(width: CGFloat, height: CGFloat) {
167 | super.init(width: width, height: height)
168 | }
169 |
170 | fileprivate func getRules() -> [BindViewWithRule] {
171 | return rules
172 | }
173 |
174 | public func addRule(rule: RelativeRule, view: UIView) {
175 | rules[rule.getValue()].VIEW = view
176 | rules[rule.getValue()].RULE = rule
177 | rules[rule.getValue()].TYPE = .BIND
178 | self.setAlignParentValue(rule, true)
179 | }
180 |
181 | public func addRule(rule: RelativeRule) {
182 | rules[rule.getValue()].RULE = rule
183 | rules[rule.getValue()].TYPE = .BIND
184 | self.setAlignParentValue(rule, true)
185 | }
186 |
187 | public func removeRule(rule: RelativeRule) {
188 | rules[rule.getValue()] = BindViewWithRule.generateDefaultBind()
189 | removeAlignParentValue()
190 | }
191 |
192 | private func setAlignParentValue(_ rule: RelativeRule,
193 | _ value: Bool) {
194 | switch rule {
195 | case .ALIGN_PARENT_RIGHT, .ALIGN_PARENT_LEFT, .ALIGN_PARENT_TOP, .ALIGN_PARENT_BOTTOM:
196 | self.alignWithParent = value
197 | default:
198 | break
199 | }
200 | }
201 |
202 | private func removeAlignParentValue() {
203 | var hasParentRule: Bool = false
204 | loop: for item in rules {
205 | switch item.RULE {
206 | case .ALIGN_PARENT_RIGHT, .ALIGN_PARENT_LEFT, .ALIGN_PARENT_TOP, .ALIGN_PARENT_BOTTOM:
207 | hasParentRule = true
208 | break loop
209 | default:
210 | continue
211 | }
212 | }
213 |
214 | self.alignWithParent = hasParentRule
215 | }
216 |
217 | public func alignParentTop() {
218 | addRule(rule: .ALIGN_PARENT_TOP)
219 | }
220 |
221 | public func alignParentLeft() {
222 | addRule(rule: .ALIGN_PARENT_LEFT)
223 | }
224 |
225 | public func alignParentBottom() {
226 | addRule(rule: .ALIGN_BOTTOM)
227 | }
228 |
229 | public func alignParentRight() {
230 | addRule(rule: .ALIGN_PARENT_RIGHT)
231 | }
232 |
233 | public func alignTopTo(top: UIView) {
234 | addRule(rule: .ALIGN_TOP, view: top)
235 | }
236 |
237 | public func alignLeftTo(left: UIView) {
238 | addRule(rule: .ALIGN_LEFT, view: left)
239 | }
240 |
241 | public func alignRightTo(right: UIView) {
242 | addRule(rule: .ALIGN_RIGHT, view: right)
243 | }
244 |
245 | public func alignBottomTo(bottom: UIView) {
246 | addRule(rule: .ALIGN_BOTTOM, view: bottom)
247 | }
248 |
249 | public func rightOf(_ target: UIView) {
250 | addRule(rule: .RIGHT_OF, view: target)
251 | }
252 |
253 | public func leftOf(_ target: UIView) {
254 | addRule(rule: .LEFT_OF, view: target)
255 | }
256 |
257 | public func aboveOf(_ target: UIView) {
258 | addRule(rule: .ABOVE, view: target)
259 | }
260 |
261 | public func bellowOf(_ target: UIView) {
262 | addRule(rule: .BELOW, view: target)
263 | }
264 |
265 | public func centerInParent() {
266 | addRule(rule: .CENTER_IN_PARENT)
267 | layoutGravity = layoutGravity | Gravity.CENTER
268 | }
269 |
270 | public func centerInHorizontal() {
271 | addRule(rule: .CENTER_HORIZONTAL)
272 | layoutGravity = layoutGravity | Gravity.CENTER_VERTICAL
273 | }
274 |
275 | public func centerInVertical() {
276 | addRule(rule: .CENTER_VERTICAL)
277 | layoutGravity = layoutGravity | Gravity.CENTER_HORIZONTAL
278 | }
279 |
280 | public static func generateDefaultParams() -> RelativeLayoutParams {
281 | return RelativeLayoutParams(width: LayoutParams.WRAP_CONTENT,
282 | height: LayoutParams.WRAP_CONTENT)
283 | }
284 | }
285 |
286 | open class JustRelativeLayout: JustViewGroup {
287 |
288 | private var mSortedHorizontalChildren: [UIView] = []
289 |
290 | private var mSortedVerticalChildren: [UIView] = []
291 |
292 | private var mMeasuredView: [CGSize] = []
293 |
294 | private var mDGraph: DependencyGraph = DependencyGraph()
295 |
296 | private var mDirtyFresh = true
297 |
298 | private var layoutSize = CGSize.zero
299 |
300 | override open func sizeThatFits(_ size: CGSize) -> CGSize {
301 | var childLayoutSize: CGSize = CGSize.zero
302 | childLayoutSize = measureChild(size)
303 | return uiViewExtension.padding.getMaxSize(size: childLayoutSize)
304 | }
305 |
306 | override public func onLayout(_ changed: Bool, _ top: CGFloat, _ left: CGFloat, _ right: CGFloat, _ bottom: CGFloat) {
307 | super.onLayout(changed, top, left, right, bottom)
308 |
309 | for (_, child) in subviews.enumerated() {
310 |
311 | if child.isHidden {
312 | continue
313 | }
314 |
315 | let params = child.uiViewExtension.layoutParams as! RelativeLayoutParams
316 |
317 | child.frame = CGRect(
318 | x: params.mLeft,
319 | y: params.mTop,
320 | width: params.width,
321 | height: params.height)
322 | child.layoutSubviews()
323 | }
324 | }
325 |
326 | override public func onMeasure(_ size: CGSize) {
327 | super.onMeasure(size)
328 | layoutSize = measureChild(size)
329 | }
330 |
331 | private func measureChild(_ size: CGSize) -> CGSize {
332 |
333 | let selfSize = uiViewExtension.padding.getMinSize(size: size)
334 |
335 | let padding = uiViewExtension.padding
336 |
337 | let pTop = frame.origin.y + padding.paddingTop,
338 | pLeft = frame.origin.x + padding.paddingLeft,
339 | pRight = pLeft + size.width - padding.paddingRight,
340 | pBottom = pTop + size.height - padding.paddingBottom
341 |
342 | let height = selfSize.height
343 | let width = selfSize.width
344 |
345 | var minTop: CGFloat = 0
346 | var minLeft: CGFloat = 0
347 | var maxRight: CGFloat = 0
348 | var maxBottom: CGFloat = 0
349 |
350 | if mDirtyFresh {
351 | mDirtyFresh = false
352 | sortChildren()
353 | }
354 |
355 | var views: [UIView] = mSortedHorizontalChildren
356 | var count = views.count
357 |
358 | // initial params with first unhidden view
359 | var initFlag: Bool = true
360 |
361 | for index in 0 ..< count {
362 |
363 | let child: UIView = views[index]
364 |
365 | if child.isHidden {
366 | continue
367 | }
368 |
369 | let params: RelativeLayoutParams = child.getLayoutParams() as! RelativeLayoutParams
370 | var rules: [BindViewWithRule] = params.getRules()
371 |
372 | applyHorizontalSizeRules(params: params, width: width, rules: &rules)
373 | measureChildHorizontal(view: child, width: width, height: height)
374 | positionHorizontalChildViews(child: child, left: pLeft, right: pRight)
375 |
376 | if initFlag {
377 | initFlag = false
378 | minTop = params.mTop
379 | minLeft = params.mLeft
380 | maxBottom = params.mBottom
381 | maxRight = params.mRight
382 | }
383 |
384 | minTop = min(minTop, params.mTop)
385 | minLeft = min(minLeft, params.mLeft)
386 | maxBottom = max(maxBottom, params.mBottom)
387 | maxRight = max(maxBottom, params.mRight)
388 | }
389 |
390 | views = mSortedVerticalChildren
391 | count = views.count
392 |
393 | for index in 0 ..< count {
394 | let child: UIView = views[index]
395 |
396 | if child.isHidden {
397 | continue
398 | }
399 |
400 | let params: RelativeLayoutParams = child.getLayoutParams() as! RelativeLayoutParams
401 | var rules: [BindViewWithRule] = params.getRules()
402 |
403 | applyVerticalSizeRules(params: params, height: height, rules: &rules)
404 | measureChildVertical(view: child, width: width, height: height)
405 | positionVerticalChildViews(child: child, top: pTop, bottom: pBottom)
406 |
407 | minTop = min(minTop, params.mTop)
408 | minLeft = min(minLeft, params.mLeft)
409 | maxBottom = max(maxBottom, params.mBottom)
410 | maxRight = max(maxRight, params.mRight)
411 | }
412 |
413 | return CGSize(width: maxRight - minLeft, height: maxBottom - minTop)
414 | }
415 |
416 | private func applyVerticalSizeRules(params childParams: RelativeLayoutParams, height: CGFloat,
417 | rules: inout [BindViewWithRule]) {
418 | func hasBindView(rule: RelativeRule) -> Bool {
419 | let ruleValue: BindViewWithRule = rules[rule.getValue()]
420 | return ruleValue.VIEW != nil && ruleValue.TYPE == BindType.BIND
421 | }
422 |
423 | var anchorParams: RelativeLayoutParams?
424 |
425 | childParams.mTop = RelativeLayoutParams.VALUE_NOT_SET
426 | childParams.mBottom = RelativeLayoutParams.VALUE_NOT_SET
427 |
428 | anchorParams = getRelatedViewParams(rules: &rules, relation: .ABOVE)
429 |
430 | if anchorParams != nil {
431 | childParams.mBottom = anchorParams!.mTop - CGFloat(anchorParams!.topMargin +
432 | childParams.bottomMargin)
433 | } else if childParams.alignWithParent && hasBindView(rule: .ABOVE) {
434 | if (height >= 0) {
435 | childParams.mBottom = height - CGFloat(childParams.bottomMargin)
436 | }
437 | }
438 |
439 | anchorParams = getRelatedViewParams(rules: &rules, relation: .BELOW)
440 |
441 | if anchorParams != nil {
442 | childParams.mTop = anchorParams!.mBottom + CGFloat(anchorParams!.bottomMargin +
443 | childParams.topMargin);
444 | } else if childParams.alignWithParent && hasBindView(rule: .BELOW) {
445 | childParams.mTop = CGFloat(childParams.topMargin)
446 | }
447 |
448 | anchorParams = getRelatedViewParams(rules: &rules, relation: .ALIGN_TOP)
449 |
450 | if anchorParams != nil {
451 | childParams.mTop = anchorParams!.mTop + CGFloat(childParams.topMargin)
452 | } else if childParams.alignWithParent && hasBindView(rule: .ALIGN_TOP) {
453 | childParams.mTop = CGFloat(childParams.topMargin)
454 | }
455 |
456 | anchorParams = getRelatedViewParams(rules: &rules, relation: .ALIGN_BOTTOM)
457 |
458 | if anchorParams != nil {
459 | childParams.mBottom = anchorParams!.mBottom - CGFloat(childParams.bottomMargin)
460 | } else if childParams.alignWithParent && hasBindView(rule: .ALIGN_BOTTOM) {
461 | if (height >= 0) {
462 | childParams.mBottom = height - CGFloat(childParams.bottomMargin)
463 | }
464 | }
465 |
466 | if hasBindView(rule: .ALIGN_PARENT_TOP) {
467 | childParams.mTop = CGFloat(childParams.topMargin)
468 | }
469 |
470 | if hasBindView(rule: .ALIGN_PARENT_BOTTOM) {
471 | if (height >= 0) {
472 | childParams.mBottom = height - CGFloat(childParams.bottomMargin)
473 | }
474 | }
475 | }
476 |
477 | private func measureChildVertical(view: UIView,
478 | width: CGFloat,
479 | height: CGFloat) {
480 | var childWidth: CGFloat = 0
481 | var childSize: CGSize = CGSize()
482 | let params: RelativeLayoutParams = view.uiViewExtension.layoutParams as! RelativeLayoutParams
483 |
484 | switch (params.width) {
485 | case LayoutParams.MATCH_PARENT:
486 | childWidth = width
487 | case LayoutParams.WRAP_CONTENT:
488 | childSize = view.sizeThatFits(
489 | CGSize(width: width,
490 | height: height))
491 |
492 | childWidth = childSize.width
493 | default:
494 | childWidth = params.width
495 | }
496 |
497 | childWidth = min(childWidth, width)
498 |
499 | params.width = childWidth
500 | }
501 |
502 | private func measureChildHorizontal(view: UIView,
503 | width: CGFloat,
504 | height: CGFloat) {
505 | let params: RelativeLayoutParams = view.uiViewExtension.layoutParams as! RelativeLayoutParams
506 |
507 | var childHeight: CGFloat = 0
508 | var childSize: CGSize = CGSize()
509 |
510 | switch params.height {
511 | case LayoutParams.MATCH_PARENT:
512 | childHeight = width
513 | case LayoutParams.WRAP_CONTENT:
514 | childSize = view.sizeThatFits(
515 | CGSize(width: width,
516 | height: height))
517 | childHeight = childSize.height
518 | default:
519 | childHeight = params.height
520 | }
521 |
522 | childHeight = min(childHeight, height)
523 | params.height = childHeight
524 |
525 | if childSize.height == childHeight {
526 | params.width = childSize.width
527 | }
528 | }
529 |
530 | public func positionVerticalChildViews(child: UIView,
531 | top: CGFloat,
532 | bottom: CGFloat) {
533 |
534 | let childParams: RelativeLayoutParams = child.uiViewExtension.layoutParams as! RelativeLayoutParams
535 |
536 | if childParams.mTop == RelativeLayoutParams.VALUE_NOT_SET && childParams.mBottom != RelativeLayoutParams.VALUE_NOT_SET {
537 | // set mLeft
538 | childParams.mTop = childParams.mBottom - childParams.height
539 | } else if childParams.mTop != RelativeLayoutParams.VALUE_NOT_SET && childParams.mBottom == RelativeLayoutParams.VALUE_NOT_SET {
540 | childParams.mBottom = childParams.mTop + childParams.height
541 | } else if childParams.mTop == RelativeLayoutParams.VALUE_NOT_SET && childParams.mBottom == RelativeLayoutParams.VALUE_NOT_SET {
542 | let verticalGravity = Gravity.getVerticalGravity(gravity: childParams.layoutGravity)
543 | let childHeight = childParams.height
544 | switch verticalGravity {
545 | case Gravity.CENTER_VERTICAL.getValue():
546 | childParams.mTop = (bottom - top - childHeight) / 2
547 | childParams.mTop += CGFloat(childParams.topMargin - childParams.bottomMargin)
548 | case Gravity.BOTTOM.getValue():
549 | childParams.mTop = bottom - top - childHeight
550 | default:
551 | childParams.mTop = top + CGFloat(childParams.topMargin)
552 | }
553 | childParams.mBottom = childParams.mTop + childParams.height
554 | }
555 | }
556 |
557 | public func positionHorizontalChildViews(child: UIView,
558 | left: CGFloat,
559 | right: CGFloat) {
560 |
561 | let childParams: RelativeLayoutParams = child.uiViewExtension.layoutParams as! RelativeLayoutParams
562 | let childWidth = childParams.width
563 |
564 | if childParams.mLeft == RelativeLayoutParams.VALUE_NOT_SET && childParams.mRight != RelativeLayoutParams.VALUE_NOT_SET {
565 | // set mLeft
566 | childParams.mLeft = childParams.mRight - childParams.width
567 | } else if childParams.mLeft != RelativeLayoutParams.VALUE_NOT_SET && childParams.mRight == RelativeLayoutParams.VALUE_NOT_SET {
568 | childParams.mRight = childParams.mLeft + childParams.height
569 | } else if childParams.mLeft == RelativeLayoutParams.VALUE_NOT_SET && childParams.mRight == RelativeLayoutParams.VALUE_NOT_SET {
570 | let horizontalGravity = Gravity.getHorizontalGravity(gravity: childParams.layoutGravity)
571 | switch horizontalGravity {
572 | case Gravity.CENTER_HORIZONTAL.getValue():
573 | childParams.mLeft = (right - left - childWidth) / 2 + left
574 | childParams.mLeft += (CGFloat(childParams.leftMargin - childParams.rightMargin))
575 | case Gravity.RIGHT.getValue():
576 | childParams.mLeft = right - left - childWidth - CGFloat(childParams.rightMargin)
577 | default:
578 | childParams.mLeft = left + CGFloat(childParams.leftMargin)
579 | }
580 | childParams.mRight = childParams.mLeft + childParams.width
581 | }
582 | }
583 |
584 | ///
585 | /// horizontal rules
586 | ///
587 | private func applyHorizontalSizeRules(params childParams: RelativeLayoutParams, width: CGFloat,
588 | rules: inout [BindViewWithRule]) {
589 |
590 | func hasBindView(rule: RelativeRule) -> Bool {
591 | let ruleValue: BindViewWithRule = rules[rule.getValue()]
592 | return ruleValue.VIEW != nil && ruleValue.TYPE == BindType.BIND
593 | }
594 |
595 | var anchorParams: RelativeLayoutParams?
596 |
597 | // min
598 | childParams.mLeft = RelativeLayoutParams.VALUE_NOT_SET
599 | childParams.mRight = RelativeLayoutParams.VALUE_NOT_SET
600 |
601 | // get the view left of current View
602 | anchorParams = getRelatedViewParams(rules: &rules, relation: .LEFT_OF)
603 |
604 | if anchorParams != nil {
605 | childParams.mRight = anchorParams!.mLeft
606 | - CGFloat(anchorParams!.leftMargin + anchorParams!.rightMargin)
607 | } else if childParams.alignWithParent && hasBindView(rule: .LEFT_OF) {
608 | if width >= 0 {
609 | childParams.mRight = width - CGFloat(childParams.rightMargin)
610 | }
611 | }
612 |
613 | anchorParams = getRelatedViewParams(rules: &rules, relation: .RIGHT_OF)
614 |
615 | if anchorParams != nil {
616 | childParams.mLeft = anchorParams!.mRight + CGFloat(anchorParams!.leftMargin + anchorParams!.rightMargin)
617 | } else if childParams.alignWithParent && hasBindView(rule: .RIGHT_OF) {
618 | childParams.mLeft = CGFloat(childParams.leftMargin)
619 | }
620 |
621 | anchorParams = getRelatedViewParams(rules: &rules, relation: .ALIGN_LEFT)
622 | if anchorParams != nil {
623 | childParams.mLeft = anchorParams!.mLeft + CGFloat(childParams.leftMargin)
624 | } else if childParams.alignWithParent && hasBindView(rule: .ALIGN_LEFT) {
625 | childParams.mLeft = CGFloat(childParams.leftMargin)
626 | }
627 |
628 | anchorParams = getRelatedViewParams(rules: &rules, relation: .ALIGN_RIGHT);
629 | if (anchorParams != nil) {
630 | childParams.mRight = anchorParams!.mRight - CGFloat(childParams.rightMargin)
631 | } else if childParams.alignWithParent && hasBindView(rule: .ALIGN_RIGHT) {
632 | if (width >= 0) {
633 | childParams.mRight = width - CGFloat(childParams.rightMargin)
634 | }
635 | }
636 |
637 | if hasBindView(rule: .ALIGN_PARENT_LEFT) {
638 | childParams.mLeft = CGFloat(childParams.leftMargin)
639 | }
640 |
641 | if hasBindView(rule: .ALIGN_PARENT_RIGHT) {
642 | if (width >= 0) {
643 | childParams.mRight = width - CGFloat(childParams.rightMargin)
644 | }
645 | }
646 | }
647 |
648 |
649 | private func getRelatedViewParams(rules: inout [BindViewWithRule], relation: RelativeRule) ->
650 | RelativeLayoutParams? {
651 | let view: UIView? = getRelatedView(rules: rules, relation: relation)
652 |
653 | if view != nil {
654 | let params: RelativeLayoutParams = view!.getLayoutParams() as! RelativeLayoutParams
655 | return params
656 | }
657 |
658 | return nil
659 | }
660 |
661 | private func getRelatedView(rules: [BindViewWithRule], relation: RelativeRule) -> UIView? {
662 | let view = rules[relation.getValue()].VIEW
663 |
664 | if view == nil {
665 | return view
666 | }
667 |
668 | let id = view!.getViewId()
669 |
670 | if id.viewId != 0 {
671 | var node: Node? = mDGraph.mKeyNodes.object(forKey: id)
672 |
673 | if node == nil {
674 | return nil
675 | }
676 |
677 | var view: UIView = (node?.view)!
678 |
679 | while view.isHidden {
680 | let l_rules: [BindViewWithRule] = (view.getLayoutParams() as! RelativeLayoutParams).getRules()
681 | node = mDGraph.mKeyNodes.object(forKey: l_rules[relation.getValue()].VIEW?.getViewId())
682 | if node == nil {
683 | return nil
684 | }
685 | view = (node?.view)!
686 | }
687 |
688 | return view
689 | }
690 |
691 | return nil
692 | }
693 |
694 | private func sortChildren() {
695 | let graph = mDGraph
696 |
697 | for (_, child) in subviews.enumerated() {
698 | graph.add(view: child)
699 | }
700 |
701 | mSortedHorizontalChildren = graph.getSortedViews(rules: RelativeRule.RULES_HORIZONTAL)
702 |
703 | mSortedVerticalChildren = graph.getSortedViews(rules: RelativeRule.RULES_VERTICAL)
704 | }
705 |
706 | fileprivate class Node {
707 | var view: UIView!
708 |
709 | var dependents: NSMapTable = NSMapTable()
710 |
711 | var dependencies: NSMapTable = NSMapTable()
712 |
713 | static var mPool: ReleasePool = ReleasePool()
714 |
715 | init(view: UIView) {
716 | self.view = view
717 | }
718 |
719 | init() {
720 | // none init
721 | }
722 |
723 | static func acquire(view: UIView) -> Node {
724 | var node: Node? = mPool.acquire()
725 | if node == nil {
726 | node = Node(view: view)
727 | } else {
728 | node!.view = view
729 | }
730 | return node!
731 | }
732 |
733 | public func release() {
734 | self.view = nil
735 | dependents.removeAllObjects()
736 | dependencies.removeAllObjects()
737 | }
738 |
739 | public static func ==(_ a: Node, _ b: Node) -> Bool {
740 | if (a.view?.getViewId())! == (b.view?.getViewId())! {
741 | return true
742 | }
743 | return false
744 | }
745 | }
746 |
747 | fileprivate class DependencyGraph {
748 |
749 | public var mNodes: Array = Array()
750 |
751 | public var mKeyNodes: NSMapTable = NSMapTable()
752 |
753 | public var mRoots: Queue = Queue()
754 |
755 | public func clear() {
756 | var nodes = mNodes
757 | for item in nodes {
758 | item.release()
759 | }
760 | nodes.removeAll()
761 | mKeyNodes.removeAllObjects()
762 | mRoots.clear()
763 | }
764 |
765 | public func add(view: UIView) {
766 | let viewId = view.getViewId()
767 | let node = Node.acquire(view: view)
768 |
769 | if viewId.viewId != -1 {
770 | mKeyNodes.setObject(node, forKey: viewId)
771 | }
772 |
773 | mNodes.append(node)
774 | }
775 |
776 | public func getSortedViews(rules: [RelativeRule]) -> [UIView] {
777 | var roots: Queue = findRoots(rulesFilter: rules)
778 | var sorted: [UIView] = []
779 |
780 | var node: Node? = roots.dequeue()
781 |
782 | while node != nil {
783 | let view: UIView = node!.view!
784 | let key: InnerInteger = view.getViewId()
785 | sorted.append(view)
786 | let dependents: NSMapTable = node!.dependents
787 | for dependent in dependents.keyEnumerator() {
788 | let node = dependent as! Node
789 | let dependencies = node.dependencies
790 | dependencies.removeObject(forKey: key)
791 | if dependencies.count == 0 {
792 | roots.enqueue(node)
793 | }
794 | }
795 |
796 | // update node
797 | node = roots.dequeue()
798 | }
799 |
800 | return sorted
801 | }
802 |
803 | public func findRoots(rulesFilter: [RelativeRule]) -> Queue {
804 | let keyNodes = mKeyNodes
805 | let nodes = mNodes
806 |
807 | // Find roots can be invoked several times, so make sure to clear
808 | // all dependents and dependencies before running the algorithm
809 | for item in nodes {
810 | item.dependents.removeAllObjects()
811 | item.dependencies.removeAllObjects()
812 | }
813 |
814 | // Builds up the dependents and dependencies for each node of the graph
815 | for node: Node in nodes {
816 | let layoutParams = node.view!.uiViewExtension.layoutParams as! RelativeLayoutParams
817 |
818 | let rules = layoutParams.rules
819 |
820 | let ruleCount = rulesFilter.count
821 |
822 | for index in 0 ..< ruleCount {
823 | let rule: BindViewWithRule = rules[rulesFilter[index].getValue()]
824 |
825 | if rule.RULE.getValue() >= 0 {
826 | let dependency = keyNodes.object(forKey: rule.VIEW?.getViewId())
827 |
828 | if dependency == nil || dependency! == node {
829 | continue
830 | }
831 |
832 | dependency?.dependents.setObject(self, forKey: node)
833 | node.dependencies.setObject(dependency, forKey: rule.VIEW?.getViewId())
834 | }
835 | }
836 | }
837 |
838 | var roots: Queue = mRoots
839 | roots.clear()
840 |
841 | for node: Node in nodes {
842 | if node.dependencies.count == 0 {
843 | roots.enqueue(node)
844 | }
845 | }
846 |
847 | return roots
848 | }
849 | }
850 |
851 | public func addView(view: UIView, params: RelativeLayoutParams = RelativeLayoutParams.generateDefaultParams()) {
852 | view.uiViewExtension.layoutParams = params
853 |
854 | if view.superview != nil {
855 | return
856 | }
857 |
858 | if view is JustViewGroup {
859 | (view as! JustViewGroup).setParent(viewGroup: self)
860 | }
861 |
862 | addSubview(view)
863 |
864 | // bind view with params
865 | view.setViewId(id: UIView.generateViewId())
866 | params.bindWith(view: view)
867 | }
868 |
869 | override public func addView(view: UIView) {
870 | super.addView(view: view)
871 | self.addView(view: view, params: RelativeLayoutParams.generateDefaultParams())
872 | }
873 | }
874 |
--------------------------------------------------------------------------------