BulletinBoard assign gesture for ImageView - ios

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
}
}

Related

How do I add an identifier to the UIImageView?

I have an array with separate UIImages and I am displaying them using an UIImageView, how do I add an identifier to them so that I can switch to the view controller with the specific data related to that image.
Below is the code:
class Orders2ViewController: UIViewController, OrdersBaseCoordinated {
var orderList: [OrderInfo] = [OrderInfo( itemImage: UIImage(named: "printer.jpeg")!, itemSKU: 12567), OrderInfo(itemImage: UIImage(named: "ipad.jpeg")!, itemSKU: 34521), OrderInfo( itemImage: UIImage(named: "hoodie.jpeg")!, itemSKU: 93620)]
lazy var someImageView: UIImageView = {
let theImageView = UIImageView()
let tap = UITapGestureRecognizer(target: self, action: #selector(Orders2ViewController.tappedMe))
theImageView.addGestureRecognizer(tap)
theImageView.isUserInteractionEnabled = true
theImageView.image = orderList[selectedIndex].itemImage
theImageView.translatesAutoresizingMaskIntoConstraints = false
return theImageView
}()
#objc func tappedMe(sender: UITapGestureRecognizer)
{
coordinator?.passImageData(j: )
}
I want to pass an identifier in my tappedMe function to recognize which image was tapped on, I did find other answers on SO that mentioned gesture.view.tag but I don't want to create another view, rather navigate to the next controller with an identifier. Is there a way to do this?
Since UIImageView inherits from UIView, you can use it’s parameter called tag. In your example you can set theImageView.tag = orderedList[selectedIndex].itemSKU. Then each time tap was recognized, you can just use this itemSKU to do move to the next screen.
However it seems that you have only one UIImageView on the screen and you use selectedIndex to determine which image you need. So you can just do like that:
#objc func tappedMe(sender: UITapGestureRecognizer) {
coordinator?.passImageData(j: orderList[selectedIndex].itemImage)
}
I passed the itemImage just to show you how it can be done. You can use whatever you need.

Assign two different UITapGestureRecognizer for a custom control using swift

using swift, I'm trying to create a dynamic and generic control to reuse it, basically, the control should have a general behavior inside.
To be more specific, I have a UIScrollView and it's filled using UIViews, when you click over an UIView, the background should change.
That is working correctly.
But, for the implementation, my class of the generic control, accepts a Selector as parameter.
Both works separately, but together are not working.
The specific part of codes are:
Generic class
let clickAgendaEvent = UITapGestureRecognizer(target: self, action: #selector (self.agendaClicked (_:)))
cellSubView.addGestureRecognizer(clickAgendaEvent)
cell.addSubview(cellSubView)
let itemClickedEvent = UITapGestureRecognizer(target: viewController.self, action: self.agendaItemClicked! )
cell.addGestureRecognizer(itemClickedEvent)
And a ViewController with an implementation like this:
#objc func eventDailyAgenda(sender:UIView!){
print("Item clicked!")
}
As you can see, the second event, is not inside of the generic class, the second event is a separated implementation if the ViewController.
But, the generic class, would be implemented for other UIViewController.
Someone have an idea about how can handle it?
Look into UIGestureRecognizerDelegate to handle both gestures simultaneously. Check out the callback gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) . Return true to have both handled simultaneously.
The easier way to do it, is implementing UIGestureRecognizerDelegate.
But for my specific case didn't work, because, I have different classes implementing the behavior.
But, I found a way to do it.
And is implementing NSObject (if you are in a UIViewController you don't have to implement it.
For my case I have my class:
class MyClass:NSObject {
func createAll(){
let clickAgendaEvent = UITapGestureRecognizer(target: self, action: #selector (self.agendaClicked (_:)))
cellSubView.addGestureRecognizer(clickAgendaEvent)
cellSubView.tag = index
cell.addSubview(cellSubView)
}
#objc func agendaClicked(_ sender:AnyObject) {
baseView.setTransparentToSubViews()
print("Here")
let tap = sender as! UITapGestureRecognizer
tap.view?.backgroundColor = UIColor().hexStringToUIColor(hex: "#e0e0e0")
if let v = tap.view {
// use button
print("The tag is \(v.tag)")
}
if let c: NSObject.Type = NSClassFromString(viewController.className) as? NSObject.Type{
let c_tmp = c.init()
c_tmp.perform(Selector(("test")))
c.perform(Selector(("static_test")))
}
}
}
Add in your ViewController
#objc public func test(){
print("This is Test!!!")
}
#objc public class func static_test(){
print("This is Static Test")
}
And this extension:
import Foundation
import UIKit
extension UIViewController {
var className: String {
return NSStringFromClass(self.classForCoder)
}
}
Now, you can execute all the methods you want.
For this case, once the user touch an element, the next event is fired from the touch, and not is necessary to add a new delegate.
Maybe is not the better way, but is totally functional.

Swipe to show additional buttons on UICollectionView

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
}

How do I hide image on touch with an array of imageviews?

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.

tapGesture hyperLink swift

I have an image and I want it to go to my website when anyone hit the picture
I used tapGesture to convert the image to a big button , but what I don't know how to do it , is that I want the app to take the user to my website when the user hit the image
That depends a bit on where you want the link to open. The two standard approaches are to either open the URL in a UIWebView you provide inside the app, or to tell the system to open the link in the mobile Safari browser (which will send your app to the background).
To me it sounds like it this second behaviour you want. You can achieve it by telling the UIApplication to open the URL, like so:
#IBAction func linkTapped(sender:UITapGestureRecognizer) {
if let url = NSURL(string: "http://stackoverflow.com/") {
UIApplication.sharedApplication().openURL(url)
}
}
Edit:
Some more info on how to set this up in the way you described: in your viewDidLoad, set up your gesture recognizer like this:
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "linkTapped:")
self.yourImageView.addGestureRecognizer(tapGestureRecognizer)
self.yourImageView.userInteractionEnabled = true
Make sure the IBOutlet for yourImageView is connected correctly. Then simply add the code given in the original answer as a method to the same class containing your viewDidLoad method. If the gesture recognizer fires, it should now execute the code in the linkTapped: method and open the URL.
Edit 2:
And because it actually fits in ~10 lines of code, here's a minimal view controller class as an example implementation.
class ViewController: UIViewController {
#IBOutlet var myImageView: UIImageView! //Check if connected correctly!
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "linkTapped:")
myImageView.addGestureRecognizer(tapGestureRecognizer)
myImageView.userInteractionEnabled = true
}
func linkTapped(sender:UITapGestureRecognizer) {
if let url = NSURL(string: "http://stackoverflow.com/") {
UIApplication.sharedApplication().openURL(url)
}
}
}

Resources