Skip to content
This repository has been archived by the owner on May 31, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
marlokessler committed Jul 20, 2020
0 parents commit f90ceaa
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
7 changes: 7 additions & 0 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
24 changes: 24 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "PageView",
platforms: [
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6),
.macOS(.v10_15)
],
products: [
.library(
name: "PageView",
targets: ["PageView"]),
],
targets: [
.target(
name: "PageView",
dependencies: [])
]
)
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# PageView

This package contains a PageView purely written in SwiftUI.
17 changes: 17 additions & 0 deletions Sources/PageView/IndicatorPosition.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// IndicatorPosition.swift
// ViewCTestApp
//
// Created by Marlo Kessler on 20.07.20.
// Copyright © 2020 Marlo Kessler. All rights reserved.
//

import Foundation

@available(iOS 13, *)
public enum IndicatorPosition {
case topOutBounds
case topInBounds
case bottomOutBounds
case bottomInBounds
}
49 changes: 49 additions & 0 deletions Sources/PageView/PageIndicator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// PageIndicator.swift
// ViewCTestApp
//
// Created by Marlo Kessler on 20.07.20.
// Copyright © 2020 Marlo Kessler. All rights reserved.
//

import SwiftUI

@available(iOS 13, *)
struct PageIndicator: UIViewRepresentable {

@Binding var currentIndex: Int
var pageNumber: Int
var pageIndicatorColor: UIColor?
var currentPageIndicatorColor: UIColor?

private let pageControl = UIPageControl()

func makeUIView(context: Context) -> UIPageControl {
pageControl.numberOfPages = pageNumber
if let color = pageIndicatorColor{ pageControl.pageIndicatorTintColor = color }
if let color = currentPageIndicatorColor{ pageControl.currentPageIndicatorTintColor = color }
pageControl.addTarget(context.coordinator, action: #selector(context.coordinator.change), for: .valueChanged)
return pageControl
}

func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentIndex
}

func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}

class Coordinator {

init(parent: PageIndicator) {
self.parent = parent
}

private let parent: PageIndicator

@objc func change() {
parent.currentIndex = parent.pageControl.currentPage
}
}
}
137 changes: 137 additions & 0 deletions Sources/PageView/PageView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//
// PageView.swift
// ViewCTestApp
//
// Created by Marlo Kessler on 18.07.20.
// Copyright © 2020 Marlo Kessler. All rights reserved.
//

import SwiftUI

@available(iOS 13, *)
public struct PageView<Content: View>: View {

public init(pageCount: Int,
currentIndex: Binding<Int> = Binding<Int>(get: {return 0}, set: {_ in}),
@ViewBuilder content: @escaping () -> Content)
{
self.pageCount = pageCount
self._currentIndex = currentIndex
self.content = content
}

private init(_ pageCount: Int,
_ currentIndex: Binding<Int>,
_ hideIndicator: Bool,
_ indicatorPosition: IndicatorPosition,
_ currentPageIndicatorColor: UIColor?,
_ indicatorColor: UIColor?,
_ indicatorBackgroundColor:Color?,
@ViewBuilder _ content: @escaping () -> Content)
{
self.pageCount = pageCount
self._currentIndex = currentIndex

self.hideIndicator = hideIndicator
self.indicatorPosition = indicatorPosition
self.currentPageIndicatorColor = currentPageIndicatorColor
self.indicatorColor = indicatorColor
self.indicatorBackgroundColor = indicatorBackgroundColor

self.content = content
}



// MARK: - Variables
private let pageCount: Int
@Binding private var currentIndex: Int
private let content: () -> Content

@GestureState private var translation: CGFloat = 0

private var hideIndicator: Bool = false
private var indicatorPosition: IndicatorPosition = .bottomInBounds
private var indicatorColor: UIColor?
private var currentPageIndicatorColor: UIColor?
private var indicatorBackgroundColor: Color?



// MARK: - Methods
public func indicator(position: IndicatorPosition = .bottomInBounds, current: UIColor? = nil, other: UIColor? = nil, background: Color? = nil) -> PageView {
return PageView(pageCount, $currentIndex, hideIndicator, position, current, other, background, content)
}

public func hideIndicator(_ hide: Bool = true) -> PageView {
return PageView(pageCount, $currentIndex, hide, indicatorPosition, currentPageIndicatorColor, indicatorColor, indicatorBackgroundColor, content)
}



// MARK: - View
private var indicator: some View {
PageIndicator(currentIndex: self.$currentIndex,
pageNumber: self.pageCount,
pageIndicatorColor: self.indicatorColor,
currentPageIndicatorColor: self.currentPageIndicatorColor)
.frame(height: 15)
.padding(.horizontal, 8)
.background(self.indicatorBackgroundColor ?? Color.clear.opacity(0.5))
.clipped()
.cornerRadius(7.5)
}

public var body: some View {
GeometryReader { geometry in

ZStack {

if self.indicatorPosition == .topInBounds {
VStack {
self.indicator
.offset(y: 16)
Spacer()
}
.zIndex(1)
}

VStack {

if self.indicatorPosition == .topOutBounds { self.indicator }

HStack(spacing: 0) {
self.content().frame(width: geometry.size.width)
}
.frame(width: geometry.size.width, alignment: .leading)
.offset(x: -CGFloat(self.currentIndex) * geometry.size.width)
.offset(x: self.translation)
.clipped()
.animation(.interactiveSpring())
.gesture(
DragGesture()
.updating(self.$translation) { value, state, _ in
state = value.translation.width
}
.onEnded { value in
let offset = value.translation.width / geometry.size.width
let newIndex = (CGFloat(self.currentIndex) - offset).rounded()
self.currentIndex = min(max(Int(newIndex), 0), self.pageCount - 1)
}
)

if self.indicatorPosition == .bottomOutBounds { self.indicator }
}

if self.indicatorPosition == .bottomInBounds {
VStack {
Spacer()
self.indicator
.offset(y: -16)
}
}

}
}
}
}

0 comments on commit f90ceaa

Please sign in to comment.