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
- Single or multiple selection.
- Horizontal or vertical stacking.
- Can show text and images together.
- Use from either storyboard or code.
- 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.5")
]
TODO
- foreground color of selected segment should be/appear transparent
- configure segment
layoutMargins
,stackView.spacing
Meta
https://github.com/yonat/MultiSelectSegmentedControl