diff --git a/.github/contributing.md b/.github/contributing.md new file mode 100644 index 0000000..221c6cd --- /dev/null +++ b/.github/contributing.md @@ -0,0 +1,58 @@ +## How to contribute to Segmentio + +#### **Did you find a bug?** + +* **Ensure the bug was not already reported** by searching under [Issues](https://github.com/Yalantis/Segmentio/issues). + +* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Yalantis/Segmentio/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **example project** demonstrating the expected behavior that is not occurring. + +* Fill appropriate section in issue template and remove the section you aren't interested in. + +#### **Did you write a patch that fixes a bug?** + +* Open a new GitHub pull request with the patch. + +* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + +* Ensure the PR doesn't extend the number of existing issues. + +#### **Did you fix whitespace, format code, or make a purely cosmetic patch?** + +* Changes that are **cosmetic** in nature and **do not add anything substantial** to the stability or functionality of Segmentio will generally **not be accepted**. + +#### **Did you write patch that extends functionality?** + +* Ensure the functionality you trying to add needed not only for your case. + +#### Each issue will be labeled by it's `type`, `priority` and `status`. + +**Issue types:** +* Bug +* Enhancement + +**These are the available priority labels:** +* Critical +* High +* Medium +* Low + +**Status label will be assigned to your issue to keep the issue tracker easy to follow:** +* Queued (will be reviewed soon) +* Reviewed (assignee has read it) +* Pending (will work on it soon) +* Work in progress (is working on it now) +* On hold +* Invalid (if bug it's not reproducible) +* Need feedback (signal to get people to read and comment or provide help) + +#### **Coding Style** + +* Most importantly, match the existing code style as much as possible. + +#### **Do you have a question?** + +For any usage questions that are not specific to the project itself, please ask on [Stack Overflow](https://stackoverflow.com/). By doing so, you'll be more likely to quickly solve your problem, and you'll allow anyone else with the same question to find the answer. This also allows maintainers to focus on improving the project for others. + +## Thank you! + +#### [![Yalantis](https://raw.githubusercontent.com/Yalantis/PullToMakeSoup/master/PullToMakeSoupDemo/Resouces/badge_dark.png)](https://Yalantis.com/?utm_source=github) diff --git a/LICENSE b/LICENSE index 228d900..7dda022 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright © 2016 Yalantis +Copyright © 2017 Yalantis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 25fa44d..2c72d8e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -##Segmentio +## Segmentio [![Platform](http://img.shields.io/badge/platform-iOS-blue.svg?style=flat)](https://cocoapods.org/?q=segmentio) [![License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/Yalantis/Segmentio/blob/master/LICENSE) ![Swift 3.x](https://img.shields.io/badge/Swift-3.0-orange.svg) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) Animated top/bottom segmented control written in Swift. @@ -7,15 +7,15 @@ Animated top/bottom segmented control written in Swift. Check this project on dribbble. -##Requirements +## Requirements - Xcode 8 - iOS 8.x+ - Swift 3 -##Installation +## Installation -####[CocoaPods](http://cocoapods.org) +#### [CocoaPods](http://cocoapods.org) ```ruby use_frameworks! @@ -24,24 +24,24 @@ pod 'Segmentio', '~> 2.1' *CocoaPods v1.1.0 or later required* -####[Carthage](http://github.com/Carthage/Carthage) +#### [Carthage](http://github.com/Carthage/Carthage) ```ruby github "Yalantis/Segmentio" ~> 2.1 ``` -##Usage -####Import `Segmentio` module +## Usage +#### Import `Segmentio` module ```swift import Segmentio ``` -####Init +#### Init You can initialize a `Segmentio` instance from code: ```swift var segmentioView: Segmentio! -let segmentioViewRect = CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.width, height: 125) +let segmentioViewRect = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 125) segmentioView = Segmentio(frame: segmentioViewRect) view.addSubview(segmentioView) ``` @@ -54,9 +54,9 @@ add a `UIView` instance in your .storyboard or .xib, set `Segmentio` class and c @IBOutlet weak var segmentioView: Segmentio! ``` -####Setup `Segmentio` +#### Setup `Segmentio` ```swift -segmentioView.setupContent( +segmentioView.setup( content: [SegmentioItem], style: SegmentioStyle, options: SegmentioOptions? @@ -66,7 +66,7 @@ segmentioView.setupContent( To start with default options you can just pass `nil` to the `options` parameter. ```swift -segmentioView.setupContent( +segmentioView.setup( content: [SegmentioItem], style: SegmentioStyle, options: nil @@ -74,7 +74,7 @@ segmentioView.setupContent( ``` -####Configuring items +#### Configuring items In order to set items you need to create an array of `SegmentioItem` instances: ```swift @@ -87,14 +87,14 @@ let tornadoItem = SegmentioItem( content.append(tornadoItem) ``` -####Handling selection +#### Handling selection You can specify selected item manually: ```swift -segmentioView.selectedSegmentIndex = 0 +segmentioView.selectedSegmentioIndex = 0 ``` -####Handling callback +#### Handling callback ```swift segmentioView.valueDidChange = { segmentio, segmentIndex in @@ -102,22 +102,20 @@ segmentioView.valueDidChange = { segmentio, segmentIndex in } ``` -####Customization +#### Customization `Segmentio` can be customized by passing an instance of `SegmentioOptions` struct: ```swift SegmentioOptions( - backgroundColor: UIColor.whiteColor(), - maxVisibleItems: 3, - scrollEnabled: true, - indicatorOptions: SegmentioIndicatorOptions, - horizontalSeparatorOptions: SegmentioHorizontalSeparatorOptions, - verticalSeparatorOptions: SegmentioVerticalSeparatorOptions, - imageContentMode: UIViewContentMode.Center, - labelTextNumberOfLines: 1, - labelTextAlignment: NSTextAlignment.Center, - segmentStates: SegmentioStates, // tuple of SegmentioState (defaultState, selectState, highlightedState) - animationDuration: 0.1 + backgroundColor: .white, + maxVisibleItems: 3, + scrollEnabled: true, + indicatorOptions: SegmentioIndicatorOptions, + horizontalSeparatorOptions: SegmentioHorizontalSeparatorOptions, + verticalSeparatorOptions: SegmentioVerticalSeparatorOptions, + imageContentMode: .center, + labelTextAlignment: .center, + segmentStates: SegmentioStates ) ``` @@ -125,10 +123,10 @@ Selection indicator can be customized by passing an instance of `SegmentioIndica ```swift SegmentioIndicatorOptions( - type: .Bottom, - ratio: 1, - height: 5, - color: UIColor.orangeColor() + type: .bottom, + ratio: 1, + height: 5, + color: .orange ) ``` @@ -136,9 +134,9 @@ Horizontal borders can be customized by passing an instance of `SegmentioHorizon ```swift SegmentioHorizontalSeparatorOptions( - type: SegmentioHorizontalSeparatorType.TopAndBottom, // Top, Bottom, TopAndBottom - height: 1, - color: UIColor.grayColor() + type: SegmentioHorizontalSeparatorType.topAndBottom, // Top, Bottom, TopAndBottom + height: 1, + color: .gray ) ``` @@ -146,8 +144,8 @@ Separators between segments can be customized by passing an instance of `Segmen ```swift SegmentioVerticalSeparatorOptions( - ratio: 0.6 // from 0.1 to 1 - color: UIColor.grayColor() + ratio: 0.6, // from 0.1 to 1 + color: .gray ) ``` @@ -155,34 +153,34 @@ In order to set `SegmentioStates` you need to create a tuple of `SegmentioState` ```swift SegmentioStates( - defaultState: segmentioState( - backgroundColor: UIColor.clearColor(), - titleFont: UIFont.systemFontOfSize(UIFont.smallSystemFontSize()), - titleTextColor: UIColor.blackColor() - ), - selectState: segmentioState( - backgroundColor: UIColor.orangeColor(), - titleFont: UIFont.systemFontOfSize(UIFont.smallSystemFontSize()), - titleTextColor: UIColor.whiteColor() - ), - highlightedState: segmentioState( - backgroundColor: UIColor.lightGrayColor().colorWithAlphaComponent(0.6), - titleFont: UIFont.boldSystemFontOfSize(UIFont.smallSystemFontSize()), - titleTextColor: UIColor.blackColor() - ) + defaultState: SegmentioState( + backgroundColor: .clear, + titleFont: UIFont.systemFont(ofSize: UIFont.smallSystemFontSize), + titleTextColor: .black + ), + selectedState: SegmentioState( + backgroundColor: .orange, + titleFont: UIFont.systemFont(ofSize: UIFont.smallSystemFontSize), + titleTextColor: .white + ), + highlightedState: SegmentioState( + backgroundColor: UIColor.lightGray.withAlphaComponent(0.6), + titleFont: UIFont.boldSystemFont(ofSize: UIFont.smallSystemFontSize), + titleTextColor: .black + ) ) ``` -####Let us know! +#### Let us know! We’d be really happy if you sent us links to your projects where you use our component. Just send an email to github@yalantis.com And do let us know if you have any questions or suggestion regarding the animation. P.S. We’re going to publish more awesomeness wrapped in code and a tutorial on how to make UI for iOS (Android) better than better. Stay tuned! -##License +## License The MIT License (MIT) -Copyright © 2016 Yalantis +Copyright © 2017 Yalantis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Segmentio.podspec b/Segmentio.podspec index f09fb14..d32a0ae 100644 --- a/Segmentio.podspec +++ b/Segmentio.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Segmentio" - spec.version = "2.1.1" + spec.version = "2.1.2" spec.homepage = "https://github.com/Yalantis/Segmentio" spec.summary = "Animated top/bottom segmented control written in Swift!" diff --git a/Segmentio/Source/Cells/SegmentioCell.swift b/Segmentio/Source/Cells/SegmentioCell.swift index 7e2a478..30f8793 100644 --- a/Segmentio/Source/Cells/SegmentioCell.swift +++ b/Segmentio/Source/Cells/SegmentioCell.swift @@ -49,7 +49,7 @@ class SegmentioCell: UICollectionViewCell { segmentTitleLabel?.font = isHighlighted ? highlightedState.titleFont : highlightedTitleFont } - backgroundColor = isHighlighted ? highlightedState.backgroundColor : defaultState.backgroundColor + backgroundColor = isHighlighted ? highlightedState.backgroundColor : .clear } } } @@ -130,7 +130,7 @@ class SegmentioCell: UICollectionViewCell { configurateBadgeWithCount(content.badgeCount, color: content.badgeColor) } - func configure(selected: Bool) { + func configure(selected: Bool, selectedImage: UIImage? = nil, image: UIImage? = nil) { cellSelected = selected let selectedState = options.states.selectedState @@ -140,6 +140,10 @@ class SegmentioCell: UICollectionViewCell { segmentTitleLabel?.textColor = selected ? selectedState.titleTextColor : defaultState.titleTextColor segmentTitleLabel?.font = selected ? selectedState.titleFont : defaultState.titleFont } + + if (style != .onlyLabel) { + segmentImageView?.image = selected ? selectedImage : image + } } func configurateBadgeWithCount(_ badgeCount: Int?, color: UIColor?) { @@ -173,38 +177,43 @@ class SegmentioCell: UICollectionViewCell { // MARK: - Private functions fileprivate func setupContainerConstraints() { - guard let segmentTitleLabel = segmentTitleLabel else { - return - } - guard let containerView = containerView else { + guard let segmentTitleLabel = segmentTitleLabel, let containerView = containerView else { return } - let segmentTitleLabelHorizontalCenterConstraint = - NSLayoutConstraint( - item: segmentTitleLabel, - attribute: .centerX, - relatedBy: .equal, - toItem: containerView, - attribute: .centerX, - multiplier: 1, - constant: 0 + let segmentTitleLabelVerticalCenterConstraint = NSLayoutConstraint( + item: segmentTitleLabel, + attribute: .centerY, + relatedBy: .equal, + toItem: containerView, + attribute: .centerY, + multiplier: 1, + constant: 0 + ) + let segmentTitleLabelTrailingConstraint = NSLayoutConstraint( + item: segmentTitleLabel, + attribute: .trailing, + relatedBy: .equal, + toItem: containerView, + attribute: .trailingMargin, + multiplier: 1.0, + constant: 0 + ) + let segmentTitleLabelLeadingConstraint = NSLayoutConstraint( + item: segmentTitleLabel, + attribute: .leading, + relatedBy: .equal, + toItem: containerView, + attribute: .leadingMargin, + multiplier: 1.0, + constant: 0 ) - let segmentTitleLabelVerticalCenterConstraint = - NSLayoutConstraint( - item: segmentTitleLabel, - attribute: .centerY, - relatedBy: .equal, - toItem: containerView, - attribute: .centerY, - multiplier: 1, - constant: 0 - ) addConstraints([ - segmentTitleLabelHorizontalCenterConstraint, - segmentTitleLabelVerticalCenterConstraint - ]) + segmentTitleLabelTrailingConstraint, + segmentTitleLabelVerticalCenterConstraint, + segmentTitleLabelLeadingConstraint + ]) } fileprivate func setupImageContainerConstraints() { diff --git a/Segmentio/Source/Segmentio.swift b/Segmentio/Source/Segmentio.swift index 987eadd..f7f7e68 100644 --- a/Segmentio/Source/Segmentio.swift +++ b/Segmentio/Source/Segmentio.swift @@ -97,6 +97,7 @@ open class Segmentio: UIView { collectionView.bounces = true collectionView.isScrollEnabled = segmentioOptions.scrollEnabled collectionView.backgroundColor = .clear + collectionView.accessibilityIdentifier = "segmentio_collection_view" segmentioCollectionView = collectionView @@ -113,6 +114,8 @@ open class Segmentio: UIView { let separatorHeight = horizontalSeparatorOptions.height switch horizontalSeparatorOptions.type { + case .none: + separatorsHeight = 0 case .top: collectionViewFrameMinY = separatorHeight separatorsHeight = separatorHeight @@ -252,7 +255,7 @@ open class Segmentio: UIView { bottomSeparatorView = UIView(frame: CGRect.zero) setupConstraintsForSeparatorView( separatorView: bottomSeparatorView, - originY: frame.maxY - height + originY: bounds.maxY - height ) } } @@ -270,7 +273,7 @@ open class Segmentio: UIView { item: separatorView, attribute: .top, relatedBy: .equal, - toItem: superview, + toItem: self, attribute: .top, multiplier: 1, constant: originY @@ -549,6 +552,8 @@ open class Segmentio: UIView { let isIndicatorTop = indicatorOptions.type == .top switch horizontalSeparatorOptions.type { + case .none: + break case .top: indicatorPointY = isIndicatorTop ? indicatorPointY + separatorHeight : indicatorPointY case .bottom: @@ -578,14 +583,20 @@ extension Segmentio: UICollectionViewDataSource { withReuseIdentifier: segmentioStyle.rawValue, for: indexPath) as! SegmentioCell + let content = segmentioItems[indexPath.row] + cell.configure( - content: segmentioItems[indexPath.row], + content: content, style: segmentioStyle, options: segmentioOptions, isLastCell: indexPath.row == segmentioItems.count - 1 ) - cell.configure(selected: (indexPath.row == selectedSegmentioIndex)) + cell.configure( + selected: (indexPath.row == selectedSegmentioIndex), + selectedImage: content.selectedImage, + image: content.image + ) return cell } diff --git a/Segmentio/Source/SegmentioOptions.swift b/Segmentio/Source/SegmentioOptions.swift index 66bf964..6c48c2a 100644 --- a/Segmentio/Source/SegmentioOptions.swift +++ b/Segmentio/Source/SegmentioOptions.swift @@ -14,6 +14,7 @@ public struct SegmentioItem { public var title: String? public var image: UIImage? + public var selectedImage: UIImage? public var badgeCount: Int? public var badgeColor: UIColor? public var intrinsicWidth: CGFloat { @@ -23,9 +24,10 @@ public struct SegmentioItem { return label.intrinsicContentSize.width } - public init(title: String?, image: UIImage?) { + public init(title: String?, image: UIImage?, selectedImage: UIImage? = nil) { self.title = title self.image = image + self.selectedImage = selectedImage ?? image } public mutating func addBadge(_ count: Int, color: UIColor) { @@ -62,7 +64,7 @@ public struct SegmentioState { // MARK: - Horizontal separator public enum SegmentioHorizontalSeparatorType { - + case none case top case bottom case topAndBottom