touchUpInside event not triggered - ios

I'm new to IOS programming , but strangely same code works in a different class so I don't have any idea why isn't it working
It's in Swift 3
class BottomMenu : NSObject{
//Container view
var bottomView: UIView!
//Button
var buttonContents : UIButton!
init(bottomView : UIView) {
super.init()
self.bottomView = bottomView
buttonContents = UIButton(frame: getFrame(index: 0))
buttonContents.backgroundColor = UIColor.blue //To see where to click on the screen
bottomView.addSubview(buttonContents)
buttonContents.addTarget(self, action: #selector(onClick), for: .touchUpInside)
}
func getFrame(index : CGFloat!) -> CGRect{
let screenW = UIScreen.main.bounds.width
return CGRect(x: (screenW/3) * index,
y: 0,
width: screenW/3,
height: self.bottomView.frame.size.height)
}
func onClick(sender: UIButton!){
NSLog("click")
}
}
here's the implementation of this class :
let bottomMenu = BottomMenu(bottomView: bottomNavBarContainer)
So, the "click" log never shows

Your code works fine in Playground. The error must be in the usage of the class. Parent view has userInteraction disabled or such.
import UIKit
import Foundation
import PlaygroundSupport
class BottomMenu : NSObject{
//Container view
var bottomView: UIView!
//Button
var buttonContents : UIButton!
init(bottomView : UIView) {
super.init()
self.bottomView = bottomView
buttonContents = UIButton(frame: getFrame(index: 0))
buttonContents.backgroundColor = UIColor.blue //To see where to click on the screen
bottomView.addSubview(buttonContents)
buttonContents.addTarget(self, action: #selector(onClick), for: .touchUpInside)
}
func getFrame(index : CGFloat!) -> CGRect{
let screenW = UIScreen.main.bounds.width
return CGRect(x: (screenW/3) * index,
y: 0,
width: screenW/3,
height: self.bottomView.frame.size.height)
}
func onClick(sender: UIButton!){
NSLog("click")
}
}
var container = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
container.addSubview(view)
let buttonContents = BottomMenu(bottomView: view)
PlaygroundPage.current.liveView = container

NSObject is not a UIResponder, so it cannot process UIEvent. A solution could be to make the class descend from UIView instead of NSObject or exposing the button to add the target inside of a ViewController.

The selector #selector(onClick) indicates a function with no parameters. Your onClick function has a single parameter, so the selector should be #selector(onClick(sender:)). At least I think that's the selector format in Swift 3. I'm Still getting used to Swift selector syntax.

For Swift 3 adaptation, there are two main changes when adding a target.
Change your selector to
buttonContents.addTarget(self, action: #selector(BottomMenu.onClick(_:)), for: .touchUpInside)
Add underscore to the method
func onClick(_ sender: UIButton!){
Just to clarify:
class BottomMenu : NSObject{
//Container view
var bottomView: UIView!
//Button
var buttonContents : UIButton!
init(bottomView : UIView) {
super.init()
self.bottomView = bottomView
buttonContents = UIButton(frame: getFrame(index: 0))
buttonContents.backgroundColor = UIColor.blue //To see where to click on the screen
bottomView.addSubview(buttonContents)
buttonContents.addTarget(self, action: #selector(self.onClick(_:)), for: .touchUpInside)
}
func getFrame(index : CGFloat!) -> CGRect{
let screenW = UIScreen.main.bounds.width
return CGRect(x: (screenW/3) * index,
y: 0,
width: screenW/3,
height: self.bottomView.frame.size.height)
}
func onClick(_ sender: UIButton!){
NSLog("click")
}
}

Related

Swift add Custom View to screen with UIApplication.shared.keyWindow?.addSubview

hope this is an easy one...
I am in a empty new project.
I have added a custom view called MyCustomView:
import UIKit
public class MyCustomView: UIView{
private var littleView: UIView!
open class func show() -> UIView{
let bigView = MyCustomView()
bigView.configureView()
UIApplication.shared.keyWindow?.addSubview(bigView)
return bigView
}
private func configureView(){
let screenSize = UIScreen.main.bounds.size
self.frame = CGRect(x: 0,
y: 0,
width: screenSize.width,
height: screenSize.height)
littleView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
littleView.backgroundColor = .black
addSubview(littleView)
}
}
In the ViewController doing this:
override func viewDidLoad() {
let test = MyFirstView.show()
}
I hoped this will present the view, but I still have to use self.view.addSubview(test) to see it....
I thought with UIApplication.shared.keyWindow?.addSubview(bigView) and adding a subView to it, it should present the View.
What am I missing?
Add the subview in viewDidAppear
override func viewDidAppear() {
let test = MyFirstView.show()
}

Resize UISwitch in Swift 4

I would like to change the default size of the UISwitch in Swift 4.
I have looked at various options but they all relate to v3 and do not work.
Please can someone suggest an example that does so programmatically in Swift 4?
Thank you,
Edit:
I have tried the following examples:
switchTest.transform = CGAffineTransformMakeScale(0.75, 0.75)
switchTest.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
UISwitch *switchTest = [UISwitch new];
switchTest.transform = CGAffineTransformMakeScale(0.75, 0.75);
The error message that I received is always the same and says this:
Expected declaration
Swift 4 Code
Method 1
Drag UISwitch Storyboard. Make an outlet of your UISwitch and replace ViewDidLoad method by this code.
#IBOutlet weak var switchDemo: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
switchDemo.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
}
Method 2
Make UISwitch through programmatically.
class ViewController: UIViewController {
let switchSwift4 = UISwitch(frame:CGRect(x: 150, y: 300, width: 0, height: 0))
override func viewDidLoad() {
super.viewDidLoad()
self.switchSwift4.isOn = true
switchSwift4.setOn(true, animated: false)
switchSwift4.addTarget(self, action: #selector(switchValueDidChange(_:)), for: .valueChanged)
switchSwift4.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
self.view!.addSubview(switchSwift4)
}
#objc func switchValueDidChange(_ sender: UISwitch) {
if switchSwift4.isOn == true {
print("On")
}
else {
print("Off")
}
}
}

Firebase Data Returning Nil

I am trying to create programmatic Radio Buttons based on dynamic Firebase data. The number of Radio Buttonsis dependent on an integer value stored in Firebase, named numberOfChildren.
The value I am receiving from Firebase is coming back nil and I cannot figure out why. Any help on how to resolve this issue so that I can return an integer value would be appreciated:
import UIKit
import FirebaseDatabase
import DLRadioButton
class PollController: UIViewController {
#IBOutlet weak var passLabel: UILabel!
#IBOutlet weak var pollImage: UIImageView!
var ref: FIRDatabaseReference!
var pollRef: FIRDatabaseReference!
var pass = ""
var passedImageURL = ""
var posX = 0;
var posY = 0;
var numberOfChildren: Int!
let label2 = UILabel(frame: CGRect(x: 90, y: 160, width: 200, height: 70))
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
pollRef = ref.child("Polls").child(pass)
passLabel.text = pass
pollImage.sd_setImage(with: URL(string: passedImageURL), placeholderImage: UIImage(named: "test"))
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
print(self.numberOfChildren)
})
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let firstRadioButton = self.createRadioButton(frame: CGRect(x: CGFloat(x)*32, y: self.view.center.y, width: 40.0, height: 20.0), title: String(x), color: UIColor.green)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.otherButtons = buttons
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> DLRadioButton {
let radioButton = DLRadioButton(frame: frame);
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: UIControlState.normal);
radioButton.setTitleColor(color, for: UIControlState.normal);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
radioButton.addTarget(self, action: #selector(self.logSelectedButton(_:)), for: UIControlEvents.touchUpInside);
return radioButton;
}
#objc private func logSelectedButton(_ sender: DLRadioButton){
print("Selected Button Tag = \(sender.tag) and Title \(sender.titleLabel?.text)")
}
}
The problem is in the way you nest the code. Firebase loads the data asynchronously, that's why you pass in a callback block: so that it can call your code block once the data has loaded. By the time you look over self.numChildren that data hasn't loaded yet.
The solution is to move the code that requires numChildren into the callback block.
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let firstRadioButton = self.createRadioButton(frame: CGRect(x: CGFloat(x)*32, y: self.view.center.y, width: 40.0, height: 20.0), title: String(x), color: UIColor.green)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.otherButtons = buttons
})
This way the loop is only invoked once numChildren has been initialized from the database.

IOS, Swift: UIScrollView zoom

I am a beginner. I am unable to solve the following problem:
I would like to place a lot of buttons in a page. These buttons must appear in small size, but must have a possibility to zoom in for clicking on these items. I tried the following without success:
class myViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let myArray =
[["O","1","2","3","4","5","6","7","8","9","10","11","12"],
["1","2","3","4","5","6","7","8","9","10","11","12","13"],
["1","2","3","4","5","6","7","8","9","10","11","12","13"],
["1","2","3","4","5","6","7","8","9","10","11","12","13"]]
var buttonY: CGFloat = 50
for index in 0...myArray.count-1 {
buttonY = buttonY + 45
var buttonX: CGFloat = 10
for (index2, myArraytxt) in myArray[index].enumerate() {
let myButton = UIButton(frame: CGRect(x: buttonX, y: buttonY, width: 30, height: 30))
buttonX = buttonX + 40
myButton.backgroundColor = UIColor.greenColor()
myButton.setTitle(myArraytxt, forState: UIControlState.Normal)
myButton.addTarget(self, action: "pressed:", forControlEvents: UIControlEvents.TouchUpInside)
}
self.scrollView.addSubview(myButton)
}
self.scrollView.minimumZoomScale = 0.4
self.scrollView.maximumZoomScale = 3.0
self.scrollView.zoomScale = 0.4
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.view
}
}
Any help or idea is appreciated!
Regards: Zoltan

IOS8 and Swift multiple views with gestures dont work

I'm trying to build a user interface based on generic classes which are based on the same extension of the UIViewController class. This example puts squares on the screen and the tap event would be dealt with in the parent class, but it doesnt work. What am I doing wrong?
Main ViewController.swift:
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//FIRST SQUARE
let widget1 = TestWidget()
widget1.viewX = 10
widget1.viewY = 10
self.view.addSubview(widget1.view)
self.addChildViewController(widget1)
widget1.didMoveToParentViewController(self)
//SECOND SQUARE
let widget2 = TestWidget()
widget2.viewX = 100
widget2.viewY = 100
self.view.addSubview(widget2.view)
self.addChildViewController(widget2)
widget2.didMoveToParentViewController(self)
}
}
Here is the TestWidget class:
class TestWidget : UIViewController {
var viewX : CGFloat!
var viewY : CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
let square = UIView()
square.frame = CGRect(x : viewX, y : viewY, width: 50, height: 50)
square.backgroundColor = UIColor.orangeColor()
self.view.addSubview(square)
//GESTURE PART
var tapForSquare = UITapGestureRecognizer()
tapForSquare.addTarget(self, action : "onTap")
square.addGestureRecognizer(tapForSquare)
square.userInteractionEnabled = true
square.multipleTouchEnabled = true
}
func onTap() {
println("square tapped")
}
}
I have both squares on the screen but the tap action only works on the second one. Is there any problem with this?
onTap() takes an argument. It should be:
onTap(gestureRecognizer: UITapGestureRecognizer)
and add a colon after "onTop" in this line:
tapForSquare.addTarget(self, action : "onTap")
Thanks everyone, it seems interestingly this works only if you set the parent views frame as well.
So something like:
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = CGRect(x : viewX, y : viewY, width: 50, height: 50)
let square = UIView()
square.frame = CGRect(x : 0, y : 0, width: 50, height: 50)
square.backgroundColor = UIColor.orangeColor()
self.view.addSubview(square)
...
}

Resources