Skip to content

Commit

Permalink
Merge pull request #4 from campierce88/customDirection
Browse files Browse the repository at this point in the history
Adding the ability to pass in an image for the circle slider view.
  • Loading branch information
quver authored Jan 4, 2017
2 parents f473224 + 641ac69 commit 0316464
Showing 1 changed file with 111 additions and 19 deletions.
130 changes: 111 additions & 19 deletions Sources/SlidableImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@

import UIKit

/// A enum used to determine which direction the slider should slide from
public enum SlideDirection: Int {
case left
case right
case top
case bottom
}

/// A struct containing border information for the slider. You can use this struct to define the width and color of the slider border.
public struct SlidableImageBorder {
var borderWidth: CGFloat
var borderColor: UIColor

public init(borderWidth width: CGFloat, borderColor color: UIColor) {
self.borderWidth = width
self.borderColor = color
}
}

/// Super easy Slider for before&after images
open class SlidableImage: UIView {

Expand All @@ -20,16 +39,27 @@ open class SlidableImage: UIView {
/// Circle view with icon for sliding images. You can override it with your custom view.
open var sliderCircle: UIView

/// Enum that describes which direction the slider will slide from.
open var slideDirection: SlideDirection

/// Struct that tells the slider if there should be a border view added
open var sliderBorder: SlidableImageBorder? = nil
private var sliderBorderView: UIView?

/// Generic initializer with views
///
/// - Parameters:
/// - frame: Frame size
/// - firstView: First view - should have size equal to frame and second view
/// - secondView: Second view - should have size equal to frame and second view
public init(frame: CGRect, firstView: UIView, secondView: UIView) {
/// - slideDirection: Optional parameter for the direction that the slider should slide. The default value is .right.
/// - sliderBorder: Optional paramter that will add a border to the slider of the specfied size and color
public init(frame: CGRect, firstView: UIView, secondView: UIView, sliderImage: UIImage? = nil, slideDirection: SlideDirection? = nil, sliderBorder: SlidableImageBorder? = nil) {
self.firstView = firstView
self.secondView = secondView
sliderCircle = SlidableImage.setupSliderCircle()
self.sliderCircle = SlidableImage.setupSliderCircle(sliderImage: sliderImage)
self.slideDirection = slideDirection ?? .right
self.sliderBorder = sliderBorder
super.init(frame: frame)

initializeViews()
Expand All @@ -42,11 +72,13 @@ open class SlidableImage: UIView {
/// - frame: Frame size
/// - firstImage: First image for sliding
/// - secondImage: Second image for sliding
convenience public init(frame: CGRect, firstImage: UIImage, secondImage: UIImage) {
/// - slideDirection: Optional parameter for the direction that the slider should slide. The default value is .right.
/// - sliderBorder: Optional paramter that will add a border to the slider of the specfied size and color
convenience public init(frame: CGRect, firstImage: UIImage, secondImage: UIImage, sliderImage: UIImage? = nil, slideDirection: SlideDirection? = nil, sliderBorder: SlidableImageBorder? = nil) {
let firstView = SlidableImage.setup(image: firstImage, frame: frame)
let secondView = SlidableImage.setup(image: secondImage, frame: frame)

self.init(frame: frame, firstView: firstView, secondView: secondView)
self.init(frame: frame, firstView: firstView, secondView: secondView, sliderImage: sliderImage, slideDirection: slideDirection, sliderBorder: sliderBorder)
}

required public init?(coder aDecoder: NSCoder) {
Expand All @@ -57,26 +89,69 @@ open class SlidableImage: UIView {
///
/// - Parameter maskLocation: Position of slider
open func updateMask(location maskLocation: CGFloat) {
let maskRectPath = UIBezierPath(rect: CGRect(x: bounds.minX,
var maskRectPath: UIBezierPath
let mask = CAShapeLayer()
switch slideDirection {
case .left:
maskRectPath = UIBezierPath(rect: CGRect(x: maskLocation,
y: bounds.minY,
width: bounds.width,
height: bounds.height))
case .right:
maskRectPath = UIBezierPath(rect: CGRect(x: bounds.minX,
y: bounds.minY,
width: maskLocation,
height: bounds.height))
let mask = CAShapeLayer()
case .top:
maskRectPath = UIBezierPath(rect: CGRect(x: bounds.minX,
y: maskLocation,
width: bounds.width,
height: bounds.height))
case .bottom:
maskRectPath = UIBezierPath(rect: CGRect(x: bounds.minX,
y: bounds.minY,
width: bounds.width,
height: maskLocation))
}
mask.path = maskRectPath.cgPath
secondView.layer.mask = mask

sliderCircle.center.x = maskLocation
switch slideDirection {
case .left, .right:
sliderCircle.center.x = maskLocation
case .top, .bottom:
sliderCircle.center.y = maskLocation
}
}

/// Private wrapper for setup view
fileprivate func initializeViews() {
clipsToBounds = true
sliderCircle.center = center
updateMask(location: center.x)

switch slideDirection {
case .left, .right:
updateMask(location: center.x)
case .top, .bottom:
updateMask(location: center.y)
}

addSubview(firstView)
addSubview(secondView)
addSubview(sliderCircle)

// Only add the slider to the view if a non nil sliderBorder was set
if let sliderBorder = sliderBorder {
sliderBorderView = UIView()
sliderBorderView?.translatesAutoresizingMaskIntoConstraints = false
sliderBorderView?.backgroundColor = sliderBorder.borderColor
addSubview(sliderBorderView!)
addConstraints([
NSLayoutConstraint(item: sliderBorderView!, attribute: .centerX, relatedBy: .equal, toItem: sliderCircle, attribute: .centerX, multiplier: 1.0, constant: 0.0),
NSLayoutConstraint(item: sliderBorderView!, attribute: .centerY, relatedBy: .equal, toItem: sliderCircle, attribute: .centerY, multiplier: 1.0, constant: 0.0),
NSLayoutConstraint(item: sliderBorderView!, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1.0, constant: 0.0),
NSLayoutConstraint(item: sliderBorderView!, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: sliderBorder.borderWidth)
])
bringSubview(toFront: sliderCircle)
}
}

/// Private wrapper for adding gesture recognizer
Expand All @@ -88,20 +163,37 @@ open class SlidableImage: UIView {
@objc private func gestureHandler(_ panGestureRecognizer: UIPanGestureRecognizer) {
let location = panGestureRecognizer.location(in: firstView)

guard (bounds.minX...bounds.maxX ~= location.x) else {
return
switch slideDirection {
case .left, .right:
guard (bounds.minX...bounds.maxX ~= location.x) else { return }
updateMask(location: location.x)
case .top, .bottom:
guard (bounds.minY...bounds.maxY ~= location.y) else { return }
updateMask(location: location.y)
}

updateMask(location: location.x)
}

/// Private wrapper for setup circle slider view
///
/// - Parameters:
/// - image: Content image for slider circle
/// - Returns: Slider circle
private class func setupSliderCircle() -> UIView {
let frame = CGRect(x: 0, y: 0, width: 50, height: 50)

return ArrowsView(frame: frame)
private class func setupSliderCircle(sliderImage: UIImage? = nil) -> UIView {
// Workaround - without this view, gesture recognizer doesn't work
let circle = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))

guard let sliderImage = sliderImage else {
return ArrowsView(frame: frame)
}

circle.layer.cornerRadius = circle.bounds.width / 2

let imageView = UIImageView(image: sliderImage)
imageView.contentMode = .scaleAspectFill
circle.addSubview(imageView)
imageView.center = circle.center

return circle
}

/// Private wrapper for setup image view
Expand Down

0 comments on commit 0316464

Please sign in to comment.