200 lines
7.1 KiB
Swift
200 lines
7.1 KiB
Swift
//
|
|
// ZLAdjustSlider.swift
|
|
// ZLPhotoBrowser
|
|
//
|
|
// Created by long on 2021/12/17.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
import UIKit
|
|
|
|
class ZLAdjustSlider: UIView {
|
|
static let maximumValue: Float = 1
|
|
|
|
static let minimumValue: Float = -1
|
|
|
|
let sliderWidth: CGFloat = 5
|
|
|
|
lazy var valueLabel: UILabel = {
|
|
let label = UILabel()
|
|
label.font = UIFont.systemFont(ofSize: 12)
|
|
label.layer.shadowColor = UIColor.black.withAlphaComponent(0.6).cgColor
|
|
label.layer.shadowOffset = .zero
|
|
label.layer.shadowOpacity = 1
|
|
label.textColor = .white
|
|
label.textAlignment = ZLPhotoUIConfiguration.default().adjustSliderType == .vertical ? .right : .center
|
|
label.adjustsFontSizeToFitWidth = true
|
|
label.minimumScaleFactor = 0.6
|
|
return label
|
|
}()
|
|
|
|
lazy var separator: UIView = {
|
|
let view = UIView()
|
|
view.backgroundColor = .zl.rgba(230, 230, 230)
|
|
return view
|
|
}()
|
|
|
|
lazy var shadowView: UIView = {
|
|
let view = UIView()
|
|
view.backgroundColor = .zl.adjustSliderNormalColor
|
|
view.layer.cornerRadius = sliderWidth / 2
|
|
view.layer.shadowColor = UIColor.black.withAlphaComponent(0.4).cgColor
|
|
view.layer.shadowOffset = .zero
|
|
view.layer.shadowOpacity = 1
|
|
view.layer.shadowRadius = 3
|
|
return view
|
|
}()
|
|
|
|
lazy var whiteView: UIView = {
|
|
let view = UIView()
|
|
view.backgroundColor = .zl.adjustSliderNormalColor
|
|
view.layer.cornerRadius = sliderWidth / 2
|
|
view.layer.masksToBounds = true
|
|
return view
|
|
}()
|
|
|
|
lazy var tintView: UIView = {
|
|
let view = UIView()
|
|
view.backgroundColor = .zl.adjustSliderTintColor
|
|
return view
|
|
}()
|
|
|
|
lazy var pan = UIPanGestureRecognizer(target: self, action: #selector(panAction(_:)))
|
|
|
|
private var impactFeedback: UIImpactFeedbackGenerator?
|
|
|
|
private var valueForPanBegan: Float = 0
|
|
|
|
var value: Float = 0 {
|
|
didSet {
|
|
valueLabel.text = String(Int(roundf(value * 100)))
|
|
tintView.frame = calculateTintFrame()
|
|
}
|
|
}
|
|
|
|
private var isVertical = ZLPhotoUIConfiguration.default().adjustSliderType == .vertical
|
|
|
|
var beginAdjust: (() -> Void)?
|
|
|
|
var valueChanged: ((Float) -> Void)?
|
|
|
|
var endAdjust: (() -> Void)?
|
|
|
|
deinit {
|
|
zl_debugPrint("ZLAdjustSlider deinit")
|
|
}
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupUI()
|
|
|
|
let editConfig = ZLPhotoConfiguration.default().editImageConfiguration
|
|
if editConfig.impactFeedbackWhenAdjustSliderValueIsZero {
|
|
impactFeedback = UIImpactFeedbackGenerator(style: editConfig.impactFeedbackStyle)
|
|
}
|
|
|
|
addGestureRecognizer(pan)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
|
|
if isVertical {
|
|
shadowView.frame = CGRect(x: 40, y: 0, width: sliderWidth, height: bounds.height)
|
|
whiteView.frame = shadowView.frame
|
|
tintView.frame = calculateTintFrame()
|
|
let separatorH: CGFloat = 1
|
|
separator.frame = CGRect(x: 0, y: (bounds.height - separatorH) / 2, width: sliderWidth, height: separatorH)
|
|
valueLabel.frame = CGRect(x: 0, y: bounds.height / 2 - 10, width: 38, height: 20)
|
|
} else {
|
|
valueLabel.frame = CGRect(x: 0, y: 0, width: zl.width, height: 38)
|
|
shadowView.frame = CGRect(x: 0, y: valueLabel.zl.bottom + 2, width: zl.width, height: sliderWidth)
|
|
whiteView.frame = shadowView.frame
|
|
tintView.frame = calculateTintFrame()
|
|
let separatorW: CGFloat = 1
|
|
separator.frame = CGRect(x: (zl.width - separatorW) / 2, y: 0, width: separatorW, height: sliderWidth)
|
|
}
|
|
}
|
|
|
|
private func setupUI() {
|
|
addSubview(shadowView)
|
|
addSubview(whiteView)
|
|
whiteView.addSubview(tintView)
|
|
whiteView.addSubview(separator)
|
|
addSubview(valueLabel)
|
|
}
|
|
|
|
private func calculateTintFrame() -> CGRect {
|
|
if isVertical {
|
|
let totalH = zl.height / 2
|
|
let tintH = totalH * abs(CGFloat(value)) / CGFloat(ZLAdjustSlider.maximumValue)
|
|
if value > 0 {
|
|
return CGRect(x: 0, y: totalH - tintH, width: sliderWidth, height: tintH)
|
|
} else {
|
|
return CGRect(x: 0, y: totalH, width: sliderWidth, height: tintH)
|
|
}
|
|
} else {
|
|
let totalW = zl.width / 2
|
|
let tintW = totalW * abs(CGFloat(value)) / CGFloat(ZLAdjustSlider.maximumValue)
|
|
if value > 0 {
|
|
return CGRect(x: totalW, y: 0, width: tintW, height: sliderWidth)
|
|
} else {
|
|
return CGRect(x: totalW - tintW, y: 0, width: tintW, height: sliderWidth)
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc private func panAction(_ pan: UIPanGestureRecognizer) {
|
|
let translation = pan.translation(in: self)
|
|
|
|
if pan.state == .began {
|
|
valueForPanBegan = value
|
|
beginAdjust?()
|
|
impactFeedback?.prepare()
|
|
} else if pan.state == .changed {
|
|
let transValue = isVertical ? -translation.y : translation.x
|
|
let totalLength = isVertical ? zl.height / 2 : zl.width / 2
|
|
var temp = valueForPanBegan + Float(transValue / totalLength)
|
|
temp = max(ZLAdjustSlider.minimumValue, min(ZLAdjustSlider.maximumValue, temp))
|
|
|
|
if (-0.0049..<0.005) ~= temp {
|
|
temp = 0
|
|
}
|
|
|
|
guard value != temp else { return }
|
|
|
|
value = temp
|
|
valueChanged?(value)
|
|
|
|
guard #available(iOS 10.0, *) else { return }
|
|
if value == 0 {
|
|
impactFeedback?.impactOccurred()
|
|
}
|
|
} else {
|
|
valueForPanBegan = value
|
|
endAdjust?()
|
|
}
|
|
}
|
|
}
|