【发布时间】: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 stackoverflow.
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),但是平移旋转的一个优点是可以用一根手指完成,用户可以用一只手操作任务。
标签: ios swift uiview uitapgesturerecognizer cgaffinetransform