Проблема, с которой вы столкнулись, связана с определением переменной panGestureRecognizer
в определении класса здесь:
//Here I create the reference to the recognizer
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
Вы можете инициализировать его таким образом, но кажется, что self
не настроен при создании этой переменной. Таким образом, ваше действие никогда не регистрируется.
Есть несколько способов исправить это с помощью вашего кода, вы можете продолжить инициализировать его как переменную экземпляра, но вам нужно будет настроить цель / действие в вашей функции initialize()
let panGestureRecognizer = UIPanGestureRecognizer()
func initialize() {
// add your target/action here
panGestureRecognizer.addTarget(self, action: #selector(handlePan(_:)))
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
addGestureRecognizer(panGestureRecognizer)
}
Или вы можете просто инициализировать ваш распознаватель жестов в вашей функции инициализации и не использовать переменную экземпляра
func initialize() {
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
addGestureRecognizer(panGestureRecognizer)
}
Мой оригинальный ответ
Вот решение, которое работает с использованием ограничений с представлением, определенным в раскадровке, или путем непосредственного манипулирования кадром.
Пример с ограничениями
import UIKit
// Delegate protocol for managing constraint updates if needed
protocol MorphDelegate: class {
// tells the delegate to change its size constraints
func morph(x: CGFloat, y: CGFloat)
}
class ExpandableView: UIView {
var delegate: MorphDelegate?
init() {
// frame is set later if needed by creator when using this init method
super.init(frame: CGRect.zero)
configureGestureRecognizers()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configureGestureRecognizers()
}
override init(frame: CGRect) {
super.init(frame: frame)
configureGestureRecognizers()
}
// setup UIPanGestureRecognizer
internal func configureGestureRecognizers() {
let panGR = UIPanGestureRecognizer.init(target: self, action: #selector(didPan(_:)))
addGestureRecognizer(panGR)
}
@objc func didPan(_ panGR: UIPanGestureRecognizer) {
// get the translation
let translation = panGR.translation(in: self).applying(transform)
if let delegate = delegate {
// tell delegate to change the constraints using this translation
delegate.morph(x: translation.x, y: translation.y)
} else {
// If you want the view to expand/contract in opposite direction
// of drag then swap the + and - in the 2 lines below
let newOriginY = frame.origin.y + translation.y
let newHeight = frame.size.height - translation.y
// expand self via frame manipulation
let newFrame = CGRect(x: frame.origin.x, y: newOriginY, width: frame.size.width, height: newHeight)
frame = newFrame
}
// reset translation
panGR.setTranslation(CGPoint.zero, in: self)
}
}
Если вы хотите использовать этот класс, определив его в раскадровке и манипулируя его ограничениями, вы должны сделать это следующим образом.
Сначала определите ваш вид в раскадровке и ограничьте его ширину и высоту. Для демонстрации, которую я ограничил, это позиция x к центру вида, а снизу к SafeArea.bottom
Создайте IBOutlet для представления, а также ограничение по высоте для вашего файла ViewController.
Для этого примера я установил синий цвет фона.
В контроллере представления я определил функцию для настройки представления (в настоящее время только устанавливает делегат для обратных вызовов манипулирования ограничениями), а затем определил расширение для обработки вызовов делегатов для обновления ограничений.
class ViewController: UIViewController {
@IBOutlet weak var expandingView: ExpandableView!
@IBOutlet weak var constraint_expViewHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// call to configure our expanding view
configureExpandingView()
}
// this sets the delegate for an expanding view defined in the storyboard
func configureExpandingView() {
expandingView.delegate = self
}
}
// setup the delegate callback to handle constraint manipulation
extension ViewController: MorphDelegate {
func morph(x: CGFloat, y: CGFloat) {
// this will update the view's height based on the amount
// you drag your finger in the view. You can '+=' below if
// you want to reverse the expanding behavior based on pan
// movements.
constraint_expViewHeight.constant -= y
}
}
Выполнение этого через ограничения дает мне это при запуске проекта:
Пример с манипулированием кадрами
Чтобы использовать это и манипулировать высотой, используя только свойство frame, контроллер вида может реализовать создание вида примерно так:
override func viewDidLoad() {
super.viewDidLoad()
setupExpandingView()
}
func setupExpandingView() {
let newView = ExpandableView()
newView.backgroundColor = .red
newView.frame = CGRect(x: 20, y: 200, width: 100, height: 100)
view.addSubview(newView)
}
Используя только манипуляции с кадрами, я получаю это: