Как изменить размер UIView, перетаскивая его края? - PullRequest
20 голосов
/ 11 декабря 2011

В моем приложении для iPad я хочу, чтобы пользователи могли изменять размер UIView, перетаскивая вид из его краев.Я буду использовать iOS 5 SDK, так какой же самый чистый подход для этого?Есть ли альтернативы достижению этого, не касаясь прикосновений Beg, touchesMoved и т. Д.?

Ответы [ 5 ]

52 голосов
/ 12 января 2012

Вы можете сделать это, проверив точку начала касания.Если он попадает в один из четырех ваших углов, вы можете изменить размер в зависимости от расстояния между этой точкой касания и текущей точкой касания.(Если точка начала касания не достигла угла, мы просто перемещаем вид вместо изменения размера.)

Определите размер ваших перетаскиваемых углов.

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);
    }
} 
9 голосов
/ 11 декабря 2011

Я предполагаю, что ваш пользовательский интерфейс включает в себя какие-то маркеры по бокам вида, и присоединение простого UIPanGestureRecognizer к этим элементам управления дескриптора делает всю проблему довольно простой.

В методе действия из распознавателя жестов просто получите -translationInView: относительно размера, который вы изменяете, сохраните исходный кадр, когда состояние распознавателя жестов равно UIGestureRecognizerStateBegan, и непрерывно корректируйте кадр представления, пока состояние UIGestureRecognizerStateChanged.

8 голосов
/ 05 июля 2018

Я обновил приведенный выше код, используя 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: currentPoint.x + deltaWidth, height: currentPoint.y + 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. Сохраняет состояние касания пользователя.

6 голосов
/ 26 марта 2017

Swift Версия решения @Prerna Chavan, решение 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

        }
    }
3 голосов
/ 20 января 2019

Это Swift 4.2 решение, которое работает с AutoLayout & Constraint-Animation .

Поскольку рекомендуется анимировать ограничения, а не фактический размерпрямоугольник при работе с AutoLayout, это решение делает именно это.

Дополнительные функции:

  • Изменение размера только одной стороны, когда не на краю.
  • Перемещение всегопрямоугольник на ощупь в середине it.

Просмотрите видео об этом здесь: https://imgur.com/a/CrkARLi

Импорт - это соединение ограничений как выходов для их анимации.

Connect the constraints as outlets to animate them

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

...