UIPanGestureRecognizer 不触发动作
UIPanGestureRecognizer doesn't trigger action
我正在尝试创建 UIView 的子class,以便通过平移来展开视图。它应该以这种方式工作:如果用户向顶部平移,则视图的高度会降低,相反,如果平移向底部,则它应该增加。为了实现该功能,我试图将 UIPanGestureRecognizer 添加到视图中,但它似乎不起作用。我是这样做的:
第一个片段是 uiView subclass 声明
class ExpandibleView: UIView {
//Here I create the reference to the recognizer
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
//And here I set its minimumNumberOfTouches and maximumNumberOfTouches properties and add it to the view
func initialize() {
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
self.addGestureRecognizer(panGestureRecognizer)
}
//here's the function that should handle the pan but who instead doesn't seem to been called at all
@objc func handlePan(_ sender:UIPanGestureRecognizer) {
//Here's I handle the Pan
}
}
第二个是视图控制器内部的实现。
class MapViewController: UIViewController {
@IBOutlet weak var profileView: ExpandibleView!
//MARK: - ViewController Delegate Methods
override func viewDidLoad() {
super.viewDidLoad()
//Here I set the View
profileView.isUserInteractionEnabled = true
profileView.initialize()
profileView.minHeight = 100
profileView.maxHeight = 190
}
}
我在情节提要中将视图的 class 设置为我创建的子 class 但识别器根本不会触发所有处理程序。
尝试改变这个
class ExpandibleView: UIView {
func initialize() {
}
//here's the function that should handle the pan but who instead doesn't seem to been called at all
func handlePan() {
//your function
}
}
class MapViewController: UIViewController {
@IBOutlet weak var profileView: ExpandibleView!
//MARK: - ViewController Delegate Methods
override func viewDidLoad() {
super.viewDidLoad()
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
profileView.addGestureRecognizer(panGestureRecognizer)
//Here I set the View
profileView.isUserInteractionEnabled = true
profileView.initialize()
profileView.minHeight = 100
profileView.maxHeight = 190
}
@objc func handlePan(_ sender:UIPanGestureRecognizer) {
profileView.handlePan()
}
}
或者您可以在其他视图中创建一个调用委托。
祝你好运!
您遇到的问题是由于您在此处的 class 定义中定义了 panGestureRecognizer
变量:
//Here I create the reference to the recognizer
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
你可以用这种方式初始化它,但似乎 self
在创建这个变量时没有设置。所以你的操作永远不会被注册。
有几种方法可以使用您的代码解决此问题,您可以继续将其初始化为实例变量,但您需要在 initialize()
函数中设置 target/action
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)
}
}
如果您想通过在故事板中定义它并操纵它的约束来使用它 class,您可以像这样进行操作。
首先在故事板中定义您的视图并限制它的宽度和高度。对于演示,我将它的 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
}
}
当我 运行 项目时,通过约束以这种方式执行此操作给了我这个:
帧操作示例
要使用它并仅使用框架 属性 来操纵高度,视图控制器可能会像这样实现视图创建:
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)
}
仅使用帧操作我得到这个:
我正在尝试创建 UIView 的子class,以便通过平移来展开视图。它应该以这种方式工作:如果用户向顶部平移,则视图的高度会降低,相反,如果平移向底部,则它应该增加。为了实现该功能,我试图将 UIPanGestureRecognizer 添加到视图中,但它似乎不起作用。我是这样做的:
第一个片段是 uiView subclass 声明
class ExpandibleView: UIView {
//Here I create the reference to the recognizer
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
//And here I set its minimumNumberOfTouches and maximumNumberOfTouches properties and add it to the view
func initialize() {
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
self.addGestureRecognizer(panGestureRecognizer)
}
//here's the function that should handle the pan but who instead doesn't seem to been called at all
@objc func handlePan(_ sender:UIPanGestureRecognizer) {
//Here's I handle the Pan
}
}
第二个是视图控制器内部的实现。
class MapViewController: UIViewController {
@IBOutlet weak var profileView: ExpandibleView!
//MARK: - ViewController Delegate Methods
override func viewDidLoad() {
super.viewDidLoad()
//Here I set the View
profileView.isUserInteractionEnabled = true
profileView.initialize()
profileView.minHeight = 100
profileView.maxHeight = 190
}
}
我在情节提要中将视图的 class 设置为我创建的子 class 但识别器根本不会触发所有处理程序。
尝试改变这个
class ExpandibleView: UIView {
func initialize() {
}
//here's the function that should handle the pan but who instead doesn't seem to been called at all
func handlePan() {
//your function
}
}
class MapViewController: UIViewController {
@IBOutlet weak var profileView: ExpandibleView!
//MARK: - ViewController Delegate Methods
override func viewDidLoad() {
super.viewDidLoad()
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
panGestureRecognizer.minimumNumberOfTouches = 1
panGestureRecognizer.maximumNumberOfTouches = 1
profileView.addGestureRecognizer(panGestureRecognizer)
//Here I set the View
profileView.isUserInteractionEnabled = true
profileView.initialize()
profileView.minHeight = 100
profileView.maxHeight = 190
}
@objc func handlePan(_ sender:UIPanGestureRecognizer) {
profileView.handlePan()
}
}
或者您可以在其他视图中创建一个调用委托。
祝你好运!
您遇到的问题是由于您在此处的 class 定义中定义了 panGestureRecognizer
变量:
//Here I create the reference to the recognizer
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
你可以用这种方式初始化它,但似乎 self
在创建这个变量时没有设置。所以你的操作永远不会被注册。
有几种方法可以使用您的代码解决此问题,您可以继续将其初始化为实例变量,但您需要在 initialize()
函数中设置 target/action
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)
}
}
如果您想通过在故事板中定义它并操纵它的约束来使用它 class,您可以像这样进行操作。
首先在故事板中定义您的视图并限制它的宽度和高度。对于演示,我将它的 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
}
}
当我 运行 项目时,通过约束以这种方式执行此操作给了我这个:
帧操作示例
要使用它并仅使用框架 属性 来操纵高度,视图控制器可能会像这样实现视图创建:
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)
}
仅使用帧操作我得到这个: