Skip to content

Instantly share code, notes, and snippets.

@mbernson
Last active December 10, 2024 11:14
Show Gist options
  • Save mbernson/3a45ca1df8deddb2d2f36e6afeed6762 to your computer and use it in GitHub Desktop.
Save mbernson/3a45ca1df8deddb2d2f36e6afeed6762 to your computer and use it in GitHub Desktop.
UIPageControl for use with SwiftUI. It has a two-way binding to a generic selection value.
import SwiftUI
import UIKit
struct PageControl<SelectionValue: Hashable>: UIViewRepresentable {
let items: [SelectionValue]
@Binding var selection: SelectionValue?
func makeUIView(context: Context) -> UIPageControl {
let pageControl = UIPageControl()
pageControl.pageIndicatorTintColor = .gray
pageControl.currentPageIndicatorTintColor = .black
pageControl.addTarget(context.coordinator, action: #selector(Coordinator.valueDidChange), for: .valueChanged)
return pageControl
}
func updateUIView(_ pageControl: UIPageControl, context: Context) {
pageControl.numberOfPages = items.count
if let selection, let selectedIndex = items.firstIndex(of: selection) {
pageControl.currentPage = selectedIndex
}
context.coordinator.items = items
}
func sizeThatFits(_ proposal: ProposedViewSize, uiView: UIPageControl, context: Context) -> CGSize? {
uiView.size(forNumberOfPages: items.count)
}
func makeCoordinator() -> Coordinator {
Coordinator(selection: $selection, items: items)
}
class Coordinator {
@Binding var selection: SelectionValue?
var items: [SelectionValue]
init(selection: Binding<SelectionValue?>, items: [SelectionValue]) {
self._selection = selection
self.items = items
}
@objc func valueDidChange(_ sender: UIPageControl) {
let selectedIndex = sender.currentPage
assert(items.indices.contains(selectedIndex), "Invalid index received")
withAnimation {
selection = items[selectedIndex]
}
}
}
}
private struct PageControl_Preview: View {
@State var numbers: [Int] = [1, 2, 3, 4, 5]
@State var selection: Int? = 1
var body: some View {
VStack {
Text(verbatim: "Selected:")
Text(selection ?? -1, format: .number)
PageControl(items: numbers, selection: $selection)
.border(.red)
PageControl(items: numbers, selection: $selection)
.border(.blue)
}
}
}
#Preview {
PageControl_Preview()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment