MultiSelectSegmentedControl
MultiSelectSegmentedControl copied to clipboard
UISegmentedControl remake that supports selecting multiple segments, vertical stacking, combining text and images.
MultiSelectSegmentedControl
UISegmentedControl remake that supports selecting multiple segments, vertical stacking, combining text and images.
Features
- [x] Single or multiple selection.
- [x] Horizontal or vertical stacking.
- [x] Can show text and images together.
- [x] Use from either storyboard or code.
- [x] UIAppearance support.
Usage
Very similar to UISegmentedControl, can be used as a drop-in replacement in most cases.
If you use Interface Builder, add a regular UIView and then set its class to MultiSelectSegmentedControl.
SwiftUI Usage
MultiSegmentPicker(
selectedSegmentIndexes: $indexSet,
items: ["One", "Two", image, [image2, "Text"], "Last"]
)
The properties mentioned below can be passed as arguments to the MultiSegmentPicker initializer, or used as view modifiers (e.g., .borderWidth(3)).
Creating Segments
Each segment can contain an image, a text, or both:
let multiSelect = MultiSelectSegmentedControl()
multiSelect.items = ["One", "Two", image, [image2, "Text"], "Last"]
Images are shown in full color (unlike UISegmentedControl). To make them render in the same tintColor as the control, use template mode:
multiSelect.items = [image1, image2, image3].map { $0.withRenderingMode(.alwaysTemplate) }
Selecting Segments
multiSelect.selectedSegmentIndexes = [1, 2, 4]
Or just single selection:
multiSelect.allowsMultipleSelection = false
multiSelect.selectedSegmentIndex = 3
Getting Selected Segments
let selectedIndices: IndexSet = multiSelect.selectedSegmentIndexes
Or to get the titles:
let titles: [String] = multiSelect.selectedSegmentTitles
Handling User Selection Changes
You can use standard target-action:
multiSelect.addTarget(self, action: #selector(selectionChanged), for: .valueChanged)
Or conform to the delegate protocol:
extension MyViewController: MultiSelectSegmentedControlDelegate {
func multiSelect(_ multiSelectSegmentedControl: MultiSelectSegmentedControl, didChange value: Bool, at index: Int) {
print("selected \(value) at \(index)")
}
}
... and set the delegate:
multiSelect.delegate = self
Changing Appearance
Color:
multiSelect.tintColor = .green
Background Color (optional - use if background color should be different from tint color):
multiSelect.selectedBackgroundColor = .blue
Shape:
multiSelect.borderWidth = 3 // Width of the dividers between segments and the border around the view.
multiSelect.borderRadius = 32 // Corner radius of the view.
Stack the segments vertically:
multiSelect.isVertical = true
Stack each segment contents vertically when it contains both image and text:
multiSelect.isVerticalSegmentContents = true
Text styling:
multiSelect.setTitleTextAttributes([.foregroundColor: UIColor.yellow], for: .selected)
multiSelect.setTitleTextAttributes([.obliqueness: 0.25], for: .normal)
More label styling:
multiSelect.titleConfigurationHandler = {
$0.numberOfLines = 0
$0.lineBreakMode = .byWordWrapping
}
Installation
CocoaPods:
pod 'MultiSelectSegmentedControl'
Swift Package Manager:
dependencies: [
.package(url: "https://github.com/yonat/MultiSelectSegmentedControl", from: "2.3.6")
]
TODO
- [ ] foreground color of selected segment should be/appear transparent
- [ ] configure segment
layoutMargins,stackView.spacing