I have an array of image views.
var imageViewArray = [UIImageView(image: UIImage())]
I use a for loop to fill this array with images from urls. I want to make it so that when I touch one of these images it becomes hidden or alpha: 0. I tried this:
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(StoryVC.imageTapped))
newImage.userInteractionEnabled = true
newImage.addGestureRecognizer(tapGestureRecognizer)
And I tried adding a tag too but I can't figure out how to get the sender. I need to be able to run the function to hide the image and know which image to hide, that is the part i'm struggling with. Thanks in advance.
You get UITapGestureRecognizer object in your selector's parameter and it has a property view that gives you the view which has been tapped.
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.imageTapped(_:)))
func imageTapped(_ sender: UITapGestureRecognizer) {
guard let tappedImage = sender.view else { return }
}
The selector should be a function within your class. Here's an example:
// Setting up the tapGestureRecognizers
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(pressed:))
newImage.userInteractionEnabled = true
newImage.addGestureRecognizer(tapGestureRecognizer)
// The function that handles the tap event
func pressed(sender: UIImageView!) {
if sender.alpha == 0{
sender.alpha = 1
}
else{
self.alpha = 0
}
}
Also make sure to double check my syntax, I don't write with Swift often, so it may have some small errors.
Related
I'm using BulletinBoard (BLTNBoard) to create dialogs in my iOS app. There's an option to embed image inside it. I would like to extend it's functionality and allow user to manipulate this image using tap gesture. But eventually when I assign a gesture to it's imageView using addGestureRecognizer nothing happens.
Here's how I initiliaze bulletin and add gesture to the image:
class ViewController: UIViewController {
lazy var bulletinManager: BLTNItemManager = {
let rootItem: BLTNPageItem = BLTNPageItem(title: "")
return BLTNItemManager(rootItem: rootItem)
}()
override func viewDidLoad() {
//etc code
let bulletinManager: BLTNItemManager = {
let item = BLTNPageItem(title: "Welcome")
item.descriptionText = "Pleas welcome to my app"
item.actionButtonTitle = "Go"
item.alternativeButtonTitle = "Try to tap here"
item.requiresCloseButton = false
item.isDismissable = false
item.actionHandler = { item in
self.bulletinManager.dismissBulletin()
}
item.alternativeHandler = { item in
//do nothing by now
}
//
item.image = UIImage(named: "welcome")
//adding gesture to its imageView
item.imageView?.isUserInteractionEnabled=true
let tap = UITapGestureRecognizer(target: self, action: Selector("tapTap:"))
item.imageView?.addGestureRecognizer(tap)
return BLTNItemManager(rootItem: item)
}()
}
#objc func tapTap(gestureRecognizer: UITapGestureRecognizer) {
print("TAPTAP!!!!!!")
}
}
and nothing happens at all (no message printed in console).
However if I assign action inside alternative button it works as expected:
item.alternativeHandler = { item in
item.imageView?.isUserInteractionEnabled=true
let tap = UITapGestureRecognizer(target: self, action: Selector("tapTap:"))
item.imageView?.addGestureRecognizer(tap)
}
I guess the only thing which can prevent me to assign the tap event to it properly is that imageView becomes available much later than the bulletin is created (for example only when it is shown on the screen).
Could you please help and correct my code. Thanks
upd.
Ok, based on Philipp's answer I have the following solution:
class myPageItem: BLTNPageItem {
override func makeContentViews(with interfaceBuilder: BLTNInterfaceBuilder) -> [UIView] {
let contentViews = super.makeContentViews(with: interfaceBuilder)
let imageView=super.imageView
imageView?.isUserInteractionEnabled=true
let tap = UITapGestureRecognizer(target: self, action: #selector(tapTap))
imageView?.addGestureRecognizer(tap)
return contentViews
}
#objc func tapTap(gestureRecognizer: UITapGestureRecognizer) {
print("TAPTAP!!!!!!")
}
}
When you're working with an open source library, it's easy to check out the source code to find the answer.
As you can see here, image setter doesn't initiate the image view.
Both makeContentViews makeArrangedSubviews (which are responsible for views initializing) doesn't have any finish notification callbacks.
Usually in such cases I had to fork the repo and add functionality by myself - then I'll make a pull request if I think this functionality may be needed by someone else.
But luckily for you the BLTNPageItem is marked open, so you can just subclass it. Override makeContentViews and add your logic there, something like this:
class YourOwnPageItem: BLTNPageItem {
override func makeContentViews(with interfaceBuilder: BLTNInterfaceBuilder) -> [UIView] {
let contentViews = super.makeContentViews(with: interfaceBuilder)
// configure the imageView here
return contentViews
}
}
I'm trying to create a feature similar to tableView swipe to show delete button, the only difference is that I show multiple buttons and have it implemented on a collectionView within a collectionViewCell. I want to be able to slide the inner collectionView to the right and have multiple options buttons snap into view on the left.
Something like this:
I understand that I'll probably need to use UIPanGestureRecognizer, the problem for me is that the collectionView to pan is nested within another collectionView, and I'm not certain as to how to use the UIGestureRecognizer correctly so that the cells slide together and the buttons snap into view.
Any suggestions are very much appreciated.
set delegate in collection view for get action
protocol ColumnBookCellDelegate: class {
func deleteBook(_ book: Book)
}
class ColumnBookCell: AZCollectionViewCell{
weak var deleteDelegate: ColumnBookCellDelegate?
var canBeRemove: Bool = false{
didSet{
if self.canBeRemove{
let swipeL = UISwipeGestureRecognizer(target: self, action: #selector(self.showDelete))
swipeL.numberOfTouchesRequired = 1
swipeL.direction = .left
self.addGestureRecognizer(swipeL)
let swipeR = UISwipeGestureRecognizer(target: self, action: #selector(self.hideDelete))
swipeR.numberOfTouchesRequired = 1
swipeR.direction = .right
self.addGestureRecognizer(swipeR)
}
}
}
// Show Delete Button
func showDelete(){
// unhidden button here
// self.button.isHidden = false
UIView.animate(withDuration: 0.2) {
self.layoutIfNeeded()
}
}
// Hide Delete Button
func hideDelete(){
// hidden button here
// self.button.isHidden = true
// self.deleteButton.aZConstraints.width?.constant = 0
UIView.animate(withDuration: 0.2) {
self.layoutIfNeeded()
}
}
// Delete Action
func deleteAction(){
self.deleteDelegate?.deleteBook(self.book)
self.hideDelete()
}
// blob blob blob
}
the UIView in question is headerView:
if isShown {
stack.alpha = 1.0
self.isStackShown = true
DispatchQueue.main.async {
self.headerView.isHidden = !isShown
self.stack.addArrangedSubview(self.headerView)
// add touch gesture recognizer to stack view header
let tapFind = UIGestureRecognizer(target: self, action: #selector(self.handleFindTap))
self.headerView.addGestureRecognizer(tapFind)
}
} else {
stack.alpha = 0.0
self.isStackShown = false
DispatchQueue.main.async {
self.headerView.isHidden = isShown
self.stack.removeArrangedSubview(self.headerView)
}
}
The tap gesture recognizer is not registering any taps
self.stack is the stack view which contains the headerView
The condition for either showing or hiding the headerView is being handled in a different method and just passes the boolean self.isStackShown to this method to show/hide accordingly.
You are using a UIGestureRecognizer. UIGestureRecognizer is a polymorphic base class and should really be subclassed. UITapGestureRecognizer is the concrete subclass for handling taps. Use it instead.
let tapFind = UITapGestureRecognizer(target: self, action: #selector(self.handleFindTap))
self.headerView.addGestureRecognizer(tapFind)
Your action is never getting called because UIGestureRecognizer has no inherent information about what kind of gesture to recognize. Only a concrete subclass of it does.
Looks like you are adding multiple gesture recognizers when changing back the alpha to 1.0 and they aren't able to recognize simultaneously. Remove all gesture recognizers when hiding and removing the headerView since you don't need one anymore and add one back when adding back the headerView and it should work. Or you can also let the gesture recognizer be when hiding the headerView since it won't work anyway and check if one exists before adding another.
if isShown {
stack.alpha = 1.0
self.isStackShown = true
DispatchQueue.main.async {
self.headerView.isHidden = !isShown
self.stack.addArrangedSubview(self.headerView)
// add touch gesture recognizer to stack view header
let tapFind = UIGestureRecognizer(target: self, action: #selector(self.handleFindTap))
self.headerView.addGestureRecognizer(tapFind)
}
} else {
stack.alpha = 0.0
self.isStackShown = false
DispatchQueue.main.async {
self.headerView.isHidden = isShown
self.headerView.gestureRecognizers?.forEach({self.headerView.removeGestureRecognizer($0)})
self.stack.removeArrangedSubview(self.headerView)
}
}
or
if isShown {
stack.alpha = 1.0
self.isStackShown = true
DispatchQueue.main.async {
self.headerView.isHidden = !isShown
self.stack.addArrangedSubview(self.headerView)
if self.headerView.gestureRecognizers?.isEmpty != false{
// add touch gesture recognizer to stack view header
let tapFind = UIGestureRecognizer(target: self, action: #selector(self.handleFindTap))
self.headerView.addGestureRecognizer(tapFind)
}
}
} else {
stack.alpha = 0.0
self.isStackShown = false
DispatchQueue.main.async {
self.headerView.isHidden = isShown
self.stack.removeArrangedSubview(self.headerView)
}
}
I'm trying to do two things in Swift:
· When the user touches the image, toggle between the filtered, and original images temporarily.
· When the user lifts their finger, toggle back.
But I don't know what functions or modules to use, any suggestions?
I have got a image View and four buttons 「New Photo」,「Filter」,「Compare」,「Share」.
Try this
override func viewDidLoad(){
super.viewDidLoad()
// add Tap gesture recognizer to ImageView
let imageView = self.your_imageView
let tapGestureRecognizer = UILongPressGestureRecognizer(target:self, action:Selector("toggleImage:"))
imageView.userInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
}
func toggleImage(sender: UILongPressGestureRecognizer){
if sender.state == .Began{
originalImage()
}else if sender.state == .Ended{
filteredImage()
}
}
It uses UILongPressGestureRecognizer()
I would recommend looking into UILongPressGestureRecognizer.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILongPressGestureRecognizer_Class/index.html#//apple_ref/occ/instp/UILongPressGestureRecognizer/minimumPressDuration
When the gesture begins, change the UIImage being displayed. You can detect when the gesture ends with UIGestureRecognizerStateEnded. I'm sure you'll figure it out!
I set the minimum press duration to 0.1 from default 0.5 to make it look like a tap button. Code changes to check if the filtered image is not nil and it is not equal to the original image. I set back and forth the image view according the state began and end
override func viewDidLoad() {
super.viewDidLoad()
// adding Tap gesture recognizer to image view
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(imageTapped(_:)))
// Enabling the user interaction for the image view
imageView.userInteractionEnabled = true
imageView.addGestureRecognizer(longPressGestureRecognizer)
// Changing the default minimum press duration from 0.5 to 0.1
longPressGestureRecognizer.minimumPressDuration = 0.1
}
// image tapped function that changes the image view when the user presses on the image view
func imageTapped(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == .Began {
imageView.image = originalImage
} else if longPressGestureRecognizer.state == .Ended {
if filteredImage != nil && filteredImage != originalImage {
imageView.image = filteredImage
}
}
}
I am trying to fire event with UITapGestureRecognizer on different uiview but it is not working.
var tap = UITapGestureRecognizer(target: self, action: Selector("tappedMe"))
AUIView.addGestureRecognizer(tap)
AUIView.tag = 1
BUIView.addGestureRecognizer(tap)
BUIView.tag = 2
func tappedMe()
{
if AUIView.tag == 1
{
println("1")
}
else if BUIView.tag == 2
{
println("2")
}
}
You cannot add the same gesture recognizer to multiple views. This answer explains why.
Either declare a new gesture recognizer, or create a copy of the existing one before adding it to the other view.
BUIView.addGestureRecognizer(tap.copy())