|
@@ -7,6 +7,26 @@
|
|
|
|
|
|
|
|
|
|
class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
|
+
|
|
|
|
+ // MARK: - 绘图属性
|
|
|
|
+ private var currentPath: UIBezierPath!
|
|
|
|
+
|
|
|
|
+ // 历史记录相关属性
|
|
|
|
+ private var pathsHistory: [CAShapeLayer] = []
|
|
|
|
+ private var undonePaths: [CAShapeLayer] = []
|
|
|
|
+ private var currentIndex: Int = -1
|
|
|
|
+ private lazy var drawingLayer: CAShapeLayer = {
|
|
|
|
+ let drawingLayer = CAShapeLayer()
|
|
|
|
+ drawingLayer.frame = drawingImageView.bounds
|
|
|
|
+ drawingLayer.fillColor = UIColor.clear.cgColor
|
|
|
|
+ drawingLayer.lineCap = .round
|
|
|
|
+ drawingLayer.lineJoin = .round
|
|
|
|
+ drawingLayer.lineWidth = brushWidth
|
|
|
|
+ drawingLayer.strokeColor = brushColor.cgColor
|
|
|
|
+ return drawingLayer
|
|
|
|
+
|
|
|
|
+ }()
|
|
|
|
+
|
|
private let minZoomScale: CGFloat = 1.0
|
|
private let minZoomScale: CGFloat = 1.0
|
|
private let maxZoomScale: CGFloat = 4.0
|
|
private let maxZoomScale: CGFloat = 4.0
|
|
private let zoomSensitivity: CGFloat = 0.2 // 灵敏度系数 (0.1-1.0)
|
|
private let zoomSensitivity: CGFloat = 0.2 // 灵敏度系数 (0.1-1.0)
|
|
@@ -29,29 +49,34 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
return iv
|
|
return iv
|
|
}()
|
|
}()
|
|
|
|
|
|
- private let slider: UISlider = {
|
|
|
|
|
|
+ lazy var slider: UISlider = {
|
|
let slider = UISlider()
|
|
let slider = UISlider()
|
|
slider.minimumValue = 1
|
|
slider.minimumValue = 1
|
|
slider.maximumValue = 100
|
|
slider.maximumValue = 100
|
|
- slider.setThumbImage(UIImage.circle(diameter: 10, color: .themeColor), for: .normal)
|
|
|
|
|
|
+ slider.setThumbImage(UIImage.circle(diameter: 22, color: .themeColor), for: .normal)
|
|
slider.minimumTrackTintColor = UIColor.themeColor
|
|
slider.minimumTrackTintColor = UIColor.themeColor
|
|
slider.maximumTrackTintColor = .white.withAlphaComponent(0.2)
|
|
slider.maximumTrackTintColor = .white.withAlphaComponent(0.2)
|
|
slider.value = 50
|
|
slider.value = 50
|
|
|
|
+ slider.addTarget(self, action: #selector(brushSizeChanged(_:)), for: .valueChanged)
|
|
|
|
+ slider.addTarget(self, action: #selector(brushSizeEnded(_:)), for: [.touchUpInside, .touchUpOutside])
|
|
return slider
|
|
return slider
|
|
}()
|
|
}()
|
|
|
|
|
|
- private let clearButton: UIButton = {
|
|
|
|
|
|
+ lazy var clearButton: UIButton = {
|
|
let button = UIButton.createButton(image: .aiRemoveClear)
|
|
let button = UIButton.createButton(image: .aiRemoveClear)
|
|
|
|
+ button.addTarget(self, action: #selector(clearDrawing), for: .touchUpInside)
|
|
return button
|
|
return button
|
|
}()
|
|
}()
|
|
|
|
|
|
- private let undoButton: UIButton = {
|
|
|
|
|
|
+ lazy var undoButton: UIButton = {
|
|
let button = UIButton.createButton(image: .aiRemoveBack)
|
|
let button = UIButton.createButton(image: .aiRemoveBack)
|
|
|
|
+ button.addTarget(self, action: #selector(undoDrawing), for: .touchUpInside)
|
|
return button
|
|
return button
|
|
}()
|
|
}()
|
|
|
|
|
|
- private let redoButton: UIButton = {
|
|
|
|
|
|
+ lazy var redoButton: UIButton = {
|
|
let button = UIButton.createButton(image: .aiRemoveGo)
|
|
let button = UIButton.createButton(image: .aiRemoveGo)
|
|
|
|
+ button.addTarget(self, action: #selector(redoDrawing), for: .touchUpInside)
|
|
return button
|
|
return button
|
|
}()
|
|
}()
|
|
|
|
|
|
@@ -70,6 +95,15 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
private var scale: CGFloat = 1.0
|
|
private var scale: CGFloat = 1.0
|
|
private var touchCenter: CGPoint = .zero
|
|
private var touchCenter: CGPoint = .zero
|
|
|
|
|
|
|
|
+
|
|
|
|
+ lazy var panRoundView: UIView = {
|
|
|
|
+ let view = UIView()
|
|
|
|
+ view.backgroundColor = brushColor
|
|
|
|
+ view.layer.borderColor = UIColor.white.cgColor
|
|
|
|
+ view.layer.borderWidth = 1.5
|
|
|
|
+ return view
|
|
|
|
+ }()
|
|
|
|
+
|
|
func setUpRemoveUploadView(){
|
|
func setUpRemoveUploadView(){
|
|
let spaceH = 176.0
|
|
let spaceH = 176.0
|
|
uploadImageViewMaxHeight = k_ScreenHeight-spaceH-k_Height_safeAreaInsetsBottom()-k_Nav_Height
|
|
uploadImageViewMaxHeight = k_ScreenHeight-spaceH-k_Height_safeAreaInsetsBottom()-k_Nav_Height
|
|
@@ -84,7 +118,6 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
setUpRemoveUploadView()
|
|
setUpRemoveUploadView()
|
|
setupUI()
|
|
setupUI()
|
|
setupGestures()
|
|
setupGestures()
|
|
- setupActions()
|
|
|
|
|
|
|
|
drawingImageView.layer.addSublayer(drawingLayer)
|
|
drawingImageView.layer.addSublayer(drawingLayer)
|
|
}
|
|
}
|
|
@@ -104,9 +137,7 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
make.width.height.equalToSuperview()
|
|
make.width.height.equalToSuperview()
|
|
}
|
|
}
|
|
cusStackView.addSubviewToStack(scrollView)
|
|
cusStackView.addSubviewToStack(scrollView)
|
|
-
|
|
|
|
- // 添加绘图视图
|
|
|
|
-
|
|
|
|
|
|
+ cusStackView.scrollView.isScrollEnabled = false
|
|
// 移除所有点击手势(较粗暴)
|
|
// 移除所有点击手势(较粗暴)
|
|
uploadImageView.gestureRecognizers?.forEach {
|
|
uploadImageView.gestureRecognizers?.forEach {
|
|
if $0 is UITapGestureRecognizer {
|
|
if $0 is UITapGestureRecognizer {
|
|
@@ -169,7 +200,6 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
make.centerY.equalToSuperview()
|
|
make.centerY.equalToSuperview()
|
|
make.leading.equalTo(62)
|
|
make.leading.equalTo(62)
|
|
make.trailing.equalTo(-55)
|
|
make.trailing.equalTo(-55)
|
|
- make.width.height.equalTo(24)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
panLineLabel.snp.makeConstraints { make in
|
|
panLineLabel.snp.makeConstraints { make in
|
|
@@ -177,20 +207,41 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
make.trailing.equalTo(-16)
|
|
make.trailing.equalTo(-16)
|
|
make.height.equalTo(24)
|
|
make.height.equalTo(24)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ panRoundView.cornerRadius = brushWidth/2.0
|
|
|
|
+ drawingImageView.addSubview(panRoundView)
|
|
|
|
+ panRoundView.snp.makeConstraints { make in
|
|
|
|
+ make.width.height.equalTo(brushWidth)
|
|
|
|
+ make.center.equalToSuperview()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kMainAfter(1.5) {
|
|
|
|
+ self.panRoundView.isHidden = true
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
private func setupGestures() {
|
|
private func setupGestures() {
|
|
- // 绘图手势
|
|
|
|
- let panGesture = ImmediatePanGestureRecognizer(target: self, action: #selector(handleDrawingPan(_:)))
|
|
|
|
- panGesture.minimumNumberOfTouches = 1
|
|
|
|
- panGesture.maximumNumberOfTouches = 1
|
|
|
|
- drawingImageView.addGestureRecognizer(panGesture)
|
|
|
|
|
|
+ // 新增点击手势
|
|
|
|
+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDrawingTap(_:)))
|
|
|
|
+ tapGesture.numberOfTapsRequired = 1
|
|
|
|
+ tapGesture.numberOfTouchesRequired = 1
|
|
|
|
+ drawingImageView.addGestureRecognizer(tapGesture)
|
|
|
|
|
|
// 双指缩放手势
|
|
// 双指缩放手势
|
|
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
|
|
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
|
|
pinchGesture.delegate = self
|
|
pinchGesture.delegate = self
|
|
scrollView.addGestureRecognizer(pinchGesture)
|
|
scrollView.addGestureRecognizer(pinchGesture)
|
|
|
|
|
|
|
|
+ // 绘图手势
|
|
|
|
+// let panGesture = ImmediatePanGestureRecognizer(target: self, action: #selector(handleDrawingPan(_:)))
|
|
|
|
+ let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrawingPan(_:)))
|
|
|
|
+ panGesture.minimumNumberOfTouches = 1
|
|
|
|
+ panGesture.maximumNumberOfTouches = 1
|
|
|
|
+ drawingImageView.addGestureRecognizer(panGesture)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
// 拖动手势(用于移动图片)
|
|
// 拖动手势(用于移动图片)
|
|
let dragGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrag(_:)))
|
|
let dragGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrag(_:)))
|
|
dragGesture.minimumNumberOfTouches = 2
|
|
dragGesture.minimumNumberOfTouches = 2
|
|
@@ -199,46 +250,33 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
scrollView.addGestureRecognizer(dragGesture)
|
|
scrollView.addGestureRecognizer(dragGesture)
|
|
}
|
|
}
|
|
|
|
|
|
- private func setupActions() {
|
|
|
|
- slider.addTarget(self, action: #selector(brushSizeChanged(_:)), for: .valueChanged)
|
|
|
|
- clearButton.addTarget(self, action: #selector(clearDrawing), for: .touchUpInside)
|
|
|
|
- undoButton.addTarget(self, action: #selector(undoDrawing), for: .touchUpInside)
|
|
|
|
- redoButton.addTarget(self, action: #selector(redoDrawing), for: .touchUpInside)
|
|
|
|
|
|
+ // 点击绘制圆点方法
|
|
|
|
+ @objc private func handleDrawingTap(_ gesture: UITapGestureRecognizer) {
|
|
|
|
+ let currentPoint = gesture.location(in: drawingImageView)
|
|
|
|
+
|
|
|
|
+ let currentPath = UIBezierPath()
|
|
|
|
+ currentPath.lineCapStyle = .round
|
|
|
|
+ currentPath.lineJoinStyle = .round
|
|
|
|
+ currentPath.move(to: currentPoint)
|
|
|
|
+ currentPath.move(to: currentPoint)
|
|
|
|
+ currentPath.addLine(to: currentPoint)
|
|
|
|
+ // 创建并添加形状图层
|
|
|
|
+ let circleLayer = createShapeLayer(from: currentPath)
|
|
|
|
+ drawingImageView.layer.addSublayer(circleLayer)
|
|
|
|
+
|
|
|
|
+ // 添加到历史记录
|
|
|
|
+ addToHistory(layer: circleLayer)
|
|
}
|
|
}
|
|
-
|
|
|
|
-
|
|
|
|
- // MARK: - 绘图属性
|
|
|
|
- private var currentPath: UIBezierPath!
|
|
|
|
-
|
|
|
|
- // 历史记录相关属性
|
|
|
|
- private var pathsHistory: [CAShapeLayer] = []
|
|
|
|
- private var undonePaths: [CAShapeLayer] = []
|
|
|
|
- private var currentIndex: Int = -1
|
|
|
|
-
|
|
|
|
- private lazy var drawingLayer: CAShapeLayer = {
|
|
|
|
- let drawingLayer = CAShapeLayer()
|
|
|
|
- drawingLayer.frame = drawingImageView.bounds
|
|
|
|
- drawingLayer.fillColor = UIColor.clear.cgColor
|
|
|
|
- drawingLayer.lineCap = .round
|
|
|
|
- drawingLayer.lineJoin = .round
|
|
|
|
- drawingLayer.lineWidth = brushWidth
|
|
|
|
- drawingLayer.strokeColor = brushColor.cgColor
|
|
|
|
- return drawingLayer
|
|
|
|
-
|
|
|
|
- }()
|
|
|
|
|
|
|
|
// MARK: - 手势处理方法
|
|
// MARK: - 手势处理方法
|
|
@objc private func handleDrawingPan(_ gesture: UIPanGestureRecognizer) {
|
|
@objc private func handleDrawingPan(_ gesture: UIPanGestureRecognizer) {
|
|
let currentPoint = gesture.location(in: drawingImageView)
|
|
let currentPoint = gesture.location(in: drawingImageView)
|
|
- drawingLayer.lineWidth = brushWidth
|
|
|
|
-
|
|
|
|
switch gesture.state {
|
|
switch gesture.state {
|
|
case .began:
|
|
case .began:
|
|
currentPath = UIBezierPath()
|
|
currentPath = UIBezierPath()
|
|
currentPath.lineCapStyle = .round
|
|
currentPath.lineCapStyle = .round
|
|
currentPath.lineJoinStyle = .round
|
|
currentPath.lineJoinStyle = .round
|
|
currentPath.move(to: currentPoint)
|
|
currentPath.move(to: currentPoint)
|
|
-
|
|
|
|
case .changed:
|
|
case .changed:
|
|
currentPath.addLine(to: currentPoint)
|
|
currentPath.addLine(to: currentPoint)
|
|
drawingLayer.path = currentPath.cgPath
|
|
drawingLayer.path = currentPath.cgPath
|
|
@@ -295,6 +333,17 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
// panLineLabel.text = "\(brushWidth)"
|
|
// panLineLabel.text = "\(brushWidth)"
|
|
panLineLabel.text = "\(Int(brushWidth))"
|
|
panLineLabel.text = "\(Int(brushWidth))"
|
|
drawingLayer.lineWidth = brushWidth
|
|
drawingLayer.lineWidth = brushWidth
|
|
|
|
+
|
|
|
|
+ panRoundView.isHidden = false
|
|
|
|
+ panRoundView.cornerRadius = brushWidth/2.0
|
|
|
|
+ panRoundView.snp.remakeConstraints { make in
|
|
|
|
+ make.width.height.equalTo(brushWidth)
|
|
|
|
+ make.center.equalToSuperview()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc private func brushSizeEnded(_ sender: UISlider) {
|
|
|
|
+ self.panRoundView.isHidden = true
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -377,9 +426,27 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
}
|
|
}
|
|
// 自定义立即响应的手势识别器
|
|
// 自定义立即响应的手势识别器
|
|
class ImmediatePanGestureRecognizer: UIPanGestureRecognizer {
|
|
class ImmediatePanGestureRecognizer: UIPanGestureRecognizer {
|
|
|
|
+// override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
|
|
+// super.touchesBegan(touches, with: event)
|
|
|
|
+// self.state = .began
|
|
|
|
+// }
|
|
|
|
+
|
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
- super.touchesBegan(touches, with: event)
|
|
|
|
- self.state = .began
|
|
|
|
|
|
+ // 只有在单指触摸时才立即开始
|
|
|
|
+ if touches.count == 1 {
|
|
|
|
+ super.touchesBegan(touches, with: event)
|
|
|
|
+ self.state = .began
|
|
|
|
+ } else {
|
|
|
|
+ // 多指触摸时不处理
|
|
|
|
+ super.touchesBegan(touches, with: event)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
|
|
+ // 确保仍然是单指操作
|
|
|
|
+ if touches.count == 1 {
|
|
|
|
+ super.touchesMoved(touches, with: event)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -453,7 +520,6 @@ extension TSAIRemovePhotlVC {
|
|
if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
return image
|
|
return image
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return nil
|
|
return nil
|
|
@@ -505,7 +571,9 @@ extension TSAIRemovePhotlVC {
|
|
|
|
|
|
// 7. 生成并返回图像
|
|
// 7. 生成并返回图像
|
|
if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
- UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
|
|
|
|
+//#if DEBUG
|
|
|
|
+// UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
|
|
+//#endif
|
|
return image
|
|
return image
|
|
}
|
|
}
|
|
|
|
|
|
@@ -513,40 +581,7 @@ extension TSAIRemovePhotlVC {
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
-extension CGLineCap {
|
|
|
|
- init(_ shapeLayerLineCap: CAShapeLayerLineCap) {
|
|
|
|
- switch shapeLayerLineCap {
|
|
|
|
- case .round: self = .round
|
|
|
|
- case .butt: self = .butt
|
|
|
|
- case .square: self = .square
|
|
|
|
- default: self = .round
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
-extension CGLineJoin {
|
|
|
|
- init(_ shapeLayerLineJoin: CAShapeLayerLineJoin) {
|
|
|
|
- switch shapeLayerLineJoin {
|
|
|
|
- case .round: self = .round
|
|
|
|
- case .bevel: self = .bevel
|
|
|
|
- case .miter: self = .miter
|
|
|
|
- default: self = .round
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// UIImage扩展 - 图像着色
|
|
|
|
-extension UIImage {
|
|
|
|
- func tinted(with color: UIColor) -> UIImage {
|
|
|
|
- UIGraphicsBeginImageContextWithOptions(size, false, scale)
|
|
|
|
- defer { UIGraphicsEndImageContext() }
|
|
|
|
-
|
|
|
|
- color.set()
|
|
|
|
- withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: size))
|
|
|
|
-
|
|
|
|
- return UIGraphicsGetImageFromCurrentImageContext() ?? self
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
// MARK: - 手势处理修复
|
|
// MARK: - 手势处理修复
|
|
extension TSAIRemovePhotlVC: UIGestureRecognizerDelegate {
|
|
extension TSAIRemovePhotlVC: UIGestureRecognizerDelegate {
|
|
@@ -637,3 +672,38 @@ extension TSAIRemovePhotlVC:UIScrollViewDelegate {
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+extension CGLineCap {
|
|
|
|
+ init(_ shapeLayerLineCap: CAShapeLayerLineCap) {
|
|
|
|
+ switch shapeLayerLineCap {
|
|
|
|
+ case .round: self = .round
|
|
|
|
+ case .butt: self = .butt
|
|
|
|
+ case .square: self = .square
|
|
|
|
+ default: self = .round
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extension CGLineJoin {
|
|
|
|
+ init(_ shapeLayerLineJoin: CAShapeLayerLineJoin) {
|
|
|
|
+ switch shapeLayerLineJoin {
|
|
|
|
+ case .round: self = .round
|
|
|
|
+ case .bevel: self = .bevel
|
|
|
|
+ case .miter: self = .miter
|
|
|
|
+ default: self = .round
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// UIImage扩展 - 图像着色
|
|
|
|
+extension UIImage {
|
|
|
|
+ func tinted(with color: UIColor) -> UIImage {
|
|
|
|
+ UIGraphicsBeginImageContextWithOptions(size, false, scale)
|
|
|
|
+ defer { UIGraphicsEndImageContext() }
|
|
|
|
+
|
|
|
|
+ color.set()
|
|
|
|
+ withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: size))
|
|
|
|
+
|
|
|
|
+ return UIGraphicsGetImageFromCurrentImageContext() ?? self
|
|
|
|
+ }
|
|
|
|
+}
|