I have a UICollectionViewcell in my code
let cell = commentSection.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CommentCell
And in CommentCell i have got this imageview
let likeIcon: UIImageView = {
let imv = UIImageView()
imv.image = #imageLiteral(resourceName: "like")
imv.translatesAutoresizingMaskIntoConstraints = false
return imv
}()
I tried adding a tap gesture to likeIcon in CommentCell and also in cellForItemAt but none of them triggered it when clicking.How can i add gestureTapRecognizer to child element of cell?
Adding UIImageView and providing gesture recognizer will increase the complexity of your development.
If you need action then use UIButton and set target action for button in cellForRowAtIndex
You can set either background image or image to UIButton.
Better keep processed image in UIImage object and assign it to UIButton.
Look at the code:
....
let imageView = UIImageView()
imageView.isUserInteractionEnabled = true
let recognizer = UITapGestureRecognizer()
recognizer.addTarget(self, action: #selector(yourHandleMethod(tapGestureRecognizer:)))
imageView.addGestureRecognizer(recognizer)
....
func yourHandleMethod(tapGestureRecognizer: UITapGestureRecognizer) {
print("tap")
}
Call this method update() outside in cellForItem (for every cell).
...
cell.update()
...
// This method inside cell
func update() {
let recognizer = UITapGestureRecognizer()
recognizer.addTarget(self, action: #selector(yourHandleMethod(tapGestureRecognizer:)))
imageView.addGestureRecognizer(recognizer)
}
Related
My issues with new collection view list cells is that I'm not able to add action handlers to a custom accessory view.
I've been trying to do the following:
protocol TappableStar: class {
func onStarTapped(_ cell: UICollectionViewCell)
}
class TranslationListCell: UICollectionViewListCell {
let starButton: UIButton = {
let starButton = UIButton()
let starImage = UIImage(systemName: "star")!.withRenderingMode(.alwaysTemplate)
starButton.setImage(starImage, for: .normal)
starButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)
starButton.addTarget(self, action: #selector(starButtonPressed(_:)), for: .touchUpInside)
starButton.tintColor = .systemOrange
return starButton
}()
var translation: TranslationModel?
weak var link: TappableStar?
override init(frame: CGRect) {
super.init(frame: frame)
accessories = [.customView(configuration: .init(customView: starButton, placement: .trailing(displayed: .always)))]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc private func starButtonPressed(_ sender: UIButton) {
link?.onStarTapped(self)
}
override func updateConfiguration(using state: UICellConfigurationState) {
// Create new configuration object and update it base on state
var newConfiguration = TranslationContentConfiguration().updated(for: state)
// Update any configuration parameters related to data item
newConfiguration.inputText = translation?.inputText
newConfiguration.outputText = translation?.outputText
contentConfiguration = newConfiguration
}
}
I subclass UICollectionViewListCell, create a button with target-action handler and add it to accessories array. I also have my own implementation of cell configuration.
Now, I create a protocol where I delegate action handling to my view controller (I also implemented new cell registration API and set cell.link = self).
My problem here is that my accessory button doesn't call starButtonPressed although this accessory view is responsive (it changes color when highlighted).
My idea is that there might be something wrong with the way I implement my action handling with a custom accessory but there seems to be little to none information about this new api.
Moreover, when choosing between predefined accessories, some of them have actionHandler closures of type UICellAccessory.ActionHandler but I don't seem to understand how to properly implement that.
Any ideas would be much appreciated.
iOS 14, using UIActions
Since iOS 14 we can initialise UIButton and other UIControls with primary actions. It becomes similar to handlers of native accessories. With this we can use any parametrized method we want. And parametrising is important, because usually we want to do some action with specific cell. #selector's cannot be parametrised, so we can't pass any information to method about which cell is to be updated.
But this solution works only for iOS 14+.
Creating UIAction:
let favoriteAction = UIAction(image: UIImage(systemName: "star"),
handler: { [weak self] _ in
guard let self = self else { return }
self.handleFavoriteAction(for: your_Entity)
})
Creating UIButton:
let favoriteButton = UIButton(primaryAction: favoriteAction)
Creating accessory:
let favoriteAccessory = UICellAccessory.CustomViewConfiguration(
customView: favoriteButton,
placement: .leading(displayed: .whenEditing)
)
Using
cell.accessories = [.customView(configuration: favoriteAccessory)]
I solved my issue by adding tap gesture recognizer to my accessory's custom view. So it works like this:
let customAccessory = UICellAccessory.CustomViewConfiguration(
customView: starButton,
placement: .trailing(displayed: .always))
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(starButtonPressed(_:)))
customAccessory.customView.addGestureRecognizer(tapGesture)
accessories = [.customView(configuration: customAccessory)]
Haven't seen it documented anywhere so hope it helps somebody.
I followed a similar approach to yours, but instead of a UITapGestureRecognizer, I added a target to the button.
var starButton = UIButton(type: .contactAdd)
starButton.addTarget(self, action: #selector(self.starButtonTapped), for: .touchUpInside)
let customAccessory = UICellAccessory.CustomViewConfiguration(customView: starButton, placement: .trailing(displayed: .always))
cell.accessories = [.customView(configuration: customAccessory)]
I first tried the tap gesture recognizer and it didn't work for me.
I am new in swift and I want to get the value of label from tableview on button click
I am using code like this but it is getting crash
in cellforrowatindexpath
cell.btnsubmit.tag = indexPath.row
cell.btnsubmit.addTarget(self, action: #selector(buttonSelected), for: .touchUpInside)
#objc func buttonSelected(sender: UIButton){
print(sender.tag)
let cell = sender.superview?.superview as! PatientUpdateVCCell
surgery_date = cell.surgeryDateTextField.text!
discharge_date = cell.dischargeDateTextField.text!
follow_up_duration = cell.lblfolowup.text!
follow_up_date = cell.firstFollowUpTextField.text!
patient_status = cell.patientStatusTextView.text!
}
but it is getting crash. How can I achieve this
crash
Could not cast value of type 'UITableViewCellContentView' (0x11a794af0) to 'appname.PatientUpdateVCCell' (0x10ae74ae0).
According to your crash last superView is contentView then it's superView is the needed cell , so You need
let cell = sender.superview!.superview!.superview as! PatientUpdateVCCell
Target/action is pretty objective-c-ish. And view hierarchy math is pretty cumbersome.
A swiftier way is a callback closure which is called in the cell and passes the cell.
In the cell add a callback property and an IBAction. Connect the action to the button
var callback : ((UITableViewCell) -> Void)?
#IBAction func buttonSelected(_ sender: UIButton) {
callback?(self)
}
In cellForRow rather than the tag assign the closure
cell.callback = { currentCell in
self.surgery_date = currentCell.surgeryDateTextField.text!
self.discharge_date = currentCell.dischargeDateTextField.text!
self.follow_up_duration = currentCell.lblfolowup.text!
self.follow_up_date = currentCell.firstFollowUpTextField.text!
self.patient_status = currentCell.patientStatusTextView.text!
}
And delete the action method in the controller
I'm trying to add UILongPressGesture to the cell. It is working but only when I long press and move in any direction.
It should call the selector method on long press but it is calling when I long press and started to move. I'm also handling the state of the gesture but selector is not calling until I long press and start moving.
I have also tried with adding gesture to cell's content view and its UIlable element, but no luck.
let longPressGesture: UILongPressGestureRecognizer = {
let gesture = UILongPressGestureRecognizer()
gesture.addTarget(self, action: #selector(MyViewController.handleLongPressGetureForRow(_:)))
gesture.delaysTouchesBegan = false
gesture.cancelsTouchesInView = false
gesture.numberOfTouchesRequired = 1
gesture.minimumPressDuration = 0.2
return gesture
}()
cell.addGestureRecognizer(longPressGesture)
cell.tag = indexPath.row
Cells where adding gesture
Please help me. Thanks in advance.
Instead of handleLongPressGetureForRow(_:) change to self.handleLongPressGetureForRow(v:) with #objc before func
let longPressGesture: UILongPressGestureRecognizer = {
let gesture = UILongPressGestureRecognizer()
gesture.addTarget(self, action: #selector(self.handleLongPressGetureForRow(v:)))
gesture.delaysTouchesBegan = false
gesture.cancelsTouchesInView = false
gesture.numberOfTouchesRequired = 1
gesture.minimumPressDuration = 0.2
return gesture
}()
cell.addGestureRecognizer(longPressGesture)
cell.tag = indexPath.row
return cell
}
#objc func handleLongPressGetureForRow(v: UILongPressGestureRecognizer )
{
print("saghsaghghsgfsgsaghghsaghsaghghsaghashgsasa")
}
I have changed table view cell selection background color as below.
var cell = tableView.cellForRowAtIndexPath(indexPath)
let selectionColor = UIView() as UIView
selectionColor.layer.borderWidth = 1
selectionColor.layer.borderColor = utility.uicolorFromHex(0xEBEBEB).CGColor
selectionColor.backgroundColor = utility.uicolorFromHex(0xEBEBEB)
cell!.selectedBackgroundView = selectionColor
it change the background color but when i long press cell then background color remain same as default (dark grey). i want to change press and long press cell selection background color. how to do that ?
You have to disable the selection style (because selection style contains default gray color)
cell.selectionStyle = .None
After that add long press gesture and on the action of it. do desired coding.
let longpress = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")
tableView.addGestureRecognizer(longpress)
Now, add the longPressGestureRecognized function with the follow code:
Copy
func longPressGestureRecognized(gestureRecognizer: UIGestureRecognizer) {
}
Inside the longPressGestureRecognized() function, start by getting the location of the gesture in the table view and the corresponding tableViewCell.
Add the following code inside the longPressGestureRecognized() function:
Copy
let longPress = gestureRecognizer as UILongPressGestureRecognizer
let state = longPress.state
var locationInView = longPress.locationInView(tableView)
var indexPath = tableView.indexPathForRowAtPoint(locationInView)
Hope it helps.
Good morning everyone,
I am a newbie Swift developer and I am facing the following problem implementing an exercise I am dealing with.
I have a collection view with collection cells displaying images I have imported in XCODE; when I tap with the finger on the screen I would like to replace the image currently being display with another one that i have also imported, and animate this replacement.
I am implementing the UITapLongPressureRecognizer method but i am getting confused on which state to implement for the recognizer, just to replace the first image view with the one I want to be shown when I tap the screen to scroll up-down.
As you can see from the code below the two recognizer I think should be more appropriate to be implemented are the "Begin" and "Ended".
My problem is that when the state .Begin starts I don't know how to animate the replacement of one image view with another and so when the state is .Ended I don't know how to replace the second image with the first one and animate the replacement (I want it to be like for example a Modal segue with "Cross Dissolve" transition).
Thank you in advance for your kindness and patience.
class MainViewController: UICollectionViewController {
var fashionArray = [Fashion]()
private var selectedIndexPath: NSIndexPath?
override func viewDidLoad() {
super.viewDidLoad()
selectedIndexPath = NSIndexPath()
//Register the cell
let collectionViewCellNIB = UINib(nibName: "CollectionViewCell", bundle: nil)
self.collectionView!.registerNib(collectionViewCellNIB, forCellWithReuseIdentifier: reuseIdentifier)
//Configure the size of the image according to the device size
let layout = collectionViewLayout as! UICollectionViewFlowLayout
let bounds = UIScreen.mainScreen().bounds
let width = bounds.size.width
let height = bounds.size.height
layout.itemSize = CGSize(width: width, height: height)
let longPressRecogn = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
collectionView!.addGestureRecognizer(longPressRecogn)
}
func handleLongPress(recognizer: UILongPressGestureRecognizer){
var cell: CollectionViewCell!
let location = recognizer.locationInView(collectionView)
let indexPath = collectionView!.indexPathForItemAtPoint(location)
if let indexPath = indexPath {
cell = collectionView!.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
}
switch recognizer.state {
case .Began:
cell.screenTapped = false
case .Ended:
cell.screenTapped = false
default:
println("")
}
}
First of all, I suggest you to use UITapGestureRecognizer instead of long press. Because, as far as I understand, you only tap once instead of pressing for a time.
let tapRecognizer = UITapGestureRecognizer(target: self, action:Selector("tapped:"))
collectionView.addGestureRecognizer(tapRecognizer)
And when the user tapped, you can use UIView animations to change the image. You can check the Example II from the following link to get insight about animations.
http://www.appcoda.com/view-animation-in-swift/