-
Notifications
You must be signed in to change notification settings - Fork 423
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #684 from rechsteiner/indicator-style
Add custom style for indicator view when using SwiftUI
- Loading branch information
Showing
6 changed files
with
196 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import Parchment | ||
import SwiftUI | ||
import UIKit | ||
|
||
struct CustomIndicatorView: View { | ||
var body: some View { | ||
PageView { | ||
Page("Scone") { | ||
Text("Scone") | ||
.font(.largeTitle) | ||
.foregroundColor(.gray) | ||
} | ||
|
||
Page("Cinnamon Roll") { | ||
Text("Cinnamon Roll") | ||
.font(.largeTitle) | ||
.foregroundColor(.gray) | ||
} | ||
|
||
Page("Croissant") { | ||
Text("Croissant") | ||
.font(.largeTitle) | ||
.foregroundColor(.gray) | ||
} | ||
|
||
Page("Muffin") { | ||
Text("Muffin") | ||
.font(.largeTitle) | ||
.foregroundColor(.gray) | ||
} | ||
} | ||
.borderColor(.black.opacity(0.1)) | ||
.indicatorOptions(.visible(height: 2)) | ||
.indicatorStyle(SquigglyIndicatorStyle()) | ||
|
||
} | ||
} | ||
|
||
struct SquigglyIndicatorStyle: PagingIndicatorStyle { | ||
func makeBody(configuration: Configuration) -> some View { | ||
SquigglyShape() | ||
.stroke(.blue, style: StrokeStyle(lineWidth: 3, lineCap: .round)) | ||
} | ||
} | ||
|
||
struct SquigglyShape: Shape { | ||
func path(in rect: CGRect) -> Path { | ||
var path = Path() | ||
path.move(to: .zero) | ||
|
||
for x in stride(from: 0, through: rect.width, by: 1) { | ||
let sine = sin(x / 1.5) | ||
let y = rect.height * sine | ||
path.addLine(to: CGPoint(x: x, y: y)) | ||
} | ||
|
||
return path | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import UIKit | ||
import SwiftUI | ||
|
||
/// A custom `UICollectionViewReusableView` subclass used to display a | ||
/// view that indicates the currently selected cell. You can subclass | ||
/// this type if you need further customization; just override the | ||
/// `indicatorClass` property in `PagingViewController`. | ||
@available(iOS 14.0, *) | ||
final class PagingHostingIndicatorView: PagingIndicatorView { | ||
private let hostingController: UIHostingController<PagingIndicator> | ||
|
||
override init(frame: CGRect) { | ||
let configuration = PagingIndicatorConfiguration(backgroundColor: .clear) | ||
let rootView = PagingIndicator(configuration: configuration) | ||
self.hostingController = UIHostingController(rootView: rootView) | ||
|
||
super.init(frame: frame) | ||
|
||
hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] | ||
hostingController.view.backgroundColor = .clear | ||
hostingController.view.clipsToBounds = false | ||
clipsToBounds = false | ||
} | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func didMoveToWindow() { | ||
super.didMoveToWindow() | ||
if window == nil { | ||
hostingController.willMove(toParent: nil) | ||
hostingController.removeFromParent() | ||
hostingController.didMove(toParent: nil) | ||
} else if let parent = parentViewController() { | ||
hostingController.willMove(toParent: parent) | ||
parent.addChild(hostingController) | ||
addSubview(hostingController.view) | ||
hostingController.didMove(toParent: parent) | ||
} | ||
} | ||
|
||
public override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { | ||
if let attributes = layoutAttributes as? PagingIndicatorLayoutAttributes { | ||
let configuration = PagingIndicatorConfiguration( | ||
backgroundColor: Color(attributes.backgroundColor ?? .clear) | ||
) | ||
hostingController.rootView = PagingIndicator(configuration: configuration) | ||
hostingController.view.frame = bounds | ||
} | ||
} | ||
|
||
private func parentViewController() -> UIViewController? { | ||
var responder: UIResponder? = self | ||
while let nextResponder = responder?.next { | ||
if let viewController = nextResponder as? UIViewController { | ||
return viewController | ||
} | ||
responder = nextResponder | ||
} | ||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import Foundation | ||
import SwiftUI | ||
|
||
@available(iOS 14.0, *) | ||
public protocol PagingIndicatorStyle { | ||
associatedtype Body: View | ||
typealias Configuration = PagingIndicatorConfiguration | ||
@ViewBuilder func makeBody(configuration: Configuration) -> Body | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
struct PagingIndicator: View { | ||
let configuration: PagingIndicatorConfiguration | ||
|
||
@Environment(\.indicatorStyle) var style | ||
|
||
var body: some View { | ||
AnyView(style.makeBody(configuration: configuration)) | ||
} | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
public struct PagingIndicatorConfiguration { | ||
public let backgroundColor: Color | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
struct DefaultPagingIndicatorStyle: PagingIndicatorStyle { | ||
func makeBody(configuration: Configuration) -> some View { | ||
Rectangle() | ||
.fill(configuration.backgroundColor) | ||
} | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
struct PagingIndicatorStyleKey: EnvironmentKey { | ||
static var defaultValue: any PagingIndicatorStyle = DefaultPagingIndicatorStyle() | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
extension EnvironmentValues { | ||
var indicatorStyle: any PagingIndicatorStyle { | ||
get { self[PagingIndicatorStyleKey.self] } | ||
set { self[PagingIndicatorStyleKey.self] = newValue } | ||
} | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
extension View { | ||
public func indicatorStyle(_ style: some PagingIndicatorStyle) -> some View { | ||
environment(\.indicatorStyle, style) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters