├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── stale.yml
├── .gitignore
├── .travis.yml
├── Example
├── AppDelegate.swift
├── Assets.xcassets
│ ├── 1-selected.imageset
│ │ ├── 1-selected.png
│ │ ├── 1-selected@2x.png
│ │ └── Contents.json
│ ├── 1.imageset
│ │ ├── 1.png
│ │ ├── 1@2x.png
│ │ └── Contents.json
│ ├── 2-selected.imageset
│ │ ├── 2-selected.png
│ │ ├── 2-selected@2x.png
│ │ └── Contents.json
│ ├── 2.imageset
│ │ ├── 2.png
│ │ ├── 2@2x.png
│ │ └── Contents.json
│ ├── 3-selected.imageset
│ │ ├── 3-selected.png
│ │ ├── 3-selected@2x.png
│ │ └── Contents.json
│ ├── 3.imageset
│ │ ├── 3.png
│ │ ├── 3@2x.png
│ │ └── Contents.json
│ ├── 4-selected.imageset
│ │ ├── 4-selected.png
│ │ ├── 4-selected@2x.png
│ │ └── Contents.json
│ ├── 4.imageset
│ │ ├── 4.png
│ │ ├── 4@2x.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── earthquakes.imageset
│ │ ├── Contents.json
│ │ ├── eathquakes.png
│ │ ├── eathquakes@2x.png
│ │ └── eathquakes@3x.png
│ ├── eruption.imageset
│ │ ├── Contents.json
│ │ ├── eruption.png
│ │ ├── eruption@2x.png
│ │ └── eruption@3x.png
│ ├── floods.imageset
│ │ ├── Contents.json
│ │ ├── floods.png
│ │ ├── floods@2x.png
│ │ └── floods@3x.png
│ ├── heat.imageset
│ │ ├── Contents.json
│ │ ├── heat.png
│ │ ├── heat@2x.png
│ │ └── heat@3x.png
│ ├── tornado.imageset
│ │ ├── Contents.json
│ │ ├── tornado.png
│ │ ├── tornado@2x.png
│ │ └── tornado@3x.png
│ └── wildfires.imageset
│ │ ├── Contents.json
│ │ ├── wildfires.png
│ │ ├── wildfires@2x.png
│ │ └── wildfires@3x.png
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── CustomViewController.swift
├── HMSegmentedControlViewController.swift
├── Info.plist
├── SegmentioViewController.swift
└── TopBarViewController.swift
├── LICENSE
├── MXSegmentedControl.podspec
├── MXSegmentedControl.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── MXSegmentedControl.xcscheme
├── MXSegmentedControl
├── Info.plist
├── MXIndicator.swift
├── MXSegment.swift
├── MXSegmentedControl.h
└── MXSegmentedControl.swift
├── Package.swift
├── README.md
└── screencast.gif
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | NOTE: ISSUES ARE NOT FOR CODE HELP - Ask for Help at https://stackoverflow.com
9 |
10 | Your issue may already be reported!
11 | Please search on the [issue tracker](../) before creating one.
12 |
13 | #### Issue Description
14 | * When Issue Happens
15 | * Steps To Reproduce
16 |
17 | #### Environment Information
18 | * Lib Version
19 | * OS Version
20 |
21 | #### Your Code
22 |
23 | ```
24 | If relevant, paste all of your challenge code in here
25 | ```
26 |
27 | #### Screenshot
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Description
4 |
5 |
6 | ## Motivation and Context
7 |
8 |
9 |
10 | ## How Has This Been Tested?
11 |
12 |
13 |
14 |
15 | ## Screenshots (if appropriate):
16 |
17 | ## Types of changes
18 |
19 | - [ ] Bug fix (non-breaking change which fixes an issue)
20 | - [ ] New feature (non-breaking change which adds functionality)
21 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
22 |
23 | ## Checklist:
24 |
25 |
26 | - [ ] My code follows the code style of this project.
27 | - [ ] My change requires a change to the documentation.
28 | - [ ] I have updated the documentation accordingly.
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-stale - https://github.com/probot/stale
2 |
3 | # Number of days of inactivity before an Issue or Pull Request becomes stale
4 | daysUntilStale: 60
5 |
6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
8 | daysUntilClose: 7
9 |
10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
11 | onlyLabels: []
12 |
13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
14 | exemptLabels:
15 | - bug
16 | - help wanted
17 | - enhancement
18 | - need review
19 |
20 | # Label to use when marking as stale
21 | staleLabel: stale
22 |
23 | # Comment to post when marking as stale. Set to `false` to disable
24 | markComment: >
25 | This issue has been automatically marked as stale because it has not had
26 | recent activity. It will be closed if no further activity occurs. Thank you
27 | for your contributions.
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | xcuserdata
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode11.2
3 | env:
4 | global:
5 | - FRAMEWORK_NAME=MXSegmentedControl
6 | before_install:
7 | - brew update
8 | - brew outdated carthage || brew upgrade carthage
9 | install:
10 | - gem install cocoapods
11 | - gem install xcpretty --no-document --quiet
12 | script:
13 | - set -o pipefail && xcodebuild -project MXSegmentedControl.xcodeproj -scheme $FRAMEWORK_NAME
14 | -sdk iphonesimulator13.2 -configuration Release | xcpretty -c
15 | - pod lib lint --quick
16 | before_deploy:
17 | - carthage build --no-skip-current
18 | - carthage archive $FRAMEWORK_NAME
19 | deploy:
20 | provider: releases
21 | api_key:
22 | secure: GCbSn67brClZCNGbnlqGkwnWjFLSgYwWkjAOhkqBGIKzh/pARW227QXdDZP9vPz3oLxO/ux/tM1aojweakJCzIoYXENijTcB5rt7teUDsFiH/UInjfTCxNRLNzREUrvwOywAwEq37Ysdw3QH222SnJIVPl14ucwCyXXDMMQUmeyHLJg46AfNhZBheuWdzH5skAel9K68FOMeW9rbDEAUiXi+UHFRfmpEy0g0ukfVsVmnXB7YYQLN7ATz3fTwe6rMwPBneh5eibG7mNA81ROfsyLV7JUibjSzDIaXYPjsS+PCD8c7hWgfaTUdEeqjgOAAhwlbJz0yq5Z/ONtpRoCVFzniMV9gghr32rrt8+RvyrL9ELiqoWg9IvTQg9gNZ0wtMyT0pPTRuFxX4iD4kd0Q4YQjiPRsekxN3sOInE/njBYer69m3+geX25PcAxLCSZiuj2tXEcm4GPrApX+M822uU1PFq/8yOw6z8zfdTTgKu6l0HJaDTtqQ9BLU7m5lf0B2xQ7aloRucBPoJK+G2xOC/z6uZ06vJPoHi4eNRuiCSbThWg9NCBnWcAqYfcK/0kbQTc7E2olI13Wo5hXjXLQTpWIjkRt42Y5d11Hy4tUDF6qCx696W3rWWZnkkEWqtA7n0YYxhws8MiK7X1sedx7XrF8UfZU33TybPXt7pv726s=
23 | file: "$FRAMEWORK_NAME.framework.zip"
24 | skip_cleanup: true
25 | on:
26 | repo: maxep/MXSegmentedControl
27 | tags: true
28 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | // AppDelegate.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 |
25 | @UIApplicationMain
26 | class AppDelegate: UIResponder, UIApplicationDelegate {
27 |
28 | var window: UIWindow?
29 |
30 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
31 | // Override point for customization after application launch.
32 | return true
33 | }
34 |
35 | func applicationWillResignActive(_ application: UIApplication) {
36 | // 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.
37 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
38 | }
39 |
40 | func applicationDidEnterBackground(_ application: UIApplication) {
41 | // 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.
42 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
43 | }
44 |
45 | func applicationWillEnterForeground(_ application: UIApplication) {
46 | // 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.
47 | }
48 |
49 | func applicationDidBecomeActive(_ application: UIApplication) {
50 | // 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.
51 | }
52 |
53 | func applicationWillTerminate(_ application: UIApplication) {
54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
55 | }
56 |
57 |
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1-selected.imageset/1-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/1-selected.imageset/1-selected.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1-selected.imageset/1-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/1-selected.imageset/1-selected@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "1-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1.imageset/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/1.imageset/1.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1.imageset/1@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/1.imageset/1@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "1@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2-selected.imageset/2-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/2-selected.imageset/2-selected.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2-selected.imageset/2-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/2-selected.imageset/2-selected@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "2-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "2-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2.imageset/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/2.imageset/2.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2.imageset/2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/2.imageset/2@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "2@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3-selected.imageset/3-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/3-selected.imageset/3-selected.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3-selected.imageset/3-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/3-selected.imageset/3-selected@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "3-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "3-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3.imageset/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/3.imageset/3.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3.imageset/3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/3.imageset/3@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "3@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4-selected.imageset/4-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/4-selected.imageset/4-selected.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4-selected.imageset/4-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/4-selected.imageset/4-selected@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "4-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "4-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4.imageset/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/4.imageset/4.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4.imageset/4@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/4.imageset/4@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "4.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "4@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "size" : "1024x1024",
46 | "scale" : "1x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/earthquakes.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "eathquakes.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "eathquakes@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "eathquakes@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/earthquakes.imageset/eathquakes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/earthquakes.imageset/eathquakes.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/earthquakes.imageset/eathquakes@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/earthquakes.imageset/eathquakes@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/earthquakes.imageset/eathquakes@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/earthquakes.imageset/eathquakes@3x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/eruption.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "eruption.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "eruption@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "eruption@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/eruption.imageset/eruption.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/eruption.imageset/eruption.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/eruption.imageset/eruption@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/eruption.imageset/eruption@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/eruption.imageset/eruption@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/eruption.imageset/eruption@3x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/floods.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "floods.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "floods@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "floods@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/floods.imageset/floods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/floods.imageset/floods.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/floods.imageset/floods@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/floods.imageset/floods@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/floods.imageset/floods@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/floods.imageset/floods@3x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/heat.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "heat.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "heat@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "heat@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/heat.imageset/heat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/heat.imageset/heat.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/heat.imageset/heat@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/heat.imageset/heat@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/heat.imageset/heat@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/heat.imageset/heat@3x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/tornado.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tornado.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tornado@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "tornado@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/tornado.imageset/tornado.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/tornado.imageset/tornado.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/tornado.imageset/tornado@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/tornado.imageset/tornado@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/tornado.imageset/tornado@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/tornado.imageset/tornado@3x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/wildfires.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "wildfires.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "wildfires@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "wildfires@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/wildfires.imageset/wildfires.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/wildfires.imageset/wildfires.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/wildfires.imageset/wildfires@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/wildfires.imageset/wildfires@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/wildfires.imageset/wildfires@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/Example/Assets.xcassets/wildfires.imageset/wildfires@3x.png
--------------------------------------------------------------------------------
/Example/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 |
--------------------------------------------------------------------------------
/Example/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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
--------------------------------------------------------------------------------
/Example/CustomViewController.swift:
--------------------------------------------------------------------------------
1 | // CustomViewController.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 | import MXSegmentedControl
25 |
26 | class CustomViewController: UIViewController {
27 |
28 | @IBOutlet weak var segmentedControl1: MXSegmentedControl!
29 | @IBOutlet weak var segmentedControl2: MXSegmentedControl!
30 | @IBOutlet weak var segmentedControl3: MXSegmentedControl!
31 | @IBOutlet weak var scrollView: UIScrollView!
32 |
33 | override func viewDidLoad() {
34 | super.viewDidLoad()
35 |
36 | segmentedControl1.append(title: "First")
37 | segmentedControl1.append(title: "Second")
38 | segmentedControl1.append(title: "Third")
39 | segmentedControl1.append(title: "Fourth")
40 | segmentedControl1.append(title: "Fifth")
41 | segmentedControl1.append(title: "Sixth")
42 | segmentedControl1.append(title: "Seven")
43 | segmentedControl1.append(title: "Eight")
44 | segmentedControl1.append(title: "Nine")
45 | segmentedControl1.animation.duration = 0
46 |
47 | segmentedControl2.append(title: "First")
48 | segmentedControl2.append(title: "Second")
49 |
50 | segmentedControl3.append(title: "First")
51 | .set(titleColor: #colorLiteral(red: 0.9981629252, green: 0.6096215844, blue: 0.6670924425, alpha: 1), for: .selected)
52 | segmentedControl3.append(title: "Second")
53 | .set(titleColor: #colorLiteral(red: 1, green: 0.7996580601, blue: 0.4006214142, alpha: 1), for: .selected)
54 | segmentedControl3.append(title: "Third")
55 | .set(titleColor: #colorLiteral(red: 0.9995033145, green: 0.9875727296, blue: 0.4039593935, alpha: 1), for: .selected)
56 | segmentedControl3.append(title: "Fourth")
57 | .set(titleColor: #colorLiteral(red: 0.8013994098, green: 0.9842005372, blue: 0.4007700682, alpha: 1), for: .selected)
58 | segmentedControl3.append(title: "Fifth")
59 | .set(titleColor: #colorLiteral(red: 0.4016934037, green: 0.9801344275, blue: 0.3977853954, alpha: 1), for: .selected)
60 |
61 | segmentedControl3.indicator.boxView.alpha = 0.1
62 |
63 | segmentedControl3.addTarget(self, action: #selector(changeIndex(segmentedControl:)), for: .valueChanged)
64 | }
65 |
66 | @objc func changeIndex(segmentedControl: MXSegmentedControl) {
67 |
68 | if let segment = segmentedControl.segment(at: segmentedControl.selectedIndex) {
69 | segmentedControl.indicator.boxView.backgroundColor = segment.titleColor(for: .selected)
70 | segmentedControl.indicator.lineView.backgroundColor = segment.titleColor(for: .selected)
71 | }
72 | }
73 |
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/Example/HMSegmentedControlViewController.swift:
--------------------------------------------------------------------------------
1 | // HMSegmentedControlViewController.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 | import MXSegmentedControl
25 |
26 | class HMSegmentedControlViewController: UIViewController {
27 |
28 | @IBOutlet weak var segmentControl1: MXSegmentedControl!
29 | @IBOutlet weak var segmentControl2: MXSegmentedControl!
30 | @IBOutlet weak var segmentControl3: MXSegmentedControl!
31 | @IBOutlet weak var segmentControl4: MXSegmentedControl!
32 | @IBOutlet weak var segmentControl5: MXSegmentedControl!
33 |
34 | override func viewDidLoad() {
35 | super.viewDidLoad()
36 |
37 | segmentControl1.append(title: "Trending")
38 | segmentControl1.append(title: "News")
39 | segmentControl1.append(title: "Library")
40 | segmentControl1.indicator.linePosition = .top
41 |
42 | segmentControl2.append(title: "One")
43 | segmentControl2.append(title: "Two")
44 | segmentControl2.append(title: "Three")
45 | segmentControl2.append(title: "Four")
46 | segmentControl2.append(title: "Five")
47 | segmentControl2.append(title: "Six")
48 | segmentControl2.append(title: "Seven")
49 | segmentControl2.append(title: "Eight")
50 | segmentControl2.segmentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 10)
51 |
52 | segmentControl3.append(image: #imageLiteral(resourceName: "1"))
53 | .set(image: #imageLiteral(resourceName: "1-selected"), for: .selected)
54 | .set(image: .left)
55 | .imageView?.contentMode = .scaleAspectFit
56 | segmentControl3.append(image: #imageLiteral(resourceName: "2"))
57 | .set(image: #imageLiteral(resourceName: "2-selected"), for: .selected)
58 | .set(image: .left)
59 | .imageView?.contentMode = .scaleAspectFit
60 | segmentControl3.append(image: #imageLiteral(resourceName: "3"))
61 | .set(image: #imageLiteral(resourceName: "3-selected"), for: .selected)
62 | .set(image: .left)
63 | .imageView?.contentMode = .scaleAspectFit
64 | segmentControl3.append(image: #imageLiteral(resourceName: "4"))
65 | .set(image: #imageLiteral(resourceName: "4-selected"), for: .selected)
66 | .set(image: .left)
67 | .imageView?.contentMode = .scaleAspectFit
68 |
69 | segmentControl4.append(title: "One")
70 | segmentControl4.append(title: "Two")
71 | segmentControl4.append(title: "Three")
72 | segmentControl4.append(title: "4")
73 | segmentControl4.append(title: "Five")
74 |
75 | segmentControl5.append(title: "Worldwide")
76 | segmentControl5.append(title: "Local")
77 | segmentControl5.append(title: "Headlines")
78 | segmentControl5.indicator.linePosition = .top
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/Example/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 |
38 |
39 |
--------------------------------------------------------------------------------
/Example/SegmentioViewController.swift:
--------------------------------------------------------------------------------
1 | // SegmentioViewController.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 | import MXSegmentedControl
25 |
26 | class SegmentioViewController: UIViewController {
27 |
28 | @IBOutlet weak var segmentControl1: MXSegmentedControl!
29 | @IBOutlet weak var segmentControl2: MXSegmentedControl!
30 | @IBOutlet weak var segmentControl3: MXSegmentedControl!
31 | @IBOutlet weak var segmentControl4: MXSegmentedControl!
32 | @IBOutlet weak var segmentControl5: MXSegmentedControl!
33 | @IBOutlet weak var segmentControl6: MXSegmentedControl!
34 |
35 | override func viewDidLoad() {
36 | super.viewDidLoad()
37 |
38 | segmentControl1.append(title: "Tornado")
39 | segmentControl1.append(title: "Earthquakes")
40 | segmentControl1.append(title: "Extreme heat")
41 | segmentControl1.append(title: "Eruption")
42 | segmentControl1.append(title: "Floods")
43 | segmentControl1.append(title: "Wildfires")
44 |
45 | segmentControl2.append(image: #imageLiteral(resourceName: "tornado"))
46 | segmentControl2.append(image: #imageLiteral(resourceName: "earthquakes"))
47 | segmentControl2.append(image: #imageLiteral(resourceName: "heat"))
48 | segmentControl2.append(image: #imageLiteral(resourceName: "eruption"))
49 | segmentControl2.append(image: #imageLiteral(resourceName: "floods"))
50 | segmentControl2.append(image: #imageLiteral(resourceName: "wildfires"))
51 | segmentControl2.segmentWidth = 128
52 |
53 | segmentControl3.append(title: "Tornado")
54 | .set(image: #imageLiteral(resourceName: "tornado"))
55 | .set(image: .top)
56 | .set(padding: 16)
57 | segmentControl3.append(title: "Earthquakes")
58 | .set(image: #imageLiteral(resourceName: "earthquakes"))
59 | .set(image: .top)
60 | .set(padding: 16)
61 | segmentControl3.append(title: "Extreme heat")
62 | .set(image: #imageLiteral(resourceName: "heat"))
63 | .set(image: .top)
64 | .set(padding: 16)
65 | segmentControl3.append(title: "Eruption")
66 | .set(image: #imageLiteral(resourceName: "eruption"))
67 | .set(image: .top)
68 | .set(padding: 16)
69 | segmentControl3.append(title: "Floods")
70 | .set(image: #imageLiteral(resourceName: "floods"))
71 | .set(image: .top)
72 | .set(padding: 16)
73 | segmentControl3.append(title: "Wildfires")
74 | .set(image: #imageLiteral(resourceName: "wildfires"))
75 | .set(image: .top)
76 | .set(padding: 16)
77 |
78 | segmentControl4.append(title: "Tornado")
79 | .set(image: #imageLiteral(resourceName: "tornado"))
80 | .set(image: .bottom)
81 | .set(padding: 16)
82 | segmentControl4.append(title: "Earthquakes")
83 | .set(image: #imageLiteral(resourceName: "earthquakes"))
84 | .set(image: .top)
85 | .set(padding: 16)
86 | segmentControl4.append(title: "Extreme heat")
87 | .set(image: #imageLiteral(resourceName: "heat"))
88 | .set(image: .right)
89 | segmentControl4.append(title: "Eruption")
90 | .set(image: #imageLiteral(resourceName: "eruption"))
91 | .set(image: .left)
92 | segmentControl4.append(title: "Floods")
93 | .set(image: #imageLiteral(resourceName: "floods"))
94 | .set(image: .bottom)
95 | .set(padding: 16)
96 | segmentControl4.append(title: "Wildfires")
97 | .set(image: #imageLiteral(resourceName: "wildfires"))
98 | .set(image: .top)
99 | .set(padding: 16)
100 | }
101 |
102 | }
103 |
104 | extension UIFont {
105 |
106 | class func exampleAvenirMedium(ofSize size: CGFloat) -> UIFont {
107 | return UIFont(name: "Avenir-Book", size: size) ?? UIFont.systemFont(ofSize: size)
108 | }
109 |
110 | class func exampleAvenirLight(ofSize size: CGFloat) -> UIFont {
111 | return UIFont(name: "Avenir-Light", size: size) ?? UIFont.systemFont(ofSize: size)
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/Example/TopBarViewController.swift:
--------------------------------------------------------------------------------
1 | // ViewController.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 | import MXSegmentedControl
25 |
26 | class TopBarViewController: UIViewController {
27 |
28 | @IBOutlet weak var segmentedControl: MXSegmentedControl!
29 |
30 | override func viewDidLoad() {
31 | super.viewDidLoad()
32 |
33 | segmentedControl.append(title: "Segmentio")
34 | .set(titleColor: #colorLiteral(red: 0.08598647267, green: 0.093843095, blue: 0.1104642078, alpha: 1), for: .selected)
35 | segmentedControl.append(title: "HMSegmentedControl")
36 | .set(titleColor: #colorLiteral(red: 0.08598647267, green: 0.093843095, blue: 0.1104642078, alpha: 1), for: .selected)
37 | segmentedControl.append(title: "Other")
38 | .set(titleColor: #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1), for: .selected)
39 |
40 | segmentedControl.indicator.lineView.backgroundColor = #colorLiteral(red: 0.9568627451, green: 0.4392156863, blue: 0.3803921569, alpha: 1)
41 | segmentedControl.addTarget(self, action: #selector(changeIndex(segmentedControl:)), for: .valueChanged)
42 |
43 | navigationItem.titleView = segmentedControl
44 | }
45 |
46 | @objc func changeIndex(segmentedControl: MXSegmentedControl) {
47 |
48 | switch segmentedControl.selectedIndex {
49 | case 0:
50 | segmentedControl.indicator.lineView.backgroundColor = #colorLiteral(red: 0.9568627451, green: 0.4392156863, blue: 0.3803921569, alpha: 1)
51 | case 1:
52 | segmentedControl.indicator.lineView.backgroundColor = #colorLiteral(red: 0.2044631541, green: 0.7111002803, blue: 0.898917675, alpha: 1)
53 | case 2:
54 | segmentedControl.indicator.lineView.backgroundColor = #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)
55 | default:
56 | break
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 Maxime Epain
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/MXSegmentedControl.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "MXSegmentedControl"
3 | s.version = "1.1.0"
4 | s.summary = "A very customizable segmented control for iOS."
5 | s.description = <<-DESC
6 | MXSegmentedControl is a segmented control framework for iOS:
7 | - Very customizable UI.
8 | - Supports storyboard design.
9 | - Can be linked with a scroll view.
10 | DESC
11 |
12 | s.homepage = "https://github.com/maxep/MXSegmentedControl"
13 | s.license = 'MIT'
14 | s.author = { "Maxime Epain" => "maxime.epain@gmail.com" }
15 | s.source = { :git => "https://github.com/maxep/MXSegmentedControl.git", :tag => s.version.to_s }
16 | s.social_media_url = 'https://twitter.com/MaximeEpain'
17 |
18 | s.platform = :ios, '8.0'
19 | s.requires_arc = true
20 | s.swift_version = '4.2'
21 |
22 | s.source_files = 'MXSegmentedControl/*.swift'
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/MXSegmentedControl.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9C801BC31E72BD9200E75652 /* MXSegmentedControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C801BC11E72BD9200E75652 /* MXSegmentedControl.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 9C801BCA1E72BDDC00E75652 /* MXSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C801BC91E72BDDC00E75652 /* MXSegmentedControl.swift */; };
12 | 9C801BD41E72F96800E75652 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C801BD31E72F96800E75652 /* AppDelegate.swift */; };
13 | 9C801BD61E72F96800E75652 /* CustomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C801BD51E72F96800E75652 /* CustomViewController.swift */; };
14 | 9C801BD91E72F96800E75652 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C801BD71E72F96800E75652 /* Main.storyboard */; };
15 | 9C801BDB1E72F96800E75652 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9C801BDA1E72F96800E75652 /* Assets.xcassets */; };
16 | 9C801BDE1E72F96800E75652 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C801BDC1E72F96800E75652 /* LaunchScreen.storyboard */; };
17 | 9C801BE31E72F9AA00E75652 /* MXSegmentedControl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C801BBE1E72BD9200E75652 /* MXSegmentedControl.framework */; };
18 | 9C801BE41E72F9AA00E75652 /* MXSegmentedControl.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9C801BBE1E72BD9200E75652 /* MXSegmentedControl.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
19 | 9C8C7DA21F32124000560FF8 /* TopBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8C7DA11F32124000560FF8 /* TopBarViewController.swift */; };
20 | 9C8C7DA41F33762E00560FF8 /* SegmentioViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8C7DA31F33762E00560FF8 /* SegmentioViewController.swift */; };
21 | 9CCDC53D1FB35C010073B7A9 /* HMSegmentedControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCDC53C1FB35C010073B7A9 /* HMSegmentedControlViewController.swift */; };
22 | 9CF63C2D1E7C01EE00C56E1B /* MXSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CF63C2C1E7C01EE00C56E1B /* MXSegment.swift */; };
23 | 9CF63C301E7C023200C56E1B /* MXIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CF63C2F1E7C023200C56E1B /* MXIndicator.swift */; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXContainerItemProxy section */
27 | 9C801BE51E72F9AA00E75652 /* PBXContainerItemProxy */ = {
28 | isa = PBXContainerItemProxy;
29 | containerPortal = 9C801BB51E72BD9200E75652 /* Project object */;
30 | proxyType = 1;
31 | remoteGlobalIDString = 9C801BBD1E72BD9200E75652;
32 | remoteInfo = MXSegmentedControl;
33 | };
34 | /* End PBXContainerItemProxy section */
35 |
36 | /* Begin PBXCopyFilesBuildPhase section */
37 | 9C801BE71E72F9AA00E75652 /* Embed Frameworks */ = {
38 | isa = PBXCopyFilesBuildPhase;
39 | buildActionMask = 2147483647;
40 | dstPath = "";
41 | dstSubfolderSpec = 10;
42 | files = (
43 | 9C801BE41E72F9AA00E75652 /* MXSegmentedControl.framework in Embed Frameworks */,
44 | );
45 | name = "Embed Frameworks";
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | /* End PBXCopyFilesBuildPhase section */
49 |
50 | /* Begin PBXFileReference section */
51 | 9C801BBE1E72BD9200E75652 /* MXSegmentedControl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MXSegmentedControl.framework; sourceTree = BUILT_PRODUCTS_DIR; };
52 | 9C801BC11E72BD9200E75652 /* MXSegmentedControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXSegmentedControl.h; sourceTree = ""; };
53 | 9C801BC21E72BD9200E75652 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
54 | 9C801BC91E72BDDC00E75652 /* MXSegmentedControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSegmentedControl.swift; sourceTree = ""; };
55 | 9C801BD11E72F96800E75652 /* MXSegmentedControl Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MXSegmentedControl Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
56 | 9C801BD31E72F96800E75652 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
57 | 9C801BD51E72F96800E75652 /* CustomViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomViewController.swift; sourceTree = ""; };
58 | 9C801BD81E72F96800E75652 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
59 | 9C801BDA1E72F96800E75652 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
60 | 9C801BDD1E72F96800E75652 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
61 | 9C801BDF1E72F96800E75652 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
62 | 9C857EA61FB4B0C100D44719 /* screencast.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = screencast.gif; sourceTree = ""; };
63 | 9C8C7DA11F32124000560FF8 /* TopBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBarViewController.swift; sourceTree = ""; };
64 | 9C8C7DA31F33762E00560FF8 /* SegmentioViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentioViewController.swift; sourceTree = ""; };
65 | 9C9BD41A1E787F0800485B8E /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
66 | 9C9BD41B1E787F0800485B8E /* MXSegmentedControl.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = MXSegmentedControl.podspec; sourceTree = ""; };
67 | 9C9BD41C1E787F0800485B8E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
68 | 9C9BD41D1E787FD800485B8E /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; };
69 | 9CCDC53C1FB35C010073B7A9 /* HMSegmentedControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMSegmentedControlViewController.swift; sourceTree = ""; };
70 | 9CF63C2C1E7C01EE00C56E1B /* MXSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSegment.swift; sourceTree = ""; };
71 | 9CF63C2F1E7C023200C56E1B /* MXIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXIndicator.swift; sourceTree = ""; };
72 | /* End PBXFileReference section */
73 |
74 | /* Begin PBXFrameworksBuildPhase section */
75 | 9C801BBA1E72BD9200E75652 /* Frameworks */ = {
76 | isa = PBXFrameworksBuildPhase;
77 | buildActionMask = 2147483647;
78 | files = (
79 | );
80 | runOnlyForDeploymentPostprocessing = 0;
81 | };
82 | 9C801BCE1E72F96800E75652 /* Frameworks */ = {
83 | isa = PBXFrameworksBuildPhase;
84 | buildActionMask = 2147483647;
85 | files = (
86 | 9C801BE31E72F9AA00E75652 /* MXSegmentedControl.framework in Frameworks */,
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | /* End PBXFrameworksBuildPhase section */
91 |
92 | /* Begin PBXGroup section */
93 | 9C801BB41E72BD9200E75652 = {
94 | isa = PBXGroup;
95 | children = (
96 | 9C9BD4191E787EF200485B8E /* Metadata */,
97 | 9C801BC01E72BD9200E75652 /* MXSegmentedControl */,
98 | 9C801BD21E72F96800E75652 /* Example */,
99 | 9C801BBF1E72BD9200E75652 /* Products */,
100 | );
101 | sourceTree = "";
102 | };
103 | 9C801BBF1E72BD9200E75652 /* Products */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 9C801BBE1E72BD9200E75652 /* MXSegmentedControl.framework */,
107 | 9C801BD11E72F96800E75652 /* MXSegmentedControl Example.app */,
108 | );
109 | name = Products;
110 | sourceTree = "";
111 | };
112 | 9C801BC01E72BD9200E75652 /* MXSegmentedControl */ = {
113 | isa = PBXGroup;
114 | children = (
115 | 9C801BC11E72BD9200E75652 /* MXSegmentedControl.h */,
116 | 9C801BC21E72BD9200E75652 /* Info.plist */,
117 | 9C801BC91E72BDDC00E75652 /* MXSegmentedControl.swift */,
118 | 9CF63C2C1E7C01EE00C56E1B /* MXSegment.swift */,
119 | 9CF63C2F1E7C023200C56E1B /* MXIndicator.swift */,
120 | );
121 | path = MXSegmentedControl;
122 | sourceTree = "";
123 | };
124 | 9C801BD21E72F96800E75652 /* Example */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 9C801BD31E72F96800E75652 /* AppDelegate.swift */,
128 | 9C8C7DA11F32124000560FF8 /* TopBarViewController.swift */,
129 | 9C8C7DA31F33762E00560FF8 /* SegmentioViewController.swift */,
130 | 9CCDC53C1FB35C010073B7A9 /* HMSegmentedControlViewController.swift */,
131 | 9C801BD51E72F96800E75652 /* CustomViewController.swift */,
132 | 9C801BD71E72F96800E75652 /* Main.storyboard */,
133 | 9C801BDA1E72F96800E75652 /* Assets.xcassets */,
134 | 9C801BDC1E72F96800E75652 /* LaunchScreen.storyboard */,
135 | 9C801BDF1E72F96800E75652 /* Info.plist */,
136 | );
137 | path = Example;
138 | sourceTree = "";
139 | };
140 | 9C9BD4191E787EF200485B8E /* Metadata */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 9C9BD41C1E787F0800485B8E /* README.md */,
144 | 9C9BD41B1E787F0800485B8E /* MXSegmentedControl.podspec */,
145 | 9C9BD41D1E787FD800485B8E /* .travis.yml */,
146 | 9C9BD41A1E787F0800485B8E /* LICENSE */,
147 | 9C857EA61FB4B0C100D44719 /* screencast.gif */,
148 | );
149 | name = Metadata;
150 | sourceTree = "";
151 | };
152 | /* End PBXGroup section */
153 |
154 | /* Begin PBXHeadersBuildPhase section */
155 | 9C801BBB1E72BD9200E75652 /* Headers */ = {
156 | isa = PBXHeadersBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | 9C801BC31E72BD9200E75652 /* MXSegmentedControl.h in Headers */,
160 | );
161 | runOnlyForDeploymentPostprocessing = 0;
162 | };
163 | /* End PBXHeadersBuildPhase section */
164 |
165 | /* Begin PBXNativeTarget section */
166 | 9C801BBD1E72BD9200E75652 /* MXSegmentedControl */ = {
167 | isa = PBXNativeTarget;
168 | buildConfigurationList = 9C801BC61E72BD9200E75652 /* Build configuration list for PBXNativeTarget "MXSegmentedControl" */;
169 | buildPhases = (
170 | 9C801BB91E72BD9200E75652 /* Sources */,
171 | 9C801BBA1E72BD9200E75652 /* Frameworks */,
172 | 9C801BBB1E72BD9200E75652 /* Headers */,
173 | 9C801BBC1E72BD9200E75652 /* Resources */,
174 | );
175 | buildRules = (
176 | );
177 | dependencies = (
178 | );
179 | name = MXSegmentedControl;
180 | productName = MXSegmentedControl;
181 | productReference = 9C801BBE1E72BD9200E75652 /* MXSegmentedControl.framework */;
182 | productType = "com.apple.product-type.framework";
183 | };
184 | 9C801BD01E72F96800E75652 /* Example */ = {
185 | isa = PBXNativeTarget;
186 | buildConfigurationList = 9C801BE01E72F96800E75652 /* Build configuration list for PBXNativeTarget "Example" */;
187 | buildPhases = (
188 | 9C801BCD1E72F96800E75652 /* Sources */,
189 | 9C801BCE1E72F96800E75652 /* Frameworks */,
190 | 9C801BCF1E72F96800E75652 /* Resources */,
191 | 9C801BE71E72F9AA00E75652 /* Embed Frameworks */,
192 | );
193 | buildRules = (
194 | );
195 | dependencies = (
196 | 9C801BE61E72F9AA00E75652 /* PBXTargetDependency */,
197 | );
198 | name = Example;
199 | productName = Example;
200 | productReference = 9C801BD11E72F96800E75652 /* MXSegmentedControl Example.app */;
201 | productType = "com.apple.product-type.application";
202 | };
203 | /* End PBXNativeTarget section */
204 |
205 | /* Begin PBXProject section */
206 | 9C801BB51E72BD9200E75652 /* Project object */ = {
207 | isa = PBXProject;
208 | attributes = {
209 | LastSwiftUpdateCheck = 0820;
210 | LastUpgradeCheck = 1010;
211 | ORGANIZATIONNAME = "Maxime Epain";
212 | TargetAttributes = {
213 | 9C801BBD1E72BD9200E75652 = {
214 | CreatedOnToolsVersion = 8.2;
215 | DevelopmentTeam = C75GEDTP26;
216 | LastSwiftMigration = 0900;
217 | ProvisioningStyle = Automatic;
218 | };
219 | 9C801BD01E72F96800E75652 = {
220 | CreatedOnToolsVersion = 8.2;
221 | DevelopmentTeam = C75GEDTP26;
222 | LastSwiftMigration = 0900;
223 | ProvisioningStyle = Automatic;
224 | };
225 | };
226 | };
227 | buildConfigurationList = 9C801BB81E72BD9200E75652 /* Build configuration list for PBXProject "MXSegmentedControl" */;
228 | compatibilityVersion = "Xcode 3.2";
229 | developmentRegion = English;
230 | hasScannedForEncodings = 0;
231 | knownRegions = (
232 | English,
233 | en,
234 | Base,
235 | );
236 | mainGroup = 9C801BB41E72BD9200E75652;
237 | productRefGroup = 9C801BBF1E72BD9200E75652 /* Products */;
238 | projectDirPath = "";
239 | projectRoot = "";
240 | targets = (
241 | 9C801BBD1E72BD9200E75652 /* MXSegmentedControl */,
242 | 9C801BD01E72F96800E75652 /* Example */,
243 | );
244 | };
245 | /* End PBXProject section */
246 |
247 | /* Begin PBXResourcesBuildPhase section */
248 | 9C801BBC1E72BD9200E75652 /* Resources */ = {
249 | isa = PBXResourcesBuildPhase;
250 | buildActionMask = 2147483647;
251 | files = (
252 | );
253 | runOnlyForDeploymentPostprocessing = 0;
254 | };
255 | 9C801BCF1E72F96800E75652 /* Resources */ = {
256 | isa = PBXResourcesBuildPhase;
257 | buildActionMask = 2147483647;
258 | files = (
259 | 9C801BDE1E72F96800E75652 /* LaunchScreen.storyboard in Resources */,
260 | 9C801BDB1E72F96800E75652 /* Assets.xcassets in Resources */,
261 | 9C801BD91E72F96800E75652 /* Main.storyboard in Resources */,
262 | );
263 | runOnlyForDeploymentPostprocessing = 0;
264 | };
265 | /* End PBXResourcesBuildPhase section */
266 |
267 | /* Begin PBXSourcesBuildPhase section */
268 | 9C801BB91E72BD9200E75652 /* Sources */ = {
269 | isa = PBXSourcesBuildPhase;
270 | buildActionMask = 2147483647;
271 | files = (
272 | 9CF63C2D1E7C01EE00C56E1B /* MXSegment.swift in Sources */,
273 | 9CF63C301E7C023200C56E1B /* MXIndicator.swift in Sources */,
274 | 9C801BCA1E72BDDC00E75652 /* MXSegmentedControl.swift in Sources */,
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | 9C801BCD1E72F96800E75652 /* Sources */ = {
279 | isa = PBXSourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 9C801BD61E72F96800E75652 /* CustomViewController.swift in Sources */,
283 | 9C801BD41E72F96800E75652 /* AppDelegate.swift in Sources */,
284 | 9CCDC53D1FB35C010073B7A9 /* HMSegmentedControlViewController.swift in Sources */,
285 | 9C8C7DA41F33762E00560FF8 /* SegmentioViewController.swift in Sources */,
286 | 9C8C7DA21F32124000560FF8 /* TopBarViewController.swift in Sources */,
287 | );
288 | runOnlyForDeploymentPostprocessing = 0;
289 | };
290 | /* End PBXSourcesBuildPhase section */
291 |
292 | /* Begin PBXTargetDependency section */
293 | 9C801BE61E72F9AA00E75652 /* PBXTargetDependency */ = {
294 | isa = PBXTargetDependency;
295 | target = 9C801BBD1E72BD9200E75652 /* MXSegmentedControl */;
296 | targetProxy = 9C801BE51E72F9AA00E75652 /* PBXContainerItemProxy */;
297 | };
298 | /* End PBXTargetDependency section */
299 |
300 | /* Begin PBXVariantGroup section */
301 | 9C801BD71E72F96800E75652 /* Main.storyboard */ = {
302 | isa = PBXVariantGroup;
303 | children = (
304 | 9C801BD81E72F96800E75652 /* Base */,
305 | );
306 | name = Main.storyboard;
307 | sourceTree = "";
308 | };
309 | 9C801BDC1E72F96800E75652 /* LaunchScreen.storyboard */ = {
310 | isa = PBXVariantGroup;
311 | children = (
312 | 9C801BDD1E72F96800E75652 /* Base */,
313 | );
314 | name = LaunchScreen.storyboard;
315 | sourceTree = "";
316 | };
317 | /* End PBXVariantGroup section */
318 |
319 | /* Begin XCBuildConfiguration section */
320 | 9C801BC41E72BD9200E75652 /* Debug */ = {
321 | isa = XCBuildConfiguration;
322 | buildSettings = {
323 | ALWAYS_SEARCH_USER_PATHS = NO;
324 | CLANG_ANALYZER_NONNULL = YES;
325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
326 | CLANG_CXX_LIBRARY = "libc++";
327 | CLANG_ENABLE_MODULES = YES;
328 | CLANG_ENABLE_OBJC_ARC = YES;
329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
330 | CLANG_WARN_BOOL_CONVERSION = YES;
331 | CLANG_WARN_COMMA = YES;
332 | CLANG_WARN_CONSTANT_CONVERSION = YES;
333 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
335 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
336 | CLANG_WARN_EMPTY_BODY = YES;
337 | CLANG_WARN_ENUM_CONVERSION = YES;
338 | CLANG_WARN_INFINITE_RECURSION = YES;
339 | CLANG_WARN_INT_CONVERSION = YES;
340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
345 | CLANG_WARN_STRICT_PROTOTYPES = YES;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNREACHABLE_CODE = YES;
348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
350 | COPY_PHASE_STRIP = NO;
351 | CURRENT_PROJECT_VERSION = 1;
352 | DEBUG_INFORMATION_FORMAT = dwarf;
353 | ENABLE_STRICT_OBJC_MSGSEND = YES;
354 | ENABLE_TESTABILITY = YES;
355 | GCC_C_LANGUAGE_STANDARD = gnu99;
356 | GCC_DYNAMIC_NO_PIC = NO;
357 | GCC_NO_COMMON_BLOCKS = YES;
358 | GCC_OPTIMIZATION_LEVEL = 0;
359 | GCC_PREPROCESSOR_DEFINITIONS = (
360 | "DEBUG=1",
361 | "$(inherited)",
362 | );
363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
365 | GCC_WARN_UNDECLARED_SELECTOR = YES;
366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
367 | GCC_WARN_UNUSED_FUNCTION = YES;
368 | GCC_WARN_UNUSED_VARIABLE = YES;
369 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
370 | MTL_ENABLE_DEBUG_INFO = YES;
371 | ONLY_ACTIVE_ARCH = YES;
372 | SDKROOT = iphoneos;
373 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
374 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
375 | TARGETED_DEVICE_FAMILY = "1,2";
376 | VERSIONING_SYSTEM = "apple-generic";
377 | VERSION_INFO_PREFIX = "";
378 | };
379 | name = Debug;
380 | };
381 | 9C801BC51E72BD9200E75652 /* Release */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | ALWAYS_SEARCH_USER_PATHS = NO;
385 | CLANG_ANALYZER_NONNULL = YES;
386 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
387 | CLANG_CXX_LIBRARY = "libc++";
388 | CLANG_ENABLE_MODULES = YES;
389 | CLANG_ENABLE_OBJC_ARC = YES;
390 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
391 | CLANG_WARN_BOOL_CONVERSION = YES;
392 | CLANG_WARN_COMMA = YES;
393 | CLANG_WARN_CONSTANT_CONVERSION = YES;
394 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
396 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
397 | CLANG_WARN_EMPTY_BODY = YES;
398 | CLANG_WARN_ENUM_CONVERSION = YES;
399 | CLANG_WARN_INFINITE_RECURSION = YES;
400 | CLANG_WARN_INT_CONVERSION = YES;
401 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
402 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
403 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
404 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
405 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
406 | CLANG_WARN_STRICT_PROTOTYPES = YES;
407 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
408 | CLANG_WARN_UNREACHABLE_CODE = YES;
409 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
410 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
411 | COPY_PHASE_STRIP = NO;
412 | CURRENT_PROJECT_VERSION = 1;
413 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
414 | ENABLE_NS_ASSERTIONS = NO;
415 | ENABLE_STRICT_OBJC_MSGSEND = YES;
416 | GCC_C_LANGUAGE_STANDARD = gnu99;
417 | GCC_NO_COMMON_BLOCKS = YES;
418 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
419 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
420 | GCC_WARN_UNDECLARED_SELECTOR = YES;
421 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
422 | GCC_WARN_UNUSED_FUNCTION = YES;
423 | GCC_WARN_UNUSED_VARIABLE = YES;
424 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
425 | MTL_ENABLE_DEBUG_INFO = NO;
426 | SDKROOT = iphoneos;
427 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
428 | TARGETED_DEVICE_FAMILY = "1,2";
429 | VALIDATE_PRODUCT = YES;
430 | VERSIONING_SYSTEM = "apple-generic";
431 | VERSION_INFO_PREFIX = "";
432 | };
433 | name = Release;
434 | };
435 | 9C801BC71E72BD9200E75652 /* Debug */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | CLANG_ENABLE_MODULES = YES;
439 | CODE_SIGN_IDENTITY = "";
440 | DEFINES_MODULE = YES;
441 | DEVELOPMENT_TEAM = C75GEDTP26;
442 | DYLIB_COMPATIBILITY_VERSION = 1;
443 | DYLIB_CURRENT_VERSION = 1;
444 | DYLIB_INSTALL_NAME_BASE = "@rpath";
445 | INFOPLIST_FILE = MXSegmentedControl/Info.plist;
446 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
447 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
448 | PRODUCT_BUNDLE_IDENTIFIER = fr.maxep.MXSegmentedControl;
449 | PRODUCT_NAME = "$(TARGET_NAME)";
450 | SKIP_INSTALL = YES;
451 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
452 | SWIFT_VERSION = 4.2;
453 | };
454 | name = Debug;
455 | };
456 | 9C801BC81E72BD9200E75652 /* Release */ = {
457 | isa = XCBuildConfiguration;
458 | buildSettings = {
459 | CLANG_ENABLE_MODULES = YES;
460 | CODE_SIGN_IDENTITY = "";
461 | DEFINES_MODULE = YES;
462 | DEVELOPMENT_TEAM = C75GEDTP26;
463 | DYLIB_COMPATIBILITY_VERSION = 1;
464 | DYLIB_CURRENT_VERSION = 1;
465 | DYLIB_INSTALL_NAME_BASE = "@rpath";
466 | INFOPLIST_FILE = MXSegmentedControl/Info.plist;
467 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
468 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
469 | PRODUCT_BUNDLE_IDENTIFIER = fr.maxep.MXSegmentedControl;
470 | PRODUCT_NAME = "$(TARGET_NAME)";
471 | SKIP_INSTALL = YES;
472 | SWIFT_VERSION = 4.2;
473 | };
474 | name = Release;
475 | };
476 | 9C801BE11E72F96800E75652 /* Debug */ = {
477 | isa = XCBuildConfiguration;
478 | buildSettings = {
479 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
480 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
481 | DEVELOPMENT_TEAM = C75GEDTP26;
482 | INFOPLIST_FILE = Example/Info.plist;
483 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
484 | PRODUCT_BUNDLE_IDENTIFIER = fr.maxep.MXSegmentedControl.Example;
485 | PRODUCT_NAME = "MXSegmentedControl Example";
486 | SWIFT_VERSION = 4.0;
487 | };
488 | name = Debug;
489 | };
490 | 9C801BE21E72F96800E75652 /* Release */ = {
491 | isa = XCBuildConfiguration;
492 | buildSettings = {
493 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
494 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
495 | DEVELOPMENT_TEAM = C75GEDTP26;
496 | INFOPLIST_FILE = Example/Info.plist;
497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
498 | PRODUCT_BUNDLE_IDENTIFIER = fr.maxep.MXSegmentedControl.Example;
499 | PRODUCT_NAME = "MXSegmentedControl Example";
500 | SWIFT_VERSION = 4.0;
501 | };
502 | name = Release;
503 | };
504 | /* End XCBuildConfiguration section */
505 |
506 | /* Begin XCConfigurationList section */
507 | 9C801BB81E72BD9200E75652 /* Build configuration list for PBXProject "MXSegmentedControl" */ = {
508 | isa = XCConfigurationList;
509 | buildConfigurations = (
510 | 9C801BC41E72BD9200E75652 /* Debug */,
511 | 9C801BC51E72BD9200E75652 /* Release */,
512 | );
513 | defaultConfigurationIsVisible = 0;
514 | defaultConfigurationName = Release;
515 | };
516 | 9C801BC61E72BD9200E75652 /* Build configuration list for PBXNativeTarget "MXSegmentedControl" */ = {
517 | isa = XCConfigurationList;
518 | buildConfigurations = (
519 | 9C801BC71E72BD9200E75652 /* Debug */,
520 | 9C801BC81E72BD9200E75652 /* Release */,
521 | );
522 | defaultConfigurationIsVisible = 0;
523 | defaultConfigurationName = Release;
524 | };
525 | 9C801BE01E72F96800E75652 /* Build configuration list for PBXNativeTarget "Example" */ = {
526 | isa = XCConfigurationList;
527 | buildConfigurations = (
528 | 9C801BE11E72F96800E75652 /* Debug */,
529 | 9C801BE21E72F96800E75652 /* Release */,
530 | );
531 | defaultConfigurationIsVisible = 0;
532 | defaultConfigurationName = Release;
533 | };
534 | /* End XCConfigurationList section */
535 | };
536 | rootObject = 9C801BB51E72BD9200E75652 /* Project object */;
537 | }
538 |
--------------------------------------------------------------------------------
/MXSegmentedControl.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MXSegmentedControl.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MXSegmentedControl.xcodeproj/xcshareddata/xcschemes/MXSegmentedControl.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/MXSegmentedControl/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.1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/MXSegmentedControl/MXIndicator.swift:
--------------------------------------------------------------------------------
1 | // MXIndicator.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 |
25 | @objcMembers
26 | public class MXIndicator: UIView {
27 |
28 | /// The indicator line position
29 | ///
30 | /// - top: The line will be drawn at the top of the segemented control
31 | /// - bottom: The line will be drawn at the bottom of the segemented control
32 | public enum Position {
33 | case top
34 | case bottom
35 | }
36 |
37 | /// The indicator insets
38 | public var contentEdgeInsets = UIEdgeInsets.zero
39 |
40 | /// The indicator line view.
41 | public let lineView = UIView()
42 |
43 | public var linePosition = Position.bottom
44 |
45 | /// The indicator box view.
46 | public let boxView = UIView()
47 |
48 | /// The line height value.
49 | public var lineHeight: CGFloat = 1
50 |
51 | /// :nodoc:
52 | required public init?(coder aDecoder: NSCoder) {
53 | super.init(coder: aDecoder)
54 | initialize()
55 | }
56 |
57 | /// :nodoc:
58 | override public init(frame: CGRect) {
59 | super.init(frame: frame)
60 | initialize()
61 | }
62 |
63 | private func initialize() {
64 |
65 | lineView.backgroundColor = tintColor
66 | boxView.backgroundColor = tintColor
67 | boxView.alpha = 0
68 |
69 | addSubview(boxView)
70 | addSubview(lineView)
71 | }
72 |
73 | /// :nodoc:
74 | override public func layoutSubviews() {
75 | super.layoutSubviews()
76 |
77 | var frame = self.bounds //container.inset(by: margin)
78 | //UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
79 |
80 | if linePosition == .top {
81 |
82 | lineView.frame = CGRect(x: 0, y: 0, width: frame.width, height: lineHeight)
83 |
84 | frame.origin.y = lineHeight
85 | frame.size.height -= lineHeight
86 | boxView.frame = frame
87 |
88 | } else {
89 | frame.size.height -= lineHeight
90 | boxView.frame = frame
91 |
92 | frame.origin.y = frame.size.height
93 | frame.size.height = lineHeight
94 | lineView.frame = frame
95 | }
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/MXSegmentedControl/MXSegment.swift:
--------------------------------------------------------------------------------
1 | // MXSegment.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 |
25 | /// A segment button embed in MXSegmentedControl
26 | @objcMembers
27 | public class MXSegment: UIButton {
28 |
29 | /// The Image position in segment related to title.
30 | ///
31 | /// - top: Image will be placed on top of the title.
32 | /// - left: Image will be placed at the left of the title.
33 | /// - bottom: Image will be placed below the title.
34 | /// - right: Image will be placed at the right of the title.
35 | public enum ImagePosition {
36 | case top
37 | case left
38 | case bottom
39 | case right
40 | }
41 |
42 | /// The image position related to the title.
43 | public var imagePosition = ImagePosition.top
44 |
45 | /// Padding between segment title and image
46 | public var padding: CGFloat = 8
47 |
48 | /// The segment width
49 | public var width: CGFloat {
50 | get {
51 | guard _width == UIView.noIntrinsicMetric else { return _width }
52 | return intrinsicContentSize.width
53 | }
54 | set { _width = newValue }
55 | }
56 |
57 | private var _width: CGFloat = UIView.noIntrinsicMetric
58 |
59 | @discardableResult public func set(width: CGFloat) -> MXSegment {
60 | self.width = width
61 | return self
62 | }
63 |
64 | @discardableResult public func set(image position: ImagePosition) -> MXSegment {
65 | self.imagePosition = position
66 | return self
67 | }
68 |
69 | @discardableResult public func set(padding: CGFloat) -> MXSegment {
70 | self.padding = padding
71 | return self
72 | }
73 |
74 | @discardableResult public func set(title: String?, for state: UIControl.State = .normal) -> MXSegment {
75 | super.setTitle(title, for: state)
76 | return self
77 | }
78 |
79 | @discardableResult public func set(titleColor: UIColor?, for state: UIControl.State = .normal) -> MXSegment {
80 | super.setTitleColor(titleColor, for: state)
81 | return self
82 | }
83 |
84 | @discardableResult public func set(image: UIImage?, for state: UIControl.State = .normal) -> MXSegment {
85 | super.setImage(image, for: state)
86 | return self
87 | }
88 |
89 | @discardableResult public func set(background image: UIImage?, for state: UIControl.State = .normal) -> MXSegment {
90 | super.setBackgroundImage(image, for: state)
91 | return self
92 | }
93 |
94 | @discardableResult public func set(attributedTitle: NSAttributedString?, for state: UIControl.State = .normal) -> MXSegment {
95 | super.setAttributedTitle(attributedTitle, for: state)
96 | return self
97 | }
98 |
99 | }
100 |
101 | // MARK: - Layouts
102 |
103 | extension MXSegment {
104 |
105 | /// :nodoc:
106 | public override func layoutSubviews() {
107 | super.layoutSubviews()
108 |
109 | guard let titleLabel = titleLabel, let imageView = imageView else {
110 | return
111 | }
112 |
113 | guard !titleLabel.frame.isEmpty, !imageView.frame.isEmpty else {
114 | return
115 | }
116 |
117 | switch imagePosition {
118 | case .top:
119 | layoutTop(imageView, titleLabel)
120 | case .left:
121 | layoutLeft(imageView, titleLabel)
122 | case .bottom:
123 | layoutBottom(imageView, titleLabel)
124 | case .right:
125 | layoutRight(imageView, titleLabel)
126 | }
127 | }
128 |
129 | /// :nodoc:
130 | public override var intrinsicContentSize: CGSize {
131 | let titleSize = titleLabel?.intrinsicContentSize
132 | let imageSize = imageView?.intrinsicContentSize
133 |
134 | var size = CGSize.zero
135 |
136 | switch imagePosition {
137 | case .top, .bottom:
138 |
139 | if let titleSize = titleSize {
140 | size.height += titleSize.height
141 | size.height += titleEdgeInsets.top
142 | size.height += titleEdgeInsets.bottom
143 |
144 | var width = titleSize.width
145 | width += titleEdgeInsets.left
146 | width += titleEdgeInsets.right
147 |
148 | size.width = width
149 | }
150 |
151 | if let imageSize = imageSize {
152 | size.height += imageSize.height
153 | size.height += imageEdgeInsets.top
154 | size.height += imageEdgeInsets.bottom
155 |
156 | var width = imageSize.width
157 | width += imageEdgeInsets.left
158 | width += imageEdgeInsets.right
159 |
160 | size.width = max(size.width, width)
161 | }
162 |
163 | if titleLabel != nil || imageView != nil {
164 | size.height += padding
165 | }
166 |
167 | case .left, .right:
168 |
169 | if let titleSize = titleSize {
170 | size.width += titleSize.width
171 | size.width += titleEdgeInsets.left
172 | size.width += titleEdgeInsets.right
173 |
174 | var height = titleSize.height
175 | height += titleEdgeInsets.top
176 | height += titleEdgeInsets.bottom
177 |
178 | size.height = height
179 | }
180 |
181 | if let imageSize = imageSize {
182 | size.width += imageSize.height
183 | size.width += imageEdgeInsets.left
184 | size.width += imageEdgeInsets.right
185 |
186 | var height = imageSize.height
187 | height += imageEdgeInsets.top
188 | height += imageEdgeInsets.bottom
189 |
190 | size.height = max(size.height, height)
191 | }
192 |
193 | if titleLabel != nil || imageView != nil {
194 | size.width += padding
195 | }
196 | }
197 |
198 | if titleLabel != nil || imageView != nil {
199 | size.width += contentEdgeInsets.left
200 | size.width += contentEdgeInsets.right
201 |
202 | size.height += contentEdgeInsets.top
203 | size.height += contentEdgeInsets.bottom
204 | }
205 | return size
206 | }
207 |
208 | private func layoutTop(_ imageView: UIImageView, _ titleLabel: UILabel) {
209 | let contentRect = self.contentRect(forBounds: bounds)
210 | let imageSize = imageView.intrinsicContentSize
211 | let titleSize = titleLabel.intrinsicContentSize
212 |
213 | // Compute Image View Frame
214 | var width = contentRect.width
215 | width -= imageEdgeInsets.left
216 | width -= imageEdgeInsets.right
217 | width = min(width, imageSize.width)
218 |
219 | var height = contentRect.height
220 | height -= imageEdgeInsets.top
221 | height -= imageEdgeInsets.bottom
222 | height -= titleEdgeInsets.top
223 | height -= titleEdgeInsets.bottom
224 | height -= titleSize.height
225 | height -= padding
226 | height = min(height, imageSize.height)
227 |
228 | var x = max(contentRect.minX + imageEdgeInsets.left,
229 | contentRect.midX - width / 2)
230 | var y = max(contentRect.minY + imageEdgeInsets.top,
231 | contentRect.midY - (height + titleSize.height + padding) / 2)
232 |
233 | imageView.frame = CGRect(x: x, y: y, width: width, height: height)
234 | //
235 |
236 | // Compute Title Label Frame
237 | x = max(contentRect.minX + titleEdgeInsets.left,
238 | contentRect.midX - titleSize.width / 2)
239 | y = imageView.frame.maxY
240 | y += imageEdgeInsets.bottom
241 | y += padding
242 | y += titleEdgeInsets.top
243 |
244 | width = contentRect.width
245 | width -= titleEdgeInsets.left
246 | width -= titleEdgeInsets.right
247 | width = min(width, titleSize.width)
248 |
249 | titleLabel.frame = CGRect(x: x, y: y, width: width, height: titleSize.height)
250 | //
251 | }
252 |
253 | private func layoutBottom(_ imageView: UIImageView, _ titleLabel: UILabel) {
254 | let contentRect = self.contentRect(forBounds: bounds)
255 | let imageSize = imageView.intrinsicContentSize
256 | let titleSize = titleLabel.intrinsicContentSize
257 |
258 | // Compute Title Label Frame
259 | var width = contentRect.width
260 | width -= titleEdgeInsets.left
261 | width -= titleEdgeInsets.right
262 | width = min(width, titleSize.width)
263 |
264 | var height = contentRect.height
265 | height -= imageEdgeInsets.top
266 | height -= imageEdgeInsets.bottom
267 | height -= titleEdgeInsets.top
268 | height -= titleEdgeInsets.bottom
269 | height -= titleSize.height
270 | height -= padding
271 | height = min(height, imageSize.height)
272 |
273 | var x = max(contentRect.minX + titleEdgeInsets.left,
274 | contentRect.midX - titleSize.width / 2)
275 | var y = max(contentRect.minY + titleEdgeInsets.top,
276 | contentRect.midY - (height + titleSize.height + padding) / 2)
277 |
278 | titleLabel.frame = CGRect(x: x, y: y, width: width, height: titleSize.height)
279 | //
280 |
281 | // Compute Image View Frame
282 | width = contentRect.width
283 | width -= imageEdgeInsets.left
284 | width -= imageEdgeInsets.right
285 | width = min(width, imageSize.width)
286 |
287 | x = max(contentRect.minX + imageEdgeInsets.left,
288 | contentRect.midX - width / 2)
289 |
290 | y = titleLabel.frame.maxY
291 | y += titleEdgeInsets.bottom
292 | y += padding
293 | y += imageEdgeInsets.top
294 |
295 | imageView.frame = CGRect(x: x, y: y, width: width, height: height)
296 | //
297 | }
298 |
299 | private func layoutLeft(_ imageView: UIImageView, _ titleLabel: UILabel) {
300 | let contentRect = self.contentRect(forBounds: bounds)
301 | let imageSize = imageView.intrinsicContentSize
302 | let titleSize = titleLabel.intrinsicContentSize
303 |
304 | // Compute Image View Frame
305 | var width = contentRect.width
306 | width -= imageEdgeInsets.left
307 | width -= imageEdgeInsets.right
308 | width -= titleEdgeInsets.left
309 | width -= titleEdgeInsets.right
310 | width -= padding
311 | width = min(width, imageSize.width)
312 |
313 | var height = contentRect.height
314 | height -= imageEdgeInsets.top
315 | height -= imageEdgeInsets.bottom
316 | height = min(height, imageSize.height)
317 |
318 | var x = max(contentRect.minX + imageEdgeInsets.left,
319 | contentRect.midX - (width + titleSize.width + padding) / 2)
320 | var y = max(contentRect.minY + imageEdgeInsets.top,
321 | contentRect.midY - height / 2)
322 |
323 | imageView.frame = CGRect(x: x, y: y, width: width, height: height)
324 | //
325 |
326 | // Compute Title Label Frame
327 | y = max(contentRect.minY + titleEdgeInsets.top,
328 | contentRect.midY - titleSize.height / 2)
329 | x = imageView.frame.maxX
330 | x += imageEdgeInsets.right
331 | x += padding
332 | x += titleEdgeInsets.left
333 |
334 | height = contentRect.height
335 | height -= titleEdgeInsets.top
336 | height -= titleEdgeInsets.bottom
337 | height = min(height, titleSize.height)
338 |
339 | width = contentRect.maxX
340 | width -= titleEdgeInsets.right
341 | width -= x
342 |
343 | titleLabel.frame = CGRect(x: x, y: y, width: width, height: height)
344 | //
345 | }
346 |
347 | private func layoutRight(_ imageView: UIImageView, _ titleLabel: UILabel) {
348 | let contentRect = self.contentRect(forBounds: bounds)
349 | let imageSize = imageView.intrinsicContentSize
350 | let titleSize = titleLabel.intrinsicContentSize
351 |
352 | // Compute Title Label Frame
353 | var width = contentRect.width
354 | width -= imageEdgeInsets.left
355 | width -= imageEdgeInsets.right
356 | width -= titleEdgeInsets.left
357 | width -= titleEdgeInsets.right
358 | width -= padding
359 | width -= imageSize.width
360 |
361 | var height = contentRect.height
362 | height -= titleEdgeInsets.top
363 | height -= titleEdgeInsets.bottom
364 | height = min(height, titleSize.height)
365 |
366 | var x = max(contentRect.minX + titleEdgeInsets.left,
367 | contentRect.midX - (imageSize.width + width + padding) / 2)
368 | var y = max(contentRect.minY + titleEdgeInsets.top,
369 | contentRect.midY - height / 2)
370 |
371 | titleLabel.frame = CGRect(x: x, y: y, width: width, height: height)
372 | //
373 |
374 | // Compute Image View Frame
375 | x += width
376 | x += titleEdgeInsets.right
377 | x += padding
378 | x += imageEdgeInsets.left
379 |
380 | y = max(contentRect.minY + imageEdgeInsets.top,
381 | contentRect.midY - imageSize.height / 2)
382 |
383 | width = contentRect.maxX
384 | width -= imageEdgeInsets.left
385 | width -= imageEdgeInsets.right
386 | width = min(width, imageSize.width)
387 |
388 | height = contentRect.height
389 | height -= imageEdgeInsets.top
390 | height -= imageEdgeInsets.bottom
391 | height = min(height, imageSize.height)
392 |
393 | imageView.frame = CGRect(x: x, y: y, width: width, height: height)
394 | //
395 | }
396 |
397 | }
398 |
--------------------------------------------------------------------------------
/MXSegmentedControl/MXSegmentedControl.h:
--------------------------------------------------------------------------------
1 | // MXSegmentedControl.h
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | #import
24 |
25 | //! Project version number for MXSegmentedControl.
26 | FOUNDATION_EXPORT double MXSegmentedControlVersionNumber;
27 |
28 | //! Project version string for MXSegmentedControl.
29 | FOUNDATION_EXPORT const unsigned char MXSegmentedControlVersionString[];
30 |
31 | // In this header, you should import all the public headers of your framework using statements like #import
32 |
33 |
34 |
--------------------------------------------------------------------------------
/MXSegmentedControl/MXSegmentedControl.swift:
--------------------------------------------------------------------------------
1 | // MXSegmentedControl.swift
2 | //
3 | // Copyright (c) 2019 Maxime Epain
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
13 | // all 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
21 | // THE SOFTWARE.
22 |
23 | import UIKit
24 |
25 | /// A MXSegmentedControl object is a horizontal control made of multiple segments, each segment functioning as a button. An indicator shows the current position of the selected segment.
26 | /// A segmented control can display a title (an NSString object), an attributed title (NSAttributedString object) and/or an image (UIImage object).
27 | /// The MXSegmentedControl object automatically resizes segments to fit proportionally within their superview unless they have a specific width set.
28 | ///
29 | /// You can connect a UIScrollView using the `scrollView` property to make the indicator move with the scroll view's contentOffset.
30 | ///
31 | /// You register the target-action methods for a segmented control using the valueChanged constant as shown below.
32 | ///
33 | /// segmentedControl.addTarget(self, action: "action:", forControlEvents: .ValueChanged)
34 | @IBDesignable
35 | @objcMembers
36 | open class MXSegmentedControl: UIControl {
37 |
38 | // MARK: Customizing Appearance
39 |
40 | /// A Boolean value that controls whether the segmented control bounces past the edge of content and back again.
41 | /// If the value of this property is true, the segmented control bounces when it encounters a boundary of the content. Bouncing visually indicates that control has reached an edge of the content. If the value is false, scrolling stops immediately at the content boundary without bouncing. The default value is true.
42 | @IBInspectable public dynamic var bounces: Bool {
43 | get { return _scrollView.bounces }
44 | set { _scrollView.bounces = newValue }
45 | }
46 |
47 | /// The font of the segments.
48 | /// If you are using styled text in iOS 6 or later, assigning a new value to this property causes the font to be applied to the entirety of the string in the attributedText property. If you want to apply the font to only a portion of the text, create a new attributed string with the desired style information and associate it with the segment. If you are not using styled text, this property applies to the entire segments string in the title property.
49 | /// The default value for this property is the system font at a size of 17 points (using the systemFont(ofSize:) class method of UIFont).
50 | @IBInspectable public dynamic var font = UIFont.systemFont(ofSize: 17) {
51 | didSet {
52 | for segment in contentView.segments {
53 | segment.titleLabel?.font = font
54 | }
55 | setNeedsLayout()
56 | }
57 | }
58 |
59 | /// Sets the color of the segments title to use for the normal state.
60 | @IBInspectable public dynamic var textColor: UIColor = .lightGray {
61 | didSet {
62 | for segment in contentView.segments {
63 | segment.setTitleColor(textColor, for: .normal)
64 | }
65 | }
66 | }
67 |
68 | /// Sets the color of the segments title to use for the selected state.
69 | @IBInspectable public dynamic var selectedTextColor: UIColor? {
70 | didSet {
71 | for segment in contentView.segments {
72 | segment.setTitleColor(selectedTextColor, for: .selected)
73 | }
74 | }
75 | }
76 |
77 | /// Sets the width of the segments.
78 | @IBInspectable public var segmentWidth: CGFloat = 0 {
79 | didSet {
80 | for segment in contentView.segments {
81 | segment.width = segmentWidth
82 | }
83 | setNeedsLayout()
84 | }
85 | }
86 |
87 | /// The segmented control content insets
88 | @IBInspectable public dynamic var contentEdgeInsets = UIEdgeInsets.zero
89 |
90 | /// The inset or outset margins for the rectangle surrounding all of the segments' content.
91 | /// Use this property to resize and reposition the effective drawing rectangle for the segments content. The content comprises the segment image and segment title. You can specify a different value for each of the four insets (top, left, bottom, right). A positive value shrinks, or insets, that edge—moving it closer to the center of the segment. A negative value expands, or outsets, that edge. Use the UIEdgeInsets(top:left:bottom:right:) function to construct a value for this property. The default value is UIEdgeInsetsZero.
92 | /// The segments uses this property to determine intrinsicContentSize and sizeThatFits(_:).
93 | @IBInspectable public dynamic var segmentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) {
94 | didSet {
95 | for segment in contentView.segments {
96 | segment.contentEdgeInsets = segmentEdgeInsets
97 | }
98 | setNeedsLayout()
99 | }
100 | }
101 |
102 | /// The segmented control's indicator.
103 | public let indicator = MXIndicator()
104 |
105 | /// The segmented control's separators.
106 | public internal(set) var separators: Separators {
107 | get { return contentView.separators }
108 | set { contentView.separators = newValue }
109 | }
110 |
111 | /// The indicator animation description.
112 | public var animation = Animation(duration: 0.25, delay: 0, dampingRatio: 1, velocity: 0, options: [.beginFromCurrentState, .allowUserInteraction])
113 |
114 | /// The indicator progress.
115 | public var progress: CGFloat = 0 {
116 | didSet { layoutIndicator() }
117 | }
118 |
119 | /// The currently selected segment index.
120 | public private(set) var selectedIndex: Int = 0 {
121 | willSet { contentView.segments[selectedIndex].isSelected = false }
122 | didSet {
123 | sendActions(for: .valueChanged)
124 | contentView.segments[selectedIndex].isSelected = true
125 | }
126 | }
127 |
128 | // MARK: Initializers
129 |
130 | let _scrollView = UIScrollView()
131 | let contentView = ContentView()
132 |
133 | /// :nodoc:
134 | required public init?(coder aDecoder: NSCoder) {
135 | super.init(coder: aDecoder)
136 | initialize()
137 | }
138 |
139 | /// :nodoc:
140 | override public init(frame: CGRect) {
141 | super.init(frame: frame)
142 | initialize()
143 | }
144 |
145 | /// Initializes and returns a newly allocated segmented control object with the specified titles.
146 | ///
147 | /// - Parameter titles: The segments titles.
148 | public convenience init(withTitles titles: [String]) {
149 | self.init(frame: CGRect.zero)
150 | for title in titles {
151 | append(title: title)
152 | }
153 | }
154 |
155 | /// Initializes and returns a newly allocated segmented control object with the specified titles.
156 | ///
157 | /// - Parameter titles: The segments titles.
158 | public convenience init(withAttributedTitles titles: [NSAttributedString]) {
159 | self.init(frame: CGRect.zero)
160 | for title in titles {
161 | append(attributedTitle: title)
162 | }
163 | }
164 |
165 | /// Initializes and returns a newly allocated segmented control object with the specified images.
166 | ///
167 | /// - Parameter images: The segments images.
168 | public convenience init(withImages images: [UIImage]) {
169 | self.init(frame: CGRect.zero)
170 | for image in images {
171 | append(image: image)
172 | }
173 | }
174 |
175 | private func initialize() {
176 | _scrollView.canCancelContentTouches = true
177 | _scrollView.showsVerticalScrollIndicator = false
178 | _scrollView.showsHorizontalScrollIndicator = false
179 |
180 | selectedTextColor = tintColor
181 |
182 | _scrollView.addSubview(indicator)
183 | _scrollView.addSubview(contentView)
184 | addSubview(_scrollView)
185 | }
186 |
187 | deinit {
188 | guard let scrollView = scrollView else { return }
189 | scrollView.removeObserver(self, forKeyPath: keyPath, context: &context)
190 | }
191 |
192 | // MARK: Layout
193 |
194 | /// :nodoc:
195 | open override func layoutSubviews() {
196 | super.layoutSubviews()
197 |
198 | var frame = self.bounds.inset(by: contentEdgeInsets)
199 | _scrollView.frame = frame
200 |
201 | let size = contentView.intrinsicContentSize
202 | if size.width > frame.size.width {
203 | frame.size.width = size.width
204 | }
205 |
206 | contentView.setNeedsLayout()
207 | contentView.frame = frame
208 | contentView.layoutIfNeeded()
209 |
210 | _scrollView.contentSize = frame.size
211 | _scrollView.contentInset = UIEdgeInsets.zero
212 |
213 | layoutIndicator()
214 | }
215 |
216 | private func layoutIndicator() {
217 | guard contentView.segments.count > 0 else {
218 | return
219 | }
220 |
221 | let index = min(Int(progress), contentView.segments.count - 1)
222 | let current = segment(at: index)!
223 |
224 | var frame = CGRect.zero
225 | frame.size.height = bounds.height
226 |
227 | // Compute indicator's position
228 | var x = progress < 0 ? 0 : current.frame.size.width * (progress - CGFloat(index))
229 |
230 | for i in 0.. MXSegment? {
377 | guard index < contentView.segments.count else {
378 | return nil
379 | }
380 | return contentView.segments[index]
381 | }
382 |
383 | /// Counts of segment.
384 | public var count: Int {
385 | return contentView.segments.count
386 | }
387 |
388 | public func newSegment() -> MXSegment {
389 |
390 | let segment = MXSegment()
391 |
392 | segment.setTitleColor(textColor, for: .normal)
393 | segment.setTitleColor(selectedTextColor, for: .selected)
394 | segment.contentEdgeInsets = segmentEdgeInsets
395 | segment.titleLabel?.font = font
396 | segment.isSelected = (contentView.segments.count == selectedIndex)
397 | segment.addTarget(self, action: #selector(MXSegmentedControl.select(segment:)), for: .touchUpInside)
398 |
399 | contentView.append(segment)
400 | return segment
401 | }
402 |
403 | @objc private func select(segment: MXSegment) {
404 | if let index = contentView.segments.index(of: segment) {
405 | select(index: index, animated: true)
406 | }
407 | }
408 |
409 | /// Removes the segment the given index.
410 | ///
411 | /// - Parameter index: The segment index to remove.
412 | public func remove(segmentAt index: Int) {
413 | guard index < contentView.segments.count else {
414 | return
415 | }
416 | contentView.remove( segment(at: index)! )
417 | }
418 |
419 | /// Removes all segments.
420 | public func removeAll() {
421 | for segment in contentView.segments {
422 | contentView.remove(segment)
423 | }
424 | layoutIfNeeded()
425 | }
426 |
427 | /// Creates and append a new segment with the given title.
428 | ///
429 | /// - Parameter title: The new segment title.
430 | @discardableResult public func append(title: String) -> MXSegment {
431 | let segment = newSegment()
432 | segment.setTitle(title, for: .normal)
433 | return segment
434 | }
435 |
436 | /// Creates and append a new segment with the given title.
437 | ///
438 | /// - Parameter title: The new segment title.
439 | @discardableResult public func append(attributedTitle: NSAttributedString) -> MXSegment {
440 | let segment = newSegment()
441 | segment.setAttributedTitle(attributedTitle, for: .normal)
442 | return segment
443 | }
444 |
445 | /// Creates and append a new segment with the given image.
446 | ///
447 | /// - Parameter title: The new segment image.
448 | @discardableResult public func append(image: UIImage?) -> MXSegment {
449 | let segment = newSegment()
450 | segment.setImage(image, for: .normal)
451 | return segment
452 | }
453 |
454 | /// Selects the segment at the given index.
455 | ///
456 | /// - Parameters:
457 | /// - index: The segment index to be selected.
458 | /// - animated: true if the selection should be animated, false if it should be immediate.
459 | public func select(index: Int, animated: Bool) {
460 | selectedIndex = index
461 |
462 | UIView.animate(withDuration: animated ? animation.duration : 0,
463 | delay: animation.delay,
464 | usingSpringWithDamping: animation.dampingRatio,
465 | initialSpringVelocity: animation.velocity,
466 | options: animation.options,
467 | animations: { self.progress = CGFloat(index) })
468 |
469 | if let scrollView = scrollView {
470 | var contentOffset = scrollView.contentOffset
471 | contentOffset.x = CGFloat(index) * scrollView.frame.size.width
472 | scrollView.setContentOffset(contentOffset, animated: animated)
473 | }
474 | }
475 |
476 | }
477 |
478 | // MARK: - Content View
479 |
480 | extension MXSegmentedControl {
481 |
482 | class ContentView: UIView {
483 |
484 | var segments = [MXSegment]()
485 |
486 | var separators = Separators()
487 |
488 | func append(_ segment: MXSegment) {
489 | guard !segments.contains(segment) else {
490 | return
491 | }
492 |
493 | if segments.count > 0 {
494 | let separator = CALayer()
495 | separator.backgroundColor = separators.color.cgColor
496 | layer.addSublayer(separator)
497 | separators.layers.append(separator)
498 | }
499 |
500 | addSubview(segment)
501 | segments.append(segment)
502 |
503 | invalidateIntrinsicContentSize()
504 | layoutIfNeeded()
505 | }
506 |
507 | func remove(_ segment: MXSegment) {
508 | guard var index = segments.index(of: segment) else {
509 | return
510 | }
511 |
512 | segment.removeFromSuperview()
513 | segments.remove(at: index)
514 |
515 | if segments.count > 0 {
516 | index = segments.count - 1
517 | let separator = separators.layers[index]
518 | separator.removeFromSuperlayer()
519 | separators.layers.remove(at: index)
520 | }
521 |
522 | invalidateIntrinsicContentSize()
523 | layoutIfNeeded()
524 | }
525 |
526 | override var intrinsicContentSize: CGSize {
527 | get {
528 | var size = CGSize(width: CGFloat(separators.layers.count) * separators.inset.width, height: UIView.noIntrinsicMetric)
529 | for segment in segments {
530 | size.width += segment.width
531 | size.height = max(segment.intrinsicContentSize.height, size.height)
532 | }
533 | return size
534 | }
535 | }
536 |
537 | override func layoutSubviews() {
538 | super.layoutSubviews()
539 |
540 | let segments = self.segments.sorted(by: { $0.width > $1.width })
541 |
542 | let height = frame.size.height
543 | var width = frame.size.width - CGFloat(separators.layers.count) * separators.inset.width
544 |
545 | for (index, segment) in segments.enumerated() {
546 |
547 | var frame = CGRect.zero
548 | frame.size.width = max(segment.width, width / CGFloat(self.segments.count - index))
549 | frame.size.height = height
550 | segment.layer.frame = frame
551 |
552 | width -= frame.size.width
553 | }
554 |
555 | var separatorFrame = CGRect(x: 0, y: separators.inset.top, width: separators.inset.width, height: height - separators.inset.top - separators.inset.bottom)
556 | for (index, segment) in self.segments.enumerated() {
557 |
558 | if index > 0 {
559 | separators.layers[index - 1].frame = separatorFrame
560 | separatorFrame.origin.x += separators.inset.width
561 | }
562 |
563 | var frame = segment.frame
564 | frame.origin.x = separatorFrame.origin.x
565 | segment.frame = frame
566 | separatorFrame.origin.x += frame.size.width
567 | }
568 | }
569 |
570 | }
571 |
572 | }
573 |
574 | // MARK: - Animation
575 |
576 | extension MXSegmentedControl {
577 |
578 | /// The indicator animation properties.
579 | public struct Animation {
580 |
581 | /// The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them.
582 | public var duration: TimeInterval
583 |
584 | /// The amount of time (measured in seconds) to wait before beginning the animations. Specify a value of 0 to begin the animations immediately.
585 | public var delay: TimeInterval
586 |
587 | /// The damping ratio for the spring animation as it approaches its quiescent state.
588 | /// To smoothly decelerate the animation without oscillation, use a value of 1. Employ a damping ratio closer to zero to increase oscillation.
589 | public var dampingRatio: CGFloat
590 |
591 | /// The initial spring velocity. For smooth start to the animation, match this value to the view’s velocity as it was prior to attachment.
592 | /// A value of 1 corresponds to the total animation distance traversed in one second. For example, if the total animation distance is 200 points and you want the start of the animation to match a view velocity of 100 pt/s, use a value of 0.5.
593 | public var velocity: CGFloat
594 |
595 | /// A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIViewAnimationOptions.
596 | public var options: UIView.AnimationOptions
597 | }
598 |
599 | }
600 |
601 | // MARK: - Separators
602 |
603 | extension MXSegmentedControl {
604 |
605 | /// Segmented control seperators representation.
606 | /// This structure lets you customize the seperator inset as well as the color. You can also customize the seperators layers directly.
607 | public struct Separators {
608 |
609 | /// The seperator inset representation.
610 | public struct Inset {
611 |
612 | /// The seperator inset top value.
613 | public var top: CGFloat
614 |
615 | /// The seperator inset width value.
616 | public var width: CGFloat
617 |
618 | /// The seperator inset bottom value.
619 | public var bottom: CGFloat
620 |
621 | /// Initializes a zero value seperator inset.
622 | public static var zero = Inset(top: 0, width: 0, bottom: 0)
623 |
624 | public init(top: CGFloat, width: CGFloat, bottom: CGFloat) {
625 | self.top = top
626 | self.width = width
627 | self.bottom = bottom
628 | }
629 | }
630 |
631 | /// The separators inset.
632 | public var inset = Inset.zero
633 |
634 | /// The seperators color.
635 | public var color = UIColor.lightGray
636 |
637 | /// The separators layers.
638 | public internal(set) var layers = [CALayer]()
639 | }
640 |
641 | }
642 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "MXSegmentedControl",
6 | platforms: [.iOS(.v8)],
7 | products: [
8 | .library(name: "MXSegmentedControl",
9 | targets: ["MXSegmentedControl"])
10 | ],
11 | targets: [
12 | .target(
13 | name: "MXSegmentedControl",
14 | path: "MXSegmentedControl"
15 | )
16 | ],
17 | swiftLanguageVersions: [.v5,.v4_2]
18 | )
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MXSegmentedControl
2 |
3 | [](https://travis-ci.org/maxep/MXSegmentedControl)
4 | [](http://cocoadocs.org/docsets/MXSegmentedControl)
5 | [](https://github.com/Carthage/Carthage)
6 | [](http://cocoadocs.org/docsets/MXSegmentedControl)
7 | [](http://cocoadocs.org/docsets/MXSegmentedControl)
8 |
9 | Yet another segmented control for iOS inspired by [Segmentio](https://github.com/Yalantis/Segmentio) & [HMSegmentedPager](https://github.com/HeshamMegid/HMSegmentedControl).
10 | MXSegmentedControl is easy to integrate and very customizable. It dynamically computes the segments width to fit or fill its content, it can also track a UIScrollView content offset to change segment.
11 |
12 |
13 |
14 |
15 |
16 | ## Installation
17 |
18 | MXSegmentedControl is available through [CocoaPods](https://cocoapods.org/pods/MXSegmentedControl). To install
19 | it, simply add the following line to your Podfile:
20 |
21 | ```
22 | pod 'MXSegmentedControl'
23 | ```
24 |
25 | ## Usage
26 |
27 | + You can configure a simple segmented control like following:
28 |
29 | ```swift
30 | segmentedControl.append(title: "First")
31 | segmentedControl.append(title: "Second")
32 | segmentedControl.append(title: "Third")
33 | ```
34 |
35 | ## Author
36 |
37 | [Maxime Epain](http://maxep.me)
38 |
39 | ## License
40 |
41 | MXSegmentedControl is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
42 |
--------------------------------------------------------------------------------
/screencast.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxep/MXSegmentedControl/eab7a95c36cbbddc15ef7fb2ce7be28ef56fc218/screencast.gif
--------------------------------------------------------------------------------