如何将拖动功能添加到转换后的视图?
Posted
技术标签:
【中文标题】如何将拖动功能添加到转换后的视图?【英文标题】:How to add drag to move function to a transformed view? 【发布时间】:2016-11-08 01:54:44 【问题描述】:我制作了一个自定义视图,可以通过拖动圆角按钮来调整大小和旋转。
我需要视图能够拖动以更改其位置。
我尝试了几种方法,但没有一个有效的属性(视图在组合旋转和调整大小动作时表现得很奇怪)。
这样做的正确方法是什么?
根据这个引用苹果文档的答案,What to use to move UIView self.frame or self.transform property? 我不应该将 frame 属性与转换一起使用,所以我假设我需要使用 CGAffineTransform 来更改视图的位置? (我试过这个但效果不好)
import Foundation
import UIKit
class ResizeRotateView: UIImageView, Resizable
private let buttonWidth: CGFloat = 40
private var themeColor: UIColor = UIColor.magentaColor()
// Rotation Resize
var radian: CGFloat = 0
private var tempAnglePanStart : Float = 0
private var tempAngleLastPanEnd: Float = 0
// UI Subviews
lazy var cornerButton: UIView =
let b = UIView()
b.layer.cornerRadius = self.buttonWidth / 2
b.layer.borderWidth = 1
b.layer.borderColor = self.themeColor.CGColor
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(buttonTouchMoved) )
b.addGestureRecognizer(panGesture)
return b
()
// Init
override init(frame: CGRect)
super.init(frame: frame)
setupSuviews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupSuviews()
addSubview( cornerButton )
addConstraintsWithFormat("H:[v0(\(buttonWidth))]", views: cornerButton)
addConstraintsWithFormat("V:[v0(\(buttonWidth))]", views: cornerButton)
addConstraint(NSLayoutConstraint(item: cornerButton, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: cornerButton, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0))
override func hitTest(point: CGPoint, withEvent e: UIEvent?) -> UIView? // This will enable gesture out of self.view's boundary. From ***.
if let result = super.hitTest(point, withEvent:e)
return result
for sub in self.subviews.reverse()
let pt = self.convertPoint(point, toView:sub)
if let result = sub.hitTest(pt, withEvent:e)
return result
return nil
////// Event
func buttonTouchMoved(gestureRecognizer: UIPanGestureRecognizer)
resize(gestureRecognizer)
rotate(gestureRecognizer)
////// Action
// Resize
func resize(gestureRecognizer: UIPanGestureRecognizer)
// Temporary set aglet to 0
self.transform = CGAffineTransformMakeRotation( 0 )
// Resize
let locationInSelf = gestureRecognizer.locationInView(self)
resizeByKeepingAspectRatioByDistanceFromCenter(toLocation: locationInSelf)
layoutSubviews()
// Recover angle
self.transform = CGAffineTransformMakeRotation( radian )
layoutSubviews()
// Rotation
func rotate(gestureRecognizer: UIPanGestureRecognizer)
guard let superView = self.superview else
print("#Error: Super View not found")
return
let angle = self.angle(byLocation: gestureRecognizer.locationInView( superView ) )
if gestureRecognizer.state == .Began
print("Pan begin:\(angle)")
tempAnglePanStart = angle - tempAngleLastPanEnd
let destinationAngle = angle - tempAnglePanStart
self.transform = CGAffineTransformMakeRotation( destinationAngle.degreesToRadians )
if gestureRecognizer.state == .Ended
print("Pan ended")
tempAngleLastPanEnd = destinationAngle
////// Helper
func angle( firstPoint: CGPoint, secondPoint: CGPoint ) -> Float
let dx = firstPoint.x - secondPoint.x
let dy = firstPoint.y - secondPoint.y
let angle = atan2(dy, dx).radiansToDegrees
let angleInFloat = Float( angle.double )
let formattedAngle = angleInFloat < 0 ? angleInFloat + 360.0 : angleInFloat
return formattedAngle
func angle(byLocation location: CGPoint) -> Float
let targetViewCnter = self.center
return self.angle(targetViewCnter, secondPoint: location)
func setAngle(angle: Float)
let radian = angle.degreesToRadians
self.transform = CGAffineTransformMakeRotation( radian )
self.radian = radian
更新
我非常接近。我可以通过保持旋转角度和视图大小来移动。剩下的问题是当我开始拖动时视图会跳动。
import Foundation
import UIKit
class ResizeRorateMovableView: ResizeRotateView
var startCenter: CGPoint = CGPointZero
override init(frame: CGRect)
super.init(frame: frame)
setupSuviews()
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureEvent))
addGestureRecognizer( panGesture )
userInteractionEnabled = true
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func panGestureEvent(panGesture: UIPanGestureRecognizer)
if panGesture.state == .Began
self.startCenter = self.center
return
if panGesture.state == .Changed
let location = panGesture.translationInView(self)
// Rotate first, then move
var transfrom = CGAffineTransformMakeRotation( self.radian )
transfrom = CGAffineTransformTranslate(transfrom, location.x, location.y)
self.transform = transfrom
return
【问题讨论】:
问题是大多数应用程序使用平移手势来移动,而不是像你正在做的那样旋转。考虑到许多用户习惯于(a)平移手势移动视图,(b)捏手势调整视图大小,以及(c)旋转手势旋转视图。使用您正在编码的内容,您可能几乎需要一种完全不同的编码机制——例如开始/结束旋转的独特动作和开始/结束移动的另一个独特动作。 即使一个事件触发的转换是不同的,但实际的转换是由相同的逻辑完成的,所以我想这并不重要。我也打算实现(a),(b),(c),但是平移旋转的一个优点是可以用一根手指完成,用户可以用一只手操作任务。 【参考方案1】:它可能会跳跃,因为用户不一定触摸中心,但您将中心设置为他们拖动的位置。如果你开始拖动靠近中心,它不会像你开始拖动靠近边缘那样跳跃。要修复,当手势开始时,获取从触摸到当前中心的距离,并在进行平移时使用该偏移量。
【讨论】:
我很难通过使用 CGAffineTransform 翻译来做到这一点。如果可以,请您发布代码吗? 奇怪的跳跃似乎与中心无关。即使我在离中心很近的地方点击,视图跳到中心的距离也比触摸点要远得多。 如果你能把你目前在样例项目中的代码贴出来,我来看看。 我尝试了多种方法,但似乎我发布的代码最接近解决方案。顺便说一句,我想出了一个添加超级视图来处理移动功能的想法。在这种情况下,我不必被 CAAffineTransform 的东西所困扰。如果这不起作用,我会再次发布情况。 添加超级视图来处理移动功能确实工作得很好!有时间我会贴出代码。无论如何,谢谢你的帮助,我真的很感激。【参考方案2】:我只需要添加一个超级视图来实现移动功能。
这种情况下,我可以将旋转功能和移动功能完全分开,非常容易处理。
视图 A。实现了移动功能。它在下面是可见的,以便于理解,但它的颜色应该是清晰的。我触摸了仅在 ViewB(子视图)上启用的移动功能。
视图 B。实现了旋转功能。它是 ViewA 的子视图
【讨论】:
以上是关于如何将拖动功能添加到转换后的视图?的主要内容,如果未能解决你的问题,请参考以下文章