├── .DS_Store
├── 未命名.gif
├── Demo
├── .DS_Store
├── SPMultipleSwitch
│ ├── tracker.png
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── SPMultipleSwitch
│ │ ├── SPMultipleSwitch.h
│ │ └── SPMultipleSwitch.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── AppDelegate.m
│ └── ViewController.m
├── SPMultipleSwitch.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcuserdata
│ │ │ └── leshengping.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcuserdata
│ │ └── leshengping.xcuserdatad
│ │ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── project.pbxproj
├── SPMultipleSwitchTests
│ ├── Info.plist
│ └── SPMultipleSwitchTests.m
└── SPMultipleSwitchUITests
│ ├── Info.plist
│ └── SPMultipleSwitchUITests.m
├── SPMultipleSwitch
├── SPMultipleSwitch.h
└── SPMultipleSwitch.m
├── README.md
└── SPMultipleSwitch.podspec
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SPStore/SPMultipleSwitch/HEAD/.DS_Store
--------------------------------------------------------------------------------
/未命名.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SPStore/SPMultipleSwitch/HEAD/未命名.gif
--------------------------------------------------------------------------------
/Demo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SPStore/SPMultipleSwitch/HEAD/Demo/.DS_Store
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/tracker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SPStore/SPMultipleSwitch/HEAD/Demo/SPMultipleSwitch/tracker.png
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SPStore/SPMultipleSwitch/HEAD/Demo/SPMultipleSwitch.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // SPMultipleSwitch
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // SPMultipleSwitch
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch.xcodeproj/xcuserdata/leshengping.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SPMultipleSwitch.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitchTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitchUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SPMultipleSwitch/SPMultipleSwitch.h:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitch.h
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SPMultipleSwitch : UIControl
14 |
15 | - (instancetype)initWithItems:(NSArray *)items;
16 |
17 | @property(nonatomic) NSInteger selectedSegmentIndex;
18 |
19 | @property (nonatomic, strong) UIColor *titleColor;
20 | @property (nonatomic, strong) UIColor *selectedTitleColor;
21 |
22 | @property (nonatomic, strong) UIFont *titleFont;
23 |
24 | @property (nonatomic, assign) CGFloat spacing; // label之间的间距
25 | @property (nonatomic, assign) CGFloat contentInset; // 内容内宿边距
26 |
27 | @property (nonatomic, copy) UIColor *trackerColor; // 滑块的颜色
28 | @property (nonatomic, copy) UIImage *trackerImage; // 滑块的图片
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/SPMultipleSwitch/SPMultipleSwitch.h:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitch.h
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SPMultipleSwitch : UIControl
14 |
15 | - (instancetype)initWithItems:(NSArray *)items;
16 |
17 | @property(nonatomic) NSInteger selectedSegmentIndex;
18 |
19 | @property (nonatomic, strong) UIColor *titleColor;
20 | @property (nonatomic, strong) UIColor *selectedTitleColor;
21 |
22 | @property (nonatomic, strong) UIFont *titleFont;
23 |
24 | @property (nonatomic, assign) CGFloat spacing; // label之间的间距
25 | @property (nonatomic, assign) CGFloat contentInset; // 内容内宿边距
26 |
27 | @property (nonatomic, copy) UIColor *trackerColor; // 滑块的颜色
28 | @property (nonatomic, copy) UIImage *trackerImage; // 滑块的图片
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitchTests/SPMultipleSwitchTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitchTests.m
3 | // SPMultipleSwitchTests
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SPMultipleSwitchTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation SPMultipleSwitchTests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 | }
20 |
21 | - (void)tearDown {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | - (void)testExample {
26 | // This is an example of a functional test case.
27 | // Use XCTAssert and related functions to verify your tests produce the correct results.
28 | }
29 |
30 | - (void)testPerformanceExample {
31 | // This is an example of a performance test case.
32 | [self measureBlock:^{
33 | // Put the code you want to measure the time of here.
34 | }];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SPMultipleSwitch
2 |
3 | 
4 |
5 | ## CocoaPods
6 | ```
7 | pod "SPMultipleSwitch", "~> 1.0"
8 | ```
9 |
10 | ## Use
11 | ```
12 | SPMultipleSwitch *multipleSwitch = [[SPMultipleSwitch alloc] initWithItems:@[@"Feed",@"Leaderboard"]];
13 | multipleSwitch.frame = CGRectMake(30, 100, ScreenW-60, 40);
14 | multipleSwitch.backgroundColor = [UIColor orangeColor];
15 | multipleSwitch.selectedTitleColor = [UIColor orangeColor];
16 | multipleSwitch.titleColor = [UIColor whiteColor];
17 | multipleSwitch.trackerColor = [UIColor whiteColor];
18 | multipleSwitch.contentInset = 5;
19 | multipleSwitch.spacing = 10;
20 | multipleSwitch.titleFont = [UIFont boldSystemFontOfSize:17];
21 | multipleSwitch.trackerColor = [UIColor whiteColor];
22 | [multipleSwitch addTarget:self action:@selector(multipleSwitchAction:) forControlEvents:UIControlEventTouchUpInside];
23 | [self.view addSubview:multipleSwitch];
24 | ```
25 | ## Swift版
26 | [DGRunkeeperSwitch](https://github.com/gontovnik/DGRunkeeperSwitch)
27 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitchUITests/SPMultipleSwitchUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitchUITests.m
3 | // SPMultipleSwitchUITests
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SPMultipleSwitchUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation SPMultipleSwitchUITests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 |
20 | // In UI tests it is usually best to stop immediately when a failure occurs.
21 | self.continueAfterFailure = NO;
22 |
23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
24 | [[[XCUIApplication alloc] init] launch];
25 |
26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
27 | }
28 |
29 | - (void)tearDown {
30 | // Put teardown code here. This method is called after the invocation of each test method in the class.
31 | }
32 |
33 | - (void)testExample {
34 | // Use recording to get started writing UI tests.
35 | // Use XCTAssert and related functions to verify your tests produce the correct results.
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/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 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/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" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // SPMultipleSwitch
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // 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.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // 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.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/29.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "SPMultipleSwitch.h"
11 |
12 | @interface ViewController ()
13 |
14 | @end
15 |
16 | @implementation ViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | CGFloat ScreenW = [UIScreen mainScreen].bounds.size.width;
22 |
23 | SPMultipleSwitch *switch1 = [[SPMultipleSwitch alloc] initWithItems:@[@"Weekly",@"Monthly"]];
24 | switch1.frame = CGRectMake(0, 0, 180, 30);
25 | [switch1 addTarget:self action:@selector(switchAction1:) forControlEvents:UIControlEventTouchUpInside];
26 | switch1.layer.borderWidth = 1 / [UIScreen mainScreen].scale;
27 | switch1.layer.borderColor = [UIColor whiteColor].CGColor;
28 | switch1.selectedTitleColor = [UIColor redColor];
29 | switch1.titleColor = [UIColor whiteColor];
30 | switch1.trackerColor = [UIColor whiteColor];
31 | self.navigationItem.titleView = switch1;
32 |
33 | SPMultipleSwitch *switch2 = [[SPMultipleSwitch alloc] initWithItems:@[@"Feed",@"Leaderboard"]];
34 | switch2.frame = CGRectMake(30, 100, ScreenW-60, 40);
35 | switch2.backgroundColor = [UIColor orangeColor];
36 | switch2.selectedTitleColor = [UIColor orangeColor];
37 | switch2.titleColor = [UIColor whiteColor];
38 | switch2.trackerColor = [UIColor whiteColor];
39 | switch2.contentInset = 5;
40 | switch2.spacing = 10;
41 | switch2.titleFont = [UIFont boldSystemFontOfSize:17];
42 | switch2.trackerColor = [UIColor whiteColor];
43 | [switch2 addTarget:self action:@selector(switchAction2:) forControlEvents:UIControlEventTouchUpInside];
44 | [self.view addSubview:switch2];
45 |
46 | SPMultipleSwitch *switch3 = [[SPMultipleSwitch alloc] initWithItems:@[@"私信",@"评论",@"@我",@"通知"]];
47 | switch3.frame = CGRectMake(15, 180, ScreenW-30, 50);
48 | switch3.backgroundColor = [UIColor colorWithRed:31.0/255.0 green:191.0/255.0 blue:81.0/255.0 alpha:1];
49 | switch3.selectedTitleColor = [UIColor colorWithRed:31.0/255.0 green:191.0/255.0 blue:81.0/255.0 alpha:1];
50 | switch3.titleColor = [UIColor whiteColor];
51 | switch3.trackerColor = [UIColor whiteColor];
52 | switch3.contentInset = 5;
53 | switch3.spacing = 10;
54 | switch3.trackerImage = [UIImage imageNamed:@"tracker"];
55 | [switch3 addTarget:self action:@selector(switchAction3:) forControlEvents:UIControlEventTouchUpInside];
56 | [self.view addSubview:switch3];
57 | }
58 |
59 | - (void)switchAction1:(SPMultipleSwitch *)multipleSwitch {
60 | NSLog(@"点击了第%zd个",multipleSwitch.selectedSegmentIndex);
61 | }
62 |
63 | - (void)switchAction2:(SPMultipleSwitch *)multipleSwitch {
64 | NSLog(@"点击了第%zd个",multipleSwitch.selectedSegmentIndex);
65 | }
66 |
67 | - (void)switchAction3:(SPMultipleSwitch *)multipleSwitch {
68 | NSLog(@"点击了第%zd个",multipleSwitch.selectedSegmentIndex);
69 | }
70 | @end
71 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/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 |
--------------------------------------------------------------------------------
/SPMultipleSwitch.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint SPMultipleSwitch.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see https://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |spec|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | spec.name = "SPMultipleSwitch"
19 | spec.version = "1.0"
20 | spec.summary = "一个分段选择器"
21 |
22 | # This description is used to generate tags and improve search results.
23 | # * Think: What does it do? Why did you write it? What is the focus?
24 | # * Try to keep it short, snappy and to the point.
25 | # * Write the description between the DESC delimiters below.
26 | # * Finally, don't worry about the indent, CocoaPods strips it!
27 | spec.description = <<-DESC
28 | 这是一个分段选择器
29 | DESC
30 |
31 | spec.homepage = "https://github.com/SPStore/SPMultipleSwitch"
32 | # spec.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
33 |
34 |
35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
36 | #
37 | # Licensing your code is important. See https://choosealicense.com for more info.
38 | # CocoaPods will detect a license file if there is a named LICENSE*
39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
40 | #
41 |
42 | spec.license = "MIT"
43 | # spec.license = { :type => "MIT", :file => "FILE_LICENSE" }
44 |
45 |
46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
47 | #
48 | # Specify the authors of the library, with email addresses. Email addresses
49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
50 | # accepts just a name if you'd rather not provide an email address.
51 | #
52 | # Specify a social_media_url where others can refer to, for example a twitter
53 | # profile URL.
54 | #
55 |
56 | spec.author = { "SPStore" => "lesp163@163.com" }
57 | # Or just: spec.author = "乐升平"
58 | # spec.authors = { "乐升平" => "lesp163@163.com" }
59 | # spec.social_media_url = "https://twitter.com/乐升平"
60 |
61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
62 | #
63 | # If this Pod runs only on iOS or OS X, then specify the platform and
64 | # the deployment target. You can optionally include the target after the platform.
65 | #
66 |
67 | spec.platform = :ios
68 | spec.platform = :ios, "5.0"
69 |
70 | # When using multiple platforms
71 | spec.ios.deployment_target = "5.0"
72 | # spec.osx.deployment_target = "10.7"
73 | # spec.watchos.deployment_target = "2.0"
74 | # spec.tvos.deployment_target = "9.0"
75 |
76 |
77 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
78 | #
79 | # Specify the location from where the source should be retrieved.
80 | # Supports git, hg, bzr, svn and HTTP.
81 | #
82 |
83 | spec.source = { :git => "https://github.com/SPStore/SPMultipleSwitch.git", :tag => spec.version }
84 |
85 |
86 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
87 | #
88 | # CocoaPods is smart about how it includes source code. For source files
89 | # giving a folder will include any swift, h, m, mm, c & cpp files.
90 | # For header files it will include any header in the folder.
91 | # Not including the public_header_files will make all headers public.
92 | #
93 |
94 | spec.source_files = "SPMultipleSwitch"
95 | spec.exclude_files = "Classes/Exclude"
96 |
97 | # spec.public_header_files = "Classes/**/*.h"
98 |
99 |
100 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
101 | #
102 | # A list of resources included with the Pod. These are copied into the
103 | # target bundle with a build phase script. Anything else will be cleaned.
104 | # You can preserve files from being cleaned, please don't preserve
105 | # non-essential files like tests, examples and documentation.
106 | #
107 |
108 | # spec.resource = "icon.png"
109 | # spec.resources = "Resources/*.png"
110 |
111 | # spec.preserve_paths = "FilesToSave", "MoreFilesToSave"
112 |
113 |
114 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
115 | #
116 | # Link your library with frameworks, or libraries. Libraries do not include
117 | # the lib prefix of their name.
118 | #
119 |
120 | # spec.framework = "SomeFramework"
121 | # spec.frameworks = "SomeFramework", "AnotherFramework"
122 |
123 | # spec.library = "iconv"
124 | # spec.libraries = "iconv", "xml2"
125 |
126 |
127 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
128 | #
129 | # If your library depends on compiler flags you can set them in the xcconfig hash
130 | # where they will only apply to your library. If you depend on other Podspecs
131 | # you can include multiple dependencies to ensure it works.
132 |
133 | # spec.requires_arc = true
134 |
135 | # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
136 | # spec.dependency "JSONKit", "~> 1.4"
137 |
138 | end
139 |
--------------------------------------------------------------------------------
/SPMultipleSwitch/SPMultipleSwitch.m:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitch.m
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/28.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import "SPMultipleSwitch.h"
10 |
11 | @interface SPMultipleSwitchLayer : CALayer
12 |
13 | @end
14 |
15 | @implementation SPMultipleSwitchLayer
16 | - (instancetype)init {
17 | if (self = [super init]) {
18 | self.masksToBounds = YES;
19 | }
20 | return self;
21 | }
22 |
23 | - (void)setFrame:(CGRect)frame {
24 | [super setFrame:frame];
25 | self.cornerRadius = frame.size.height/2.0;
26 | }
27 |
28 | - (void)setCornerRadius:(CGFloat)cornerRadius {
29 | [super setCornerRadius:self.bounds.size.height/2.0];
30 | }
31 |
32 | + (Class)layerClass{
33 | return [SPMultipleSwitchLayer class];
34 | }
35 |
36 | @end
37 |
38 | @interface SPMultipleSwitch()
39 | @property (nonatomic, strong) UIView *labelContentView;
40 | @property (nonatomic, strong) UIView *selectedLabelContentView;
41 | @property (nonatomic, strong) UIImageView *tracker;
42 | @property (nonatomic, strong) NSMutableArray *labels;
43 | @property (nonatomic, strong) NSMutableArray *selectedLabels;
44 | @property (nonatomic, strong) UIView *maskTracker;
45 | @property (nonatomic, assign) CGPoint beginPoint;
46 | @end
47 |
48 | @implementation SPMultipleSwitch
49 |
50 | + (Class)layerClass{
51 | return [SPMultipleSwitchLayer class];
52 | }
53 |
54 | - (instancetype)initWithItems:(NSArray *)items {
55 | if (self = [self init]) {
56 |
57 | // 创建子控件
58 | [self setupSubviewsWithItems:items];
59 |
60 | [self.tracker addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
61 |
62 | }
63 | return self;
64 | }
65 |
66 | - (instancetype)init {
67 | if (self = [super init]) {
68 | _titleFont = [UIFont systemFontOfSize:17];
69 | _titleColor = [UIColor redColor];
70 | _selectedTitleColor = [UIColor whiteColor];
71 | }
72 | return self;
73 | }
74 |
75 | #pragma mark - KVO
76 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
77 | if (object == self.tracker) {
78 | if ([keyPath isEqualToString:@"frame"]) {
79 | self.maskTracker.frame = self.tracker.frame;
80 | }
81 | } else {
82 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
83 | }
84 | }
85 |
86 | #pragma mark - UIControl Override
87 |
88 | - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
89 | [super beginTrackingWithTouch:touch withEvent:event];
90 | _beginPoint = [touch locationInView:self];
91 | NSInteger index = [self indexForPoint:_beginPoint];
92 | self.selectedSegmentIndex = index;
93 | return YES;
94 | }
95 |
96 | - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
97 | [super continueTrackingWithTouch:touch withEvent:event];
98 |
99 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
100 |
101 | CGPoint currentPoint = [touch locationInView:self];
102 | CGFloat diff = currentPoint.x - _beginPoint.x;
103 | CGRect trackerFrame = self.tracker.frame;
104 | trackerFrame.origin.x += diff;
105 | trackerFrame.origin.x = MAX(MIN(CGRectGetMinX(trackerFrame),contentRect.size.width - trackerFrame.size.width), 0);
106 | self.tracker.frame = trackerFrame;
107 | _beginPoint = currentPoint;
108 |
109 | [self sendActionsForControlEvents:UIControlEventValueChanged];
110 | return YES;
111 | }
112 |
113 | - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
114 | [super endTrackingWithTouch:touch withEvent:event];
115 | NSInteger index = [self indexForPoint:self.tracker.center];
116 | self.selectedSegmentIndex = index;
117 | }
118 |
119 | - (void)cancelTrackingWithEvent:(UIEvent *)event {
120 | [super cancelTrackingWithEvent:event];
121 | NSInteger index = [self indexForPoint:self.tracker.center];
122 | self.selectedSegmentIndex = index;
123 | }
124 |
125 | // 根据一个点,取出离该点最近的label对应的index
126 | - (NSInteger)indexForPoint:(CGPoint)point {
127 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
128 | NSInteger index = MAX(0, MIN(_labels.count - 1, point.x / (contentRect.size.width / (CGFloat)(_labels.count))));
129 | return index;
130 | }
131 |
132 | #pragma mark - setter
133 |
134 | - (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex {
135 | _selectedSegmentIndex = MAX(0, MIN(selectedSegmentIndex, _labels.count-1));
136 | UILabel *label = _labels[_selectedSegmentIndex];
137 | CGPoint trackerCenter = self.tracker.center;
138 | trackerCenter.x = label.center.x;
139 | self.tracker.center = trackerCenter;
140 | // 这行代码主要是为了走一遍KVO监听的方法
141 | self.tracker.frame = self.tracker.frame;
142 | }
143 |
144 | - (void)setContentInset:(CGFloat)contentInset {
145 | _contentInset = contentInset;
146 | [self setNeedsLayout];
147 | [self layoutIfNeeded];
148 | }
149 |
150 | - (void)setSpacing:(CGFloat)spacing {
151 | _spacing = spacing;
152 | [self setNeedsLayout];
153 | [self layoutIfNeeded];
154 | }
155 |
156 | - (void)setTrackerColor:(UIColor *)trackerColor {
157 | _trackerColor = trackerColor;
158 | self.tracker.backgroundColor = _trackerColor;
159 | }
160 |
161 | - (void)setTrackerImage:(UIImage *)trackerImage {
162 | _trackerImage = trackerImage;
163 | self.tracker.image = _trackerImage;
164 | }
165 |
166 | - (void)setTitleColor:(UIColor *)titleColor {
167 | _titleColor = titleColor;
168 | [_labels setValue:_titleColor forKeyPath:@"textColor"];
169 | }
170 |
171 | - (void)setSelectedTitleColor:(UIColor *)selectedTitleColor {
172 | _selectedTitleColor = selectedTitleColor;
173 | [_selectedLabels setValue:_selectedTitleColor forKeyPath:@"textColor"];
174 | }
175 |
176 | - (void)setTitleFont:(UIFont *)titleFont {
177 | _titleFont = titleFont;
178 | [_labels setValue:_titleFont forKeyPath:@"font"];
179 | [_selectedLabels setValue:_titleFont forKeyPath:@"font"];
180 | }
181 |
182 | #pragma mark - 添加子控件
183 |
184 | - (void)setupSubviewsWithItems:(NSArray *)items {
185 |
186 | self.labels = [NSMutableArray array];
187 | self.selectedLabels = [NSMutableArray array];
188 |
189 | // 第一层
190 | {
191 | UIView *labelContentView = [[UIView alloc] init];
192 | labelContentView.userInteractionEnabled = NO;
193 | labelContentView.layer.masksToBounds = YES;
194 | [self addSubview:labelContentView];
195 | _labelContentView = labelContentView;
196 |
197 | for (int i = 0; i < items.count; i++) {
198 | UILabel *label = [[UILabel alloc] init];
199 | label.textAlignment = NSTextAlignmentCenter;
200 | label.text = items[i];
201 | label.textColor = [UIColor blackColor];
202 | [labelContentView addSubview:label];
203 | [self.labels addObject:label];
204 | }
205 | UIImageView *tracker = [[UIImageView alloc] init];
206 | tracker.userInteractionEnabled = NO;
207 | tracker.layer.masksToBounds = YES;
208 | tracker.backgroundColor = [UIColor redColor];
209 | [labelContentView addSubview:tracker];
210 | _tracker = tracker;
211 | }
212 | // 第二层
213 | {
214 | UIView *selectedLabelContentView = [[UIView alloc] init];
215 | selectedLabelContentView.userInteractionEnabled = NO;
216 | selectedLabelContentView.layer.masksToBounds = YES;
217 | [self addSubview:selectedLabelContentView];
218 | _selectedLabelContentView = selectedLabelContentView;
219 |
220 | for (int i = 0; i < items.count; i++) {
221 | UILabel *label = [[UILabel alloc] init];
222 | label.textAlignment = NSTextAlignmentCenter;
223 | label.text = items[i];
224 | label.textColor = [UIColor whiteColor];
225 | [selectedLabelContentView addSubview:label];
226 | [self.selectedLabels addObject:label];
227 | }
228 | UIView *maskTracker = [[UIView alloc] init];
229 | maskTracker.userInteractionEnabled = NO;
230 | maskTracker.backgroundColor = [UIColor redColor];
231 | _maskTracker = maskTracker;
232 |
233 | // 设置selectedLabelContentView的maskView,stackView是UIView的非渲染型子类,它无法设置backgroundColor,maskView等属性
234 | _selectedLabelContentView.maskView = maskTracker;
235 | }
236 | }
237 |
238 | - (void)layoutSubviews {
239 | [super layoutSubviews];
240 |
241 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
242 | self.labelContentView.frame = contentRect;
243 | self.selectedLabelContentView.frame = contentRect;
244 | self.labelContentView.layer.cornerRadius = contentRect.size.height / 2.0;
245 | self.selectedLabelContentView.layer.cornerRadius = contentRect.size.height / 2.0;
246 |
247 | CGFloat labelW = (contentRect.size.width - _spacing * self.labels.count) / self.labels.count;
248 | [self.labels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
249 | label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing) , 0, labelW, contentRect.size.height);
250 | }];
251 | [self.selectedLabels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
252 | label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing), 0, labelW, contentRect.size.height);
253 | }];
254 |
255 | CGFloat averageWidth = contentRect.size.width / self.labels.count;
256 | self.tracker.frame = CGRectMake(_selectedSegmentIndex * averageWidth, 0, averageWidth, contentRect.size.height);
257 | self.tracker.layer.cornerRadius = contentRect.size.height / 2.0;
258 | self.maskTracker.layer.cornerRadius = contentRect.size.height / 2.0;
259 | }
260 |
261 | - (void)dealloc {
262 | [self.tracker removeObserver:self forKeyPath:@"frame"];
263 | }
264 |
265 | @end
266 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch/SPMultipleSwitch/SPMultipleSwitch.m:
--------------------------------------------------------------------------------
1 | //
2 | // SPMultipleSwitch.m
3 | // SPSegment
4 | //
5 | // Created by 乐升平 on 2018/12/28.
6 | // Copyright © 2018 乐升平. All rights reserved.
7 | //
8 |
9 | #import "SPMultipleSwitch.h"
10 |
11 | @interface SPMultipleSwitchLayer : CALayer
12 |
13 | @end
14 |
15 | @implementation SPMultipleSwitchLayer
16 | - (instancetype)init {
17 | if (self = [super init]) {
18 | self.masksToBounds = YES;
19 | }
20 | return self;
21 | }
22 |
23 | - (void)setFrame:(CGRect)frame {
24 | [super setFrame:frame];
25 | self.cornerRadius = frame.size.height/2.0;
26 | }
27 |
28 | - (void)setCornerRadius:(CGFloat)cornerRadius {
29 | [super setCornerRadius:self.bounds.size.height/2.0];
30 | }
31 |
32 | + (Class)layerClass{
33 | return [SPMultipleSwitchLayer class];
34 | }
35 |
36 | @end
37 |
38 | @interface SPMultipleSwitch()
39 | @property (nonatomic, strong) UIView *labelContentView;
40 | @property (nonatomic, strong) UIView *selectedLabelContentView;
41 | @property (nonatomic, strong) UIImageView *tracker;
42 | @property (nonatomic, strong) NSMutableArray *labels;
43 | @property (nonatomic, strong) NSMutableArray *selectedLabels;
44 | @property (nonatomic, strong) UIView *maskTracker;
45 | @property (nonatomic, assign) CGPoint beginPoint;
46 | @end
47 |
48 | @implementation SPMultipleSwitch
49 |
50 | + (Class)layerClass{
51 | return [SPMultipleSwitchLayer class];
52 | }
53 |
54 | - (instancetype)initWithItems:(NSArray *)items {
55 | if (self = [self init]) {
56 |
57 | // 创建子控件
58 | [self setupSubviewsWithItems:items];
59 |
60 | [self.tracker addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
61 |
62 | }
63 | return self;
64 | }
65 |
66 | - (instancetype)init {
67 | if (self = [super init]) {
68 | _titleFont = [UIFont systemFontOfSize:17];
69 | _titleColor = [UIColor redColor];
70 | _selectedTitleColor = [UIColor whiteColor];
71 | }
72 | return self;
73 | }
74 |
75 | #pragma mark - KVO
76 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
77 | if (object == self.tracker) {
78 | if ([keyPath isEqualToString:@"frame"]) {
79 | self.maskTracker.frame = self.tracker.frame;
80 | }
81 | } else {
82 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
83 | }
84 | }
85 |
86 | #pragma mark - UIControl Override
87 |
88 | - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
89 | [super beginTrackingWithTouch:touch withEvent:event];
90 | _beginPoint = [touch locationInView:self];
91 | NSInteger index = [self indexForPoint:_beginPoint];
92 | self.selectedSegmentIndex = index;
93 | return YES;
94 | }
95 |
96 | - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
97 | [super continueTrackingWithTouch:touch withEvent:event];
98 |
99 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
100 |
101 | CGPoint currentPoint = [touch locationInView:self];
102 | CGFloat diff = currentPoint.x - _beginPoint.x;
103 | CGRect trackerFrame = self.tracker.frame;
104 | trackerFrame.origin.x += diff;
105 | trackerFrame.origin.x = MAX(MIN(CGRectGetMinX(trackerFrame),contentRect.size.width - trackerFrame.size.width), 0);
106 | self.tracker.frame = trackerFrame;
107 | _beginPoint = currentPoint;
108 |
109 | [self sendActionsForControlEvents:UIControlEventValueChanged];
110 | return YES;
111 | }
112 |
113 | - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
114 | [super endTrackingWithTouch:touch withEvent:event];
115 | NSInteger index = [self indexForPoint:self.tracker.center];
116 | self.selectedSegmentIndex = index;
117 | }
118 |
119 | - (void)cancelTrackingWithEvent:(UIEvent *)event {
120 | [super cancelTrackingWithEvent:event];
121 | NSInteger index = [self indexForPoint:self.tracker.center];
122 | self.selectedSegmentIndex = index;
123 | }
124 |
125 | // 根据一个点,取出离该点最近的label对应的index
126 | - (NSInteger)indexForPoint:(CGPoint)point {
127 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
128 | NSInteger index = MAX(0, MIN(_labels.count - 1, point.x / (contentRect.size.width / (CGFloat)(_labels.count))));
129 | return index;
130 | }
131 |
132 | #pragma mark - setter
133 |
134 | - (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex {
135 | _selectedSegmentIndex = MAX(0, MIN(selectedSegmentIndex, _labels.count-1));
136 | UILabel *label = _labels[_selectedSegmentIndex];
137 | CGPoint trackerCenter = self.tracker.center;
138 | trackerCenter.x = label.center.x;
139 | self.tracker.center = trackerCenter;
140 | // 这行代码主要是为了走一遍KVO监听的方法
141 | self.tracker.frame = self.tracker.frame;
142 | }
143 |
144 | - (void)setContentInset:(CGFloat)contentInset {
145 | _contentInset = contentInset;
146 | [self setNeedsLayout];
147 | [self layoutIfNeeded];
148 | }
149 |
150 | - (void)setSpacing:(CGFloat)spacing {
151 | _spacing = spacing;
152 | [self setNeedsLayout];
153 | [self layoutIfNeeded];
154 | }
155 |
156 | - (void)setTrackerColor:(UIColor *)trackerColor {
157 | _trackerColor = trackerColor;
158 | self.tracker.backgroundColor = _trackerColor;
159 | }
160 |
161 | - (void)setTrackerImage:(UIImage *)trackerImage {
162 | _trackerImage = trackerImage;
163 | self.tracker.image = _trackerImage;
164 | }
165 |
166 | - (void)setTitleColor:(UIColor *)titleColor {
167 | _titleColor = titleColor;
168 | [_labels setValue:_titleColor forKeyPath:@"textColor"];
169 | }
170 |
171 | - (void)setSelectedTitleColor:(UIColor *)selectedTitleColor {
172 | _selectedTitleColor = selectedTitleColor;
173 | [_selectedLabels setValue:_selectedTitleColor forKeyPath:@"textColor"];
174 | }
175 |
176 | - (void)setTitleFont:(UIFont *)titleFont {
177 | _titleFont = titleFont;
178 | [_labels setValue:_titleFont forKeyPath:@"font"];
179 | [_selectedLabels setValue:_titleFont forKeyPath:@"font"];
180 | }
181 |
182 | #pragma mark - 添加子控件
183 |
184 | - (void)setupSubviewsWithItems:(NSArray *)items {
185 |
186 | self.labels = [NSMutableArray array];
187 | self.selectedLabels = [NSMutableArray array];
188 |
189 | // 第一层
190 | {
191 | UIView *labelContentView = [[UIView alloc] init];
192 | labelContentView.userInteractionEnabled = NO;
193 | labelContentView.layer.masksToBounds = YES;
194 | [self addSubview:labelContentView];
195 | _labelContentView = labelContentView;
196 |
197 | for (int i = 0; i < items.count; i++) {
198 | UILabel *label = [[UILabel alloc] init];
199 | label.textAlignment = NSTextAlignmentCenter;
200 | label.text = items[i];
201 | label.textColor = [UIColor blackColor];
202 | [labelContentView addSubview:label];
203 | [self.labels addObject:label];
204 | }
205 | UIImageView *tracker = [[UIImageView alloc] init];
206 | tracker.userInteractionEnabled = NO;
207 | tracker.layer.masksToBounds = YES;
208 | tracker.backgroundColor = [UIColor redColor];
209 | [labelContentView addSubview:tracker];
210 | _tracker = tracker;
211 | }
212 | // 第二层
213 | {
214 | UIView *selectedLabelContentView = [[UIView alloc] init];
215 | selectedLabelContentView.userInteractionEnabled = NO;
216 | selectedLabelContentView.layer.masksToBounds = YES;
217 | [self addSubview:selectedLabelContentView];
218 | _selectedLabelContentView = selectedLabelContentView;
219 |
220 | for (int i = 0; i < items.count; i++) {
221 | UILabel *label = [[UILabel alloc] init];
222 | label.textAlignment = NSTextAlignmentCenter;
223 | label.text = items[i];
224 | label.textColor = [UIColor whiteColor];
225 | [selectedLabelContentView addSubview:label];
226 | [self.selectedLabels addObject:label];
227 | }
228 | UIView *maskTracker = [[UIView alloc] init];
229 | maskTracker.userInteractionEnabled = NO;
230 | maskTracker.backgroundColor = [UIColor redColor];
231 | _maskTracker = maskTracker;
232 |
233 | // 设置selectedLabelContentView的maskView,stackView是UIView的非渲染型子类,它无法设置backgroundColor,maskView等属性
234 | _selectedLabelContentView.maskView = maskTracker;
235 | }
236 | }
237 |
238 | - (void)layoutSubviews {
239 | [super layoutSubviews];
240 |
241 | CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
242 | self.labelContentView.frame = contentRect;
243 | self.selectedLabelContentView.frame = contentRect;
244 | self.labelContentView.layer.cornerRadius = contentRect.size.height / 2.0;
245 | self.selectedLabelContentView.layer.cornerRadius = contentRect.size.height / 2.0;
246 |
247 | CGFloat labelW = (contentRect.size.width - _spacing * self.labels.count) / self.labels.count;
248 | [self.labels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
249 | label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing) , 0, labelW, contentRect.size.height);
250 | }];
251 | [self.selectedLabels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
252 | label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing), 0, labelW, contentRect.size.height);
253 | }];
254 |
255 | CGFloat averageWidth = contentRect.size.width / self.labels.count;
256 | self.tracker.frame = CGRectMake(_selectedSegmentIndex * averageWidth, 0, averageWidth, contentRect.size.height);
257 | self.tracker.layer.cornerRadius = contentRect.size.height / 2.0;
258 | self.maskTracker.layer.cornerRadius = contentRect.size.height / 2.0;
259 | }
260 |
261 | - (void)dealloc {
262 | [self.tracker removeObserver:self forKeyPath:@"frame"];
263 | }
264 |
265 | @end
266 |
--------------------------------------------------------------------------------
/Demo/SPMultipleSwitch.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 52FA602E21D750A900936C9E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA602D21D750A900936C9E /* AppDelegate.m */; };
11 | 52FA603121D750A900936C9E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA603021D750A900936C9E /* ViewController.m */; };
12 | 52FA603421D750A900936C9E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52FA603221D750A900936C9E /* Main.storyboard */; };
13 | 52FA603621D750AC00936C9E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52FA603521D750AC00936C9E /* Assets.xcassets */; };
14 | 52FA603921D750AC00936C9E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52FA603721D750AC00936C9E /* LaunchScreen.storyboard */; };
15 | 52FA603C21D750AC00936C9E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA603B21D750AC00936C9E /* main.m */; };
16 | 52FA604621D750AC00936C9E /* SPMultipleSwitchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA604521D750AC00936C9E /* SPMultipleSwitchTests.m */; };
17 | 52FA605121D750AC00936C9E /* SPMultipleSwitchUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA605021D750AC00936C9E /* SPMultipleSwitchUITests.m */; };
18 | 52FA606121D7511200936C9E /* SPMultipleSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FA605F21D7511200936C9E /* SPMultipleSwitch.m */; };
19 | 52FA606321D7515100936C9E /* tracker.png in Resources */ = {isa = PBXBuildFile; fileRef = 52FA606221D7515100936C9E /* tracker.png */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXContainerItemProxy section */
23 | 52FA604221D750AC00936C9E /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = 52FA602121D750A900936C9E /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = 52FA602821D750A900936C9E;
28 | remoteInfo = SPMultipleSwitch;
29 | };
30 | 52FA604D21D750AC00936C9E /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 52FA602121D750A900936C9E /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 52FA602821D750A900936C9E;
35 | remoteInfo = SPMultipleSwitch;
36 | };
37 | /* End PBXContainerItemProxy section */
38 |
39 | /* Begin PBXFileReference section */
40 | 52FA602921D750A900936C9E /* SPMultipleSwitch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SPMultipleSwitch.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 52FA602C21D750A900936C9E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
42 | 52FA602D21D750A900936C9E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
43 | 52FA602F21D750A900936C9E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
44 | 52FA603021D750A900936C9E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
45 | 52FA603321D750A900936C9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
46 | 52FA603521D750AC00936C9E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
47 | 52FA603821D750AC00936C9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
48 | 52FA603A21D750AC00936C9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
49 | 52FA603B21D750AC00936C9E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
50 | 52FA604121D750AC00936C9E /* SPMultipleSwitchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPMultipleSwitchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
51 | 52FA604521D750AC00936C9E /* SPMultipleSwitchTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPMultipleSwitchTests.m; sourceTree = ""; };
52 | 52FA604721D750AC00936C9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | 52FA604C21D750AC00936C9E /* SPMultipleSwitchUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPMultipleSwitchUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 52FA605021D750AC00936C9E /* SPMultipleSwitchUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPMultipleSwitchUITests.m; sourceTree = ""; };
55 | 52FA605221D750AC00936C9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | 52FA605F21D7511200936C9E /* SPMultipleSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPMultipleSwitch.m; sourceTree = ""; };
57 | 52FA606021D7511200936C9E /* SPMultipleSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPMultipleSwitch.h; sourceTree = ""; };
58 | 52FA606221D7515100936C9E /* tracker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tracker.png; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 52FA602621D750A900936C9E /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | 52FA603E21D750AC00936C9E /* Frameworks */ = {
70 | isa = PBXFrameworksBuildPhase;
71 | buildActionMask = 2147483647;
72 | files = (
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | 52FA604921D750AC00936C9E /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | );
81 | runOnlyForDeploymentPostprocessing = 0;
82 | };
83 | /* End PBXFrameworksBuildPhase section */
84 |
85 | /* Begin PBXGroup section */
86 | 52FA602021D750A900936C9E = {
87 | isa = PBXGroup;
88 | children = (
89 | 52FA602B21D750A900936C9E /* SPMultipleSwitch */,
90 | 52FA604421D750AC00936C9E /* SPMultipleSwitchTests */,
91 | 52FA604F21D750AC00936C9E /* SPMultipleSwitchUITests */,
92 | 52FA602A21D750A900936C9E /* Products */,
93 | );
94 | sourceTree = "";
95 | };
96 | 52FA602A21D750A900936C9E /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 52FA602921D750A900936C9E /* SPMultipleSwitch.app */,
100 | 52FA604121D750AC00936C9E /* SPMultipleSwitchTests.xctest */,
101 | 52FA604C21D750AC00936C9E /* SPMultipleSwitchUITests.xctest */,
102 | );
103 | name = Products;
104 | sourceTree = "";
105 | };
106 | 52FA602B21D750A900936C9E /* SPMultipleSwitch */ = {
107 | isa = PBXGroup;
108 | children = (
109 | 52FA605E21D7511200936C9E /* SPMultipleSwitch */,
110 | 52FA602C21D750A900936C9E /* AppDelegate.h */,
111 | 52FA602D21D750A900936C9E /* AppDelegate.m */,
112 | 52FA602F21D750A900936C9E /* ViewController.h */,
113 | 52FA603021D750A900936C9E /* ViewController.m */,
114 | 52FA603221D750A900936C9E /* Main.storyboard */,
115 | 52FA603521D750AC00936C9E /* Assets.xcassets */,
116 | 52FA606221D7515100936C9E /* tracker.png */,
117 | 52FA603721D750AC00936C9E /* LaunchScreen.storyboard */,
118 | 52FA603A21D750AC00936C9E /* Info.plist */,
119 | 52FA603B21D750AC00936C9E /* main.m */,
120 | );
121 | path = SPMultipleSwitch;
122 | sourceTree = "";
123 | };
124 | 52FA604421D750AC00936C9E /* SPMultipleSwitchTests */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 52FA604521D750AC00936C9E /* SPMultipleSwitchTests.m */,
128 | 52FA604721D750AC00936C9E /* Info.plist */,
129 | );
130 | path = SPMultipleSwitchTests;
131 | sourceTree = "";
132 | };
133 | 52FA604F21D750AC00936C9E /* SPMultipleSwitchUITests */ = {
134 | isa = PBXGroup;
135 | children = (
136 | 52FA605021D750AC00936C9E /* SPMultipleSwitchUITests.m */,
137 | 52FA605221D750AC00936C9E /* Info.plist */,
138 | );
139 | path = SPMultipleSwitchUITests;
140 | sourceTree = "";
141 | };
142 | 52FA605E21D7511200936C9E /* SPMultipleSwitch */ = {
143 | isa = PBXGroup;
144 | children = (
145 | 52FA605F21D7511200936C9E /* SPMultipleSwitch.m */,
146 | 52FA606021D7511200936C9E /* SPMultipleSwitch.h */,
147 | );
148 | path = SPMultipleSwitch;
149 | sourceTree = "";
150 | };
151 | /* End PBXGroup section */
152 |
153 | /* Begin PBXNativeTarget section */
154 | 52FA602821D750A900936C9E /* SPMultipleSwitch */ = {
155 | isa = PBXNativeTarget;
156 | buildConfigurationList = 52FA605521D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitch" */;
157 | buildPhases = (
158 | 52FA602521D750A900936C9E /* Sources */,
159 | 52FA602621D750A900936C9E /* Frameworks */,
160 | 52FA602721D750A900936C9E /* Resources */,
161 | );
162 | buildRules = (
163 | );
164 | dependencies = (
165 | );
166 | name = SPMultipleSwitch;
167 | productName = SPMultipleSwitch;
168 | productReference = 52FA602921D750A900936C9E /* SPMultipleSwitch.app */;
169 | productType = "com.apple.product-type.application";
170 | };
171 | 52FA604021D750AC00936C9E /* SPMultipleSwitchTests */ = {
172 | isa = PBXNativeTarget;
173 | buildConfigurationList = 52FA605821D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitchTests" */;
174 | buildPhases = (
175 | 52FA603D21D750AC00936C9E /* Sources */,
176 | 52FA603E21D750AC00936C9E /* Frameworks */,
177 | 52FA603F21D750AC00936C9E /* Resources */,
178 | );
179 | buildRules = (
180 | );
181 | dependencies = (
182 | 52FA604321D750AC00936C9E /* PBXTargetDependency */,
183 | );
184 | name = SPMultipleSwitchTests;
185 | productName = SPMultipleSwitchTests;
186 | productReference = 52FA604121D750AC00936C9E /* SPMultipleSwitchTests.xctest */;
187 | productType = "com.apple.product-type.bundle.unit-test";
188 | };
189 | 52FA604B21D750AC00936C9E /* SPMultipleSwitchUITests */ = {
190 | isa = PBXNativeTarget;
191 | buildConfigurationList = 52FA605B21D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitchUITests" */;
192 | buildPhases = (
193 | 52FA604821D750AC00936C9E /* Sources */,
194 | 52FA604921D750AC00936C9E /* Frameworks */,
195 | 52FA604A21D750AC00936C9E /* Resources */,
196 | );
197 | buildRules = (
198 | );
199 | dependencies = (
200 | 52FA604E21D750AC00936C9E /* PBXTargetDependency */,
201 | );
202 | name = SPMultipleSwitchUITests;
203 | productName = SPMultipleSwitchUITests;
204 | productReference = 52FA604C21D750AC00936C9E /* SPMultipleSwitchUITests.xctest */;
205 | productType = "com.apple.product-type.bundle.ui-testing";
206 | };
207 | /* End PBXNativeTarget section */
208 |
209 | /* Begin PBXProject section */
210 | 52FA602121D750A900936C9E /* Project object */ = {
211 | isa = PBXProject;
212 | attributes = {
213 | LastUpgradeCheck = 1010;
214 | ORGANIZATIONNAME = "乐升平";
215 | TargetAttributes = {
216 | 52FA602821D750A900936C9E = {
217 | CreatedOnToolsVersion = 10.1;
218 | };
219 | 52FA604021D750AC00936C9E = {
220 | CreatedOnToolsVersion = 10.1;
221 | TestTargetID = 52FA602821D750A900936C9E;
222 | };
223 | 52FA604B21D750AC00936C9E = {
224 | CreatedOnToolsVersion = 10.1;
225 | TestTargetID = 52FA602821D750A900936C9E;
226 | };
227 | };
228 | };
229 | buildConfigurationList = 52FA602421D750A900936C9E /* Build configuration list for PBXProject "SPMultipleSwitch" */;
230 | compatibilityVersion = "Xcode 9.3";
231 | developmentRegion = en;
232 | hasScannedForEncodings = 0;
233 | knownRegions = (
234 | en,
235 | Base,
236 | );
237 | mainGroup = 52FA602021D750A900936C9E;
238 | productRefGroup = 52FA602A21D750A900936C9E /* Products */;
239 | projectDirPath = "";
240 | projectRoot = "";
241 | targets = (
242 | 52FA602821D750A900936C9E /* SPMultipleSwitch */,
243 | 52FA604021D750AC00936C9E /* SPMultipleSwitchTests */,
244 | 52FA604B21D750AC00936C9E /* SPMultipleSwitchUITests */,
245 | );
246 | };
247 | /* End PBXProject section */
248 |
249 | /* Begin PBXResourcesBuildPhase section */
250 | 52FA602721D750A900936C9E /* Resources */ = {
251 | isa = PBXResourcesBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | 52FA603921D750AC00936C9E /* LaunchScreen.storyboard in Resources */,
255 | 52FA603621D750AC00936C9E /* Assets.xcassets in Resources */,
256 | 52FA606321D7515100936C9E /* tracker.png in Resources */,
257 | 52FA603421D750A900936C9E /* Main.storyboard in Resources */,
258 | );
259 | runOnlyForDeploymentPostprocessing = 0;
260 | };
261 | 52FA603F21D750AC00936C9E /* Resources */ = {
262 | isa = PBXResourcesBuildPhase;
263 | buildActionMask = 2147483647;
264 | files = (
265 | );
266 | runOnlyForDeploymentPostprocessing = 0;
267 | };
268 | 52FA604A21D750AC00936C9E /* Resources */ = {
269 | isa = PBXResourcesBuildPhase;
270 | buildActionMask = 2147483647;
271 | files = (
272 | );
273 | runOnlyForDeploymentPostprocessing = 0;
274 | };
275 | /* End PBXResourcesBuildPhase section */
276 |
277 | /* Begin PBXSourcesBuildPhase section */
278 | 52FA602521D750A900936C9E /* Sources */ = {
279 | isa = PBXSourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 52FA603121D750A900936C9E /* ViewController.m in Sources */,
283 | 52FA603C21D750AC00936C9E /* main.m in Sources */,
284 | 52FA606121D7511200936C9E /* SPMultipleSwitch.m in Sources */,
285 | 52FA602E21D750A900936C9E /* AppDelegate.m in Sources */,
286 | );
287 | runOnlyForDeploymentPostprocessing = 0;
288 | };
289 | 52FA603D21D750AC00936C9E /* Sources */ = {
290 | isa = PBXSourcesBuildPhase;
291 | buildActionMask = 2147483647;
292 | files = (
293 | 52FA604621D750AC00936C9E /* SPMultipleSwitchTests.m in Sources */,
294 | );
295 | runOnlyForDeploymentPostprocessing = 0;
296 | };
297 | 52FA604821D750AC00936C9E /* Sources */ = {
298 | isa = PBXSourcesBuildPhase;
299 | buildActionMask = 2147483647;
300 | files = (
301 | 52FA605121D750AC00936C9E /* SPMultipleSwitchUITests.m in Sources */,
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | };
305 | /* End PBXSourcesBuildPhase section */
306 |
307 | /* Begin PBXTargetDependency section */
308 | 52FA604321D750AC00936C9E /* PBXTargetDependency */ = {
309 | isa = PBXTargetDependency;
310 | target = 52FA602821D750A900936C9E /* SPMultipleSwitch */;
311 | targetProxy = 52FA604221D750AC00936C9E /* PBXContainerItemProxy */;
312 | };
313 | 52FA604E21D750AC00936C9E /* PBXTargetDependency */ = {
314 | isa = PBXTargetDependency;
315 | target = 52FA602821D750A900936C9E /* SPMultipleSwitch */;
316 | targetProxy = 52FA604D21D750AC00936C9E /* PBXContainerItemProxy */;
317 | };
318 | /* End PBXTargetDependency section */
319 |
320 | /* Begin PBXVariantGroup section */
321 | 52FA603221D750A900936C9E /* Main.storyboard */ = {
322 | isa = PBXVariantGroup;
323 | children = (
324 | 52FA603321D750A900936C9E /* Base */,
325 | );
326 | name = Main.storyboard;
327 | sourceTree = "";
328 | };
329 | 52FA603721D750AC00936C9E /* LaunchScreen.storyboard */ = {
330 | isa = PBXVariantGroup;
331 | children = (
332 | 52FA603821D750AC00936C9E /* Base */,
333 | );
334 | name = LaunchScreen.storyboard;
335 | sourceTree = "";
336 | };
337 | /* End PBXVariantGroup section */
338 |
339 | /* Begin XCBuildConfiguration section */
340 | 52FA605321D750AC00936C9E /* Debug */ = {
341 | isa = XCBuildConfiguration;
342 | buildSettings = {
343 | ALWAYS_SEARCH_USER_PATHS = NO;
344 | CLANG_ANALYZER_NONNULL = YES;
345 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
346 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
347 | CLANG_CXX_LIBRARY = "libc++";
348 | CLANG_ENABLE_MODULES = YES;
349 | CLANG_ENABLE_OBJC_ARC = YES;
350 | CLANG_ENABLE_OBJC_WEAK = YES;
351 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
352 | CLANG_WARN_BOOL_CONVERSION = YES;
353 | CLANG_WARN_COMMA = YES;
354 | CLANG_WARN_CONSTANT_CONVERSION = YES;
355 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
356 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
357 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
358 | CLANG_WARN_EMPTY_BODY = YES;
359 | CLANG_WARN_ENUM_CONVERSION = YES;
360 | CLANG_WARN_INFINITE_RECURSION = YES;
361 | CLANG_WARN_INT_CONVERSION = YES;
362 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
363 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
364 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
365 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
366 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
367 | CLANG_WARN_STRICT_PROTOTYPES = YES;
368 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
369 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
370 | CLANG_WARN_UNREACHABLE_CODE = YES;
371 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
372 | CODE_SIGN_IDENTITY = "iPhone Developer";
373 | COPY_PHASE_STRIP = NO;
374 | DEBUG_INFORMATION_FORMAT = dwarf;
375 | ENABLE_STRICT_OBJC_MSGSEND = YES;
376 | ENABLE_TESTABILITY = YES;
377 | GCC_C_LANGUAGE_STANDARD = gnu11;
378 | GCC_DYNAMIC_NO_PIC = NO;
379 | GCC_NO_COMMON_BLOCKS = YES;
380 | GCC_OPTIMIZATION_LEVEL = 0;
381 | GCC_PREPROCESSOR_DEFINITIONS = (
382 | "DEBUG=1",
383 | "$(inherited)",
384 | );
385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
386 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
387 | GCC_WARN_UNDECLARED_SELECTOR = YES;
388 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
389 | GCC_WARN_UNUSED_FUNCTION = YES;
390 | GCC_WARN_UNUSED_VARIABLE = YES;
391 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
392 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
393 | MTL_FAST_MATH = YES;
394 | ONLY_ACTIVE_ARCH = YES;
395 | SDKROOT = iphoneos;
396 | };
397 | name = Debug;
398 | };
399 | 52FA605421D750AC00936C9E /* Release */ = {
400 | isa = XCBuildConfiguration;
401 | buildSettings = {
402 | ALWAYS_SEARCH_USER_PATHS = NO;
403 | CLANG_ANALYZER_NONNULL = YES;
404 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
405 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
406 | CLANG_CXX_LIBRARY = "libc++";
407 | CLANG_ENABLE_MODULES = YES;
408 | CLANG_ENABLE_OBJC_ARC = YES;
409 | CLANG_ENABLE_OBJC_WEAK = YES;
410 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
411 | CLANG_WARN_BOOL_CONVERSION = YES;
412 | CLANG_WARN_COMMA = YES;
413 | CLANG_WARN_CONSTANT_CONVERSION = YES;
414 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
415 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
416 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
417 | CLANG_WARN_EMPTY_BODY = YES;
418 | CLANG_WARN_ENUM_CONVERSION = YES;
419 | CLANG_WARN_INFINITE_RECURSION = YES;
420 | CLANG_WARN_INT_CONVERSION = YES;
421 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
422 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
423 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
424 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
425 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
426 | CLANG_WARN_STRICT_PROTOTYPES = YES;
427 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
428 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
429 | CLANG_WARN_UNREACHABLE_CODE = YES;
430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
431 | CODE_SIGN_IDENTITY = "iPhone Developer";
432 | COPY_PHASE_STRIP = NO;
433 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
434 | ENABLE_NS_ASSERTIONS = NO;
435 | ENABLE_STRICT_OBJC_MSGSEND = YES;
436 | GCC_C_LANGUAGE_STANDARD = gnu11;
437 | GCC_NO_COMMON_BLOCKS = YES;
438 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
439 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
440 | GCC_WARN_UNDECLARED_SELECTOR = YES;
441 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
442 | GCC_WARN_UNUSED_FUNCTION = YES;
443 | GCC_WARN_UNUSED_VARIABLE = YES;
444 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
445 | MTL_ENABLE_DEBUG_INFO = NO;
446 | MTL_FAST_MATH = YES;
447 | SDKROOT = iphoneos;
448 | VALIDATE_PRODUCT = YES;
449 | };
450 | name = Release;
451 | };
452 | 52FA605621D750AC00936C9E /* Debug */ = {
453 | isa = XCBuildConfiguration;
454 | buildSettings = {
455 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
456 | CODE_SIGN_STYLE = Automatic;
457 | DEVELOPMENT_TEAM = MP8K63J94Y;
458 | INFOPLIST_FILE = SPMultipleSwitch/Info.plist;
459 | LD_RUNPATH_SEARCH_PATHS = (
460 | "$(inherited)",
461 | "@executable_path/Frameworks",
462 | );
463 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitch;
464 | PRODUCT_NAME = "$(TARGET_NAME)";
465 | TARGETED_DEVICE_FAMILY = "1,2";
466 | };
467 | name = Debug;
468 | };
469 | 52FA605721D750AC00936C9E /* Release */ = {
470 | isa = XCBuildConfiguration;
471 | buildSettings = {
472 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
473 | CODE_SIGN_STYLE = Automatic;
474 | DEVELOPMENT_TEAM = MP8K63J94Y;
475 | INFOPLIST_FILE = SPMultipleSwitch/Info.plist;
476 | LD_RUNPATH_SEARCH_PATHS = (
477 | "$(inherited)",
478 | "@executable_path/Frameworks",
479 | );
480 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitch;
481 | PRODUCT_NAME = "$(TARGET_NAME)";
482 | TARGETED_DEVICE_FAMILY = "1,2";
483 | };
484 | name = Release;
485 | };
486 | 52FA605921D750AC00936C9E /* Debug */ = {
487 | isa = XCBuildConfiguration;
488 | buildSettings = {
489 | BUNDLE_LOADER = "$(TEST_HOST)";
490 | CODE_SIGN_STYLE = Automatic;
491 | DEVELOPMENT_TEAM = SXULSRC6Y5;
492 | INFOPLIST_FILE = SPMultipleSwitchTests/Info.plist;
493 | LD_RUNPATH_SEARCH_PATHS = (
494 | "$(inherited)",
495 | "@executable_path/Frameworks",
496 | "@loader_path/Frameworks",
497 | );
498 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitchTests;
499 | PRODUCT_NAME = "$(TARGET_NAME)";
500 | TARGETED_DEVICE_FAMILY = "1,2";
501 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SPMultipleSwitch.app/SPMultipleSwitch";
502 | };
503 | name = Debug;
504 | };
505 | 52FA605A21D750AC00936C9E /* Release */ = {
506 | isa = XCBuildConfiguration;
507 | buildSettings = {
508 | BUNDLE_LOADER = "$(TEST_HOST)";
509 | CODE_SIGN_STYLE = Automatic;
510 | DEVELOPMENT_TEAM = SXULSRC6Y5;
511 | INFOPLIST_FILE = SPMultipleSwitchTests/Info.plist;
512 | LD_RUNPATH_SEARCH_PATHS = (
513 | "$(inherited)",
514 | "@executable_path/Frameworks",
515 | "@loader_path/Frameworks",
516 | );
517 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitchTests;
518 | PRODUCT_NAME = "$(TARGET_NAME)";
519 | TARGETED_DEVICE_FAMILY = "1,2";
520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SPMultipleSwitch.app/SPMultipleSwitch";
521 | };
522 | name = Release;
523 | };
524 | 52FA605C21D750AC00936C9E /* Debug */ = {
525 | isa = XCBuildConfiguration;
526 | buildSettings = {
527 | CODE_SIGN_STYLE = Automatic;
528 | DEVELOPMENT_TEAM = SXULSRC6Y5;
529 | INFOPLIST_FILE = SPMultipleSwitchUITests/Info.plist;
530 | LD_RUNPATH_SEARCH_PATHS = (
531 | "$(inherited)",
532 | "@executable_path/Frameworks",
533 | "@loader_path/Frameworks",
534 | );
535 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitchUITests;
536 | PRODUCT_NAME = "$(TARGET_NAME)";
537 | TARGETED_DEVICE_FAMILY = "1,2";
538 | TEST_TARGET_NAME = SPMultipleSwitch;
539 | };
540 | name = Debug;
541 | };
542 | 52FA605D21D750AC00936C9E /* Release */ = {
543 | isa = XCBuildConfiguration;
544 | buildSettings = {
545 | CODE_SIGN_STYLE = Automatic;
546 | DEVELOPMENT_TEAM = SXULSRC6Y5;
547 | INFOPLIST_FILE = SPMultipleSwitchUITests/Info.plist;
548 | LD_RUNPATH_SEARCH_PATHS = (
549 | "$(inherited)",
550 | "@executable_path/Frameworks",
551 | "@loader_path/Frameworks",
552 | );
553 | PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPMultipleSwitchUITests;
554 | PRODUCT_NAME = "$(TARGET_NAME)";
555 | TARGETED_DEVICE_FAMILY = "1,2";
556 | TEST_TARGET_NAME = SPMultipleSwitch;
557 | };
558 | name = Release;
559 | };
560 | /* End XCBuildConfiguration section */
561 |
562 | /* Begin XCConfigurationList section */
563 | 52FA602421D750A900936C9E /* Build configuration list for PBXProject "SPMultipleSwitch" */ = {
564 | isa = XCConfigurationList;
565 | buildConfigurations = (
566 | 52FA605321D750AC00936C9E /* Debug */,
567 | 52FA605421D750AC00936C9E /* Release */,
568 | );
569 | defaultConfigurationIsVisible = 0;
570 | defaultConfigurationName = Release;
571 | };
572 | 52FA605521D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitch" */ = {
573 | isa = XCConfigurationList;
574 | buildConfigurations = (
575 | 52FA605621D750AC00936C9E /* Debug */,
576 | 52FA605721D750AC00936C9E /* Release */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | 52FA605821D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitchTests" */ = {
582 | isa = XCConfigurationList;
583 | buildConfigurations = (
584 | 52FA605921D750AC00936C9E /* Debug */,
585 | 52FA605A21D750AC00936C9E /* Release */,
586 | );
587 | defaultConfigurationIsVisible = 0;
588 | defaultConfigurationName = Release;
589 | };
590 | 52FA605B21D750AC00936C9E /* Build configuration list for PBXNativeTarget "SPMultipleSwitchUITests" */ = {
591 | isa = XCConfigurationList;
592 | buildConfigurations = (
593 | 52FA605C21D750AC00936C9E /* Debug */,
594 | 52FA605D21D750AC00936C9E /* Release */,
595 | );
596 | defaultConfigurationIsVisible = 0;
597 | defaultConfigurationName = Release;
598 | };
599 | /* End XCConfigurationList section */
600 | };
601 | rootObject = 52FA602121D750A900936C9E /* Project object */;
602 | }
603 |
--------------------------------------------------------------------------------