UIView
的大小。 我将使用iOS 5 SDK,那么最干净的方法是什么? 是否有其他方法可以在不涉及touchesBegan,touchesMoved等事件的情况下实现这一点?您可以通过检查触摸起始点来实现此操作。如果它碰到你的四个角之一,你可以根据该触摸起始点和当前触摸点之间的距离进行缩放调整。(如果触摸起始点没有碰到一个角,我们只是移动视图而不是调整大小。)
CGFloat kResizeThumbSize = 45.0f;
@interface MY_CLASS_NAME : UIView {
BOOL isResizingLR;
BOOL isResizingUL;
BOOL isResizingUR;
BOOL isResizingLL;
CGPoint touchStart;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
touchStart = [[touches anyObject] locationInView:self];
isResizingLR = (self.bounds.size.width - touchStart.x < kResizeThumbSize && self.bounds.size.height - touchStart.y < kResizeThumbSize);
isResizingUL = (touchStart.x <kResizeThumbSize && touchStart.y <kResizeThumbSize);
isResizingUR = (self.bounds.size.width-touchStart.x < kResizeThumbSize && touchStart.y<kResizeThumbSize);
isResizingLL = (touchStart.x <kResizeThumbSize && self.bounds.size.height -touchStart.y <kResizeThumbSize);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self];
CGPoint previous = [[touches anyObject] previousLocationInView:self];
CGFloat deltaWidth = touchPoint.x - previous.x;
CGFloat deltaHeight = touchPoint.y - previous.y;
// get the frame values so we can calculate changes below
CGFloat x = self.frame.origin.x;
CGFloat y = self.frame.origin.y;
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
if (isResizingLR) {
self.frame = CGRectMake(x, y, touchPoint.x+deltaWidth, touchPoint.y+deltaWidth);
} else if (isResizingUL) {
self.frame = CGRectMake(x+deltaWidth, y+deltaHeight, width-deltaWidth, height-deltaHeight);
} else if (isResizingUR) {
self.frame = CGRectMake(x, y+deltaHeight, width+deltaWidth, height-deltaHeight);
} else if (isResizingLL) {
self.frame = CGRectMake(x+deltaWidth, y, width-deltaWidth, height+deltaHeight);
} else {
// not dragging from a corner -- move the view
self.center = CGPointMake(self.center.x + touchPoint.x - touchStart.x,
self.center.y + touchPoint.y - touchStart.y);
}
}
我使用了enum
更新了上面的代码。
class ResizableView: UIView {
enum Edge {
case topLeft, topRight, bottomLeft, bottomRight, none
}
static var edgeSize: CGFloat = 44.0
private typealias `Self` = ResizableView
var currentEdge: Edge = .none
var touchStart = CGPoint.zero
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
touchStart = touch.location(in: self)
currentEdge = {
if self.bounds.size.width - touchStart.x < Self.edgeSize && self.bounds.size.height - touchStart.y < Self.edgeSize {
return .bottomRight
} else if touchStart.x < Self.edgeSize && touchStart.y < Self.edgeSize {
return .topLeft
} else if self.bounds.size.width-touchStart.x < Self.edgeSize && touchStart.y < Self.edgeSize {
return .topRight
} else if touchStart.x < Self.edgeSize && self.bounds.size.height - touchStart.y < Self.edgeSize {
return .bottomLeft
}
return .none
}()
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let currentPoint = touch.location(in: self)
let previous = touch.previousLocation(in: self)
let originX = self.frame.origin.x
let originY = self.frame.origin.y
let width = self.frame.size.width
let height = self.frame.size.height
let deltaWidth = currentPoint.x - previous.x
let deltaHeight = currentPoint.y - previous.y
switch currentEdge {
case .topLeft:
self.frame = CGRect(x: originX + deltaWidth, y: originY + deltaHeight, width: width - deltaWidth, height: height - deltaHeight)
case .topRight:
self.frame = CGRect(x: originX, y: originY + deltaHeight, width: width + deltaWidth, height: height - deltaHeight)
case .bottomRight:
self.frame = CGRect(x: originX, y: originY, width: width + deltaWidth, height: height + deltaWidth)
case .bottomLeft:
self.frame = CGRect(x: originX + deltaWidth, y: originY, width: width - deltaWidth, height: height + deltaHeight)
default:
// Moving
self.center = CGPoint(x: self.center.x + currentPoint.x - touchStart.x,
y: self.center.y + currentPoint.y - touchStart.y)
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
currentEdge = .none
}
}
currentEdge
保存用户触摸位置的状态。
我猜测你的UI使用了视图边缘上的某种手柄,并且将一个简单的UIPanGestureRecognizer
附加到这些手柄控件上能够使整个问题变得非常容易。
在手势识别器的动作方法中,只需要获取与正在调整大小的视图相关的-translationInView:
,在手势识别器的状态为UIGestureRecognizerStateBegan
时保存原始帧,而在状态为UIGestureRecognizerStateChanged
时不断地调整视图的帧即可。
这是一个使用AutoLayout和Constraint-Animation的 Swift 4.2 解决方案。
由于在使用AutoLayout时建议动画约束而不是实际矩形的大小,因此该解决方案正是如此。
其他功能:
在此处查看其视频演示: https://imgur.com/a/CrkARLi
导入是将约束作为输出连接以进行动画处理。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var topConstraint: NSLayoutConstraint!
@IBOutlet weak var rightConstraint: NSLayoutConstraint!
@IBOutlet weak var leftConstraint: NSLayoutConstraint!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
@IBOutlet weak var rect: UIView!
struct ResizeRect{
var topTouch = false
var leftTouch = false
var rightTouch = false
var bottomTouch = false
var middelTouch = false
}
var touchStart = CGPoint.zero
var proxyFactor = CGFloat(10)
var resizeRect = ResizeRect()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let touchStart = touch.location(in: self.view)
print(touchStart)
resizeRect.topTouch = false
resizeRect.leftTouch = false
resizeRect.rightTouch = false
resizeRect.bottomTouch = false
resizeRect.middelTouch = false
if touchStart.y > rect.frame.minY + (proxyFactor*2) && touchStart.y < rect.frame.maxY - (proxyFactor*2) && touchStart.x > rect.frame.minX + (proxyFactor*2) && touchStart.x < rect.frame.maxX - (proxyFactor*2){
resizeRect.middelTouch = true
print("middle")
return
}
if touchStart.y > rect.frame.maxY - proxyFactor && touchStart.y < rect.frame.maxY + proxyFactor {
resizeRect.bottomTouch = true
print("bottom")
}
if touchStart.x > rect.frame.maxX - proxyFactor && touchStart.x < rect.frame.maxX + proxyFactor {
resizeRect.rightTouch = true
print("right")
}
if touchStart.x > rect.frame.minX - proxyFactor && touchStart.x < rect.frame.minX + proxyFactor {
resizeRect.leftTouch = true
print("left")
}
if touchStart.y > rect.frame.minY - proxyFactor && touchStart.y < rect.frame.minY + proxyFactor {
resizeRect.topTouch = true
print("top")
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let currentTouchPoint = touch.location(in: self.view)
let previousTouchPoint = touch.previousLocation(in: self.view)
let deltaX = currentTouchPoint.x - previousTouchPoint.x
let deltaY = currentTouchPoint.y - previousTouchPoint.y
if resizeRect.middelTouch{
topConstraint.constant += deltaY
leftConstraint.constant += deltaX
rightConstraint.constant -= deltaX
bottomConstraint.constant -= deltaY
}
if resizeRect.topTouch {
topConstraint.constant += deltaY
}
if resizeRect.leftTouch {
leftConstraint.constant += deltaX
}
if resizeRect.rightTouch {
rightConstraint.constant -= deltaX
}
if resizeRect.bottomTouch {
bottomConstraint.constant -= deltaY
}
UIView.animate(withDuration: 0.25, delay: 0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.view.layoutIfNeeded()
}, completion: { (ended) in
})
}
}
}
我也将其作为在Github上工作的项目: https://github.com/ppoh71/resizeRectangleOnTouchDrag
以下是@Prerna Chavan解决方案的Swift版本,Prerna的解决方案无法检测用户是否触摸边缘,只能检测角落,但下面的代码可以检测所有情况。
class OverlayView: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
static var kResizeThumbSize:CGFloat = 44.0
private typealias `Self` = OverlayView
var imageView = UIImageView()
var isResizingLeftEdge:Bool = false
var isResizingRightEdge:Bool = false
var isResizingTopEdge:Bool = false
var isResizingBottomEdge:Bool = false
var isResizingBottomRightCorner:Bool = false
var isResizingLeftCorner:Bool = false
var isResizingRightCorner:Bool = false
var isResizingBottomLeftCorner:Bool = false
//Define your initialisers here
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let currentPoint = touch.location(in: self)
isResizingBottomRightCorner = (self.bounds.size.width - currentPoint.x < Self.kResizeThumbSize && self.bounds.size.height - currentPoint.y < Self.kResizeThumbSize);
isResizingLeftCorner = (currentPoint.x < Self.kResizeThumbSize && currentPoint.y < Self.kResizeThumbSize);
isResizingRightCorner = (self.bounds.size.width-currentPoint.x < Self.kResizeThumbSize && currentPoint.y < Self.kResizeThumbSize);
isResizingBottomLeftCorner = (currentPoint.x < Self.kResizeThumbSize && self.bounds.size.height - currentPoint.y < Self.kResizeThumbSize);
isResizingLeftEdge = (currentPoint.x < Self.kResizeThumbSize)
isResizingTopEdge = (currentPoint.y < Self.kResizeThumbSize)
isResizingRightEdge = (self.bounds.size.width - currentPoint.x < Self.kResizeThumbSize)
isResizingBottomEdge = (self.bounds.size.height - currentPoint.y < Self.kResizeThumbSize)
// do something with your currentPoint
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let currentPoint = touch.location(in: self)
// do something with your currentPoint
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let currentPoint = touch.location(in: self)
// do something with your currentPoint
isResizingLeftEdge = false
isResizingRightEdge = false
isResizingTopEdge = false
isResizingBottomEdge = false
isResizingBottomRightCorner = false
isResizingLeftCorner = false
isResizingRightCorner = false
isResizingBottomLeftCorner = false
}
}
这是我对@Peter Pohlmann的回答做出的一个小修正
,它不允许拖动或移动视图到视图框架
之外
唯一需要修改的部分在override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?)
中
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let currentTouchPoint = touch.location(in: self.view)
let previousTouchPoint = touch.previousLocation(in: self.view)
let deltaX = currentTouchPoint.x - previousTouchPoint.x
let deltaY = currentTouchPoint.y - previousTouchPoint.y
if resizeRect.middelTouch {
if topConstraint.constant + deltaY > 0 && leftConstraint.constant + deltaX > 0 && rightConstraint.constant - deltaX > 0 && bottomConstraint.constant - deltaY > 40 {
topConstraint.constant += deltaY
leftConstraint.constant += deltaX
rightConstraint.constant -= deltaX
bottomConstraint.constant -= deltaY
}
}
if resizeRect.topTouch {
if topConstraint.constant + deltaY > 0 {
topConstraint.constant += deltaY
}
}
if resizeRect.leftTouch {
if leftConstraint.constant + deltaX > 0 {
leftConstraint.constant += deltaX
}
}
if resizeRect.rightTouch {
if rightConstraint.constant - deltaX > 0 {
rightConstraint.constant -= deltaX
}
}
if resizeRect.bottomTouch {
if bottomConstraint.constant - deltaY > 0 {
bottomConstraint.constant -= deltaY
}
}
UIView.animate(withDuration: 0.25, delay: 0, options: UIView.AnimationOptions.curveLinear, animations: {
self.view.layoutIfNeeded()
}, completion: { (ended) in
})
}
}