Currently, I have a collection view with a UILongPressGestureRecognizer on the cell in cellForItemAt:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressOnCell))
cell.addGestureRecognizer(longPress)
When the user holds down on a cell, it triggers a function to show a menu called cellDeleteAppear(). However, after the menu is on the screen, the user can then hold down on another cell which will cause the menu to pop up again.
#objc func handleLongPressOnCell(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
cellDeleteAppear()
let gestureLocation = sender.location(in: self.trayCollectionView)
if let indexPath = self.trayCollectionView.indexPathForItem(at: gestureLocation) {
indexPathForDeletion = indexPath
trayCollectionView.allowsSelection = false
} else {
print("long press error at index path")
}
}
}
My goal is: while the menu is active, the user should not be able to hold down on another cell to trigger the menu to pop up. Any help is appreciated!
Then do
var menuShown = false
#objc func handleLongPressOnCell(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
guard !menuShown else { return }
menuShown = true
And when you hide it do
menuShown = false
Related
I have many textfields to enter values for calculation.
For each textfield I also added a LongPressGestureRecognizer so that I can update my calculations with interim results that I store in the placeholders.
#IBAction func lTap1(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began && lTap1.placeholder!.isNumeric
{
lTap1.text = lTap1.placeholder
Calculation()
}
}
Is there a more convenient way with less code to add the long tap function to each text field instead of repeating the #IBAction function for lTap2, lTap3, etc.?
First assign tag to all Textfields
then declare the array of TextFields there are two ways to declare
#IBOutlet var textFields: [UITextField]!
and
let textFields = [lTap1, lTap2, lTap3,...]
then
#objc func textFeildLongPressed(_ sender: UILongPressGestureRecognizer) {
guard let tag = sender.view?.tag else { return }
guard let textField = textFields[tag] else {
return
}
if sender.state == .began && textField.placeholder!.isNumeric {
textField.text = textField.placeholder
Calculation()
}
}
Now assign gesture to all textFields in viewDidLoad function
textFields.forEach {
let tap = UILongPressGestureRecognizer(target: self, action: #selector(textFeildLongPressed(_:)))
tap.view?.tag = $0.tag
$0.isUserInteractionEnabled = true
$0.addGestureRecognizer(tap)
}
Thanks.
Hello i am adding UILongPressGesture in my tableview and i have added successfully but issue is that how to show that cell is selected i mean i want change color of selected cell and when i again do longpress on selected cell than i want to delselect cell
i have try to add long press in my tableview with code and assign delegates on LongPress here is my code
#objc func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizer.State.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tblList)
if let indexPath = tblList.indexPathForRow(at: touchPoint) {
}
}
}
And in viewDidload() i am writing this code
let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(SMSChatViewController.longPress(_:)))
longPressGesture.minimumPressDuration = 1.0 // 1 second press
longPressGesture.delegate = self
self.tblList.addGestureRecognizer(longPressGesture)
so from this code i am able to select cell but how to show user that the cell is selected i don't know how to do this
so i just want like that when user is do longpress than cell color change and set as selected and then again do longpress than deselect cell with its original color
What about you change just the backgroundColor of the cell, when the longPressGesture is recognized? Something like this:
#objc func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizer.State.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tblList)
if let indexPath = tblList.indexPathForRow(at: touchPoint) {
let cell = tblList.cellForRow(at: indexPath)
if (cell.isSelected) {
cell.backgroundColor = UIColor.clear // or whatever color you need as default
cell.setSelected(false, animated: true)
} else {
cell.backgroundColor = UIColor.orange
cell.setSelected(true, animated: true)
}
}
}
}
If you need clarification or i missunderstood a thing let me know and i will edit my answer.
I'm building a table view and I cannot seem to get both regular taps and long presses to work.
I have placed this code in my viewDidLoad:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
myTableView.addGestureRecognizer(longPress)
and this code is my gesture recognizer:
#objc func handleLongPress(sender: UILongPressGestureRecognizer){
if UILongPressGestureRecognizer.state == UIGestureRecognizer.State.began {
let touchPoint = UILongPressGestureRecognizer.location(in: self.myTableView)
if let indexPath = self.myTableView.indexPathForRowAtPoint(touchPoint) {
print(indexPath.row)
}
}
}
I have found this code here on Stack Overflow, but I do not think it is up to date for Swift 4 because I can not even run it without the build failing.
UILongPressGestureRecognizer.state should be sender.state and UILongPressGesutreRecognizer.location should be sender.location. Also, the signature for indexPathForRowAtPoint() has been updated to indexPathForRow(at:).
Corrrected code:
#objc func handleLongPress(sender: UILongPressGestureRecognizer) {
if sender.state == .began {
let touchPoint = sender.location(in: self.myTableView)
if let indexPath = self.myTableView.indexPathForRow(at:touchPoint) {
print(indexPath.row)
}
}
}
UILongPressGestureRecognizer is a class name, you need to be calling the class instance.
I have a UIView that I added a UILongPressGestureRecognizer to so that I can handle clicks and have that UIView work like a button.
let longPressGtr = UILongPressGestureRecognizer(target: self, action:#selector(longPressSelector))
longPressGtr.minimumPressDuration = 0.1
myView.isUserInteractionEnabled = true
myView.addGestureRecognizer(longPressGtr)
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
myView.backgroundColor = UIColor.gray
} else if gestureRecognizer.state == .ended {
myView.backgroundColor = UIColor.blue // my button is blue
doSomething()
}
}
func doSomething() {
print("view was pressed")
}
This works, but the one thing that doesn't is when I press and hold on my UIView but drag my finger off the view, the "button" doesn't unselect. It still fires doSomething(). A regular UIButton will deselect the button and not fire it's onClick if you are holding down on it an drag your finger off the view.
How can I implement this functionality into my UIView?
Or is there a better way to make a UIView act like a button?
You need to check whether the gesture is inside the view.
#objc func longPresserDidFire(_ presser: UILongPressGestureRecognizer) {
let gestureIsInside = myView.point(inside: presser.location(in: myView), with: nil)
switch presser.state {
case .began, .changed:
if gestureIsInside {
myView.backgroundColor = .blue
} else {
myView.backgroundColor = .gray
}
case .cancelled:
myView.backgroundColor = .gray
case .ended:
myView.backgroundColor = .gray
if gestureIsInside {
doSomething()
}
default: break
}
}
You are not adding condition of gestureRecognizer state changed that's why it is accepting the end state.
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
} else if gestureRecognizer.state == .changed {
}else if gestureRecognizer.state == .ended {
}
}
Add one more condition and check if it works.
When you drag your finger outside of the view, gestureRecognizer is probably translated to failed or cancelled state, so you need to add handling of this cases gestureRecognizer.state == .failed and gestureRecognizer.state == .cancelled.
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
}
Place UILongPressGestureRecognizer instead of UITapGestureRecognizer and check it
say, I have a button lying under UITableView, how can I click the button through the UITableViewCell but do not trigger the cell click event:
The reason I put the button behind the tableview is that I want to see and click the button under the cell whose color set to be clear, and when I scroll the table, the button can be covered by cell which is not with clear color
I created a sample project and got it working:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let tap = UITapGestureRecognizer(target: self, action: #selector(TableViewVC.handleTap))
tap.numberOfTapsRequired = 1
self.view.addGestureRecognizer(tap)
}
func handleTap(touch: UITapGestureRecognizer) {
let touchPoint = touch.locationInView(self.view)
let isPointInFrame = CGRectContainsPoint(button.frame, touchPoint)
print(isPointInFrame)
if isPointInFrame == true {
print("button pressed")
}
}
To check of button is really being pressed we need to use long tap gesture:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let tap = UILongPressGestureRecognizer(target: self, action: #selector(TableViewVC.handleTap))
tap.minimumPressDuration = 0.01
self.view.addGestureRecognizer(tap)
}
func handleTap(touch: UILongPressGestureRecognizer) {
let touchPoint = touch.locationInView(self.view)
print(" pressed")
if touch.state == .Began {
let isPointInFrame = CGRectContainsPoint(button.frame, touchPoint)
print(isPointInFrame)
if isPointInFrame == true {
print("button pressed")
button.backgroundColor = UIColor.lightGrayColor()
}
}else if touch.state == .Ended {
button.backgroundColor = UIColor.whiteColor()
}
}
Get the touch point on the main view. Then use following method to check the touch point lies inside the button frame or not.
bool CGRectContainsPoint(CGRect rect, CGPoint point)
You can write your custom view to touch button or special view behind the topview
class MyView: UIView {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
for subview in self.subviews {
if subview is UIButton {
let subviewPoint = self.convertPoint(point, toView: subview)
if subview.hitTest(subviewPoint, withEvent: event) != nil { // if touch inside button view, return button to handle event
return subview
}
}
}
// if not inside button return nomal action
return super.hitTest(point, withEvent: event)
}
}
Then set your controller view to custom MyView class