Skip to content

Commit

Permalink
Added wedgeForSliceAtIndex() method to SpinWheelControlDataSource pro…
Browse files Browse the repository at this point in the history
…tocol...

Created and implemented SpinWheelWedge class.
Created and implemented SpinWheelWedgeLabel.
Created and implemented SpinWheelWedgeShape.
Implemented snapOrientation IBInspectable variable.
Created Degrees extension with toRadians computed variable.
Created degreesValue computed variable to SpinWheelDirection enum.
Added .md extension to the License file.
Updated the readme file.
Cleaned up code.
  • Loading branch information
joshdhenry committed May 19, 2017
1 parent 97baca2 commit 0e07b5c
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 83 deletions.
File renamed without changes.
6 changes: 5 additions & 1 deletion README.md
@@ -1,4 +1,4 @@
# Spin Wheel Control v0.1.3
# Spin Wheel Control v0.1.4

## Synopsis

Expand Down Expand Up @@ -91,6 +91,10 @@ The following data source methods are available:
//Specify the number of wedges in the spin wheel by returning a positive value that is greater than 1

func numberOfWedgesInSpinWheel(spinWheel: SpinWheelControl) -> UInt

//Returns the SpinWheelWedge at the specified index of the SpinWheelControl

func wedgeForSliceAtIndex(index: UInt) -> SpinWheelWedge
```


Expand Down
4 changes: 2 additions & 2 deletions SpinWheelControl.podspec
@@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'SpinWheelControl'
s.version = '0.1.3'
s.version = '0.1.4'
s.summary = 'An inertial spinning wheel UI control that allows selection of an item.'

s.description = <<-DESC
Spin Wheel Control is a wheel of fortune-style inertial spinning wheel UI control that allows selection of an item. It is written in the Swift programming language and to be used in iOS apps. The code is a Swift derivation, port, and enhancement based loosely on the Objective-C SMWheelControl CocoaPod written by Cesare Rocchi and Simone Civetta found at https://cocoapods.org/pods/SMWheelControl.
DESC

s.homepage = 'https://github.com/joshdhenry/SpinWheelControl'
s.license = { :type => 'BSD', :file => 'LICENSE' }
s.license = { :type => 'BSD', :file => 'LICENSE.md' }
s.author = { 'Josh Henry' => 'Josh@BigSmashSoftware.com' }
s.source = { :git => 'https://github.com/joshdhenry/SpinWheelControl.git', :tag => s.version.to_s }

Expand Down
24 changes: 20 additions & 4 deletions SpinWheelControl.xcodeproj/project.pbxproj
Expand Up @@ -13,9 +13,13 @@
0326275E1EB2AC9100AED82E /* SpinWheelControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0326275D1EB2AC9100AED82E /* SpinWheelControl.swift */; };
032627601EB2BBEC00AED82E /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 0326275F1EB2BBEC00AED82E /* README.md */; };
032627671EB5BA4B00AED82E /* SpinWheelControlDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032627661EB5BA4B00AED82E /* SpinWheelControlDataSource.swift */; };
03C1675F1EB82CE1009B5C5B /* LICENSE in Sources */ = {isa = PBXBuildFile; fileRef = 03C1675E1EB82CE1009B5C5B /* LICENSE */; };
03C1675F1EB82CE1009B5C5B /* LICENSE.md in Sources */ = {isa = PBXBuildFile; fileRef = 03C1675E1EB82CE1009B5C5B /* LICENSE.md */; };
03C167611EB9A991009B5C5B /* SpinWheelControlDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03C167601EB9A991009B5C5B /* SpinWheelControlDelegate.swift */; };
03D3868A1ECC20CB006B4C25 /* SpinWheelControl.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 03D386891ECC20CB006B4C25 /* SpinWheelControl.podspec */; };
03D386D91ECED967006B4C25 /* SpinWheelWedge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D386D81ECED967006B4C25 /* SpinWheelWedge.swift */; };
03D386DB1ECED9BE006B4C25 /* SpinWheelWedgeShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D386DA1ECED9BE006B4C25 /* SpinWheelWedgeShape.swift */; };
03D386DD1ECED9D8006B4C25 /* SpinWheelWedgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D386DC1ECED9D8006B4C25 /* SpinWheelWedgeLabel.swift */; };
03D386DF1ECED9F2006B4C25 /* Degrees+MathMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D386DE1ECED9F2006B4C25 /* Degrees+MathMethods.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -38,9 +42,13 @@
0326275D1EB2AC9100AED82E /* SpinWheelControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelControl.swift; sourceTree = "<group>"; };
0326275F1EB2BBEC00AED82E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
032627661EB5BA4B00AED82E /* SpinWheelControlDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelControlDataSource.swift; sourceTree = "<group>"; };
03C1675E1EB82CE1009B5C5B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
03C1675E1EB82CE1009B5C5B /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = "<group>"; };
03C167601EB9A991009B5C5B /* SpinWheelControlDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelControlDelegate.swift; sourceTree = "<group>"; };
03D386891ECC20CB006B4C25 /* SpinWheelControl.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SpinWheelControl.podspec; sourceTree = "<group>"; };
03D386D81ECED967006B4C25 /* SpinWheelWedge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelWedge.swift; sourceTree = "<group>"; };
03D386DA1ECED9BE006B4C25 /* SpinWheelWedgeShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelWedgeShape.swift; sourceTree = "<group>"; };
03D386DC1ECED9D8006B4C25 /* SpinWheelWedgeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinWheelWedgeLabel.swift; sourceTree = "<group>"; };
03D386DE1ECED9F2006B4C25 /* Degrees+MathMethods.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Degrees+MathMethods.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -66,7 +74,7 @@
isa = PBXGroup;
children = (
03D386891ECC20CB006B4C25 /* SpinWheelControl.podspec */,
03C1675E1EB82CE1009B5C5B /* LICENSE */,
03C1675E1EB82CE1009B5C5B /* LICENSE.md */,
0326275F1EB2BBEC00AED82E /* README.md */,
032627451EB2AC7700AED82E /* SpinWheelControl */,
032627501EB2AC7700AED82E /* SpinWheelControlTests */,
Expand All @@ -91,6 +99,10 @@
0326275D1EB2AC9100AED82E /* SpinWheelControl.swift */,
032627661EB5BA4B00AED82E /* SpinWheelControlDataSource.swift */,
03C167601EB9A991009B5C5B /* SpinWheelControlDelegate.swift */,
03D386D81ECED967006B4C25 /* SpinWheelWedge.swift */,
03D386DA1ECED9BE006B4C25 /* SpinWheelWedgeShape.swift */,
03D386DC1ECED9D8006B4C25 /* SpinWheelWedgeLabel.swift */,
03D386DE1ECED9F2006B4C25 /* Degrees+MathMethods.swift */,
);
path = SpinWheelControl;
sourceTree = "<group>";
Expand Down Expand Up @@ -219,10 +231,14 @@
buildActionMask = 2147483647;
files = (
03C167611EB9A991009B5C5B /* SpinWheelControlDelegate.swift in Sources */,
03C1675F1EB82CE1009B5C5B /* LICENSE in Sources */,
03C1675F1EB82CE1009B5C5B /* LICENSE.md in Sources */,
03D386D91ECED967006B4C25 /* SpinWheelWedge.swift in Sources */,
032627671EB5BA4B00AED82E /* SpinWheelControlDataSource.swift in Sources */,
032627601EB2BBEC00AED82E /* README.md in Sources */,
03D386DB1ECED9BE006B4C25 /* SpinWheelWedgeShape.swift in Sources */,
0326275E1EB2AC9100AED82E /* SpinWheelControl.swift in Sources */,
03D386DF1ECED9F2006B4C25 /* Degrees+MathMethods.swift in Sources */,
03D386DD1ECED9D8006B4C25 /* SpinWheelWedgeLabel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
17 changes: 17 additions & 0 deletions SpinWheelControl/Degrees+MathMethods.swift
@@ -0,0 +1,17 @@
//
// Degrees+MathMethods.swift
// SpinWheelPractice
//
// Created by Josh Henry on 5/19/17.
// Copyright © 2017 Big Smash Software. All rights reserved.
//

import Foundation
import UIKit

extension Degrees {

var toRadians: Radians {
return self * CGFloat.pi / 180
}
}
123 changes: 50 additions & 73 deletions SpinWheelControl/SpinWheelControl.swift
Expand Up @@ -36,11 +36,25 @@ public enum SpinWheelDirection {
return Radians.pi
}
}

var degreesValue: Degrees {
switch self {
case .up:
return 90
case .right:
return 0
case .down:
return 270
case .left:
return 180
}
}
}

@IBDesignable
open class SpinWheelControl: UIControl {

//MARK: Properties
@IBInspectable var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
Expand All @@ -54,6 +68,7 @@ open class SpinWheelControl: UIControl {
}
}


@IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
Expand All @@ -62,7 +77,13 @@ open class SpinWheelControl: UIControl {
}


//MARK: Properties
@IBInspectable var snapOrientation: CGFloat = SpinWheelDirection.up.degreesValue {
didSet {
snappingPositionRadians = snapOrientation.toRadians
}
}


weak public var dataSource: SpinWheelControlDataSource?
public var delegate: SpinWheelControlDelegate?

Expand All @@ -80,8 +101,6 @@ open class SpinWheelControl: UIControl {
let kCircleRadians: Radians = 2 * CGFloat.pi

var spinWheelView: UIView!
//var spinWheelView: UIView = UIView()


private var numberOfWedges: UInt!
private var radiansPerWedge: CGFloat!
Expand All @@ -101,13 +120,12 @@ open class SpinWheelControl: UIControl {

var currentDecelerationVelocity: Velocity!

var snappingPositionRadians: Radians = SpinWheelDirection.up.radiansValue
var snapDestinationRadians: Radians!
var snapIncrementRadians: Radians!

public var selectedIndex: Int = 0

let colorPalette: [UIColor] = [UIColor.blue, UIColor.brown, UIColor.cyan, UIColor.darkGray, UIColor.green, UIColor.magenta, UIColor.red, UIColor.orange, UIColor.black, UIColor.gray, UIColor.lightGray, UIColor.purple, UIColor.yellow, UIColor.white]

//MARK: Computed Properties
var spinWheelCenter: CGPoint {
return convert(center, from: superview)
Expand All @@ -117,6 +135,7 @@ open class SpinWheelControl: UIControl {
return 360 / CGFloat(numberOfWedges)
}

//The radius of the spin wheel's circle
var radius: CGFloat {
return self.frame.width / 2
}
Expand All @@ -126,16 +145,11 @@ open class SpinWheelControl: UIControl {
return atan2(self.spinWheelView.transform.b, self.spinWheelView.transform.a)
}

// This determines which angle the numbers are deemed to be selected. In this case it is pi / 2, which is the top center of the wheel
var snappingPositionRadians: Radians {
return SpinWheelDirection.up.radiansValue
}

//How many radians there are to snapDestinationRadians
var radiansToDestinationSlice: Radians {
return snapDestinationRadians - currentRadians
}


//The velocity of the spinwheel
var velocity: Velocity {
var computedVelocity: Velocity = 0
Expand Down Expand Up @@ -165,6 +179,13 @@ open class SpinWheelControl: UIControl {
self.drawWheel()
}

//TODO: Implement snapOrientation here
public init(frame: CGRect, snapOrientation: SpinWheelDirection) {
super.init(frame: frame)

self.drawWheel()
}


required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Expand All @@ -174,6 +195,7 @@ open class SpinWheelControl: UIControl {


//MARK: Methods
//Clear the SpinWheelControl from the screen
public func clear() {
for subview in spinWheelView.subviews {
subview.removeFromSuperview()
Expand All @@ -187,9 +209,8 @@ open class SpinWheelControl: UIControl {
}


//Draw the spinWheelView
public func drawWheel() {
NSLog("Drawing wheel...")

spinWheelView = UIView(frame: self.bounds)

guard self.dataSource?.numberOfWedgesInSpinWheel(spinWheel: self) != nil else {
Expand All @@ -203,14 +224,23 @@ open class SpinWheelControl: UIControl {

radiansPerWedge = kCircleRadians / CGFloat(numberOfWedges)

//Draw each individual wedge
for wedgeNumber in 0..<numberOfWedges {
drawWedge(wedgeNumber: wedgeNumber)
guard let source = self.dataSource else {
return
}

//Draw each individual label
for wedgeNumber in 0..<numberOfWedges {
drawWedgeLabel(wedgeNumber: wedgeNumber)
let wedge: SpinWheelWedge = source.wedgeForSliceAtIndex(index: wedgeNumber)

//Wedge shape
wedge.shape.configureWedgeShape(index: wedgeNumber, radius: radius, position: spinWheelCenter, degreesPerWedge: degreesPerWedge)
wedge.layer.addSublayer(wedge.shape)

//Wedge label
wedge.label.configureWedgeLabel(index: wedgeNumber, width: radius, position: spinWheelCenter, radiansPerWedge: radiansPerWedge)
wedge.addSubview(wedge.label)

//Add the shape and label to the spinWheelView
spinWheelView.addSubview(wedge)
}

self.spinWheelView.isUserInteractionEnabled = false
Expand All @@ -222,47 +252,7 @@ open class SpinWheelControl: UIControl {
}


func drawWedge(wedgeNumber: UInt) {
NSLog("Drawing wedge...")

let newWedge: CAShapeLayer = CAShapeLayer()
newWedge.fillColor = colorPalette[Int(wedgeNumber)].cgColor
newWedge.strokeColor = UIColor.black.cgColor
newWedge.lineWidth = 3.0

let newWedgePath: UIBezierPath = UIBezierPath()
newWedgePath.move(to: spinWheelCenter)

let startRadians: Radians = CGFloat(wedgeNumber) * degreesPerWedge * CGFloat.pi / 180
let endRadians: Radians = CGFloat(wedgeNumber + 1) * degreesPerWedge * CGFloat.pi / 180

newWedgePath.addArc(withCenter: spinWheelCenter, radius: radius, startAngle: startRadians, endAngle: endRadians, clockwise: true)

newWedgePath.close()
newWedge.path = newWedgePath.cgPath

spinWheelView.layer.addSublayer(newWedge)
}


func drawWedgeLabel(wedgeNumber: UInt) {
NSLog("Drawing label...")

let wedgeLabelFrame: CGRect = CGRect(x: 0, y: 0, width: radius / 2, height: 30)

let wedgeLabel: UILabel = UILabel(frame: wedgeLabelFrame)
wedgeLabel.layer.anchorPoint = CGPoint(x: 1.50, y: 0.5)
wedgeLabel.layer.position = spinWheelCenter

wedgeLabel.transform = CGAffineTransform(rotationAngle: radiansPerWedge * CGFloat(wedgeNumber) + CGFloat.pi + (radiansPerWedge / 2))

wedgeLabel.textColor = UIColor.white
wedgeLabel.text = "Label #" + String(wedgeNumber)
wedgeLabel.shadowColor = UIColor.black
spinWheelView.addSubview(wedgeLabel)
}


//When the SpinWheelControl ends rotation, trigger the UIControl's valueChanged to reflect the newly selected value.
func didEndRotationOnWedgeAtIndex(index: UInt) {
selectedIndex = Int(index)
delegate?.spinWheelDidEndDecelerating?(spinWheel: self)
Expand All @@ -272,8 +262,6 @@ open class SpinWheelControl: UIControl {

//User began touching/dragging the UIControl
override open func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
//NSLog("Begin Tracking...")

switch currentStatus {
case SpinWheelStatus.idle:
currentlyDetectingTap = true
Expand Down Expand Up @@ -329,9 +317,8 @@ open class SpinWheelControl: UIControl {

//User ended touching/dragging the UIControl
override open func endTracking(_ touch: UITouch?, with event: UIEvent?) {
//NSLog("End Tracking...")

let tapCount = touch?.tapCount != nil ? (touch?.tapCount)! : 0
//TODO: Implement tap to move to wedge
//If the user just tapped, move to that wedge
if currentStatus == .idle &&
tapCount > 0 &&
Expand All @@ -345,8 +332,6 @@ open class SpinWheelControl: UIControl {

//After user has lifted their finger from dragging, begin the deceleration
func beginDeceleration() {
//NSLog("Beginning deceleration...")

currentDecelerationVelocity = velocity

//If the wheel was spun, begin deceleration
Expand Down Expand Up @@ -386,8 +371,6 @@ open class SpinWheelControl: UIControl {

//End decelerating the spinwheel
func endDeceleration() {
//NSLog("End Decelerating...")

decelerationDisplayLink?.invalidate()
snapToNearestWedge()
}
Expand Down Expand Up @@ -422,14 +405,11 @@ open class SpinWheelControl: UIControl {

//End snapping
func endSnap() {
//NSLog("End snap...")

//snappingPositionRadians is the default snapping position (in this case, up)
//currentRadians in this case is where in the wheel it is currently snapped
//Distance of zero wedge from the default snap position (up)
var indexSnapped: Radians = (-(snappingPositionRadians) - currentRadians - (radiansPerWedge / 2))


//Number of wedges from the zero wedge to the default snap position (up)
indexSnapped = indexSnapped / radiansPerWedge + CGFloat(numberOfWedges)

Expand All @@ -455,7 +435,6 @@ open class SpinWheelControl: UIControl {

//Select a wedge with an index offset relative to 0 position. May be positive or negative.
func selectWedgeAtIndexOffset(index: Int, animated: Bool) {
//NSLog("Select wedge at index " + String(index))
snapDestinationRadians = -(snappingPositionRadians) + (CGFloat(index) * radiansPerWedge) - (radiansPerWedge / 2)

if currentRadians != snapDestinationRadians {
Expand Down Expand Up @@ -485,8 +464,6 @@ open class SpinWheelControl: UIControl {

//Clear all views and redraw the spin wheel
public func reloadData() {
NSLog("Reloading...")

clear()
drawWheel()
}
Expand Down

0 comments on commit 0e07b5c

Please sign in to comment.