Skip to content

Commit

Permalink
Add continue pan color pick.
Browse files Browse the repository at this point in the history
  • Loading branch information
noppefoxwolf committed Jun 30, 2022
1 parent a553530 commit 9582bd5
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 21 deletions.
5 changes: 1 addition & 4 deletions Example.swiftpm/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ struct App: SwiftUI.App {

var body: some Scene {
WindowGroup {
HStack {
ContentView().ignoresSafeArea()
LinearGradient(colors: [.white, .black], startPoint: .top, endPoint: .bottom)
}
ContentView()
}
}
}
32 changes: 31 additions & 1 deletion Example.swiftpm/ContentView.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import SwiftUI
import ColorPicker
import SnapKit
import Combine

struct ContentView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> some UIViewController {
Expand All @@ -12,6 +13,8 @@ struct ContentView: UIViewControllerRepresentable {
}

class ContentViewController: UIViewController {
var cancellables: Set<AnyCancellable> = []

override func viewDidLoad() {
super.viewDidLoad()

Expand All @@ -28,10 +31,37 @@ class ContentViewController: UIViewController {
}))
let imageView = UIImageView(image: UIImage(named: "image"))
imageView.contentMode = .scaleAspectFit
let eyeDropperButton = UIButton(configuration: .filled())
eyeDropperButton.configuration?.image = UIImage(systemName: "eyedropper")
eyeDropperButton.configuration?.title = "Tap or drag here"
eyeDropperButton.addAction(UIAction { [unowned self] _ in
let picker = ScopeColorPicker(windowScene: self.view.window!.windowScene!)
Task {
let color = await picker.pickColor()
print(color)
}
}, for: .primaryActionTriggered)
let goOut = GoOutPanGestureRecognizer()
goOut
.publisher(for: \.state)
.filter({ $0 == .began })
.sink { [unowned self] state in
print("GO")
let picker = ScopeColorPicker(
windowScene: self.view.window!.windowScene!,
panGestureRecognizer: goOut
)
Task {
let color = await picker.pickColor()
print(color)
}
}.store(in: &cancellables)
eyeDropperButton.addGestureRecognizer(goOut)
let stackView = UIStackView(arrangedSubviews: [
imageView,
colorPickerButton,
uiColorPickerButton
uiColorPickerButton,
eyeDropperButton
])
stackView.axis = .vertical
view.addSubview(stackView)
Expand Down
4 changes: 2 additions & 2 deletions Example.swiftpm/Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/SnapKit/SnapKit",
"state": {
"branch": null,
"revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6",
"version": "5.0.1"
"revision": "f222cbdf325885926566172f6f5f06af95473158",
"version": "5.6.0"
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/SnapKit/SnapKit", from: "5.0.1"),
.package(url: "https://github.com/SnapKit/SnapKit", from: "5.6.0"),
],
targets: [
.target(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import UIKit

/// Viewの外に出た時に初めてbeganになるPanジェスチャ
public class GoOutPanGestureRecognizer: UIPanGestureRecognizer {

public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {

}

public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
if state == .possible {
let location = touches.first!.location(in: view)
if !view!.bounds.contains(location) {
super.touchesBegan(touches, with: event)
super.touchesMoved(touches, with: event)
}
} else {
super.touchesMoved(touches, with: event)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ public class ScopeColorPicker {
let pickerWindow: ScopeColorPickerWindow
var continuation: CheckedContinuation<CGColor, Never>? = nil

public init(windowScene: UIWindowScene) {
self.pickerWindow = .init(windowScene: windowScene)
public init(
windowScene: UIWindowScene,
panGestureRecognizer: UIPanGestureRecognizer? = nil
) {
self.pickerWindow = .init(windowScene: windowScene, panGestureRecognizer: panGestureRecognizer)
pickerWindow.delegate = self
pickerWindow.dataSource = self
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ class ScopeColorPickerWindow: UIWindow {
weak var dataSource: ScopeColorPickerDataSource? = nil
var translationX: Double = 0
var translationY: Double = 0
let isContinuePan: Bool
weak var panGestureRecognizer: UIPanGestureRecognizer? = nil

override init(windowScene: UIWindowScene) {
init(
windowScene: UIWindowScene,
panGestureRecognizer: UIPanGestureRecognizer? = nil
) {
isContinuePan = panGestureRecognizer != nil
super.init(windowScene: windowScene)

addSubview(reticleView)
Expand All @@ -26,16 +32,35 @@ class ScopeColorPickerWindow: UIWindow {
make.size.equalTo(viewSize)
}

let panGesture = UIPanGestureRecognizer()
panGesture.addTarget(self, action: #selector(onPan(_:)))
addGestureRecognizer(panGesture)
let panGestureRecognizer = panGestureRecognizer ?? UIPanGestureRecognizer()
panGestureRecognizer.addTarget(self, action: #selector(onPan(_:)))
if !isContinuePan {
addGestureRecognizer(panGestureRecognizer)
}
self.panGestureRecognizer = panGestureRecognizer

isHidden = false

DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
guard let self = self else { return }
self.updateScopeContent(at: self.center)
}

if isContinuePan {
/// continue pan translation
let location = panGestureRecognizer.location(in: self)
let center = self.center
let x = location.x - center.x
let y = location.y - center.y
let initialTranslation = CGPoint(x: x, y: y)
self.translationX = initialTranslation.x
self.translationY = initialTranslation.y
panGestureRecognizer.setTranslation(initialTranslation, in: panGestureRecognizer.view)
reticleView.snp.updateConstraints { make in
make.centerX.equalToSuperview().offset(translationX)
make.centerY.equalToSuperview().offset(translationY)
}
}
}

public required init?(coder: NSCoder) {
Expand Down Expand Up @@ -64,15 +89,16 @@ class ScopeColorPickerWindow: UIWindow {
updateScopeContent(at: reticleView.center)
case .ended, .failed, .cancelled:
reticleView.isHidden = true
panGestureRecognizer?.removeTarget(self, action: #selector(onPan))
delegate?.scopePickerDidFinishColorPick(reticleView.color)
default:
break
}
}

func updateScopeContent(at location: CGPoint) {
reticleView.render { [weak self] context in
self?.dataSource?.colors(at: location, context: context)
reticleView.render { context in
dataSource?.colors(at: location, context: context)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ open class ColorSlider: UIControl {
}
trackView.addLayoutGuide(trackableLayoutGuide)
trackableLayoutGuide.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(34 / 2)
make.top.bottom.equalToSuperview()
make.horizontalEdges.equalToSuperview().inset(34 / 2)
make.verticalEdges.equalToSuperview()
}
trackView.addLayoutGuide(trackValueLayoutGuide)
trackValueLayoutGuide.snp.makeConstraints { make in
make.top.bottom.left.equalTo(trackableLayoutGuide)
make.verticalEdges.left.equalTo(trackableLayoutGuide)
make.width.equalTo(trackableLayoutGuide).multipliedBy(0)
}

Expand Down Expand Up @@ -101,7 +101,7 @@ open class ColorSlider: UIControl {
super.setNeedsUpdateConstraints()

trackValueLayoutGuide.snp.remakeConstraints { make in
make.top.bottom.left.equalTo(trackableLayoutGuide)
make.verticalEdges.left.equalTo(trackableLayoutGuide)
make.width.equalTo(trackableLayoutGuide).multipliedBy(value)
}
}
Expand Down

0 comments on commit 9582bd5

Please sign in to comment.