├── .gitignore ├── .slather.yml ├── .swift-version ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── .travis.yml ├── Assets ├── demo_ipad_cursor.gif ├── demo_main.gif ├── logo-transparent-background.png └── logo-white-background.png ├── BetterSegmentedControl.podspec ├── Example ├── BetterSegmentedControl.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── BetterSegmentedControl.xcscheme ├── BetterSegmentedControl.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── BetterSegmentedControl │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── facebook.imageset │ │ │ ├── Contents.json │ │ │ ├── icons8-facebook-100.png │ │ │ └── icons8-facebook-50.png │ │ └── twitter.imageset │ │ │ ├── Contents.json │ │ │ ├── icons8-twitter-100.png │ │ │ └── icons8-twitter-50.png │ ├── Info.plist │ └── ViewController.swift ├── Podfile ├── Podfile.lock └── Tests │ ├── BetterSegmentedControlTests.swift │ ├── Info.plist │ ├── ReferenceImages │ └── BetterSegmentedControlTests │ │ ├── a_BetterSegmentedControl__its_appleStyled_extension__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_0@3x.png │ │ ├── a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_10@3x.png │ │ ├── a_BetterSegmentedControl__its_indicatorViewBackgroundColor_property__the_control_renders_correctly_after_updating_it@3x.png │ │ ├── a_BetterSegmentedControl__its_indicatorViewBorderColor_property__the_control_renders_correctly_when_setting_it_to_green@3x.png │ │ ├── a_BetterSegmentedControl__its_indicatorViewBorderWidth_property__the_control_renders_correctly_when_setting_it_to_4@3x.png │ │ ├── a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_0@3x.png │ │ ├── a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_4@3x.png │ │ ├── a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_an_expicit_size_is_set_in_Auto_Layout__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_the_control_auto_sizes_itself_in_Auto_Layout__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame___initializer__when_called__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_0_segments__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_1_segment__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_2_segments__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_3_segments__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_beyond_the_valid_segment_indices__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_minus_2__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_backgroundColor__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_cornerRadius__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBackgroundColor__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderColor__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderWidth__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewInset__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_28__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_8__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_zero__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_one__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_zero__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_one__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_zero__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_one__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_zero__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_3__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setOptions___method__when_setting_backgroundColor__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setOptions___method__when_setting_cornerRadius__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBackgroundColor__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBorderWidth_and_indicatorViewBorderColor__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewInset__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__when_adding_a_shadow_to_the_indicator_view__renders_correctly@3x.png │ │ ├── a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_cornerRadius_then_indicatorViewInset__renders_correctly@3x.png │ │ └── a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_indicatorViewInset_then_cornerRadius__renders_correctly@3x.png │ ├── SnapshotHelpers.swift │ ├── Test.storyboard │ └── TestViewControllers.swift ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Package.swift ├── Pod ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── BetterSegmentedControl+IBDesignable.swift │ ├── BetterSegmentedControl+IndicatorView.swift │ ├── BetterSegmentedControl+Options.swift │ ├── BetterSegmentedControl+PredefinedStyles.swift │ ├── BetterSegmentedControl+UIPointerInteractionDelegate.swift │ ├── BetterSegmentedControl.swift │ ├── Helpers │ ├── UIColor+Helpers.swift │ └── UIView+Helpers.swift │ └── Segments │ ├── BetterSegmentedControlSegment.swift │ ├── IconSegment.swift │ └── LabelSegment.swift ├── README.md └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | 27 | Example/Pods/ 28 | 29 | # Swift Package Manager 30 | .build 31 | -------------------------------------------------------------------------------- /.slather.yml: -------------------------------------------------------------------------------- 1 | xcodeproj: Example/BetterSegmentedControl.xcodeproj 2 | scheme: BetterSegmentedControl_Example 3 | workspace: Example/BetterSegmentedControl.xcworkspace 4 | source_directory: Pod/Classes 5 | binary_basename: BetterSegmentedControl 6 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.1 -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | # cache: cocoapods 7 | # podfile: Example/Podfile 8 | # before_install: 9 | # - gem install cocoapods # Since Travis is not always on latest version 10 | # - pod install --project-directory=Example 11 | script: 12 | - set -o pipefail && xcodebuild test -workspace Example/BetterSegmentedControl.xcworkspace -scheme BetterSegmentedControl-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty 13 | - pod lib lint 14 | -------------------------------------------------------------------------------- /Assets/demo_ipad_cursor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Assets/demo_ipad_cursor.gif -------------------------------------------------------------------------------- /Assets/demo_main.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Assets/demo_main.gif -------------------------------------------------------------------------------- /Assets/logo-transparent-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Assets/logo-transparent-background.png -------------------------------------------------------------------------------- /Assets/logo-white-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Assets/logo-white-background.png -------------------------------------------------------------------------------- /BetterSegmentedControl.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "BetterSegmentedControl" 3 | s.version = "2.0.1" 4 | s.swift_version = "5.1" 5 | s.summary = "An easy to use, customizable replacement for UISegmentedControl & UISwitch." 6 | s.description = <<-DESC 7 | BetterSegmentedControl is an easy to use, customizable replacement for UISegmentedControl and UISwitch written in Swift. 8 | DESC 9 | s.homepage = "https://github.com/gmarm/BetterSegmentedControl" 10 | s.license = 'MIT' 11 | s.author = { "George Marmaridis" => "gmarmas@gmail.com" } 12 | s.source = { :git => "https://github.com/gmarm/BetterSegmentedControl.git", :tag => "2.0.1" } 13 | s.social_media_url = 'https://twitter.com/gmarmas' 14 | s.platform = :ios, '9.0' 15 | s.requires_arc = true 16 | s.source_files = 'Pod/Classes/**/*' 17 | s.frameworks = 'UIKit' 18 | end 19 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4BC57C101CCB8D0700A85349 /* Test.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4BC57C0F1CCB8D0700A85349 /* Test.storyboard */; }; 11 | 4BC57C121CCB8EDD00A85349 /* TestViewControllers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57C111CCB8EDD00A85349 /* TestViewControllers.swift */; }; 12 | 5E3D40EA253C486400FCF131 /* SnapshotHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E3D40E9253C486400FCF131 /* SnapshotHelpers.swift */; }; 13 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 14 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; 15 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; 16 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 17 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 18 | 607FACEC1AFB9204008FA782 /* BetterSegmentedControlTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* BetterSegmentedControlTests.swift */; }; 19 | 90FFFDFEEFCF420B32DC095F /* Pods_BetterSegmentedControl_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FAF265B133EF9D144E4D6FB /* Pods_BetterSegmentedControl_Tests.framework */; }; 20 | D36BA20F2BF5FBB03233C68B /* Pods_BetterSegmentedControl_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61D9FAAAFFAE7994D65963C2 /* Pods_BetterSegmentedControl_Example.framework */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 607FACC81AFB9204008FA782 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 607FACCF1AFB9204008FA782; 29 | remoteInfo = BetterSegmentedControl; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 04381095F08ECC8EEFC64A13 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 35 | 12CB0D1475C52C17775132BF /* Pods-BetterSegmentedControl_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BetterSegmentedControl_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-BetterSegmentedControl_Example/Pods-BetterSegmentedControl_Example.release.xcconfig"; sourceTree = ""; }; 36 | 2FAF265B133EF9D144E4D6FB /* Pods_BetterSegmentedControl_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BetterSegmentedControl_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 4BC57C0F1CCB8D0700A85349 /* Test.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Test.storyboard; sourceTree = ""; }; 38 | 4BC57C111CCB8EDD00A85349 /* TestViewControllers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestViewControllers.swift; sourceTree = ""; }; 39 | 5E3D40E9253C486400FCF131 /* SnapshotHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotHelpers.swift; sourceTree = ""; }; 40 | 607FACD01AFB9204008FA782 /* BetterSegmentedControl_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BetterSegmentedControl_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 43 | 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 44 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 46 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 47 | 607FACE51AFB9204008FA782 /* BetterSegmentedControl_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BetterSegmentedControl_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 607FACEB1AFB9204008FA782 /* BetterSegmentedControlTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterSegmentedControlTests.swift; sourceTree = ""; }; 50 | 61D9FAAAFFAE7994D65963C2 /* Pods_BetterSegmentedControl_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BetterSegmentedControl_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 82FBC36B5CC2D9017CEACA5B /* BetterSegmentedControl.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = BetterSegmentedControl.podspec; path = ../BetterSegmentedControl.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 52 | BA399992832E9047B3FF6F8B /* Pods-BetterSegmentedControl_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BetterSegmentedControl_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-BetterSegmentedControl_Tests/Pods-BetterSegmentedControl_Tests.release.xcconfig"; sourceTree = ""; }; 53 | E35EF8EE3A68B8AA955DE5DE /* Pods-BetterSegmentedControl_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BetterSegmentedControl_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BetterSegmentedControl_Example/Pods-BetterSegmentedControl_Example.debug.xcconfig"; sourceTree = ""; }; 54 | F6F6B8A01C1E078308A9EB93 /* Pods-BetterSegmentedControl_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BetterSegmentedControl_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BetterSegmentedControl_Tests/Pods-BetterSegmentedControl_Tests.debug.xcconfig"; sourceTree = ""; }; 55 | F8ECFF07790385FABB531EC7 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 607FACCD1AFB9204008FA782 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | D36BA20F2BF5FBB03233C68B /* Pods_BetterSegmentedControl_Example.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | 607FACE21AFB9204008FA782 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | 90FFFDFEEFCF420B32DC095F /* Pods_BetterSegmentedControl_Tests.framework in Frameworks */, 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | 2E0C0F03ED9410652539F30B /* Pods */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | E35EF8EE3A68B8AA955DE5DE /* Pods-BetterSegmentedControl_Example.debug.xcconfig */, 82 | 12CB0D1475C52C17775132BF /* Pods-BetterSegmentedControl_Example.release.xcconfig */, 83 | F6F6B8A01C1E078308A9EB93 /* Pods-BetterSegmentedControl_Tests.debug.xcconfig */, 84 | BA399992832E9047B3FF6F8B /* Pods-BetterSegmentedControl_Tests.release.xcconfig */, 85 | ); 86 | name = Pods; 87 | sourceTree = ""; 88 | }; 89 | 5EA6C5B32539E65400776C82 /* Helpers */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 4BC57C0F1CCB8D0700A85349 /* Test.storyboard */, 93 | 4BC57C111CCB8EDD00A85349 /* TestViewControllers.swift */, 94 | 5E3D40E9253C486400FCF131 /* SnapshotHelpers.swift */, 95 | ); 96 | name = Helpers; 97 | sourceTree = ""; 98 | }; 99 | 607FACC71AFB9204008FA782 = { 100 | isa = PBXGroup; 101 | children = ( 102 | 607FACF51AFB993E008FA782 /* Podspec Metadata */, 103 | 607FACD21AFB9204008FA782 /* Example for BetterSegmentedControl */, 104 | 607FACE81AFB9204008FA782 /* Tests */, 105 | 607FACD11AFB9204008FA782 /* Products */, 106 | 2E0C0F03ED9410652539F30B /* Pods */, 107 | D6EA7141AF371DB117A8E6FC /* Frameworks */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | 607FACD11AFB9204008FA782 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 607FACD01AFB9204008FA782 /* BetterSegmentedControl_Example.app */, 115 | 607FACE51AFB9204008FA782 /* BetterSegmentedControl_Tests.xctest */, 116 | ); 117 | name = Products; 118 | sourceTree = ""; 119 | }; 120 | 607FACD21AFB9204008FA782 /* Example for BetterSegmentedControl */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */, 124 | 607FACD91AFB9204008FA782 /* Main.storyboard */, 125 | 607FACD71AFB9204008FA782 /* ViewController.swift */, 126 | 607FACDC1AFB9204008FA782 /* Images.xcassets */, 127 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, 128 | 607FACD31AFB9204008FA782 /* Supporting Files */, 129 | ); 130 | name = "Example for BetterSegmentedControl"; 131 | path = BetterSegmentedControl; 132 | sourceTree = ""; 133 | }; 134 | 607FACD31AFB9204008FA782 /* Supporting Files */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 607FACD41AFB9204008FA782 /* Info.plist */, 138 | ); 139 | name = "Supporting Files"; 140 | sourceTree = ""; 141 | }; 142 | 607FACE81AFB9204008FA782 /* Tests */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 607FACEB1AFB9204008FA782 /* BetterSegmentedControlTests.swift */, 146 | 5EA6C5B32539E65400776C82 /* Helpers */, 147 | 607FACE91AFB9204008FA782 /* Supporting Files */, 148 | ); 149 | path = Tests; 150 | sourceTree = ""; 151 | }; 152 | 607FACE91AFB9204008FA782 /* Supporting Files */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 607FACEA1AFB9204008FA782 /* Info.plist */, 156 | ); 157 | name = "Supporting Files"; 158 | sourceTree = ""; 159 | }; 160 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 82FBC36B5CC2D9017CEACA5B /* BetterSegmentedControl.podspec */, 164 | 04381095F08ECC8EEFC64A13 /* README.md */, 165 | F8ECFF07790385FABB531EC7 /* LICENSE */, 166 | ); 167 | name = "Podspec Metadata"; 168 | sourceTree = ""; 169 | }; 170 | D6EA7141AF371DB117A8E6FC /* Frameworks */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 61D9FAAAFFAE7994D65963C2 /* Pods_BetterSegmentedControl_Example.framework */, 174 | 2FAF265B133EF9D144E4D6FB /* Pods_BetterSegmentedControl_Tests.framework */, 175 | ); 176 | name = Frameworks; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXGroup section */ 180 | 181 | /* Begin PBXNativeTarget section */ 182 | 607FACCF1AFB9204008FA782 /* BetterSegmentedControl_Example */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "BetterSegmentedControl_Example" */; 185 | buildPhases = ( 186 | CBB0F927E437CCE27B11AF92 /* [CP] Check Pods Manifest.lock */, 187 | 607FACCC1AFB9204008FA782 /* Sources */, 188 | 607FACCD1AFB9204008FA782 /* Frameworks */, 189 | 607FACCE1AFB9204008FA782 /* Resources */, 190 | 7A32436EFA69C4B146882841 /* [CP] Embed Pods Frameworks */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = BetterSegmentedControl_Example; 197 | productName = BetterSegmentedControl; 198 | productReference = 607FACD01AFB9204008FA782 /* BetterSegmentedControl_Example.app */; 199 | productType = "com.apple.product-type.application"; 200 | }; 201 | 607FACE41AFB9204008FA782 /* BetterSegmentedControl_Tests */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "BetterSegmentedControl_Tests" */; 204 | buildPhases = ( 205 | 213972DCD2D93B301F89BEF2 /* [CP] Check Pods Manifest.lock */, 206 | 607FACE11AFB9204008FA782 /* Sources */, 207 | 607FACE21AFB9204008FA782 /* Frameworks */, 208 | 607FACE31AFB9204008FA782 /* Resources */, 209 | 723B1B079BEB381EA4CF7DBC /* [CP] Embed Pods Frameworks */, 210 | ); 211 | buildRules = ( 212 | ); 213 | dependencies = ( 214 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */, 215 | ); 216 | name = BetterSegmentedControl_Tests; 217 | productName = Tests; 218 | productReference = 607FACE51AFB9204008FA782 /* BetterSegmentedControl_Tests.xctest */; 219 | productType = "com.apple.product-type.bundle.unit-test"; 220 | }; 221 | /* End PBXNativeTarget section */ 222 | 223 | /* Begin PBXProject section */ 224 | 607FACC81AFB9204008FA782 /* Project object */ = { 225 | isa = PBXProject; 226 | attributes = { 227 | LastSwiftUpdateCheck = 0720; 228 | LastUpgradeCheck = 1200; 229 | ORGANIZATIONNAME = CocoaPods; 230 | TargetAttributes = { 231 | 607FACCF1AFB9204008FA782 = { 232 | CreatedOnToolsVersion = 6.3.1; 233 | LastSwiftMigration = 1020; 234 | }; 235 | 607FACE41AFB9204008FA782 = { 236 | CreatedOnToolsVersion = 6.3.1; 237 | LastSwiftMigration = 1020; 238 | TestTargetID = 607FACCF1AFB9204008FA782; 239 | }; 240 | }; 241 | }; 242 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "BetterSegmentedControl" */; 243 | compatibilityVersion = "Xcode 3.2"; 244 | developmentRegion = English; 245 | hasScannedForEncodings = 0; 246 | knownRegions = ( 247 | English, 248 | en, 249 | Base, 250 | ); 251 | mainGroup = 607FACC71AFB9204008FA782; 252 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 253 | projectDirPath = ""; 254 | projectRoot = ""; 255 | targets = ( 256 | 607FACCF1AFB9204008FA782 /* BetterSegmentedControl_Example */, 257 | 607FACE41AFB9204008FA782 /* BetterSegmentedControl_Tests */, 258 | ); 259 | }; 260 | /* End PBXProject section */ 261 | 262 | /* Begin PBXResourcesBuildPhase section */ 263 | 607FACCE1AFB9204008FA782 /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 268 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, 269 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | 607FACE31AFB9204008FA782 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | 4BC57C101CCB8D0700A85349 /* Test.storyboard in Resources */, 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | /* End PBXResourcesBuildPhase section */ 282 | 283 | /* Begin PBXShellScriptBuildPhase section */ 284 | 213972DCD2D93B301F89BEF2 /* [CP] Check Pods Manifest.lock */ = { 285 | isa = PBXShellScriptBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | ); 289 | inputPaths = ( 290 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 291 | "${PODS_ROOT}/Manifest.lock", 292 | ); 293 | name = "[CP] Check Pods Manifest.lock"; 294 | outputPaths = ( 295 | "$(DERIVED_FILE_DIR)/Pods-BetterSegmentedControl_Tests-checkManifestLockResult.txt", 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | shellPath = /bin/sh; 299 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 300 | showEnvVarsInLog = 0; 301 | }; 302 | 723B1B079BEB381EA4CF7DBC /* [CP] Embed Pods Frameworks */ = { 303 | isa = PBXShellScriptBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | inputPaths = ( 308 | "${PODS_ROOT}/Target Support Files/Pods-BetterSegmentedControl_Tests/Pods-BetterSegmentedControl_Tests-frameworks.sh", 309 | "${BUILT_PRODUCTS_DIR}/BetterSegmentedControl/BetterSegmentedControl.framework", 310 | "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", 311 | "${BUILT_PRODUCTS_DIR}/Nimble-Snapshots/Nimble_Snapshots.framework", 312 | "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", 313 | "${BUILT_PRODUCTS_DIR}/iOSSnapshotTestCase/FBSnapshotTestCase.framework", 314 | ); 315 | name = "[CP] Embed Pods Frameworks"; 316 | outputPaths = ( 317 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BetterSegmentedControl.framework", 318 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", 319 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble_Snapshots.framework", 320 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", 321 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework", 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | shellPath = /bin/sh; 325 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BetterSegmentedControl_Tests/Pods-BetterSegmentedControl_Tests-frameworks.sh\"\n"; 326 | showEnvVarsInLog = 0; 327 | }; 328 | 7A32436EFA69C4B146882841 /* [CP] Embed Pods Frameworks */ = { 329 | isa = PBXShellScriptBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | ); 333 | inputPaths = ( 334 | "${PODS_ROOT}/Target Support Files/Pods-BetterSegmentedControl_Example/Pods-BetterSegmentedControl_Example-frameworks.sh", 335 | "${BUILT_PRODUCTS_DIR}/BetterSegmentedControl/BetterSegmentedControl.framework", 336 | ); 337 | name = "[CP] Embed Pods Frameworks"; 338 | outputPaths = ( 339 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BetterSegmentedControl.framework", 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | shellPath = /bin/sh; 343 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BetterSegmentedControl_Example/Pods-BetterSegmentedControl_Example-frameworks.sh\"\n"; 344 | showEnvVarsInLog = 0; 345 | }; 346 | CBB0F927E437CCE27B11AF92 /* [CP] Check Pods Manifest.lock */ = { 347 | isa = PBXShellScriptBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | ); 351 | inputPaths = ( 352 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 353 | "${PODS_ROOT}/Manifest.lock", 354 | ); 355 | name = "[CP] Check Pods Manifest.lock"; 356 | outputPaths = ( 357 | "$(DERIVED_FILE_DIR)/Pods-BetterSegmentedControl_Example-checkManifestLockResult.txt", 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | shellPath = /bin/sh; 361 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 362 | showEnvVarsInLog = 0; 363 | }; 364 | /* End PBXShellScriptBuildPhase section */ 365 | 366 | /* Begin PBXSourcesBuildPhase section */ 367 | 607FACCC1AFB9204008FA782 /* Sources */ = { 368 | isa = PBXSourcesBuildPhase; 369 | buildActionMask = 2147483647; 370 | files = ( 371 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, 372 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | 607FACE11AFB9204008FA782 /* Sources */ = { 377 | isa = PBXSourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | 4BC57C121CCB8EDD00A85349 /* TestViewControllers.swift in Sources */, 381 | 607FACEC1AFB9204008FA782 /* BetterSegmentedControlTests.swift in Sources */, 382 | 5E3D40EA253C486400FCF131 /* SnapshotHelpers.swift in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = 607FACCF1AFB9204008FA782 /* BetterSegmentedControl_Example */; 392 | targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */; 393 | }; 394 | /* End PBXTargetDependency section */ 395 | 396 | /* Begin PBXVariantGroup section */ 397 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = { 398 | isa = PBXVariantGroup; 399 | children = ( 400 | 607FACDA1AFB9204008FA782 /* Base */, 401 | ); 402 | name = Main.storyboard; 403 | sourceTree = ""; 404 | }; 405 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { 406 | isa = PBXVariantGroup; 407 | children = ( 408 | 607FACDF1AFB9204008FA782 /* Base */, 409 | ); 410 | name = LaunchScreen.xib; 411 | sourceTree = ""; 412 | }; 413 | /* End PBXVariantGroup section */ 414 | 415 | /* Begin XCBuildConfiguration section */ 416 | 607FACED1AFB9204008FA782 /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ALWAYS_SEARCH_USER_PATHS = NO; 420 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 421 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 422 | CLANG_CXX_LIBRARY = "libc++"; 423 | CLANG_ENABLE_MODULES = YES; 424 | CLANG_ENABLE_OBJC_ARC = YES; 425 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 426 | CLANG_WARN_BOOL_CONVERSION = YES; 427 | CLANG_WARN_COMMA = YES; 428 | CLANG_WARN_CONSTANT_CONVERSION = YES; 429 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 430 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 431 | CLANG_WARN_EMPTY_BODY = YES; 432 | CLANG_WARN_ENUM_CONVERSION = YES; 433 | CLANG_WARN_INFINITE_RECURSION = YES; 434 | CLANG_WARN_INT_CONVERSION = YES; 435 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 436 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 437 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 438 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 439 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 440 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 441 | CLANG_WARN_STRICT_PROTOTYPES = YES; 442 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 443 | CLANG_WARN_UNREACHABLE_CODE = YES; 444 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 446 | COPY_PHASE_STRIP = NO; 447 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 448 | ENABLE_STRICT_OBJC_MSGSEND = YES; 449 | ENABLE_TESTABILITY = YES; 450 | GCC_C_LANGUAGE_STANDARD = gnu99; 451 | GCC_DYNAMIC_NO_PIC = NO; 452 | GCC_NO_COMMON_BLOCKS = YES; 453 | GCC_OPTIMIZATION_LEVEL = 0; 454 | GCC_PREPROCESSOR_DEFINITIONS = ( 455 | "DEBUG=1", 456 | "$(inherited)", 457 | ); 458 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 461 | GCC_WARN_UNDECLARED_SELECTOR = YES; 462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 463 | GCC_WARN_UNUSED_FUNCTION = YES; 464 | GCC_WARN_UNUSED_VARIABLE = YES; 465 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 466 | MTL_ENABLE_DEBUG_INFO = YES; 467 | ONLY_ACTIVE_ARCH = YES; 468 | SDKROOT = iphoneos; 469 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 470 | SWIFT_VERSION = 5.0; 471 | }; 472 | name = Debug; 473 | }; 474 | 607FACEE1AFB9204008FA782 /* Release */ = { 475 | isa = XCBuildConfiguration; 476 | buildSettings = { 477 | ALWAYS_SEARCH_USER_PATHS = NO; 478 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 479 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 480 | CLANG_CXX_LIBRARY = "libc++"; 481 | CLANG_ENABLE_MODULES = YES; 482 | CLANG_ENABLE_OBJC_ARC = YES; 483 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 484 | CLANG_WARN_BOOL_CONVERSION = YES; 485 | CLANG_WARN_COMMA = YES; 486 | CLANG_WARN_CONSTANT_CONVERSION = YES; 487 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 488 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 489 | CLANG_WARN_EMPTY_BODY = YES; 490 | CLANG_WARN_ENUM_CONVERSION = YES; 491 | CLANG_WARN_INFINITE_RECURSION = YES; 492 | CLANG_WARN_INT_CONVERSION = YES; 493 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 494 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 495 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 496 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 497 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 498 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 499 | CLANG_WARN_STRICT_PROTOTYPES = YES; 500 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 501 | CLANG_WARN_UNREACHABLE_CODE = YES; 502 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 503 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 504 | COPY_PHASE_STRIP = NO; 505 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 506 | ENABLE_NS_ASSERTIONS = NO; 507 | ENABLE_STRICT_OBJC_MSGSEND = YES; 508 | GCC_C_LANGUAGE_STANDARD = gnu99; 509 | GCC_NO_COMMON_BLOCKS = YES; 510 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 511 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 512 | GCC_WARN_UNDECLARED_SELECTOR = YES; 513 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 514 | GCC_WARN_UNUSED_FUNCTION = YES; 515 | GCC_WARN_UNUSED_VARIABLE = YES; 516 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 517 | MTL_ENABLE_DEBUG_INFO = NO; 518 | SDKROOT = iphoneos; 519 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 520 | SWIFT_VERSION = 5.0; 521 | VALIDATE_PRODUCT = YES; 522 | }; 523 | name = Release; 524 | }; 525 | 607FACF01AFB9204008FA782 /* Debug */ = { 526 | isa = XCBuildConfiguration; 527 | baseConfigurationReference = E35EF8EE3A68B8AA955DE5DE /* Pods-BetterSegmentedControl_Example.debug.xcconfig */; 528 | buildSettings = { 529 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 530 | INFOPLIST_FILE = BetterSegmentedControl/Info.plist; 531 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 532 | MODULE_NAME = ExampleApp; 533 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 534 | PRODUCT_NAME = "$(TARGET_NAME)"; 535 | TARGETED_DEVICE_FAMILY = "1,2"; 536 | }; 537 | name = Debug; 538 | }; 539 | 607FACF11AFB9204008FA782 /* Release */ = { 540 | isa = XCBuildConfiguration; 541 | baseConfigurationReference = 12CB0D1475C52C17775132BF /* Pods-BetterSegmentedControl_Example.release.xcconfig */; 542 | buildSettings = { 543 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 544 | INFOPLIST_FILE = BetterSegmentedControl/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 546 | MODULE_NAME = ExampleApp; 547 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 548 | PRODUCT_NAME = "$(TARGET_NAME)"; 549 | TARGETED_DEVICE_FAMILY = "1,2"; 550 | }; 551 | name = Release; 552 | }; 553 | 607FACF31AFB9204008FA782 /* Debug */ = { 554 | isa = XCBuildConfiguration; 555 | baseConfigurationReference = F6F6B8A01C1E078308A9EB93 /* Pods-BetterSegmentedControl_Tests.debug.xcconfig */; 556 | buildSettings = { 557 | BUNDLE_LOADER = "$(TEST_HOST)"; 558 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 559 | GCC_PREPROCESSOR_DEFINITIONS = ( 560 | "DEBUG=1", 561 | "$(inherited)", 562 | ); 563 | INFOPLIST_FILE = Tests/Info.plist; 564 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 565 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BetterSegmentedControl_Example.app/BetterSegmentedControl_Example"; 568 | }; 569 | name = Debug; 570 | }; 571 | 607FACF41AFB9204008FA782 /* Release */ = { 572 | isa = XCBuildConfiguration; 573 | baseConfigurationReference = BA399992832E9047B3FF6F8B /* Pods-BetterSegmentedControl_Tests.release.xcconfig */; 574 | buildSettings = { 575 | BUNDLE_LOADER = "$(TEST_HOST)"; 576 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 577 | INFOPLIST_FILE = Tests/Info.plist; 578 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 579 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; 580 | PRODUCT_NAME = "$(TARGET_NAME)"; 581 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BetterSegmentedControl_Example.app/BetterSegmentedControl_Example"; 582 | }; 583 | name = Release; 584 | }; 585 | /* End XCBuildConfiguration section */ 586 | 587 | /* Begin XCConfigurationList section */ 588 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "BetterSegmentedControl" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 607FACED1AFB9204008FA782 /* Debug */, 592 | 607FACEE1AFB9204008FA782 /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "BetterSegmentedControl_Example" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 607FACF01AFB9204008FA782 /* Debug */, 601 | 607FACF11AFB9204008FA782 /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "BetterSegmentedControl_Tests" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 607FACF31AFB9204008FA782 /* Debug */, 610 | 607FACF41AFB9204008FA782 /* Release */, 611 | ); 612 | defaultConfigurationIsVisible = 0; 613 | defaultConfigurationName = Release; 614 | }; 615 | /* End XCConfigurationList section */ 616 | }; 617 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 618 | } 619 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcodeproj/xcshareddata/xcschemes/BetterSegmentedControl.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 04/03/2016. 6 | // Copyright (c) 2016 George Marmaridis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/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 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Images.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/BetterSegmentedControl/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Images.xcassets/facebook.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-facebook-50.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-facebook-100.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/BetterSegmentedControl/Images.xcassets/facebook.imageset/icons8-facebook-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/BetterSegmentedControl/Images.xcassets/facebook.imageset/icons8-facebook-100.png -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Images.xcassets/facebook.imageset/icons8-facebook-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/BetterSegmentedControl/Images.xcassets/facebook.imageset/icons8-facebook-50.png -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Images.xcassets/twitter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-twitter-50.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-twitter-100.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/BetterSegmentedControl/Images.xcassets/twitter.imageset/icons8-twitter-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/BetterSegmentedControl/Images.xcassets/twitter.imageset/icons8-twitter-100.png -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/Images.xcassets/twitter.imageset/icons8-twitter-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/BetterSegmentedControl/Images.xcassets/twitter.imageset/icons8-twitter-50.png -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/BetterSegmentedControl/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 04/03/2016. 6 | // Copyright (c) 2016 George Marmaridis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BetterSegmentedControl 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet weak var control1: BetterSegmentedControl! 15 | @IBOutlet weak var control2: BetterSegmentedControl! 16 | @IBOutlet weak var control3: BetterSegmentedControl! 17 | 18 | // MARK: - Examples 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | 22 | let navigationSegmentedControl = BetterSegmentedControl( 23 | frame: CGRect(x: 0, y: 0, width: 200.0, height: 30.0), 24 | segments: LabelSegment.segments(withTitles: ["Lights On", "Lights Off"], 25 | normalTextColor: .lightGray, 26 | selectedTextColor: .white), 27 | options:[.backgroundColor(.darkGray), 28 | .indicatorViewBackgroundColor(UIColor(red: 0.36, green: 0.38, blue: 0.87, alpha: 1.00)), 29 | .cornerRadius(3.0), 30 | .animationSpringDamping(1.0)]) 31 | navigationSegmentedControl.addTarget(self, 32 | action: #selector(ViewController.navigationSegmentedControlValueChanged(_:)), 33 | for: .valueChanged) 34 | navigationItem.titleView = navigationSegmentedControl 35 | 36 | // Control 1: Created and designed in IB 37 | control1.segments = LabelSegment.segments(withTitles: ["Recent", "Nearby", "All"], 38 | normalTextColor: UIColor(red: 0.48, green: 0.48, blue: 0.51, alpha: 1.00)) 39 | 40 | // Control 2: Created and designed in IB 41 | control2.segments = LabelSegment.segments(withTitles: ["Music", "Movies", "Apps"], 42 | normalTextColor: .white, 43 | selectedTextColor: UIColor(red: 0.92, green: 0.29, blue: 0.15, alpha: 1.00)) 44 | 45 | // Control 3: Many options 46 | control3.segments = LabelSegment.segments(withTitles: ["One", "Two", "Three", "Four", "Five"], 47 | normalFont: .systemFont(ofSize: 14.0), 48 | normalTextColor: UIColor(red: 0.15, green: 0.39, blue: 0.96, alpha: 0.9), 49 | selectedFont: .systemFont(ofSize: 14.0), 50 | selectedTextColor: UIColor(red: 0.16, green: 0.40, blue: 0.96, alpha: 1.00)) 51 | 52 | // Control 4: Created and designed in IB, self-sizing 53 | 54 | // Control 5: Basic Icons 55 | let iconsSegmentedControl = BetterSegmentedControl( 56 | frame: CGRect(x: 0.0, y: 380.0, width: 160, height: 30.0), 57 | segments: IconSegment.segments(withIcons: [UIImage(named: "facebook")!, UIImage(named: "twitter")!], 58 | iconSize: CGSize(width: 20.0, height: 20.0), 59 | normalIconTintColor: .white, 60 | selectedIconTintColor: UIColor(red: 0.16, green: 0.64, blue: 0.94, alpha: 1.00)), 61 | options: [.cornerRadius(15.0), 62 | .backgroundColor(UIColor(red: 0.16, green: 0.64, blue: 0.94, alpha: 1.00)), 63 | .indicatorViewBackgroundColor(.white)]) 64 | iconsSegmentedControl.center.x = view.center.x 65 | view.addSubview(iconsSegmentedControl) 66 | 67 | // Control 6: Apple style 68 | let appleStyledControl: BetterSegmentedControl = .appleStyled(frame: CGRect(x: 16.0, 69 | y: 435, 70 | width: view.bounds.width - 32.0, 71 | height: 32.0), 72 | titles: ["First", "Second", "Third"]) 73 | view.addSubview(appleStyledControl) 74 | 75 | // Control 7: No initially selected segment 76 | let noSelectedSegmentControl = BetterSegmentedControl( 77 | frame: CGRect(x: 16.0, y: 490, width: view.bounds.width - 32.0, height: 44.0), 78 | segments: LabelSegment.segments(withTitles: ["One", "Two", "Three", "Four"]), 79 | index: -1) 80 | noSelectedSegmentControl.addTarget(self, action: #selector(segmentedControl1ValueChanged(_:)), for: .valueChanged) 81 | view.addSubview(noSelectedSegmentControl) 82 | } 83 | 84 | // MARK: - Action handlers 85 | @objc func navigationSegmentedControlValueChanged(_ sender: BetterSegmentedControl) { 86 | if sender.index == 0 { 87 | print("Turning lights on.") 88 | if #available(iOS 13.0, *) { 89 | view.backgroundColor = .systemGray5 90 | } else { 91 | view.backgroundColor = .white 92 | } 93 | } else { 94 | print("Turning lights off.") 95 | view.backgroundColor = .darkGray 96 | } 97 | } 98 | 99 | @IBAction func segmentedControl1ValueChanged(_ sender: BetterSegmentedControl) { 100 | print("The selected index is \(sender.index)") 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios, '9.0' 3 | use_frameworks! 4 | inhibit_all_warnings! 5 | 6 | def betterSegmentedControl 7 | pod 'BetterSegmentedControl', :path => '../', :inhibit_warnings => false 8 | end 9 | 10 | target 'BetterSegmentedControl_Example' do 11 | betterSegmentedControl 12 | end 13 | 14 | target 'BetterSegmentedControl_Tests' do 15 | betterSegmentedControl 16 | 17 | pod 'Quick', '~> 2.2' 18 | pod 'Nimble', '~> 7.3' 19 | pod 'Nimble-Snapshots', '~> 6.9' 20 | end 21 | 22 | post_install do |pi| 23 | pi.pods_project.targets.each do |t| 24 | t.build_configurations.each do |config| 25 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BetterSegmentedControl (2.0) 3 | - iOSSnapshotTestCase (5.0.2): 4 | - iOSSnapshotTestCase/SwiftSupport (= 5.0.2) 5 | - iOSSnapshotTestCase/Core (5.0.2) 6 | - iOSSnapshotTestCase/SwiftSupport (5.0.2): 7 | - iOSSnapshotTestCase/Core 8 | - Nimble (7.3.4) 9 | - Nimble-Snapshots (6.9.1): 10 | - Nimble-Snapshots/Core (= 6.9.1) 11 | - Nimble-Snapshots/Core (6.9.1): 12 | - iOSSnapshotTestCase (~> 5.0) 13 | - Nimble (~> 7.0) 14 | - Quick (2.2.0) 15 | 16 | DEPENDENCIES: 17 | - BetterSegmentedControl (from `../`) 18 | - Nimble (~> 7.3) 19 | - Nimble-Snapshots (~> 6.9) 20 | - Quick (~> 2.2) 21 | 22 | SPEC REPOS: 23 | https://github.com/CocoaPods/Specs.git: 24 | - iOSSnapshotTestCase 25 | - Nimble 26 | - Nimble-Snapshots 27 | - Quick 28 | 29 | EXTERNAL SOURCES: 30 | BetterSegmentedControl: 31 | :path: "../" 32 | 33 | SPEC CHECKSUMS: 34 | BetterSegmentedControl: ce9b68b81c963991211c561026ed2cf711f9ac63 35 | iOSSnapshotTestCase: 2d51aa06775e95cecb0a1fb9c5c159ccd1dd4596 36 | Nimble: 051e3d8912d40138fa5591c78594f95fb172af37 37 | Nimble-Snapshots: bbd1ab264bacc24a9ce24a8363bc05aac783aeb0 38 | Quick: 7fb19e13be07b5dfb3b90d4f9824c855a11af40e 39 | 40 | PODFILE CHECKSUM: 609c5442f2ad21fe0424eaab055f9caa5c2944a1 41 | 42 | COCOAPODS: 1.9.3 43 | -------------------------------------------------------------------------------- /Example/Tests/BetterSegmentedControlTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControlTests.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 23/04/16. 6 | // Copyright © 2020 George Marmaridis. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import Nimble_Snapshots 12 | @testable import BetterSegmentedControl 13 | 14 | final class BetterSegmentedControlSpec: QuickSpec { 15 | override func spec() { 16 | describe("a BetterSegmentedControl") { 17 | let testFrame = CGRect(x: 0, y: 0, width: 300, height: 44) 18 | let basicSegmentOne: [LabelSegment] = [.init(text: "One")] 19 | let basicSegmentsTwo: [LabelSegment] = [.init(text: "One"), .init(text: "Two")] 20 | let basicSegmentsThree: [LabelSegment] = [.init(text: "One"), .init(text: "Two"), .init(text: "Three")] 21 | let basicSegmentsFour: [LabelSegment] = [.init(text: "One"), .init(text: "Two"), .init(text: "Three"), .init(text: "Four")] 22 | 23 | var control: BetterSegmentedControl! 24 | 25 | // MARK: segments 26 | describe("its segments property") { 27 | context("when the control is initialized with zero segments") { 28 | beforeEach { 29 | control = .init(frame: testFrame, segments: []) 30 | } 31 | 32 | context("when setting segments to zero") { 33 | beforeEach { 34 | control.segments = [] 35 | } 36 | 37 | it("renders correctly") { 38 | //📷(control) 39 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 40 | } 41 | 42 | it("has the expected index property") { 43 | expect(control.index).to(equal(-1)) 44 | } 45 | } 46 | 47 | context("when setting segments to one") { 48 | beforeEach { 49 | control.segments = basicSegmentOne 50 | } 51 | 52 | it("renders correctly") { 53 | //📷(control) 54 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 55 | } 56 | 57 | it("has the expected index property") { 58 | expect(control.index).to(equal(0)) 59 | } 60 | } 61 | 62 | context("when setting segments to two") { 63 | beforeEach { 64 | control.segments = basicSegmentsTwo 65 | } 66 | 67 | it("renders correctly") { 68 | //📷(control) 69 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 70 | } 71 | 72 | it("has the expected index property") { 73 | expect(control.index).to(equal(0)) 74 | } 75 | } 76 | 77 | context("when setting segments to two and then three") { 78 | beforeEach { 79 | control.segments = basicSegmentsTwo 80 | control.segments = basicSegmentsThree 81 | } 82 | 83 | it("renders correctly") { 84 | //📷(control) 85 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 86 | } 87 | 88 | it("has the expected index property") { 89 | expect(control.index).to(equal(0)) 90 | } 91 | } 92 | 93 | context("when setting segments to three and then two") { 94 | beforeEach { 95 | control.segments = basicSegmentsThree 96 | control.segments = basicSegmentsTwo 97 | } 98 | 99 | it("renders correctly") { 100 | //📷(control) 101 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 102 | } 103 | 104 | it("has the expected index property") { 105 | expect(control.index).to(equal(0)) 106 | } 107 | } 108 | } 109 | 110 | context("when the control is initialized with one segment") { 111 | beforeEach { 112 | control = .init(frame: testFrame, segments: basicSegmentOne) 113 | } 114 | 115 | context("when setting segments to zero") { 116 | beforeEach { 117 | control.segments = [] 118 | } 119 | 120 | it("renders correctly") { 121 | //📷(control) 122 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 123 | } 124 | 125 | it("has the expected index property") { 126 | expect(control.index).to(equal(-1)) 127 | } 128 | } 129 | 130 | context("when setting segments to one") { 131 | beforeEach { 132 | control.segments = basicSegmentOne 133 | } 134 | 135 | it("renders correctly") { 136 | //📷(control) 137 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 138 | } 139 | 140 | it("has the expected index property") { 141 | expect(control.index).to(equal(0)) 142 | } 143 | } 144 | 145 | context("when setting segments to two") { 146 | beforeEach { 147 | control.segments = basicSegmentsTwo 148 | } 149 | 150 | it("renders correctly") { 151 | //📷(control) 152 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 153 | } 154 | 155 | it("has the expected index property") { 156 | expect(control.index).to(equal(0)) 157 | } 158 | } 159 | 160 | context("when setting segments to two and then three") { 161 | beforeEach { 162 | control.segments = basicSegmentsTwo 163 | control.segments = basicSegmentsThree 164 | } 165 | 166 | it("renders correctly") { 167 | //📷(control) 168 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 169 | } 170 | 171 | it("has the expected index property") { 172 | expect(control.index).to(equal(0)) 173 | } 174 | } 175 | 176 | context("when setting segments to three and then two") { 177 | beforeEach { 178 | control.segments = basicSegmentsThree 179 | control.segments = basicSegmentsTwo 180 | } 181 | 182 | it("renders correctly") { 183 | //📷(control) 184 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 185 | } 186 | 187 | it("has the expected index property") { 188 | expect(control.index).to(equal(0)) 189 | } 190 | } 191 | } 192 | 193 | context("when the control is initialized with two segments") { 194 | beforeEach { 195 | control = .init(frame: testFrame, segments: basicSegmentsTwo) 196 | } 197 | 198 | context("when setting segments to zero") { 199 | beforeEach { 200 | control.segments = [] 201 | } 202 | 203 | it("renders correctly") { 204 | //📷(control) 205 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 206 | } 207 | 208 | it("has the expected index property") { 209 | expect(control.index).to(equal(-1)) 210 | } 211 | } 212 | 213 | context("when setting segments to one") { 214 | beforeEach { 215 | control.segments = basicSegmentOne 216 | } 217 | 218 | it("renders correctly") { 219 | //📷(control) 220 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 221 | } 222 | 223 | it("has the expected index property") { 224 | expect(control.index).to(equal(0)) 225 | } 226 | } 227 | 228 | context("when setting segments to two") { 229 | beforeEach { 230 | control.segments = basicSegmentsTwo 231 | } 232 | 233 | it("renders correctly") { 234 | //📷(control) 235 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 236 | } 237 | 238 | it("has the expected index property") { 239 | expect(control.index).to(equal(0)) 240 | } 241 | } 242 | 243 | context("when setting segments to two and then three") { 244 | beforeEach { 245 | control.segments = basicSegmentsTwo 246 | control.segments = basicSegmentsThree 247 | } 248 | 249 | it("renders correctly") { 250 | //📷(control) 251 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 252 | } 253 | 254 | it("has the expected index property") { 255 | expect(control.index).to(equal(0)) 256 | } 257 | } 258 | 259 | context("when setting segments to three and then two") { 260 | beforeEach { 261 | control.segments = basicSegmentsThree 262 | control.segments = basicSegmentsTwo 263 | } 264 | 265 | it("renders correctly") { 266 | //📷(control) 267 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 268 | } 269 | 270 | it("has the expected index property") { 271 | expect(control.index).to(equal(0)) 272 | } 273 | } 274 | } 275 | } 276 | 277 | // MARK: cornerRadius 278 | describe("its cornerRadius property") { 279 | beforeEach { 280 | control = .init(frame: testFrame, segments: basicSegmentsThree) 281 | control.backgroundColor = .black 282 | } 283 | 284 | it("the control renders correctly when setting it to 0") { 285 | control.cornerRadius = 0 286 | 287 | //📷(control) 288 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 289 | } 290 | 291 | it("the control renders correctly when setting it to 10") { 292 | control.cornerRadius = 10 293 | 294 | //📷(control) 295 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 296 | } 297 | } 298 | 299 | // MARK: indicatorViewBackgroundColor 300 | describe("its indicatorViewBackgroundColor property") { 301 | beforeEach { 302 | control = .init(frame: testFrame, segments: basicSegmentsThree) 303 | } 304 | 305 | it("the control renders correctly after updating it") { 306 | control.indicatorViewBackgroundColor = .green 307 | 308 | //📷(control) 309 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 310 | } 311 | } 312 | 313 | // MARK: indicatorViewInset 314 | describe("its indicatorViewInset property") { 315 | beforeEach { 316 | control = .init(frame: testFrame, segments: basicSegmentsThree) 317 | control.backgroundColor = .black 318 | } 319 | 320 | it("the control renders correctly when setting it to 0") { 321 | control.indicatorViewInset = 0 322 | 323 | //📷(control) 324 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 325 | } 326 | 327 | it("the control renders correctly when setting it to 4") { 328 | control.indicatorViewInset = 4 329 | 330 | //📷(control) 331 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 332 | } 333 | } 334 | 335 | // MARK: indicatorViewBorderWidth 336 | describe("its indicatorViewBorderWidth property") { 337 | beforeEach { 338 | control = .init(frame: testFrame, segments: basicSegmentsThree) 339 | } 340 | 341 | it("the control renders correctly when setting it to 4") { 342 | control.indicatorViewBorderWidth = 4 343 | 344 | //📷(control) 345 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 346 | } 347 | } 348 | 349 | // MARK: indicatorViewBorderColor 350 | describe("its indicatorViewBorderColor property") { 351 | beforeEach { 352 | control = .init(frame: testFrame, segments: basicSegmentsThree) 353 | control.indicatorViewBorderWidth = 4 354 | } 355 | 356 | it("the control renders correctly when setting it to green") { 357 | control.indicatorViewBorderColor = .green 358 | 359 | //📷(control) 360 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 361 | } 362 | } 363 | 364 | // MARK: segmentPadding 365 | describe("its segmentPadding property") { 366 | var viewController: StoryboardTestViewController! 367 | 368 | beforeEach({ 369 | let storyboard = UIStoryboard(name: "Test", bundle: Bundle(for: type(of: self))) 370 | viewController = storyboard.instantiateInitialViewController() as? StoryboardTestViewController 371 | UIApplication.shared.keyWindow!.rootViewController = viewController 372 | _ = viewController.view 373 | 374 | control = viewController.selfSizingControl 375 | }) 376 | 377 | context("when setting it to zero") { 378 | beforeEach { 379 | control.segmentPadding = 0 380 | } 381 | 382 | it("the control renders correctly", closure: { 383 | //📷(control) 384 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 385 | }) 386 | } 387 | 388 | context("when setting it to 8") { 389 | beforeEach { 390 | control.segmentPadding = 8 391 | } 392 | 393 | it("the control renders correctly", closure: { 394 | //📷(control) 395 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 396 | }) 397 | } 398 | 399 | context("when setting it to 28") { 400 | beforeEach { 401 | control.segmentPadding = 28 402 | } 403 | 404 | it("the control renders correctly", closure: { 405 | //📷(control) 406 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 407 | }) 408 | } 409 | } 410 | 411 | // MARK: init(frame:segments:index:options:) 412 | describe("its init(frame:segments:index:options:) initializer") { 413 | context("when calling it") { 414 | context("in the most basic fashion") { 415 | beforeEach { 416 | control = .init(frame: testFrame, segments: basicSegmentsThree) 417 | } 418 | 419 | it("the control has the expected default property values") { 420 | expect(control.alwaysAnnouncesValue).to(beFalse()) 421 | expect(control.announcesValueImmediately).to(beTrue()) 422 | expect(control.panningDisabled).to(beFalse()) 423 | expect(control.animationDuration).to(equal(0.3)) 424 | expect(control.animationSpringDamping).to(equal(0.75)) 425 | expect(control.segmentPadding).to(equal(14.0)) 426 | } 427 | } 428 | 429 | // segments 430 | context("with 0 segments") { 431 | beforeEach { 432 | control = .init(frame: testFrame, segments: []) 433 | } 434 | 435 | it("the control renders correctly") { 436 | //📷(control) 437 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 438 | } 439 | } 440 | 441 | context("with 1 segment") { 442 | beforeEach { 443 | control = .init(frame: testFrame, segments: basicSegmentOne) 444 | } 445 | 446 | it("the control renders correctly") { 447 | //📷(control) 448 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 449 | } 450 | } 451 | 452 | context("with 2 segments") { 453 | beforeEach { 454 | control = .init(frame: testFrame, segments: basicSegmentsTwo) 455 | } 456 | 457 | it("the control renders correctly") { 458 | //📷(control) 459 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 460 | } 461 | } 462 | 463 | context("with 3 segments") { 464 | beforeEach { 465 | control = .init(frame: testFrame, segments: basicSegmentsThree) 466 | } 467 | 468 | it("the control renders correctly") { 469 | //📷(control) 470 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 471 | } 472 | } 473 | 474 | // index 475 | context("with a valid index") { 476 | context("that is minus 1") { 477 | beforeEach { 478 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: -1) 479 | } 480 | 481 | it("the control renders correctly") { 482 | //📷(control) 483 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 484 | } 485 | 486 | it("the index property has the expected value") { 487 | expect(control.index).to(equal(-1)) 488 | } 489 | } 490 | 491 | context("that is 0") { 492 | beforeEach { 493 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: 0) 494 | } 495 | 496 | it("the control renders correctly") { 497 | //📷(control) 498 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 499 | } 500 | 501 | it("the index property has the expected value") { 502 | expect(control.index).to(equal(0)) 503 | } 504 | } 505 | 506 | context("that is 1") { 507 | beforeEach { 508 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: 1) 509 | } 510 | 511 | it("the control renders correctly") { 512 | //📷(control) 513 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 514 | } 515 | 516 | it("the index property has the expected value") { 517 | expect(control.index).to(equal(1)) 518 | } 519 | } 520 | 521 | context("that is 2") { 522 | beforeEach { 523 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: 2) 524 | } 525 | 526 | it("the control renders correctly") { 527 | //📷(control) 528 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 529 | } 530 | 531 | it("the index property has the expected value") { 532 | expect(control.index).to(equal(2)) 533 | } 534 | } 535 | } 536 | 537 | context("with an invalid index") { 538 | context("that is minus 2") { 539 | beforeEach { 540 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: -2) 541 | } 542 | 543 | it("the control renders correctly") { 544 | //📷(control) 545 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 546 | } 547 | 548 | it("the index property has the expected value") { 549 | expect(control.index).to(equal(0)) 550 | } 551 | } 552 | 553 | context("that is beyond the valid segment indices") { 554 | beforeEach { 555 | control = .init(frame: testFrame, segments: basicSegmentsThree, index: 10) 556 | } 557 | 558 | it("the control renders correctly") { 559 | //📷(control) 560 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 561 | } 562 | 563 | it("the index property has the expected value") { 564 | expect(control.index).to(equal(0)) 565 | } 566 | } 567 | } 568 | 569 | context("with options") { 570 | context("setting the indicatorViewBackgroundColor") { 571 | beforeEach { 572 | control = .init(frame: testFrame, 573 | segments: basicSegmentsThree, 574 | options: [.indicatorViewBackgroundColor(.green)]) 575 | } 576 | 577 | it("the control renders correctly") { 578 | //📷(control) 579 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 580 | } 581 | } 582 | 583 | context("setting the indicatorViewInset") { 584 | beforeEach { 585 | control = .init(frame: testFrame, 586 | segments: basicSegmentsThree, 587 | options: [.indicatorViewInset(8.0)]) 588 | } 589 | 590 | it("the control renders correctly") { 591 | //📷(control) 592 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 593 | } 594 | } 595 | 596 | context("setting the indicatorViewBorderWidth") { 597 | beforeEach { 598 | control = .init(frame: testFrame, 599 | segments: basicSegmentsThree, 600 | options: [.indicatorViewBorderWidth(4.0)]) 601 | } 602 | 603 | it("the control renders correctly") { 604 | //📷(control) 605 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 606 | } 607 | } 608 | 609 | context("setting the indicatorViewBorderColor") { 610 | beforeEach { 611 | control = .init(frame: testFrame, 612 | segments: basicSegmentsThree, 613 | options: [.indicatorViewBorderColor(.green)]) 614 | control.indicatorViewBorderWidth = 4.0 615 | } 616 | 617 | it("the control renders correctly") { 618 | //📷(control) 619 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 620 | } 621 | } 622 | 623 | context("setting the alwaysAnnouncesValue property") { 624 | context("to true") { 625 | beforeEach { 626 | control = .init(frame: testFrame, 627 | segments: basicSegmentsThree, 628 | options: [.alwaysAnnouncesValue(true)]) 629 | } 630 | 631 | it("has the expected value") { 632 | expect(control.alwaysAnnouncesValue).to(beTrue()) 633 | } 634 | } 635 | 636 | context("to false") { 637 | beforeEach { 638 | control = .init(frame: testFrame, 639 | segments: basicSegmentsThree, 640 | options: [.alwaysAnnouncesValue(false)]) 641 | } 642 | 643 | it("has the expected value") { 644 | expect(control.alwaysAnnouncesValue).to(beFalse()) 645 | } 646 | } 647 | } 648 | 649 | context("setting the announcesValueImmediately property") { 650 | context("to true") { 651 | beforeEach { 652 | control = .init(frame: testFrame, 653 | segments: basicSegmentsThree, 654 | options: [.announcesValueImmediately(true)]) 655 | } 656 | 657 | it("has the expected value") { 658 | expect(control.announcesValueImmediately).to(beTrue()) 659 | } 660 | } 661 | 662 | context("to false") { 663 | beforeEach { 664 | control = .init(frame: testFrame, 665 | segments: basicSegmentsThree, 666 | options: [.announcesValueImmediately(false)]) 667 | } 668 | 669 | it("has the expected value") { 670 | expect(control.announcesValueImmediately).to(beFalse()) 671 | } 672 | } 673 | } 674 | 675 | context("setting the panningDisabled property") { 676 | context("to true") { 677 | beforeEach { 678 | control = .init(frame: testFrame, 679 | segments: basicSegmentsThree, 680 | options: [.panningDisabled(true)]) 681 | } 682 | 683 | it("has the expected value") { 684 | expect(control.panningDisabled).to(beTrue()) 685 | } 686 | } 687 | 688 | context("to false") { 689 | beforeEach { 690 | control = .init(frame: testFrame, 691 | segments: basicSegmentsThree, 692 | options: [.panningDisabled(false)]) 693 | } 694 | 695 | it("has the expected value") { 696 | expect(control.panningDisabled).to(beFalse()) 697 | } 698 | } 699 | } 700 | 701 | context("setting the animationDuration property") { 702 | beforeEach { 703 | control = .init(frame: testFrame, 704 | segments: basicSegmentsThree, 705 | options: [.animationDuration(10)]) 706 | } 707 | 708 | it("has the expected value") { 709 | expect(control.animationDuration).to(equal(10)) 710 | } 711 | } 712 | 713 | context("setting the animationSpringDamping property") { 714 | beforeEach { 715 | control = .init(frame: testFrame, 716 | segments: basicSegmentsThree, 717 | options: [.animationSpringDamping(0.1)]) 718 | } 719 | 720 | it("has the expected value") { 721 | expect(control.animationSpringDamping).to(equal(0.1)) 722 | } 723 | } 724 | 725 | context("setting the backgroundColor") { 726 | beforeEach { 727 | control = .init(frame: testFrame, 728 | segments: basicSegmentsThree, 729 | options: [.backgroundColor(.green)]) 730 | } 731 | 732 | it("the control renders correctly") { 733 | //📷(control) 734 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 735 | } 736 | } 737 | 738 | context("setting the cornerRadius") { 739 | beforeEach { 740 | control = .init(frame: testFrame, 741 | segments: basicSegmentsThree, 742 | options: [.cornerRadius(16.0)]) 743 | } 744 | 745 | it("the control renders correctly") { 746 | //📷(control) 747 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 748 | } 749 | } 750 | } 751 | } 752 | } 753 | 754 | // MARK: init(coder:) 755 | describe("its init(coder:) initializer") { 756 | context("when called") { 757 | var viewController: StoryboardTestViewController! 758 | 759 | beforeEach({ 760 | let storyboard = UIStoryboard(name: "Test", bundle: Bundle(for: type(of: self))) 761 | viewController = storyboard.instantiateInitialViewController() as? StoryboardTestViewController 762 | UIApplication.shared.keyWindow!.rootViewController = viewController 763 | _ = viewController.view 764 | 765 | control = viewController.explicitSizeControl 766 | }) 767 | 768 | context("when an expicit size is set in Auto Layout") { 769 | beforeEach { 770 | control = viewController.explicitSizeControl 771 | } 772 | 773 | it("the control renders correctly", closure: { 774 | //📷(control) 775 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 776 | }) 777 | } 778 | 779 | context("when the control auto sizes itself in Auto Layout") { 780 | beforeEach { 781 | control = viewController.selfSizingControl 782 | } 783 | 784 | it("the control renders correctly", closure: { 785 | //📷(control) 786 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 787 | }) 788 | } 789 | } 790 | } 791 | 792 | // MARK: init(frame:) 793 | describe("its init(frame:) initializer") { 794 | context("when called") { 795 | beforeEach { 796 | control = .init(frame: testFrame) 797 | } 798 | 799 | it("the control renders correctly") { 800 | //📷(control) 801 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 802 | } 803 | } 804 | } 805 | 806 | // MARK: init() 807 | describe("its init() initializer") { 808 | context("when called") { 809 | beforeEach { 810 | control = .init() 811 | } 812 | 813 | it("the frame to be zero") { 814 | expect(control.frame).to(equal(.zero)) 815 | } 816 | } 817 | } 818 | 819 | // MARK: setIndex() 820 | describe("its setIndex() method") { 821 | beforeEach { 822 | control = .init(frame: testFrame, segments: basicSegmentsFour) 823 | } 824 | 825 | // index 826 | context("when called with an invalid index") { 827 | context("that is too low") { 828 | beforeEach { 829 | control.setIndex(-2) 830 | } 831 | 832 | it("does not update the control index") { 833 | expect(control.index).to(equal(0)) 834 | } 835 | } 836 | 837 | context("that is too high") { 838 | beforeEach { 839 | control.setIndex(10) 840 | } 841 | 842 | it("does not update the control index") { 843 | expect(control.index).to(equal(0)) 844 | } 845 | } 846 | } 847 | 848 | context("when called with a valid index") { 849 | context("that is minus 1") { 850 | beforeEach { 851 | control.setIndex(-1) 852 | } 853 | 854 | it("the index property has the expected value") { 855 | expect(control.index).to(equal(-1)) 856 | } 857 | 858 | it("the control renders correctly") { 859 | //📷(control) 860 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 861 | } 862 | } 863 | 864 | context("that is 0") { 865 | beforeEach { 866 | control.setIndex(0) 867 | } 868 | 869 | it("the index property has the expected value") { 870 | expect(control.index).to(equal(0)) 871 | } 872 | 873 | it("the control renders correctly") { 874 | //📷(control) 875 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 876 | } 877 | } 878 | 879 | context("that is 1") { 880 | beforeEach { 881 | control.setIndex(1) 882 | } 883 | 884 | it("the index property has the expected value") { 885 | expect(control.index).to(equal(1)) 886 | } 887 | 888 | it("the control renders correctly") { 889 | //📷(control) 890 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 891 | } 892 | } 893 | 894 | context("that is 2") { 895 | beforeEach { 896 | control.setIndex(2) 897 | } 898 | 899 | it("the index property has the expected value") { 900 | expect(control.index).to(equal(2)) 901 | } 902 | 903 | it("the control renders correctly") { 904 | //📷(control) 905 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 906 | } 907 | } 908 | 909 | context("that is 3") { 910 | beforeEach { 911 | control.setIndex(3) 912 | } 913 | 914 | it("the index property has the expected value") { 915 | expect(control.index).to(equal(3)) 916 | } 917 | 918 | it("the control renders correctly") { 919 | //📷(control) 920 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 921 | } 922 | } 923 | } 924 | 925 | // alwaysAnnouncesValue 926 | context("when called with a alwaysAnnouncesValue parameter") { 927 | var testViewController: TestViewController! 928 | 929 | beforeEach { 930 | testViewController = TestViewController() 931 | control = .init(frame: testFrame, segments: basicSegmentsThree) 932 | control.addTarget(testViewController, action: #selector(TestViewController.valueChanged), for: .valueChanged) 933 | } 934 | 935 | context("when it is false") { 936 | beforeEach { 937 | control.alwaysAnnouncesValue = false 938 | } 939 | 940 | it("the control sends the expected events") { 941 | control.setIndex(0, shouldSendValueChangedEvent: true) 942 | expect(testViewController.valueChangedCalledCount).to(equal(0)) 943 | 944 | control.setIndex(1, shouldSendValueChangedEvent: true) 945 | expect(testViewController.valueChangedCalledCount).to(equal(1)) 946 | 947 | control.setIndex(0, shouldSendValueChangedEvent: true) 948 | expect(testViewController.valueChangedCalledCount).to(equal(2)) 949 | 950 | control.setIndex(0, shouldSendValueChangedEvent: true) 951 | expect(testViewController.valueChangedCalledCount).to(equal(2)) 952 | } 953 | } 954 | 955 | context("when it is true") { 956 | beforeEach { 957 | control.alwaysAnnouncesValue = true 958 | } 959 | 960 | it("the control sends the expected events") { 961 | control.setIndex(0, shouldSendValueChangedEvent: true) 962 | expect(testViewController.valueChangedCalledCount).to(equal(1)) 963 | 964 | control.setIndex(1, shouldSendValueChangedEvent: true) 965 | expect(testViewController.valueChangedCalledCount).to(equal(2)) 966 | 967 | control.setIndex(0, shouldSendValueChangedEvent: true) 968 | expect(testViewController.valueChangedCalledCount).to(equal(3)) 969 | 970 | control.setIndex(0, shouldSendValueChangedEvent: true) 971 | expect(testViewController.valueChangedCalledCount).to(equal(4)) 972 | } 973 | } 974 | } 975 | 976 | // shouldSendValueChangedEvent 977 | context("when called with a shouldSendValueChangedEvent parameter") { 978 | var testViewController: TestViewController! 979 | 980 | beforeEach { 981 | testViewController = TestViewController() 982 | control = .init(frame: testFrame, segments: basicSegmentsThree) 983 | control.addTarget(testViewController, action: #selector(TestViewController.valueChanged), for: .valueChanged) 984 | } 985 | 986 | context("when it is false") { 987 | beforeEach { 988 | control.setIndex(1, shouldSendValueChangedEvent: false) 989 | control.setIndex(2, shouldSendValueChangedEvent: false) 990 | } 991 | 992 | it("the control does not send a valueChanged event") { 993 | expect(testViewController.valueChangedCalledCount).to(equal(0)) 994 | } 995 | } 996 | 997 | context("when it is true") { 998 | beforeEach { 999 | control.setIndex(1, shouldSendValueChangedEvent: true) 1000 | control.setIndex(2, shouldSendValueChangedEvent: true) 1001 | } 1002 | 1003 | it("the control does send valueChanged events") { 1004 | expect(testViewController.valueChangedCalledCount).to(equal(2)) 1005 | } 1006 | } 1007 | } 1008 | } 1009 | 1010 | // MARK: setOptions() 1011 | describe("its setOptions() method") { 1012 | beforeEach { 1013 | control = .init(frame: testFrame, segments: basicSegmentsThree) 1014 | } 1015 | 1016 | context("when setting indicatorViewBackgroundColor") { 1017 | beforeEach { 1018 | control.setOptions([.indicatorViewBackgroundColor(.green)]) 1019 | } 1020 | 1021 | it("renders correctly") { 1022 | //📷(control) 1023 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1024 | } 1025 | } 1026 | 1027 | context("when setting indicatorViewInset") { 1028 | beforeEach { 1029 | control.setOptions([.indicatorViewInset(8)]) 1030 | } 1031 | 1032 | it("renders correctly") { 1033 | //📷(control) 1034 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1035 | } 1036 | 1037 | it("has the expected value") { 1038 | expect(control.indicatorViewInset).to(equal(8)) 1039 | } 1040 | } 1041 | 1042 | context("when setting indicatorViewBorderWidth and indicatorViewBorderColor") { 1043 | beforeEach { 1044 | control.setOptions([.indicatorViewBorderWidth(4), .indicatorViewBorderColor(.green)]) 1045 | } 1046 | 1047 | it("renders correctly") { 1048 | //📷(control) 1049 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1050 | } 1051 | 1052 | it("has the expected values") { 1053 | expect(control.indicatorViewBorderWidth).to(equal(4)) 1054 | expect(control.indicatorViewBorderColor).to(equal(.green)) 1055 | } 1056 | } 1057 | 1058 | context("when setting alwaysAnnouncesValue") { 1059 | context("to true") { 1060 | beforeEach { 1061 | control.setOptions([.alwaysAnnouncesValue(true)]) 1062 | } 1063 | 1064 | it("returns the expected property value") { 1065 | expect(control.alwaysAnnouncesValue).to(beTrue()) 1066 | } 1067 | } 1068 | context("to false") { 1069 | beforeEach { 1070 | control.setOptions([.alwaysAnnouncesValue(false)]) 1071 | } 1072 | 1073 | it("returns the expected property value") { 1074 | expect(control.alwaysAnnouncesValue).to(beFalse()) 1075 | } 1076 | } 1077 | } 1078 | 1079 | context("when setting announcesValueImmediately") { 1080 | context("to true") { 1081 | beforeEach { 1082 | control.setOptions([.announcesValueImmediately(true)]) 1083 | } 1084 | 1085 | it("returns the expected property value") { 1086 | expect(control.announcesValueImmediately).to(beTrue()) 1087 | } 1088 | } 1089 | context("to false") { 1090 | beforeEach { 1091 | control.setOptions([.announcesValueImmediately(false)]) 1092 | } 1093 | 1094 | it("returns the expected property value") { 1095 | expect(control.announcesValueImmediately).to(beFalse()) 1096 | } 1097 | } 1098 | } 1099 | 1100 | context("when setting panningDisabled") { 1101 | context("to true") { 1102 | beforeEach { 1103 | control.setOptions([.panningDisabled(true)]) 1104 | } 1105 | 1106 | it("returns the expected property value") { 1107 | expect(control.panningDisabled).to(beTrue()) 1108 | } 1109 | } 1110 | context("to false") { 1111 | beforeEach { 1112 | control.setOptions([.panningDisabled(false)]) 1113 | } 1114 | 1115 | it("returns the expected property value") { 1116 | expect(control.panningDisabled).to(beFalse()) 1117 | } 1118 | } 1119 | } 1120 | 1121 | context("when setting animationDuration") { 1122 | beforeEach { 1123 | control.setOptions([.animationDuration(10.0)]) 1124 | } 1125 | 1126 | it("returns the expected property value") { 1127 | expect(control.animationDuration).to(equal(10.0)) 1128 | } 1129 | } 1130 | 1131 | context("when setting animationSpringDamping") { 1132 | beforeEach { 1133 | control.setOptions([.animationSpringDamping(0.1)]) 1134 | } 1135 | 1136 | it("returns the expected property value") { 1137 | expect(control.animationSpringDamping).to(equal(0.1)) 1138 | } 1139 | } 1140 | 1141 | context("when setting backgroundColor") { 1142 | beforeEach { 1143 | control.setOptions([.backgroundColor(.green)]) 1144 | } 1145 | 1146 | it("renders correctly") { 1147 | //📷(control) 1148 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1149 | } 1150 | 1151 | it("has the expected value") { 1152 | expect(control.backgroundColor).to(equal(.green)) 1153 | } 1154 | } 1155 | 1156 | context("when setting cornerRadius") { 1157 | beforeEach { 1158 | control.setOptions([.cornerRadius(10.0)]) 1159 | } 1160 | 1161 | it("renders correctly") { 1162 | //📷(control) 1163 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1164 | } 1165 | } 1166 | } 1167 | 1168 | // MARK: Indicator view shadow 1169 | context("when adding a shadow to the indicator view") { 1170 | beforeEach { 1171 | control = .init(frame: testFrame, segments: basicSegmentsThree) 1172 | control.indicatorView.layer.shadowColor = UIColor.black.cgColor 1173 | control.indicatorView.layer.shadowOpacity = 0.1 1174 | control.indicatorView.layer.shadowOffset = CGSize(width: 1, height: 1) 1175 | control.indicatorView.layer.shadowRadius = 2 1176 | } 1177 | 1178 | it("renders correctly") { 1179 | //📷(control) 1180 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1181 | } 1182 | } 1183 | 1184 | // MARK: appleStyled() extension 1185 | describe("its appleStyled extension") { 1186 | beforeEach { 1187 | control = .appleStyled(frame: testFrame, titles: ["One", "Two", "Three"]) 1188 | } 1189 | 1190 | it("renders correctly") { 1191 | //📷(control) 1192 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1193 | } 1194 | } 1195 | 1196 | // added to prevent regression of https://github.com/gmarm/BetterSegmentedControl/issues/83 1197 | context("when setting cornerRadius and indicatorViewInset") { 1198 | context("first cornerRadius then indicatorViewInset") { 1199 | beforeEach { 1200 | control = .init(frame: testFrame, segments: basicSegmentsThree, options: [.cornerRadius(10.0), 1201 | .indicatorViewInset(4.0)]) 1202 | control.backgroundColor = .black 1203 | } 1204 | 1205 | it("renders correctly") { 1206 | //📷(control) 1207 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1208 | } 1209 | } 1210 | 1211 | context("first indicatorViewInset then cornerRadius") { 1212 | beforeEach { 1213 | control = .init(frame: testFrame, segments: basicSegmentsThree, options: [.indicatorViewInset(4.0), 1214 | .cornerRadius(10.0)]) 1215 | control.backgroundColor = .black 1216 | } 1217 | 1218 | it("renders correctly") { 1219 | //📷(control) 1220 | expect(control).to(haveValidSnapshotWithAcceptableTolerance()) 1221 | } 1222 | } 1223 | } 1224 | } 1225 | } 1226 | } 1227 | -------------------------------------------------------------------------------- /Example/Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_appleStyled_extension__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_appleStyled_extension__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_0@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_10@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_cornerRadius_property__the_control_renders_correctly_when_setting_it_to_10@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBackgroundColor_property__the_control_renders_correctly_after_updating_it@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBackgroundColor_property__the_control_renders_correctly_after_updating_it@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBorderColor_property__the_control_renders_correctly_when_setting_it_to_green@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBorderColor_property__the_control_renders_correctly_when_setting_it_to_green@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBorderWidth_property__the_control_renders_correctly_when_setting_it_to_4@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewBorderWidth_property__the_control_renders_correctly_when_setting_it_to_4@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_0@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_4@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_indicatorViewInset_property__the_control_renders_correctly_when_setting_it_to_4@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_an_expicit_size_is_set_in_Auto_Layout__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_an_expicit_size_is_set_in_Auto_Layout__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_the_control_auto_sizes_itself_in_Auto_Layout__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_coder___initializer__when_called__when_the_control_auto_sizes_itself_in_Auto_Layout__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame___initializer__when_called__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame___initializer__when_called__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_0_segments__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_0_segments__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_1_segment__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_1_segment__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_2_segments__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_2_segments__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_3_segments__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_3_segments__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_beyond_the_valid_segment_indices__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_beyond_the_valid_segment_indices__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_minus_2__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_an_invalid_index__that_is_minus_2__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_backgroundColor__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_backgroundColor__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_cornerRadius__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_cornerRadius__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBackgroundColor__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBackgroundColor__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderColor__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderColor__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderWidth__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewBorderWidth__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewInset__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_init_frame_segments_index_options___initializer__when_calling_it__with_options__setting_the_indicatorViewInset__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_28__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_28__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_8__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_8__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_zero__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segmentPadding_property__when_setting_it_to_zero__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_one__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_one__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_zero__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_one_segment__when_setting_segments_to_zero__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_one__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_one__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_zero__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_two_segments__when_setting_segments_to_zero__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_one__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_one__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_three_and_then_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_two_and_then_three__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_zero__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_segments_property__when_the_control_is_initialized_with_zero_segments__when_setting_segments_to_zero__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_0__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_1__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_2__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_3__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_3__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setIndex___method__when_called_with_a_valid_index__that_is_minus_1__the_control_renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_backgroundColor__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_backgroundColor__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_cornerRadius__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_cornerRadius__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBackgroundColor__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBackgroundColor__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBorderWidth_and_indicatorViewBorderColor__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewBorderWidth_and_indicatorViewBorderColor__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewInset__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__its_setOptions___method__when_setting_indicatorViewInset__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_adding_a_shadow_to_the_indicator_view__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_adding_a_shadow_to_the_indicator_view__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_cornerRadius_then_indicatorViewInset__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_cornerRadius_then_indicatorViewInset__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_indicatorViewInset_then_cornerRadius__renders_correctly@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Example/Tests/ReferenceImages/BetterSegmentedControlTests/a_BetterSegmentedControl__when_setting_cornerRadius_and_indicatorViewInset__first_indicatorViewInset_then_cornerRadius__renders_correctly@3x.png -------------------------------------------------------------------------------- /Example/Tests/SnapshotHelpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapshotHelpers.swift 3 | // BetterSegmentedControl_Tests 4 | // 5 | // Created by George Marmaridis on 18.10.20. 6 | // Copyright © 2020 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Nimble 10 | import Nimble_Snapshots 11 | 12 | public func haveValidSnapshotWithAcceptableTolerance() -> Predicate { 13 | haveValidSnapshot(named: nil, identifier: nil, usesDrawRect: false, tolerance: 0.01) 14 | } 15 | -------------------------------------------------------------------------------- /Example/Tests/Test.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 | -------------------------------------------------------------------------------- /Example/Tests/TestViewControllers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 23/04/16. 6 | // Copyright © 2020 George Marmaridis. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import BetterSegmentedControl 12 | 13 | final class StoryboardTestViewController: UIViewController { 14 | @IBOutlet weak var explicitSizeControl: BetterSegmentedControl! 15 | @IBOutlet weak var selfSizingControl: BetterSegmentedControl! 16 | } 17 | 18 | final class TestViewController: UIViewController { 19 | var valueChangedCalledCount = 0 20 | @objc func valueChanged() { 21 | valueChangedCalledCount += 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'slather' 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.2) 5 | activesupport (6.0.3.4) 6 | concurrent-ruby (~> 1.0, >= 1.0.2) 7 | i18n (>= 0.7, < 2) 8 | minitest (~> 5.1) 9 | tzinfo (~> 1.1) 10 | zeitwerk (~> 2.2, >= 2.2.2) 11 | atomos (0.1.3) 12 | claide (1.0.3) 13 | clamp (1.3.2) 14 | colored2 (3.1.2) 15 | concurrent-ruby (1.1.7) 16 | i18n (1.8.5) 17 | concurrent-ruby (~> 1.0) 18 | mini_portile2 (2.4.0) 19 | minitest (5.14.2) 20 | nanaimo (0.3.0) 21 | nokogiri (1.10.10) 22 | mini_portile2 (~> 2.4.0) 23 | slather (2.5.0) 24 | CFPropertyList (>= 2.2, < 4) 25 | activesupport 26 | clamp (~> 1.3) 27 | nokogiri (~> 1.8) 28 | xcodeproj (~> 1.7) 29 | thread_safe (0.3.6) 30 | tzinfo (1.2.7) 31 | thread_safe (~> 0.1) 32 | xcodeproj (1.19.0) 33 | CFPropertyList (>= 2.3.3, < 4.0) 34 | atomos (~> 0.1.3) 35 | claide (>= 1.0.2, < 2.0) 36 | colored2 (~> 3.1) 37 | nanaimo (~> 0.3.0) 38 | zeitwerk (2.4.0) 39 | 40 | PLATFORMS 41 | ruby 42 | 43 | DEPENDENCIES 44 | slather 45 | 46 | BUNDLED WITH 47 | 2.1.4 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 George Marmaridis 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "BetterSegmentedControl", 6 | platforms: [ 7 | .iOS(.v9), 8 | ], 9 | products: [ 10 | .library( 11 | name: "BetterSegmentedControl", 12 | targets: ["BetterSegmentedControl"] 13 | ) 14 | ], 15 | targets: [ 16 | .target( 17 | name: "BetterSegmentedControl", 18 | path: "Pod/Classes" 19 | ) 20 | ], 21 | swiftLanguageVersions: [.v5] 22 | ) 23 | -------------------------------------------------------------------------------- /Pod/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Pod/Assets/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmarm/BetterSegmentedControl/32348f8fc700c78a6aefa731214cb4497757a48b/Pod/Classes/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl+IBDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControl+IBDesignable.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 20.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | extension BetterSegmentedControl { 13 | open override func prepareForInterfaceBuilder() { 14 | super.prepareForInterfaceBuilder() 15 | 16 | setDefaultColorsIfNeeded() 17 | } 18 | open override func awakeFromNib() { 19 | super.awakeFromNib() 20 | 21 | setDefaultColorsIfNeeded() 22 | } 23 | private func setDefaultColorsIfNeeded() { 24 | if #available(iOS 13.0, *) { 25 | if backgroundColor == UIColor.systemBackground || backgroundColor == nil { 26 | backgroundColor = .appleSegmentedControlDefaultControlBackground 27 | } 28 | if indicatorViewBackgroundColor == UIColor.systemBackground || indicatorViewBackgroundColor == nil { 29 | indicatorViewBackgroundColor = .appleSegmentedControlDefaultIndicatorBackground 30 | } 31 | } else { 32 | if backgroundColor == nil { 33 | backgroundColor = .appleSegmentedControlDefaultControlBackground 34 | } 35 | if indicatorViewBackgroundColor == nil { 36 | indicatorViewBackgroundColor = .appleSegmentedControlDefaultIndicatorBackground 37 | } 38 | } 39 | } 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl+IndicatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControl+IndicatorView.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 19.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | extension BetterSegmentedControl { 13 | open class IndicatorView: UIView { 14 | // MARK: Properties 15 | let segmentMaskView = UIView() 16 | var cornerRadius: CGFloat = 0.0 { 17 | didSet { 18 | layer.cornerRadius = cornerRadius 19 | segmentMaskView.layer.cornerRadius = cornerRadius 20 | } 21 | } 22 | override open var frame: CGRect { 23 | didSet { 24 | segmentMaskView.frame = frame 25 | } 26 | } 27 | 28 | // MARK: Initialization 29 | init() { 30 | super.init(frame: CGRect.zero) 31 | completeInit() 32 | } 33 | required public init?(coder aDecoder: NSCoder) { 34 | super.init(coder: aDecoder) 35 | completeInit() 36 | } 37 | private func completeInit() { 38 | segmentMaskView.backgroundColor = .black 39 | } 40 | } 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl+Options.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Options.swift 3 | // Pods 4 | // 5 | // Created by George Marmaridis on 15/05/2017. 6 | // 7 | // 8 | 9 | #if canImport(UIKit) 10 | 11 | import UIKit 12 | 13 | public extension BetterSegmentedControl { 14 | enum Option { 15 | /* Selected segment */ 16 | case indicatorViewBackgroundColor(UIColor) 17 | case indicatorViewInset(CGFloat) 18 | case indicatorViewBorderWidth(CGFloat) 19 | case indicatorViewBorderColor(UIColor) 20 | 21 | /* Behavior */ 22 | case alwaysAnnouncesValue(Bool) 23 | case announcesValueImmediately(Bool) 24 | case panningDisabled(Bool) 25 | 26 | /* Animation */ 27 | case animationDuration(TimeInterval) 28 | case animationSpringDamping(CGFloat) 29 | 30 | /* Other */ 31 | case backgroundColor(UIColor) 32 | case cornerRadius(CGFloat) 33 | } 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl+PredefinedStyles.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControl+PredefinedStyles.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 18.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | public extension BetterSegmentedControl { 13 | class func appleStyled(frame: CGRect, titles: [String]) -> BetterSegmentedControl { 14 | let control = BetterSegmentedControl( 15 | frame: frame, 16 | segments: LabelSegment.segments(withTitles: titles), 17 | options: [.cornerRadius(8)]) 18 | control.indicatorView.layer.shadowColor = UIColor.black.cgColor 19 | control.indicatorView.layer.shadowOpacity = 0.1 20 | control.indicatorView.layer.shadowOffset = CGSize(width: 1, height: 1) 21 | control.indicatorView.layer.shadowRadius = 2 22 | 23 | return control 24 | } 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl+UIPointerInteractionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControl+UIPointerInteractionDelegate.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 19.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | @available(iOS 13.4, *) 13 | extension BetterSegmentedControl: UIPointerInteractionDelegate { 14 | public func pointerInteraction(_ interaction: UIPointerInteraction, 15 | regionFor request: UIPointerRegionRequest, 16 | defaultRegion: UIPointerRegion) -> UIPointerRegion? { 17 | let closestIndexToRequestRegion = closestIndex(toPoint: request.location) 18 | 19 | let view = (closestIndexToRequestRegion == index) ? indicatorView : pointerInteractionViews[closestIndexToRequestRegion] 20 | pointerInteractionView = view 21 | 22 | return .init(rect: view.frame) 23 | } 24 | 25 | public func pointerInteraction(_ interaction: UIPointerInteraction, 26 | styleFor region: UIPointerRegion) -> UIPointerStyle? { 27 | guard let view = pointerInteractionView else { 28 | return nil 29 | } 30 | 31 | if view === indicatorView { 32 | return .init(effect: .lift(.init(view: view))) 33 | } 34 | return .init(effect: .highlight(.init(view: view))) 35 | } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Pod/Classes/BetterSegmentedControl.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControl.swift 3 | // 4 | // Created by George Marmaridis on 01/04/16. 5 | // Copyright © 2020 George Marmaridis. All rights reserved. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | @IBDesignable open class BetterSegmentedControl: UIControl { 13 | private struct Constants { 14 | static let minimumIntrinsicContentSizeHeight: CGFloat = 32.0 15 | static let minimumSegmentIntrinsicContentSizeWidth: CGFloat = 20.0 16 | } 17 | 18 | // MARK: Properties 19 | 20 | // Public 21 | /// Indicates a no-segment-selected state. 22 | public static let noSegment = -1 23 | 24 | /// The selected index. Use `setIndex()` for setting the index. 25 | public private(set) var index: Int 26 | 27 | /// The segments available for selection. 28 | public var segments: [BetterSegmentedControlSegment] { 29 | didSet { 30 | applySegments() 31 | } 32 | } 33 | 34 | /// The currently selected index indicator view. 35 | public let indicatorView = IndicatorView() 36 | 37 | /// Whether the the control should always send the .valueChanged event, regardless of the index remaining unchanged after interaction. Defaults to `false`. 38 | @IBInspectable public var alwaysAnnouncesValue: Bool = false 39 | 40 | /// Whether to send the .valueChanged event immediately or wait for animations to complete. Defaults to `true`. 41 | @IBInspectable public var announcesValueImmediately: Bool = true 42 | 43 | /// Whether the the control should ignore pan gestures. Defaults to `false`. 44 | @IBInspectable public var panningDisabled: Bool = false 45 | 46 | /// The control's and indicator's corner radii. 47 | @IBInspectable public var cornerRadius: CGFloat { 48 | get { 49 | layer.cornerRadius 50 | } 51 | set { 52 | layer.cornerRadius = newValue 53 | updateCornerRadii() 54 | } 55 | } 56 | 57 | /// The indicator view's background color. 58 | @IBInspectable public var indicatorViewBackgroundColor: UIColor? { 59 | get { 60 | indicatorView.backgroundColor 61 | } 62 | set { 63 | indicatorView.backgroundColor = newValue 64 | } 65 | } 66 | 67 | /// The indicator view's inset. Defaults to `2.0`. 68 | @IBInspectable public var indicatorViewInset: CGFloat = 2.0 { 69 | didSet { 70 | updateCornerRadii() 71 | } 72 | } 73 | 74 | /// The indicator view's border width. 75 | @IBInspectable public var indicatorViewBorderWidth: CGFloat { 76 | get { 77 | indicatorView.layer.borderWidth 78 | } 79 | set { 80 | indicatorView.layer.borderWidth = newValue 81 | } 82 | } 83 | 84 | /// The indicator view's border color. 85 | @IBInspectable public var indicatorViewBorderColor: UIColor? { 86 | get { 87 | guard let color = indicatorView.layer.borderColor else { 88 | return nil 89 | } 90 | return UIColor(cgColor: color) 91 | } 92 | set { 93 | indicatorView.layer.borderColor = newValue?.cgColor 94 | } 95 | } 96 | 97 | /// The duration of the animation of an index change. Defaults to `0.3`. 98 | @IBInspectable public var animationDuration: TimeInterval = 0.3 99 | 100 | /// The spring damping ratio of the animation of an index change. Defaults to `0.75`. Set to `1.0` for a no bounce effect. 101 | @IBInspectable public var animationSpringDamping: CGFloat = 0.75 102 | 103 | /// When the control auto-sizes itself, this controls the additional side padding between the segments. 104 | @IBInspectable public var segmentPadding: CGFloat = 14.0 { 105 | didSet { 106 | invalidateIntrinsicContentSize() 107 | } 108 | } 109 | 110 | open override var intrinsicContentSize: CGSize { 111 | let segmentIntrinsicContentSizes = segments.map { 112 | $0.intrinsicContentSize ?? .zero 113 | } 114 | 115 | let maxSegmentIntrinsicContentSizeWidth = segmentIntrinsicContentSizes.max(by: { (a, b) in 116 | return a.width < b.width 117 | })?.width ?? 0.0 118 | 119 | let maxSegmentIntrinsicContentSizeHeight = segmentIntrinsicContentSizes.max(by: { (a, b) in 120 | return a.height < b.height 121 | })?.height ?? 0.0 122 | 123 | let singleSegmentWidth = totalInsetSize + max(maxSegmentIntrinsicContentSizeWidth, Constants.minimumSegmentIntrinsicContentSizeWidth) + segmentPadding 124 | 125 | let width = ceil(CGFloat(segments.count) * singleSegmentWidth) 126 | let height = ceil(max(maxSegmentIntrinsicContentSizeHeight + totalInsetSize, Constants.minimumIntrinsicContentSizeHeight)) 127 | 128 | return .init(width: width, height: height) 129 | } 130 | 131 | // Private 132 | private let normalSegmentViewsContainerView = UIView() 133 | private let selectedSegmentViewsContainerView = UIView() 134 | private let pointerInteractionViewsContainerView = UIView() 135 | 136 | private var initialIndicatorViewFrame: CGRect? 137 | 138 | private var tapGestureRecognizer: UITapGestureRecognizer! 139 | private var panGestureRecognizer: UIPanGestureRecognizer! 140 | 141 | private var normalSegmentViews: [UIView] = [] 142 | private var normalSegmentViewCount: Int { normalSegmentViews.count } 143 | 144 | /// `selectedSegmentViews` provide accessibility traits. 145 | private var selectedSegmentViews: [UIView] = [] 146 | 147 | var pointerInteractionViews: [UIView] = [] 148 | /// Used for iPad Pointer Interaction support. Holds the reference to the view that should be highlighted, if any. 149 | weak var pointerInteractionView: UIView? 150 | 151 | /// Contains normal segment views, selected segment views and pointer interaction views. 152 | private var allSegmentViews: [UIView] { normalSegmentViews + selectedSegmentViews + pointerInteractionViews } 153 | 154 | private var safeIndex: Int { 155 | index >= 0 ? index : 0 156 | } 157 | private var lastIndex: Int { segments.endIndex - 1 } 158 | 159 | private var totalInsetSize: CGFloat { indicatorViewInset * 2.0 } 160 | 161 | private var isLayoutDirectionRightToLeft: Bool { 162 | let layoutDirection = UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) 163 | return layoutDirection == .rightToLeft 164 | } 165 | 166 | private static var defaultOptions: [Option] = [.backgroundColor(.appleSegmentedControlDefaultControlBackground), 167 | .indicatorViewBackgroundColor(.appleSegmentedControlDefaultIndicatorBackground)] 168 | 169 | // MARK: Initialization 170 | /// Initializes a new `BetterSegmentedControl` with the parameters passed. 171 | /// 172 | /// - Parameters: 173 | /// - frame: The frame of the control. 174 | /// - segments: The segments to configure the control with. 175 | /// - index: The initially selected index. Passing `BetterSegmentedControl.noSegment` sets the index to `-1` and hides the 176 | /// indicator view. Passing an index beyond the segment indices will set the index to `0`. 177 | /// - options: An array of customization options to style and change the behavior of the control. 178 | public init(frame: CGRect, 179 | segments: [BetterSegmentedControlSegment], 180 | index: Int = 0, 181 | options: [Option]? = nil) { 182 | if segments.indices.contains(index) || index == Self.noSegment { 183 | self.index = index 184 | } else { 185 | self.index = 0 186 | } 187 | 188 | self.segments = segments 189 | 190 | super.init(frame: frame) 191 | 192 | completeInit() 193 | 194 | if index == -1 { 195 | setIndicatorViewVisible(false, animated: false, completion: nil) 196 | } 197 | 198 | setOptions(BetterSegmentedControl.defaultOptions) 199 | if let options = options { 200 | setOptions(options) 201 | } 202 | } 203 | 204 | required public init?(coder aDecoder: NSCoder) { 205 | self.index = 0 206 | self.segments = Self.generateDefaultSegments() 207 | 208 | super.init(coder: aDecoder) 209 | 210 | completeInit() 211 | } 212 | 213 | convenience override public init(frame: CGRect) { 214 | self.init(frame: frame, segments: Self.generateDefaultSegments()) 215 | } 216 | 217 | convenience init() { 218 | self.init(frame: .zero, segments: Self.generateDefaultSegments()) 219 | } 220 | 221 | private func completeInit() { 222 | layer.masksToBounds = true 223 | 224 | if #available(iOS 13.4, *) { 225 | let interaction = UIPointerInteraction(delegate: self) 226 | addInteraction(interaction) 227 | } 228 | 229 | // set up view hierarchy 230 | normalSegmentViewsContainerView.clipsToBounds = true 231 | addSubview(normalSegmentViewsContainerView) 232 | 233 | addSubview(indicatorView) 234 | 235 | selectedSegmentViewsContainerView.clipsToBounds = true 236 | addSubview(selectedSegmentViewsContainerView) 237 | selectedSegmentViewsContainerView.layer.mask = indicatorView.segmentMaskView.layer 238 | 239 | pointerInteractionViewsContainerView.clipsToBounds = true 240 | addSubview(pointerInteractionViewsContainerView) 241 | 242 | // configure gestures 243 | tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped(_:))) 244 | addGestureRecognizer(tapGestureRecognizer) 245 | 246 | panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panned(_:))) 247 | panGestureRecognizer.delegate = self 248 | addGestureRecognizer(panGestureRecognizer) 249 | 250 | applySegments(shouldResetIndex: false) 251 | } 252 | 253 | // MARK: View lifecycle 254 | override open func layoutSubviews() { 255 | super.layoutSubviews() 256 | guard normalSegmentViewCount >= 1 else { 257 | return 258 | } 259 | 260 | normalSegmentViewsContainerView.frame = bounds 261 | selectedSegmentViewsContainerView.frame = bounds 262 | pointerInteractionViewsContainerView.frame = bounds 263 | 264 | indicatorView.frame = frameForElement(atIndex: safeIndex) 265 | 266 | for (index, _) in normalSegmentViews.enumerated() { 267 | let frame = frameForElement(atIndex: index) 268 | normalSegmentViews[index].frame = frame 269 | selectedSegmentViews[index].frame = frame 270 | pointerInteractionViews[index].frame = frame 271 | } 272 | } 273 | 274 | // MARK: Index Setting 275 | /// Sets the control's index. 276 | /// 277 | /// - Parameters: 278 | /// - index: The new index. Passing `BetterSegmentedControl.noSegment` sets the index to `-1` and hides the indicator view. 279 | /// Passing an index beyond the segment indices will have no effect. 280 | /// - animated: Whether the change should be animated or not. Defaults to `true`. 281 | /// - shouldSendValueChangedEvent: Whether the index change should trigger a `.valueChanged` event or not. Defaults to 282 | /// `false`. This takes precedence over `alwaysAnnouncesValue`. 283 | public func setIndex(_ index: Int, animated: Bool = true, shouldSendValueChangedEvent: Bool = false) { 284 | guard segments.indices.contains(index) || index == Self.noSegment else { return } 285 | 286 | let previousIndex = self.index 287 | self.index = index 288 | 289 | let shouldUpdateSegmentViewTraits = (index != previousIndex) 290 | let shouldUpdateSegmentViewTraitsBeforeAnimations = announcesValueImmediately && shouldUpdateSegmentViewTraits 291 | let shouldUpdateSegmentViewTraitsAfterAnimations = !announcesValueImmediately && shouldUpdateSegmentViewTraits 292 | 293 | let shouldSendEvent = (index != previousIndex || alwaysAnnouncesValue) && shouldSendValueChangedEvent 294 | let shouldSendEventBeforeAnimations = announcesValueImmediately && shouldSendEvent 295 | let shouldSendEventAfterAnimations = !announcesValueImmediately && shouldSendEvent 296 | 297 | if shouldSendEventBeforeAnimations { 298 | sendActions(for: .valueChanged) 299 | } 300 | if shouldUpdateSegmentViewTraitsBeforeAnimations { 301 | updateSegmentViewTraits() 302 | } 303 | performIndexChange(fromPreviousIndex: previousIndex, toNewIndex: index, animated: animated, completion: { [weak self] in 304 | guard let weakSelf = self else { return } 305 | 306 | if shouldSendEventAfterAnimations { 307 | weakSelf.sendActions(for: .valueChanged) 308 | } 309 | if shouldUpdateSegmentViewTraitsAfterAnimations { 310 | weakSelf.updateSegmentViewTraits() 311 | } 312 | }) 313 | } 314 | 315 | // MARK: Option Setting 316 | /// A list of options to configure the control with. 317 | public func setOptions(_ options: [Option]) { 318 | for option in options { 319 | switch option { 320 | case let .indicatorViewBackgroundColor(value): 321 | indicatorViewBackgroundColor = value 322 | case let .indicatorViewInset(value): 323 | indicatorViewInset = value 324 | case let .indicatorViewBorderWidth(value): 325 | indicatorViewBorderWidth = value 326 | case let .indicatorViewBorderColor(value): 327 | indicatorViewBorderColor = value 328 | case let .alwaysAnnouncesValue(value): 329 | alwaysAnnouncesValue = value 330 | case let .announcesValueImmediately(value): 331 | announcesValueImmediately = value 332 | case let .panningDisabled(value): 333 | panningDisabled = value 334 | case let .backgroundColor(value): 335 | backgroundColor = value 336 | case let .cornerRadius(value): 337 | cornerRadius = value 338 | case let .animationDuration(value): 339 | animationDuration = value 340 | case let .animationSpringDamping(value): 341 | animationSpringDamping = value 342 | } 343 | } 344 | } 345 | 346 | // MARK: Animations 347 | /// Hides the indicator and selected segments view. 348 | private func setIndicatorViewVisible(_ isVisible: Bool, animated: Bool, completion: (() -> Void)?) { 349 | UIView.animate(withDuration: (animated ? 0.1 : 0.0), 350 | delay: 0.0, 351 | options: [.beginFromCurrentState, .curveEaseIn], 352 | animations: { () -> Void in 353 | self.selectedSegmentViewsContainerView.alpha = isVisible ? 1.0 : 0.0 354 | self.indicatorView.alpha = isVisible ? 1.0 : 0.0 355 | }, completion: { finished -> Void in 356 | completion?() 357 | }) 358 | } 359 | 360 | private func performIndexChange(fromPreviousIndex previousIndex: Int, 361 | toNewIndex newIndex: Int, 362 | animated: Bool, 363 | completion: @escaping () -> Void) { 364 | func moveIndicatorViewToIndex(animated: Bool, completion: @escaping () -> Void) { 365 | guard index >= 0 else { return } 366 | 367 | UIView.animate(withDuration: animated ? animationDuration : 0.0, 368 | delay: 0.0, 369 | usingSpringWithDamping: animationSpringDamping, 370 | initialSpringVelocity: 0.0, 371 | options: [.beginFromCurrentState, .curveEaseOut], 372 | animations: { () -> Void in 373 | self.indicatorView.frame = self.normalSegmentViews[self.index].frame 374 | self.layoutIfNeeded() 375 | }, completion: { finished -> Void in 376 | completion() 377 | }) 378 | } 379 | 380 | if index == Self.noSegment { 381 | setIndicatorViewVisible(false, animated: animated) { 382 | completion() 383 | } 384 | } else if previousIndex == Self.noSegment { 385 | moveIndicatorViewToIndex(animated: false, completion: { [weak self] in 386 | self?.setIndicatorViewVisible(true, animated: animated) { 387 | completion() 388 | } 389 | }) 390 | } else { 391 | moveIndicatorViewToIndex(animated: animated, completion: { 392 | completion() 393 | }) 394 | } 395 | } 396 | 397 | // MARK: Helpers 398 | /// Updates the segments and triggers a layout refresh. Resets the index if needed. 399 | private func applySegments(shouldResetIndex: Bool = true) { 400 | normalSegmentViews.forEach { $0.removeFromSuperview() } 401 | normalSegmentViews.removeAll() 402 | 403 | selectedSegmentViews.forEach { $0.removeFromSuperview() } 404 | selectedSegmentViews.removeAll() 405 | 406 | pointerInteractionViews.forEach { $0.removeFromSuperview() } 407 | pointerInteractionViews.removeAll() 408 | 409 | for segment in segments { 410 | segment.normalView.clipsToBounds = true 411 | segment.normalView.isAccessibilityElement = false 412 | 413 | segment.selectedView.clipsToBounds = true 414 | 415 | normalSegmentViewsContainerView.addSubview(segment.normalView) 416 | normalSegmentViews.append(segment.normalView) 417 | 418 | selectedSegmentViewsContainerView.addSubview(segment.selectedView) 419 | selectedSegmentViews.append(segment.selectedView) 420 | 421 | let pointerInteractionView = UIView() 422 | pointerInteractionViewsContainerView.addSubview(pointerInteractionView) 423 | pointerInteractionViews.append(pointerInteractionView) 424 | } 425 | 426 | updateSegmentViewTraits() 427 | updateCornerRadii() 428 | if shouldResetIndex { 429 | resetIndex() 430 | } 431 | 432 | invalidateIntrinsicContentSize() 433 | setNeedsLayout() 434 | } 435 | 436 | private func updateCornerRadii() { 437 | indicatorView.cornerRadius = cornerRadius - indicatorViewInset 438 | allSegmentViews.forEach { $0.layer.cornerRadius = indicatorView.cornerRadius } 439 | } 440 | 441 | private func updateSegmentViewTraits() { 442 | accessibilityElements = selectedSegmentViews 443 | 444 | for (index, _) in selectedSegmentViews.enumerated() { 445 | selectedSegmentViews[index].accessibilityTraits = (index == self.index ? [.button, .selected] : [.button]) 446 | } 447 | } 448 | 449 | private func frameForElement(atIndex index: Int) -> CGRect { 450 | let elementWidth = (width - totalInsetSize) / CGFloat(normalSegmentViewCount) 451 | let x = CGFloat(isLayoutDirectionRightToLeft ? lastIndex - index : index) * elementWidth 452 | 453 | return CGRect(x: x + indicatorViewInset, 454 | y: indicatorViewInset, 455 | width: elementWidth, 456 | height: height - totalInsetSize) 457 | } 458 | 459 | private func resetIndex() { 460 | let newIndex = (segments.count > 0 ? 0 : -1) 461 | setIndex(newIndex, animated: false, shouldSendValueChangedEvent: false) 462 | } 463 | 464 | func closestIndex(toPoint point: CGPoint) -> Int { 465 | let distances = normalSegmentViews.map { abs(point.x - $0.center.x) } 466 | return Int(distances.firstIndex(of: distances.min()!)!) 467 | } 468 | 469 | private static func generateDefaultSegments() -> [LabelSegment] { 470 | [.init(text: "First"), .init(text: "Second"), .init(text: "Third")] 471 | } 472 | 473 | // MARK: Action handlers 474 | @objc private func tapped(_ gestureRecognizer: UITapGestureRecognizer!) { 475 | let location = gestureRecognizer.location(in: self) 476 | setIndex(closestIndex(toPoint: location), shouldSendValueChangedEvent: true) 477 | } 478 | 479 | @objc private func panned(_ gestureRecognizer: UIPanGestureRecognizer!) { 480 | switch gestureRecognizer.state { 481 | case .began: 482 | initialIndicatorViewFrame = indicatorView.frame 483 | case .changed: 484 | var frame = initialIndicatorViewFrame! 485 | frame.origin.x += gestureRecognizer.translation(in: self).x 486 | frame.origin.x = max(min(frame.origin.x, bounds.width - indicatorViewInset - frame.width), indicatorViewInset) 487 | indicatorView.frame = frame 488 | case .ended, .failed, .cancelled: 489 | setIndex(closestIndex(toPoint: indicatorView.center), shouldSendValueChangedEvent: true) 490 | default: break 491 | } 492 | } 493 | } 494 | 495 | // MARK: - UIGestureRecognizerDelegate 496 | extension BetterSegmentedControl: UIGestureRecognizerDelegate { 497 | override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 498 | if gestureRecognizer == panGestureRecognizer { 499 | return indicatorView.frame.contains(gestureRecognizer.location(in: self)) && !panningDisabled 500 | } 501 | return super.gestureRecognizerShouldBegin(gestureRecognizer) 502 | } 503 | } 504 | 505 | #endif 506 | -------------------------------------------------------------------------------- /Pod/Classes/Helpers/UIColor+Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Helpers.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 16.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | extension UIColor { 13 | class var appleSegmentedControlDefaultControlBackground: UIColor { 14 | .init(red: 238.0/255.0, green: 238.0/255.0, blue: 238.0/255.0, alpha: 1.0) 15 | } 16 | class var appleSegmentedControlDefaultIndicatorBackground: UIColor { 17 | .white 18 | } 19 | class var appleSegmentedControlDefaultSegmentText: UIColor { 20 | .black 21 | } 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Pod/Classes/Helpers/UIView+Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Helpers.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 19.10.20. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | extension UIView { 13 | var width: CGFloat { bounds.width } 14 | var height: CGFloat { bounds.height } 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /Pod/Classes/Segments/BetterSegmentedControlSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BetterSegmentedControlSegment.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 08/10/2017. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | /// A segment is comprised of a normal state view and a selected state view. These need to be separate view instances. 13 | public protocol BetterSegmentedControlSegment { 14 | /// If provided, `BetterSegmentedControl` will use its value to calculate an `intrinsicContentSize` based on this. 15 | var intrinsicContentSize: CGSize? { get } 16 | 17 | /// The view to be shown for the normal or unselected state. 18 | var normalView: UIView { get } 19 | 20 | /// The view to be shown for the active or selected state. 21 | var selectedView: UIView { get } 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Pod/Classes/Segments/IconSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IconSegment.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 10/02/2018. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | open class IconSegment: BetterSegmentedControlSegment { 13 | // MARK: Constants 14 | private struct DefaultValues { 15 | static let normalBackgroundColor: UIColor = .clear 16 | static let selectedBackgroundColor: UIColor = .clear 17 | } 18 | 19 | // MARK: Properties 20 | public var icon: UIImage 21 | public var iconSize: CGSize 22 | 23 | public var normalIconTintColor: UIColor 24 | public var normalBackgroundColor: UIColor 25 | 26 | public var selectedIconTintColor: UIColor 27 | public var selectedBackgroundColor: UIColor 28 | 29 | // MARK: Lifecycle 30 | public init(icon: UIImage, 31 | iconSize: CGSize, 32 | normalBackgroundColor: UIColor? = nil, 33 | normalIconTintColor: UIColor, 34 | selectedBackgroundColor: UIColor? = nil, 35 | selectedIconTintColor: UIColor) { 36 | self.icon = icon.withRenderingMode(.alwaysTemplate) 37 | self.iconSize = iconSize 38 | self.normalBackgroundColor = normalBackgroundColor ?? DefaultValues.normalBackgroundColor 39 | self.normalIconTintColor = normalIconTintColor 40 | self.selectedBackgroundColor = selectedBackgroundColor ?? DefaultValues.selectedBackgroundColor 41 | self.selectedIconTintColor = selectedIconTintColor 42 | } 43 | 44 | // MARK: BetterSegmentedControlSegment 45 | public var intrinsicContentSize: CGSize? { nil } 46 | 47 | public lazy var normalView: UIView = { 48 | return createView(withIcon: icon, 49 | iconSize: iconSize, 50 | backgroundColor: normalBackgroundColor, 51 | iconTintColor: normalIconTintColor) 52 | }() 53 | public lazy var selectedView: UIView = { 54 | return createView(withIcon: icon, 55 | iconSize: iconSize, 56 | backgroundColor: selectedBackgroundColor, 57 | iconTintColor: selectedIconTintColor) 58 | }() 59 | private func createView(withIcon icon: UIImage, 60 | iconSize: CGSize, 61 | backgroundColor: UIColor, 62 | iconTintColor: UIColor) -> UIView { 63 | let view = UIView() 64 | view.backgroundColor = backgroundColor 65 | let imageView = UIImageView(image: icon) 66 | imageView.frame = CGRect(x: 0, 67 | y: 0, 68 | width: iconSize.width, 69 | height: iconSize.height) 70 | imageView.contentMode = .scaleAspectFit 71 | imageView.tintColor = iconTintColor 72 | imageView.autoresizingMask = [.flexibleTopMargin, 73 | .flexibleLeftMargin, 74 | .flexibleRightMargin, 75 | .flexibleBottomMargin] 76 | view.addSubview(imageView) 77 | return view 78 | } 79 | } 80 | 81 | public extension IconSegment { 82 | class func segments(withIcons icons: [UIImage], 83 | iconSize: CGSize, 84 | normalBackgroundColor: UIColor? = nil, 85 | normalIconTintColor: UIColor, 86 | selectedBackgroundColor: UIColor? = nil, 87 | selectedIconTintColor: UIColor) -> [BetterSegmentedControlSegment] { 88 | return icons.map { 89 | IconSegment(icon: $0, 90 | iconSize: iconSize, 91 | normalBackgroundColor: normalBackgroundColor, 92 | normalIconTintColor: normalIconTintColor, 93 | selectedBackgroundColor: selectedBackgroundColor, 94 | selectedIconTintColor: selectedIconTintColor) 95 | } 96 | } 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /Pod/Classes/Segments/LabelSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LabelSegment.swift 3 | // BetterSegmentedControl 4 | // 5 | // Created by George Marmaridis on 08/10/2017. 6 | // 7 | 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | 12 | open class LabelSegment: BetterSegmentedControlSegment { 13 | // MARK: Constants 14 | private struct DefaultValues { 15 | static let normalBackgroundColor: UIColor = .clear 16 | static let normalTextColor: UIColor = .black 17 | static let normalFont: UIFont = .systemFont(ofSize: 13) 18 | static let selectedBackgroundColor: UIColor = .clear 19 | static let selectedTextColor: UIColor = .black 20 | static let selectedFont: UIFont = .systemFont(ofSize: 13, weight: .medium) 21 | } 22 | 23 | // MARK: Properties 24 | public let text: String? 25 | 26 | public let normalFont: UIFont 27 | public let normalTextColor: UIColor 28 | public let normalBackgroundColor: UIColor 29 | 30 | public let selectedFont: UIFont 31 | public let selectedTextColor: UIColor 32 | public let selectedBackgroundColor: UIColor 33 | 34 | private let numberOfLines: Int 35 | private let accessibilityIdentifier: String? 36 | 37 | // MARK: Lifecycle 38 | public init(text: String? = nil, 39 | numberOfLines: Int = 1, 40 | normalBackgroundColor: UIColor? = nil, 41 | normalFont: UIFont? = nil, 42 | normalTextColor: UIColor? = nil, 43 | selectedBackgroundColor: UIColor? = nil, 44 | selectedFont: UIFont? = nil, 45 | selectedTextColor: UIColor? = nil, 46 | accessibilityIdentifier: String? = nil) { 47 | self.text = text 48 | self.numberOfLines = numberOfLines 49 | self.normalBackgroundColor = normalBackgroundColor ?? DefaultValues.normalBackgroundColor 50 | self.normalFont = normalFont ?? DefaultValues.normalFont 51 | self.normalTextColor = normalTextColor ?? DefaultValues.normalTextColor 52 | self.selectedBackgroundColor = selectedBackgroundColor ?? DefaultValues.selectedBackgroundColor 53 | self.selectedFont = selectedFont ?? DefaultValues.selectedFont 54 | self.selectedTextColor = selectedTextColor ?? DefaultValues.selectedTextColor 55 | self.accessibilityIdentifier = accessibilityIdentifier 56 | } 57 | 58 | // MARK: BetterSegmentedControlSegment 59 | public var intrinsicContentSize: CGSize? { 60 | selectedView.intrinsicContentSize 61 | } 62 | 63 | public lazy var normalView: UIView = { 64 | createLabel(withText: text, 65 | backgroundColor: normalBackgroundColor, 66 | font: normalFont, 67 | textColor: normalTextColor, 68 | accessibilityIdentifier: accessibilityIdentifier) 69 | }() 70 | public lazy var selectedView: UIView = { 71 | createLabel(withText: text, 72 | backgroundColor: selectedBackgroundColor, 73 | font: selectedFont, 74 | textColor: selectedTextColor, 75 | accessibilityIdentifier: accessibilityIdentifier) 76 | }() 77 | open func createLabel(withText text: String?, 78 | backgroundColor: UIColor, 79 | font: UIFont, 80 | textColor: UIColor, 81 | accessibilityIdentifier: String?) -> UILabel { 82 | let label = UILabel() 83 | label.text = text 84 | label.numberOfLines = numberOfLines 85 | label.backgroundColor = backgroundColor 86 | label.font = font 87 | label.textColor = textColor 88 | label.lineBreakMode = .byTruncatingTail 89 | label.textAlignment = .center 90 | label.accessibilityIdentifier = accessibilityIdentifier 91 | return label 92 | } 93 | } 94 | 95 | public extension LabelSegment { 96 | class func segments(withTitles titles: [String], 97 | numberOfLines: Int = 1, 98 | normalBackgroundColor: UIColor? = nil, 99 | normalFont: UIFont? = nil, 100 | normalTextColor: UIColor? = nil, 101 | selectedBackgroundColor: UIColor? = nil, 102 | selectedFont: UIFont? = nil, 103 | selectedTextColor: UIColor? = nil) -> [BetterSegmentedControlSegment] { 104 | titles.map { 105 | LabelSegment(text: $0, 106 | numberOfLines: numberOfLines, 107 | normalBackgroundColor: normalBackgroundColor, 108 | normalFont: normalFont, 109 | normalTextColor: normalTextColor, 110 | selectedBackgroundColor: selectedBackgroundColor, 111 | selectedFont: selectedFont, 112 | selectedTextColor: selectedTextColor) 113 | } 114 | } 115 | } 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BetterSegmentedControl 2 | 3 | ![](https://img.shields.io/badge/Swift-5.1-blue.svg?style=flat) 4 | ![](https://app.bitrise.io/app/1d06a34a06589be2/status.svg?token=i0xHqYqUAjHGkzToH5FVOg&branch=master) 5 | [![Version](https://img.shields.io/cocoapods/v/BetterSegmentedControl.svg?style=flat)](http://cocoapods.org/pods/BetterSegmentedControl) 6 | [![License](https://img.shields.io/cocoapods/l/BetterSegmentedControl.svg?style=flat)](http://cocoapods.org/pods/BetterSegmentedControl) 7 | [![Platform](https://img.shields.io/cocoapods/p/BetterSegmentedControl.svg?style=flat)](http://cocoapods.org/pods/BetterSegmentedControl) 8 | 9 |
10 |
11 |

12 | 13 |

14 |
15 | 16 | `BetterSegmentedControl` is an easy to use, customizable replacement for 17 | `UISegmentedControl` and `UISwitch` written in Swift. 18 | 19 | ## Features 20 | 21 | - [x] Can be used as a segmented control or switch 22 | - [x] Plethora of customizable options from colors to insets, radii and 23 | animations 24 | - [x] Use text or icons as segments, or add your own custom segments 25 | - [x] Designable straight in Interface Builder 26 | - [x] Accessibility support 27 | - [x] iPad cursor support 28 | - [x] Customizable behavior 29 | - [x] Right-to-left languages support 30 | - [x] Fully tested 31 | 32 | Check the latest release notes [here][release-notes]! 33 | 34 | [release-notes]: https://github.com/gmarm/BetterSegmentedControl/releases/tag/2.0.1 35 | 36 | ## Examples 37 | 38 | #### iOS 39 | ![Demo](Assets/demo_main.gif) 40 | 41 | #### iPad cursor 42 | 43 | ![Demo](Assets/demo_ipad_cursor.gif) 44 | 45 | 46 | ## Requirements 47 | 48 | - iOS 9.0+ 49 | - Xcode 8+ 50 | 51 | 52 | ## Installation 53 | 54 | ### Swift Package Manager 55 | 56 | BetterSegmentedControl is available through Swift Package Manager. To install 57 | it, simply go to Xcode under `File > Swift Packages > Add Package Dependency...` 58 | 59 | ### CocoaPods 60 | 61 | BetterSegmentedControl is available through [CocoaPods](http://cocoapods.org). 62 | To install it, simply add the following line to your Podfile: 63 | 64 | ```ruby 65 | # Swift 5.1 66 | pod 'BetterSegmentedControl', '~> 2.0' 67 | 68 | # Swift 4 69 | pod 'BetterSegmentedControl', '1.0' 70 | 71 | # Swift 3 / Objective-C 72 | pod 'BetterSegmentedControl', '0.8' 73 | ``` 74 | 75 | ### Manually 76 | 77 | If you prefer not to use CocoaPods or Swift Package Manager, you can integrate 78 | BetterSegmentedControl into your project manually. 79 | 80 | 81 | ## Usage 82 | 83 | ```swift 84 | let control = BetterSegmentedControl(frame: CGRect(x: 16.0, 85 | y: 0, 86 | width: view.bounds.width - 32.0, 87 | height: 44.0)) 88 | view.addSubview(control) 89 | ``` 90 | 91 | You can find several ways of using it, such as by designing it in a Storyboard 92 | file or creating it in code in the example project. 93 | 94 | To run the example project, clone the repo, and run `pod install` from the 95 | Example directory first. 96 | 97 | 98 | ## Contribution 99 | 100 | Feel free to submit Pull Requests or send me your feedback and suggestions! 101 | 102 | Logo by [Guillaume Galante][guillaume-dribble]. 103 | 104 | [guillaume-dribble]: https://dribbble.com/guillaumegalante 105 | 106 | ## Author 107 | 108 | George Marmaridis 109 | 110 | - https://github.com/gmarm 111 | - https://twitter.com/gmarmas 112 | - https://www.linkedin.com/in/gmarm 113 | - gmarmas@gmail.com 114 | 115 | 116 | ## License 117 | 118 | BetterSegmentedControl is available under the MIT license. See the LICENSE file 119 | for more info. 120 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------