diff --git a/Example/TactileSlider/Base.lproj/Main.storyboard b/Example/TactileSlider/Base.lproj/Main.storyboard index 39e9a97..54c182b 100644 --- a/Example/TactileSlider/Base.lproj/Main.storyboard +++ b/Example/TactileSlider/Base.lproj/Main.storyboard @@ -1,9 +1,11 @@ - + - + + + @@ -20,7 +22,7 @@ - + @@ -39,10 +41,17 @@ + + + + + + + - + @@ -62,10 +71,12 @@ + + - + @@ -85,10 +96,12 @@ + + - + @@ -108,6 +121,7 @@ + @@ -132,4 +146,10 @@ + + + + + + diff --git a/TactileSlider/Classes/TactileSlider.swift b/TactileSlider/Classes/TactileSlider.swift index b774b31..bb66915 100644 --- a/TactileSlider/Classes/TactileSlider.swift +++ b/TactileSlider/Classes/TactileSlider.swift @@ -76,7 +76,15 @@ import UIKit } } } - + + public enum ImagePosition:String{ + case right + case left + case top + case bottom + case center + } + private enum Direction { case rightToLeft case leftToRight @@ -195,6 +203,16 @@ import UIKit setTapEnabled() } } + + /// Indicates whether a drag within the slider's bounds will set its value. + /// + /// If true, drag anywhere in the slider will set it to that value. + @IBInspectable open var enableDragging: Bool = true { + didSet { + setDragEnabled() + } + } + /// An array of `UITouch.TouchType`s used to distinguish the type of touches for the ``enableTapping`` feature. /// @@ -309,6 +327,43 @@ import UIKit } } } + + /// The image of the slider. + /// + /// If the image is set, the slider will show the image in the specified location. + /// for more information about image position, check``imagePosition`` + /// (default value: ``nil``) + @IBInspectable open var image:UIImage? = nil{ + didSet{ + renderer.image = image + } + } + + /// The position of the slider's image. + /// + /// If set image position, the slider will show the image in the selected position. (default value: ``bottom``) + open var imagePosition:ImagePosition? = nil{ + didSet{ + renderer.imagePosition = imagePosition ?? .bottom + } + } + + + /** + The position of the slider image for the storyboard. + + If set image position, slider will show image in selected position.for more information about image position, check``imagePosition``(default value: ``bottom``) + - Note: If creating a view from code, use ``imagePosition`` instead. + */ + @IBInspectable open var position:String? = nil{ + didSet{ + guard let position = position?.lowercased() else { + imagePosition = nil + return + } + imagePosition = ImagePosition.init(rawValue: position) + } + } /// See [`UIView.frame`](https://developer.apple.com/documentation/uikit/uiview/1622621-frame) override open var frame: CGRect { @@ -521,6 +576,10 @@ import UIKit private func setTapEnabled() { tapGestureRecognizer.isEnabled = enableTapping } + + private func setDragEnabled() { + dragGestureRecognizer.isEnabled = enableDragging + } @available(iOS 13.4, *) private func setScrollingEnabled() { @@ -531,7 +590,7 @@ import UIKit } } - @objc func didPan(sender: UIPanGestureRecognizer) { + @objc public func didPan(sender: UIPanGestureRecognizer) { let translationLengthAlongValueAxis = valueAxisFrom(sender.translation(in: self)) accumulatedMovement += translationLengthAlongValueAxis @@ -588,7 +647,7 @@ import UIKit } } - @objc func didTap(sender: UITapGestureRecognizer) { + @objc public func didTap(sender: UITapGestureRecognizer) { if sender.state == .ended { let tapLocation: CGFloat if (reverseValueAxis && !vertical) || (!reverseValueAxis && vertical) { diff --git a/TactileSlider/Classes/TactileSliderLayerRenderer.swift b/TactileSlider/Classes/TactileSliderLayerRenderer.swift index 5654009..3f55752 100644 --- a/TactileSlider/Classes/TactileSliderLayerRenderer.swift +++ b/TactileSlider/Classes/TactileSliderLayerRenderer.swift @@ -53,13 +53,33 @@ internal class TactileSliderLayerRenderer { } } } + + var image:UIImage? = nil{ + didSet{ + updateImage() + } + } + + var imagePosition:TactileSlider.ImagePosition = .bottom{ + didSet{ + updateImageFrame() + } + } + + var imageSize:CGSize = .init(width: 20, height: 20){ + didSet{ + updateImageFrame() + } + } + let trackLayer = CALayer() let thumbLayer = CAShapeLayer() let maskLayer = CAShapeLayer() let outlineLayer = CAShapeLayer() let thumbOutlineLayer = CAShapeLayer() - + let imageLayer = CALayer() + init() { trackLayer.backgroundColor = trackBackground.cgColor thumbLayer.fillColor = thumbTint.cgColor @@ -74,12 +94,15 @@ internal class TactileSliderLayerRenderer { updateOutlineLayer(updateBounds: false) updateOutlineColors() + updateImage() + updateImageFrame() } internal func setupLayers() { trackLayer.addSublayer(thumbLayer) trackLayer.addSublayer(outlineLayer) thumbLayer.addSublayer(thumbOutlineLayer) + trackLayer.addSublayer(imageLayer) } private func updateThumbLayerPath() { @@ -185,6 +208,9 @@ internal class TactileSliderLayerRenderer { thumbOutlineLayer.position = trackLayer.position updateThumbLayerPath() + updateImage() + updateImageFrame() + if let value = tactileSlider?.value { setValue(value) } @@ -210,4 +236,40 @@ internal class TactileSliderLayerRenderer { CATransaction.commit() } + + private func updateImage(){ + guard let image else { + imageLayer.contents = nil + return + } + + imageLayer.contents = image.cgImage + } + + private func updateImageFrame(){ + + + var origin:CGPoint = .zero + switch imagePosition { + case .left: + let leftPadding = min(trackLayer.frame.maxX * 0.1, 30) + origin = .init(x: trackLayer.frame.minX + leftPadding, y: trackLayer.frame.midY-imageSize.height/2) + case .right: + let rightPadding = min(trackLayer.frame.maxX * 0.1, 30) + origin = .init(x: trackLayer.frame.maxX - imageSize.width - rightPadding, y: trackLayer.frame.midY-imageSize.height/2) + case .top: + let topPadding = min(trackLayer.frame.maxY * 0.1, 30) + origin = .init(x: trackLayer.frame.midX - imageSize.width/2, y: trackLayer.frame.minY+topPadding) + case .bottom: + let bottomPadding = min(trackLayer.frame.maxY * 0.1, 30) + origin = .init(x: trackLayer.frame.midX - imageSize.width/2, y: trackLayer.frame.maxY-imageSize.height - bottomPadding) + case .center: + origin = .init(x: trackLayer.frame.midX - imageSize.width/2, y: trackLayer.frame.midY-imageSize.height/2) + } + + + imageLayer.frame = .init(origin: origin, size: imageSize) + imageLayer.contentsGravity = .resizeAspect + imageLayer.isGeometryFlipped = true + } }