Programmatically addTarget action to UIButton - uibutton

I tested a ton of samples but none of them works for me. Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 200, height: 50))
button.backgroundColor = .green
button.setTitle("Test Button", for: .normal)
button.titleLabel?.sizeToFit()
button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), for: .touchUpInside)
self.view.addSubview(button)
}
func buttonTapped(_ sender: UIButton) {
print("Button tapped.")
}
What am I missing?

Well, following this answer the issue is with .touchUpInside. In tvOS it should be .primaryActionTriggered.
button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), for: .primaryActionTriggered)

Related

problem with images loading on top of already set images swift 4

I'm having an issue in my cellForItemAtIndexPath where I am setting an image to my cell's UIButton but every time I scroll the collectionView's cells, it's placing the image on top of the already set image again and again. I can tell because the shadow of the image is getting thicker and thicker. I'm pulling the images from an array that I created of image literals in that swift file and the correct images are loading so there's no problem there. I'm sure this is a simple fix for most but I can't seem to find an answer anywhere.
Image of my cellForItemAtIndexPath function
My app running before I scroll
App after scrolling a bit
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! HomeViewCell
collectionView.bounces = false
let imageNumber = indexPath.item
let collectionImage: UIButton = {
let image = UIButton()
image.setImage(collectionImageArray[imageNumber].withRenderingMode(.alwaysOriginal), for: .normal)
image.contentMode = .scaleAspectFit
image.addTarget(self, action: #selector(handleCollectionTap), for: .touchUpInside)
return image
}()
collectionImage.imageView?.image = collectionImageArray[imageNumber]
cell.addSubview(collectionImage)
collectionImage.anchor(top: nil, left: nil, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
collectionImage.centerXAnchor.constraint(equalTo: cell.centerXAnchor).isActive = true
collectionImage.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
print(imageNumber)
return cell
}
If anyone else comes across this issue (or maybe I'm the only dumb one), the problem was that I should have created my UIButton, added the subview, and constrained it inside of the cell class and from the cellForItem AtindexPath method set the image and target handler like this.
class HomeViewCell: UICollectionViewCell {
let collectionImage: UIButton = {
let image = UIButton(type: .custom)
image.contentMode = .scaleAspectFit
return image
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(collectionImage)
collectionImage.anchor(top: nil, left: nil, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
collectionImage.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
collectionImage.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! HomeViewCell
collectionView.bounces = false
let imageNumber = indexPath.item
let image = collectionImageArray[imageNumber].withRenderingMode(.alwaysOriginal)
cell.collectionImage.setImage(image, for: .normal)
cell.collectionImage.addTarget(self, action: #selector(handleCollectionTap), for: .touchUpInside)
print(imageNumber)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
#objc func handleCollectionTap() {
let layout = UICollectionViewFlowLayout()
let cardViewer = CardViewerController(collectionViewLayout: layout)
present(cardViewer, animated: true, completion: nil)
}
Everything is running smoothly now! :)

Swift 3 Button in UICollectionViewCell not respond to touch

I have an UICollectionViewCell and two buttons inside that, but the buttons not respond to touch, i create button programmatically and add that to cell by addSubView it works, but when i added by holder.addSubView not working!
UserInteractionEnabeld of holder is true!
help please
class FavoriteProductCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var holder: UIView!
override func awakeFromNib() {
super.awakeFromNib()
let btnFindBestPrice = UIButton(frame: CGRect(x: 0, y: 0, width: 151, height: 20))
btnFindBestPrice.setTitle("Find best price", for: .normal)
btnFindBestPrice.backgroundColor = UIColor.ButtonBackGreen
btnFindBestPrice.isUserInteractionEnabled = true
btnFindBestPrice.addTarget(self, action: #selector(findBestPrice), for: .touchUpInside)
// AddTarget not working
holder.addSubview(btnFindBestPrice)
// AddTarget works fine
addSubview(btnFindBestPrice)
}
}
I dont know why!? But i create another cell with same config that worked fine!!!!
In this case, it's better if you add self at the beginning. Like this:
self.holder.addSubview(btnFindBestPrice)

Swift 2.3 Button to open URL failing with error unrecognised selector

I have created a button to open url links and am failing with an unrecognised selector error. I would normally set the add target to be self just through how i have read online, but for this particular instance i get the error:
cannot convert value of type NSOBJECT ->() -> infoViewcontroller.infoview to expected argument type AnyObject.
So to get around this and what Xcode recommended was to set the target as NSOBJECT.self. However this no longer got an error but crashes upon the click of the button and returns the reason of: [NSObject displayWebLink]: unrecognized selector sent to class 0x106011e58. So i'm just wondering what the correct way of doing this would be and why? Below is my code.
class ActivityInfoView: UICollectionViewCell {
var activity: ActivitysEvents? {
didSet {
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var textView: UITextView = {
let tv = UITextView()
tv.userInteractionEnabled = false
return tv
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.lightGrayColor()
return view
}()
let urlLinkButton: UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.redColor()
button.titleLabel?.font = UIFont.systemFontOfSize(14)
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
// button.addTarget(self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
button.addTarget(NSObject.self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
return button
}()
func displayWebLink() {
print("abcdefghijklmnop")
if let urlLink = activity?.url {
// UIApplication.sharedApplication().openURL(NSURL(string: urlLink)!)
UIApplication.sharedApplication().openURL(NSURL(string: urlLink)!, options: [:], completionHandler: nil)
print("dhudududuhdu")
}
}
`
That's not a very helpful error message. The compiler is trying to verify that the correct object defines a method with the name displayWebLink and it seems to be using the closure type as the context where it's searching.
Try telling it where to find the method:
button.addTarget(self, action: #selector(ActivityInfoView.displayWebLink), forControlEvents: .TouchUpInside)
I fixed this issue by changing the button from 'let' to 'lazy var' as below:
lazy var urlLinkButton: UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.redColor()
button.titleLabel?.font = UIFont.systemFontOfSize(14)
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
button.addTarget(self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
//button.addTarget(self(), action: #selector(ActivityInfoView.displayWebLink), forControlEvents: .TouchUpInside)
return button
}()

ios 10 Snapshotting a view that has not been rendered results in an empty snapshot

this question ask again but i dont find for ios 10
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)
{
self.imagePicker.delegate = self
self.imagePicker.sourceType = UIImagePickerControllerSourceType.camera;
self.imagePicker.allowsEditing = false
self.imagePicker.cameraCaptureMode = .photo
//self.imagePicker.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(self.imagePicker, animated: true, completion: nil)
self.imagePicked.isUserInteractionEnabled = true
}
else
{
print("No Camera")
}
Snapshotting a view that has not been rendered results in an empty
snapshot.Ensure your view has been rendered at least once before
snapshotting or snapshot after screen updates.
when i rotate the camera and take a shot than this error occurs.
Self Solution Working for me like charm :-) hope its helpful for all
DispatchQueue.global(qos: .userInitiated).async
{
self.present(self.imagePicker, animated: true, completion: nil)
}
I got the error
This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes...
Using DispatchQueue.main.async instead works for me.
This behavior is not limited to UIImagePickerController. Below is an example of a UIViewController which presents another UIViewController modally. In the second UIViewController, Safari is launched to present a URL, thus triggering the same error message, "Cannot snapshot view (>) with afterScreenUpdates:NO, because the view is not in a window. Use afterScreenUpdates:YES."
I haven't yet found any way of suppressing the message, but in my app it does no harm. I think what's going on here is that some Apple code is taking a snapshot of the app's view hierarchy, but the keyboard (which is owned by a separate UIWIndow) has not been rendered before the snapshot is taken.
/* Generates the error message:
Cannot snapshot view (<UIKeyboardImpl: 0x7f82ded12ea0; frame = (0 0; 414 271); layer = <CALayer: 0x610000035e20>>) with afterScreenUpdates:NO, because the view is not in a window. Use afterScreenUpdates:YES.
... after the "Now Tap Me, For Glory!" label is clicked
*/
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let input = UITextField()
input.placeholder = "Tap here first -- to bring up keyboard"
input.frame = CGRect(x: 10, y: 50, width: 300, height: 20)
view.addSubview(input)
let button = UIButton()
button.setTitleColor(UIColor.blue, for: .normal)
button.setTitle("Then tap here", for: .normal)
button.addTarget(self,
action: #selector(buttonPushed),
for: .touchUpInside)
button.frame = CGRect(x: 10, y: 80, width: 200, height: 20)
view.addSubview(button)
}
func buttonPushed() {
let modalVC = ModalViewController()
present(modalVC, animated: true, completion: nil)
}
}
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
let label = UILabel()
label.text = "Now Tap Me, For Glory!"
label.frame = CGRect(x: 10, y: 50, width: 300, height: 20)
view.addSubview(label)
label.isUserInteractionEnabled = true
label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(labelTapped)))
}
func labelTapped() {
UIApplication.shared.open(URL(string: "http://planetbeagle.com")!, options: [:], completionHandler: { _ in
self.dismiss(animated: true, completion: nil) })
}
}

Swift 3 - custom segue crashed with UIStoryboardSegueTemplate.m:85

According to this link, I am trying to make my own custom segue.
In the initial view controller (titled: First), pressing 2 (UIButton) to segue to Second.
But the app always crashes at performSegue(withIdentifier: "customSegue", sender: self) with error: *** Assertion failure in -[UIStoryboardSegueTemplate segueWithDestinationViewController:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3599.6/UIStoryboardSegueTemplate.m:85
Here is the main storyboard:
Crash:
CustomSegue
import UIKit
class CustomSegue: UIStoryboardSegue {
override func perform() {
let sourceView = source.view!
let destView = destination.view!
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
destView.frame = CGRect(x: 0, y: screenHeight, width: screenWidth, height: screenHeight)
let window = UIApplication.shared.keyWindow
window?.insertSubview(destView, aboveSubview: sourceView)
UIView.animate(withDuration: 0.4, animations: {
sourceView.frame = sourceView.frame.offsetBy(dx: 0.0, dy: -screenHeight)
destView.frame = destView.frame.offsetBy(dx: 0.0, dy: -screenHeight)
}) { [weak self] (finished) in
guard let strongSelf = self else { return }
strongSelf.source.present(strongSelf.destination, animated: false, completion: nil)
}
}
}
Second is just an empty View Controller:
import UIKit
class Second: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
I compare the setup in my project with the downloaded sample but cannot find the difference.
How should I fix this crash?
For those who are interested.
It took me nearly 2 days to find this: to overcome this crash, I have to specify "Module" in Storyboard - click on Segue - Attribute inspector.