diff --git a/Attribution.md b/Attribution.md new file mode 100644 index 0000000..bf8cd3d --- /dev/null +++ b/Attribution.md @@ -0,0 +1,6 @@ +# Apps using this library + +I get the most joy from open-sourcing code when knowing people use my stuff. +So, if you'd like to, please add your app to the list of apps using this library: + +- Funeral Marketplace (in dev.) diff --git a/Example/LGSegmentedControl.xcodeproj/project.pbxproj b/Example/LGSegmentedControl.xcodeproj/project.pbxproj index f474576..482bfa4 100644 --- a/Example/LGSegmentedControl.xcodeproj/project.pbxproj +++ b/Example/LGSegmentedControl.xcodeproj/project.pbxproj @@ -166,13 +166,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0830; - LastUpgradeCheck = 0830; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = CocoaPods; TargetAttributes = { 607FACCF1AFB9204008FA782 = { CreatedOnToolsVersion = 6.3.1; - DevelopmentTeam = 578YR5HPG3; - LastSwiftMigration = 0900; + LastSwiftMigration = 1010; }; }; }; @@ -290,12 +289,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -343,12 +344,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -382,15 +385,14 @@ baseConfigurationReference = 795F6619180485F16B5697AD /* Pods-LGSegmentedControl_Example.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 578YR5HPG3; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = LGSegmentedControl/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.LGSegmentedControl-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -399,15 +401,14 @@ baseConfigurationReference = FE280B7A8DEEF77B6BE973D0 /* Pods-LGSegmentedControl_Example.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 578YR5HPG3; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = LGSegmentedControl/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.LGSegmentedControl-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Example/LGSegmentedControl.xcodeproj/xcshareddata/xcschemes/LGSegmentedControl-Example.xcscheme b/Example/LGSegmentedControl.xcodeproj/xcshareddata/xcschemes/LGSegmentedControl-Example.xcscheme index f653c3b..17b3fd6 100644 --- a/Example/LGSegmentedControl.xcodeproj/xcshareddata/xcschemes/LGSegmentedControl-Example.xcscheme +++ b/Example/LGSegmentedControl.xcodeproj/xcshareddata/xcschemes/LGSegmentedControl-Example.xcscheme @@ -1,6 +1,6 @@ Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } diff --git a/Example/LGSegmentedControl/Base.lproj/Main.storyboard b/Example/LGSegmentedControl/Base.lproj/Main.storyboard index a3baf4b..862bdc4 100644 --- a/Example/LGSegmentedControl/Base.lproj/Main.storyboard +++ b/Example/LGSegmentedControl/Base.lproj/Main.storyboard @@ -21,148 +21,170 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + @@ -171,6 +193,7 @@ + diff --git a/Example/LGSegmentedControl/ViewController.swift b/Example/LGSegmentedControl/ViewController.swift index 4b26d1b..05c1bc5 100644 --- a/Example/LGSegmentedControl/ViewController.swift +++ b/Example/LGSegmentedControl/ViewController.swift @@ -27,16 +27,17 @@ class ViewController: UIViewController { segmentedControl.deselectedBackgroundColor = #colorLiteral(red: 0.2196078431, green: 0.6235294118, blue: 0.9764705882, alpha: 0.15) segmentedControl.deselectedTextColor = .darkText - + // data source segmentedControl.segments = [ LGSegment(title: "1 day"), LGSegment(title: "3 weeks"), - LGSegment(title: "2 months"), - LGSegment(title: "Quarter") + LGSegment(title: "2 months") ] // make sure to set the selected index AFTER assigning the segments segmentedControl.selectedIndex = 1 + + segmentedControl.segments.first?.badgeCount = 3 } @IBAction func selectedSegment(_ segmentedControl: LGSegmentedControl) { diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index 80e1c6e..2119bac 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -113,8 +113,8 @@ children = ( 88474D5F21B7EDE600C99DB9 /* Extensions.swift */, 88474D6021B7EDE600C99DB9 /* LGSegment.swift */, - 881D99B621B8410100E7C951 /* LGSegmentOptions.swift */, 88474D6221B7EDE600C99DB9 /* LGSegmentedControl.swift */, + 881D99B621B8410100E7C951 /* LGSegmentOptions.swift */, 43CA6FD9C0F5D1706DF432FF510039CD /* Pod */, BBC9CCDFE83B087885C200E681A97B75 /* Support Files */, ); @@ -326,7 +326,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1010; TargetAttributes = { 676C26F2EED2C744684BA1A14DD8B06B = { LastSwiftMigration = 1010; @@ -523,7 +523,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -619,6 +619,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; SYMROOT = "${SRCROOT}/../build"; }; name = Release; @@ -683,7 +684,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/LGSegmentedControl.podspec b/LGSegmentedControl.podspec index c7fa13c..f0b4077 100644 --- a/LGSegmentedControl.podspec +++ b/LGSegmentedControl.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'LGSegmentedControl' - s.version = '1.0.0' + s.version = '1.2.1' s.summary = 'A prettier and highly customizable UISegmentedControl' # This description is used to generate tags and improve search results. @@ -18,11 +18,11 @@ Pod::Spec.new do |s| # * Finally, don't worry about the indent, CocoaPods strips it! s.description = <<-DESC -TODO: Add long description of the pod here. +LGSegmentedControl is a highly customizable and therefor prettier version of UISegmentedControl. DESC s.homepage = 'https://github.com/linusgeffarth/LGSegmentedControl' - # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' + s.screenshots = 'https://raw.githubusercontent.com/LinusGeffarth/LGSegmentedControl/master/screenshots/ss4.jpeg', 'https://raw.githubusercontent.com/LinusGeffarth/LGSegmentedControl/master/screenshots/ss1.png', 'https://raw.githubusercontent.com/LinusGeffarth/LGSegmentedControl/master/screenshots/ss2.png', 'https://raw.githubusercontent.com/LinusGeffarth/LGSegmentedControl/master/screenshots/ss3.png' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'linusgeffarth' => 'linus@geffarth.com' } s.source = { :git => 'https://github.com/linusgeffarth/LGSegmentedControl.git', :tag => s.version.to_s } diff --git a/LGSegmentedControl/Classes/Extensions.swift b/LGSegmentedControl/Classes/Extensions.swift index 89cd708..a14bf3f 100644 --- a/LGSegmentedControl/Classes/Extensions.swift +++ b/LGSegmentedControl/Classes/Extensions.swift @@ -20,6 +20,17 @@ extension UIStackView { self.addArrangedSubview(view) } } + + func removeAllArrangedSubviews() { + let removedSubviews = arrangedSubviews.reduce([]) { (allSubviews, subview) -> [UIView] in + self.removeArrangedSubview(subview) + return allSubviews + [subview] + } + // deactivate all constraints + NSLayoutConstraint.deactivate(removedSubviews.flatMap({ $0.constraints })) + // remove the views from self + removedSubviews.forEach({ $0.removeFromSuperview() }) + } } extension UIStackView.Distribution { @@ -65,3 +76,9 @@ public func ???(optional: T?, defaultValue: @autoclosure () -> String) -> Str case nil: return defaultValue() } } + +extension Int { + var string: String { + return "\(self)" + } +} diff --git a/LGSegmentedControl/Classes/LGSegment.swift b/LGSegmentedControl/Classes/LGSegment.swift index 3a7d3bb..2bc0cb4 100644 --- a/LGSegmentedControl/Classes/LGSegment.swift +++ b/LGSegmentedControl/Classes/LGSegment.swift @@ -13,10 +13,12 @@ class LGSegment { var contentView: UIView = { let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) view.backgroundColor = .clear + view.layer.zPosition = 0 return view }() var titleLabel: UILabel = { let label = UILabel() + label.textAlignment = .center label.sizeToFit() label.translatesAutoresizingMaskIntoConstraints = false return label @@ -25,15 +27,32 @@ class LGSegment { let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) view.clipsToBounds = true view.translatesAutoresizingMaskIntoConstraints = false + view.layer.zPosition = 1 return view }() - + lazy var badgeView: UIView = { + let view = UIView(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) + view.backgroundColor = options.badgeColor.background + view.translatesAutoresizingMaskIntoConstraints = false + view.layer.zPosition = 2 + return view + }() + lazy var badgeLabel: UILabel = { + let label = UILabel(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) + label.textColor = options.badgeColor.text + label.font = UIFont.systemFont(ofSize: 13, weight: .medium) + label.textAlignment = .center + label.sizeToFit() + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() lazy var tapView: UIView = { let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) view.backgroundColor = .clear view.translatesAutoresizingMaskIntoConstraints = false let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) view.addGestureRecognizer(tap) + view.layer.zPosition = 3 return view }() @@ -50,10 +69,17 @@ class LGSegment { var options = LGSegmentOptions() + public var badgeCount: Int? { + didSet { + updateAppearance(with: options) + } + } + var delegate: LGSegmentDelegate? - public init(title: String) { + public init(title: String, badgeCount: Int? = nil) { self.title = title + self.badgeCount = badgeCount updateAppearance(with: options, animated: false) @@ -62,6 +88,8 @@ class LGSegment { private func setupConstraints() { backgroundView.addSubview(titleLabel) + badgeView.addSubview(badgeLabel) + contentView.addSubview(badgeView) contentView.addSubview(backgroundView) contentView.addSubview(tapView) @@ -72,7 +100,24 @@ class LGSegment { titleLabel.centerXAnchor.constraint(equalTo: backgroundView.centerXAnchor).isActive = true titleLabel.centerYAnchor.constraint(equalTo: backgroundView.centerYAnchor).isActive = true + titleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: backgroundView.leadingAnchor, constant: 12).isActive = true + titleLabel.trailingAnchor.constraint(greaterThanOrEqualTo: backgroundView.trailingAnchor, constant: 12).isActive = true + titleLabel.topAnchor.constraint(greaterThanOrEqualTo: backgroundView.topAnchor, constant: 6).isActive = true + titleLabel.bottomAnchor.constraint(greaterThanOrEqualTo: backgroundView.bottomAnchor, constant: 6).isActive = true + + badgeLabel.centerYAnchor .constraint(equalTo: badgeView.centerYAnchor).isActive = true + badgeLabel.leadingAnchor .constraint(equalTo: badgeView.leadingAnchor , constant: 4).isActive = true + badgeLabel.trailingAnchor.constraint(equalTo: badgeView.trailingAnchor, constant: -4).isActive = true + badgeLabel.topAnchor .constraint(equalTo: badgeView.topAnchor, constant: 0.5).isActive = true + badgeLabel.bottomAnchor .constraint(equalTo: badgeView.bottomAnchor, constant:-0.5).isActive = true + badgeView.leadingAnchor .constraint(equalTo: titleLabel.trailingAnchor, constant: -2).isActive = true + badgeView.bottomAnchor .constraint(equalTo: titleLabel.topAnchor , constant: 6).isActive = true + let badgeViewSize: CGFloat = 16 + badgeView.heightAnchor .constraint(greaterThanOrEqualToConstant: badgeViewSize).isActive = true + badgeView.widthAnchor .constraint(greaterThanOrEqualToConstant: badgeViewSize).isActive = true + badgeView.layer.cornerRadius = badgeViewSize/2 + tapView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true tapView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true tapView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true @@ -84,13 +129,18 @@ class LGSegment { func updateAppearance(with options: LGSegmentOptions, animated: Bool? = nil) { self.options = options UIView.animate(withDuration: animated ?? options.animateStateChange ? 0.1 : 0) { - // status-related + // status self.titleLabel.textColor = self.textColor self.backgroundView.backgroundColor = self.backgroundColor + // badge view + self.badgeView.isHidden = self.badgeCount == nil + self.badgeView.backgroundColor = options.badgeColor.background + self.badgeLabel.textColor = options.badgeColor.text // others self.backgroundView.layer.cornerRadius = options.cornerRadius self.titleLabel.font = options.font } + badgeLabel.text = badgeCount?.string ?? "" } @objc private func handleTap() { diff --git a/LGSegmentedControl/Classes/LGSegmentOptions.swift b/LGSegmentedControl/Classes/LGSegmentOptions.swift index aedaab5..5d76f5c 100644 --- a/LGSegmentedControl/Classes/LGSegmentOptions.swift +++ b/LGSegmentedControl/Classes/LGSegmentOptions.swift @@ -11,14 +11,21 @@ class LGSegmentOptions { /// Segments' corner radius, default: 6 var cornerRadius: CGFloat = 6 - /// + + /// Determines whether there should be a short fade animation when selecting a segment var animateStateChange: Bool = true + /// Background and text color of the selected segment var selectedColor: (background: UIColor, text: UIColor) = (#colorLiteral(red: 0.2196078431, green: 0.6235294118, blue: 0.9764705882, alpha: 1), .white) + /// Background and text color of a deselected segment var deselectedColor: (background: UIColor, text: UIColor) = (.clear, .black) + /// Font of the segments' title labels var font: UIFont = UIFont.systemFont(ofSize: 15) + /// Background and text color of the segments' badges + var badgeColor: (background: UIColor, text: UIColor) = (.red, .white) + init() { } } diff --git a/LGSegmentedControl/Classes/LGSegmentedControl.swift b/LGSegmentedControl/Classes/LGSegmentedControl.swift index b4fb0d9..fc7c265 100644 --- a/LGSegmentedControl/Classes/LGSegmentedControl.swift +++ b/LGSegmentedControl/Classes/LGSegmentedControl.swift @@ -22,6 +22,10 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { }() private var stackView: UIStackView = { let stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: 150, height: 50)) + stackView.axis = .horizontal + stackView.spacing = 8 + stackView.alignment = .fill + stackView.distribution = .fill stackView.translatesAutoresizingMaskIntoConstraints = false return stackView }() @@ -41,7 +45,7 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { didSet { segments.forEach { $0.delegate = self } // remove all other segments - stackView.arrangedSubviews.forEach { stackView.removeArrangedSubview($0) } + stackView.removeAllArrangedSubviews() // add all new segments stackView.add(arrangedSubviews: segments.map { $0.contentView }) // reset previous selected index, b/c we're starting over with a new set of segments @@ -71,7 +75,7 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { private func commonInit() { addSubview(contentView) contentView.frame = bounds - contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth] + contentView.translatesAutoresizingMaskIntoConstraints = false setupConstraints() } @@ -89,12 +93,17 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { private func setupConstraints() { contentView.addSubview(stackView) + contentView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + contentView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + contentView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true stackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true - contentView.layoutIfNeeded() + self.layoutIfNeeded() } // MARK: - UI @@ -128,18 +137,12 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { // MARK: - Customization & IBInspectables - public var distribution: UIStackView.Distribution = .fillEqually { + public var distribution: UIStackView.Distribution = .fill { didSet { stackView.distribution = distribution } } -// public override var backgroundColor: UIColor? { -// didSet { -// contentView.backgroundColor = backgroundColor -// } -// } - @IBInspectable private var segmentTitles: String { get { @@ -154,11 +157,13 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { } // private b/c only used for interface builder // `distribution` actually handles the setting + /// StackView distribution, set to .fill to have each segment be as wide as required; set to .fillEqually, to have all segments be the same width, default: .fill @IBInspectable private var stackViewDistribution: String { get { return distribution.string } set { distribution = UIStackView.Distribution(newValue) ?? .fillEqually } } + /// StackView spacing, default: 8 @IBInspectable public var spacing: CGFloat { get { return stackView.spacing } @@ -169,31 +174,37 @@ class LGSegmentedControl: UIControl, LGSegmentDelegate { get { return contentView.backgroundColor } set { contentView.backgroundColor = newValue } } + /// Segments' corner radius, default: 6 @IBInspectable public var segmentsCornerRadius: CGFloat { get { return options.cornerRadius } set { options.cornerRadius = newValue; updateAppearance() } } + /// Determines whether there should be a short fade animation when selecting a segment, default: true @IBInspectable public var animateStateChange: Bool { get { return options.animateStateChange } set { options.animateStateChange = newValue; updateAppearance() } } + /// Background color of the selected segment, default: .blue-ish (#389FF9) @IBInspectable public var selectedBackgroundColor: UIColor { get { return options.selectedColor.background } set { options.selectedColor.background = newValue; updateAppearance() } } + /// Text color of the selected segment, default: .white @IBInspectable public var selectedTextColor: UIColor { get { return options.selectedColor.text } set { options.selectedColor.text = newValue; updateAppearance() } } + /// Background color of the selected segment, default: .clear @IBInspectable public var deselectedBackgroundColor: UIColor { get { return options.deselectedColor.background } set { options.deselectedColor.background = newValue; updateAppearance() } } + /// Text color of the selected segment, default: .black @IBInspectable public var deselectedTextColor: UIColor { get { return options.deselectedColor.text } diff --git a/README.md b/README.md index 676782b..bb5918e 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,19 @@ [![License](https://img.shields.io/cocoapods/l/LGSegmentedControl.svg?style=flat)](https://cocoapods.org/pods/LGSegmentedControl) [![Platform](https://img.shields.io/cocoapods/p/LGSegmentedControl.svg?style=flat)](https://cocoapods.org/pods/LGSegmentedControl) -## Example +`LGSegmentedControl` is a highly customizable and therefor prettier version of `UISegmentedControl`. -To run the example project, clone the repo, and run `pod install` from the Example directory first. + ## Requirements +- written in pure Swift 4.2 +- iOS 9.0 and higher + +## Attribution + +- not a requirement but highly appreciated: [add your app to the list of apps using this library](/Attribution.md) + ## Installation LGSegmentedControl is available through [CocoaPods](https://cocoapods.org). To install @@ -20,9 +27,134 @@ it, simply add the following line to your Podfile: pod 'LGSegmentedControl' ``` +### Storyboard + +Drag a view into your storyboard and set its class to `LGSegmentedControl`. +You'll be able to customize your segmented control from there, as well as provide static segment data: + + + +And the best? It supports live rendering in interface builder! + + + +Then, create an `@IBAction` in your view controller and link to it using the `valueChanged` action. + +### Programmatically + +Instantiate a new view: + +```swift +let control = LGSegmentedControl(frame: CGRect(x: 50, y: 50, width: 100, height: 30)) +view.addSubview(control) +``` + +...then add the segments data: + +```swift +control.segments = [ + LGSegment(title: "1 day"), + LGSegment(title: "3 weeks"), + LGSegment(title: "2 months"), + LGSegment(title: "Quarter") +] +``` + +Lastly, define the selected segment: + +```swift +control.selectedIndex = 1 // selects: "3 weeks" +``` + +To track user interaction, add a target and link to a method in your view controller using the `.valueChanged` action: + +```swift +control.addTarget(self, action: #selector(selectedSegment(_:)), for: .valueChanged) + +@objc func selectedSegment(_ segmentedControl: LGSegmentedControl) { + // selectedSegment may be nil, if selectedIndex was set to nil (and hence none was selected) + guard let segment = segmentedControl.selectedSegment else { return } + let title = segment.title // ex: "3 weeks" +} +``` + +### Badge Counts + +You can add badge counts to segments, by assigning an `Int` value: + +```swift +segment.badgeCount = 3 +``` + +This will result in: + +![toggle gif](https://github.com/LinusGeffarth/LGSegmentedControl/blob/master/screenshots/toggle.gif) + +Note, that setting the badge to `0` will still show a badge count with a value of `0`. +If you want to hide a badge, simply set the count nil: + +```swift +segment.badgeCount = nil +``` + +## Customization + +You can customize many aspects of your control: + +```swift +// StackView distribution, set to .fill to have each segment be as wide as required; set to .fillEqually, to have all segments be the same width +// default: .fill +public var distribution: UIStackView.Distribution + +// StackView spacing +// default: 8 +@IBInspectable public var spacing: CGFloat + +// Background color of the whole segment +// default: .clear +@IBInspectable override public var backgroundColor: UIColor? +``` + +### More options using `LGSegmentOptions`: + +```swift +// Corner radius of the segments +// default: 6 +var cornerRadius: CGFloat + +// Determines whether there should be a short fade animation when selecting a segment +// default: true +var animateStateChange: Bool + +// Background & text color of the selected segment +// default: .blue-ish (#389FF9), .white +var selectedColor: (background: UIColor, text: UIColor) + +// Background & text color of the deselected segment +// default: .clear, .black +var deselectedColor: (background: UIColor, text: UIColor) + +// Background & text color of the selected segment +// default: .red, .white +var badgeColor: (background: UIColor, text: UIColor) + +// Font of the titleLabel +// default: .systemFont(ofSize: 15) +var font: UIFont +``` + +There are many different ways to style a control with given options, here is a few examples: + + + +## Contribution + +If you find any bugs, please [open a new issue](https://github.com/LinusGeffarth/LGSegmentedControl/issues/new). +If you want to contribute changes and features, please [open a pull request](https://github.com/LinusGeffarth/LGSegmentedControl/compare) and I'll happily merge it! + ## Author -linusgeffarth, linus@geffarth.de +LGSegmentedControl is written and maintained by Linus Geffarth (me). If you want to say hi, reach out to me via twitter [@linusgeffarth](https://twitter.com/linusgeffarth), or email [linus@geffarth.com](mailto:linus@geffarth.com). ## License diff --git a/screenshots/ss2.png b/screenshots/ss2.png index 87473f4..954bf4d 100644 Binary files a/screenshots/ss2.png and b/screenshots/ss2.png differ diff --git a/screenshots/ss3.png b/screenshots/ss3.png new file mode 100644 index 0000000..87473f4 Binary files /dev/null and b/screenshots/ss3.png differ diff --git a/screenshots/ss4.jpeg b/screenshots/ss4.jpeg new file mode 100644 index 0000000..7c73217 Binary files /dev/null and b/screenshots/ss4.jpeg differ diff --git a/screenshots/toggle.gif b/screenshots/toggle.gif new file mode 100644 index 0000000..89d4363 Binary files /dev/null and b/screenshots/toggle.gif differ