I need to pass two parameters. How can i pass by addTarget action. If it possible what changes i need to perform?
This is my current code.
button.tag = numbers[index];
button.addTarget(self, action: #selector(ViewController.buttonClicked(_:)), forControlEvents:UIControlEvents.TouchUpInside)
func buttonClicked(sender: UIButton){
print(sender.tag)
}
If you want more then one perimeter pass then you can use a objc_setAssociatedObject.
Any thing will be pass like Dictionary,Array,String,Int.
import ObjectiveC
extension UIButton {
private struct AssociatedKeys {
static var WithValue = "KeyValue"
}
#IBInspectable var withValue: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.WithValue) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.WithValue,
newValue as NSString?,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN
)
}
}
}
}
You need to use above extension:-
import ObjectiveC
button.tag = numbers[index];
button.addTarget(self, action: #selector(ViewController.buttonClicked(_:)), forControlEvents:UIControlEvents.TouchUpInside)
//set velue
button.withVelue = "1,2,3,4"
func buttonClicked(sender: UIButton){
print(sender.withVelue)
}
Related
I have the following Swift code.
extension UIImageView {
func enableClickablePrint() {
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
// HERE
}
func toggleClickablePrint() {
// HERE
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
The problem I'm running into is how to fill out the disableClickablePrint and toggleClickablePrint functions.
I'd like to be able to do something like the following.
extension UIImageView {
var imageTap: UITapGestureRecognizer?
func enableClickablePrint() {
imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
if let theImageTap = imageTap {
self.removeGestureRecognizer(theImageTap)
imageTap = nil
}
}
func toggleClickablePrint() {
if let theImageTap = imageTap {
disableClickablePrint()
} else {
enableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
But of course the problem is you can't store properties in extensions like I'm wanting to do.
Anyway to achieve this? I want to try to keep this as clean as possible, without resorting to fancy tricks unless absolutely required.
Would the correct thing to do to be to convert this into a subclass of UIImageView? I'd like to try to avoid that if possible just because if I want to turn this into a framework or library or something, subclasses don't integrate as nicely into interface builder and the developer would have to add the extra step of changing the class of all their image views. Which I think would be awesome to avoid if possible.
Your problem is that you need to be able to recognize the UIGestureRecognizer you added, but you can't store it in a property.
Here's a (tested) solution that subclasses UITapGestureRecognizer to make the UIGestureRecognizer identifiable and then searches self.gestureRecognizers with first(where:) to see if one has been added:
extension UIImageView {
class _CFTapGestureRecognizer : UITapGestureRecognizer { }
private var _imageTap: _CFTapGestureRecognizer? { return self.gestureRecognizers?.first(where: { $0 is _CFTapGestureRecognizer }) as? _CFTapGestureRecognizer }
func enableClickablePrint() {
// Only enable once
if _imageTap == nil {
let imageTap = _CFTapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
}
func disableClickablePrint() {
if let theImageTap = _imageTap {
self.removeGestureRecognizer(theImageTap)
}
}
func toggleClickablePrint() {
if _imageTap == nil {
enableClickablePrint()
} else {
disableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
I've use this extension for years and it work not only image but with any view.
extension UIView {
func addTapGuesture(target: Any, action: Selector) {
let tap = UITapGestureRecognizer(target: target, action: action)
tap.numberOfTapsRequired = 1
addGestureRecognizer(tap)
isUserInteractionEnabled = true
}
}
Usage:
imageView.addTapGuesture(target: self, action: #selector(imageTapped))
#objc func imageTapped() {
print("Tapped")
}
You could make an extension variable using a getter/setter:
extension UIImageView {
var tap: UITapGestureRecognizer {
get {
return //the created tap
}
set(value) {
print(value)
}
}
}
Since Extensions in swift can't contain stored properties, these are the solutions:
Fisrt one is the most used workaround is to use Objective_C runtime, by using objc_getAssociatedObject and objc_setAssociatedObject functions.
OK it's a nice solution, but if there is pure swift approach to do that so why not!
In your extension, define a struct with the field that you want to use, here you want for example UITapGestureRecognizer
Tip Create this struct as private You don't need anyone to access it of course.
Then define a computed property that will use this struct....
By doing this you have achieved what you need and you don't use the Objective-C at all .
Example :
extension UIImageView {
private struct TapGestureHelper{
static var tapGestureRecognizer : UITapGestureRecognizer?
}
var imageTap: UITapGestureRecognizer?{
get {
return TapGestureHelper.tapGestureRecognizer
}
set {
TapGestureHelper.tapGestureRecognizer = newValue
}
}
func enableClickablePrint() {
imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap!)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
guard let gesture = self.gestureRecognizers?.first else {
return
}
self.removeGestureRecognizer(gesture)
self.imageTap = nil
}
func toggleClickablePrint() {
if let theImageTap = imageTap {
disableClickablePrint()
} else {
enableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
I have this app with two checkboxes that I want to save when I close and load when I open but I cannot figure it out. Please can someone help me edit the code. I know need to save in UserDefaults somehow but I don't know how to code it.
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, for: UIControlState.normal)
} else {
self.setImage(uncheckedImage, for: UIControlState.normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
self.isChecked = false
}
#objc func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
Use following to save bool value to UserDefaults:
UserDefaults.standard.set(isChecked, forKey: "com.myCompany.checkboxState")
And load it using:
self.isChecked = UserDefaults.standard.bool(forKey: "com.myCompany.checkboxState")
Read more in documentation for UserDefaults.
Just remember that if you have several checkBoxes, you have to use unique key for each one, e.g. use UIButton's tag to differentiate between them:
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, for: UIControlState.normal)
} else {
self.setImage(uncheckedImage, for: UIControlState.normal)
}
// save it like this
UserDefaults.standard.set(isChecked, forKey: "com.myCompany.checkboxStateFor\(self.tag)")
}
}
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
// load it like this
self.isChecked = UserDefaults.standard.bool(forKey: "com.myCompany.checkboxStateFor\(self.tag)")
}
#objc func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
Then don't forget to setup a different tag for each checkBox in your app.
Probably something like this you are looking for?
extension UserDefaults{
func setChecked(value: Bool, forId id: String){
set(value, forKey: id)
}
func getChecked(forId id: String) -> Int{
return bool(forKey: id)
}
}
use:
UserDefaults.standard.setChecked(true, "box1")
UserDefaults.standard.getChecked("box1")
override func awakeFromNib() {
self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControlEvents.touchUpInside)
isChecked = UserDefaults.standard.bool(forKey: "buttonChecked")
}
#objc func buttonClicked(sender: UIButton) {
isChecked = !isChecked
UserDefaults.standard.set(isChecked, forKey: "buttonChecked")
}
I made a custom checkbox with button by creatin a class of UIButton
here is the class
import UIKit
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "ic_check_box")! as UIImage
let uncheckedImage = UIImage(named: "ic_check_box_outline_blank")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
isChecked = !isChecked
}
}
}
I have two checkboxes in the viewcontroller but I dont know how to set checkbox in the ViewController.class to do when checkBox "Si" is checked, the checkbox "No" set unchecked like in the image
Your CheckBox class should adopt a delegation pattern so that it can advise its delegate (which in this case would be your view controller) that its value has changed. Then in your view controller you can update the other checkbox as required:
protocol CheckBoxDelegate {
func checkBoxDidChange(checkbox: CheckBox) -> Void
}
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "ic_check_box")! as UIImage
let uncheckedImage = UIImage(named: "ic_check_box_outline_blank")! as UIImage
weak var delegate: CheckBoxDelegate?
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}
}
Then, in your View Controller:
class ViewController: UIViewController, CheckBoxDelegate {
#IBOutlet var siCheckBox: CheckBox! // Initialise some other way if you aren't using storyboard/nib
#IBOutlet var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.delegate = self
self.noCheckBox.delegate = self
}
//Mark: CheckBoxDelegate
func checkBoxDidChange(checkbox: CheckBox) {
if checkbox == self.siCheckBox {
self.noCheckBox.isChecked = !checkbox.isChecked
} else {
self.siCheckBox.isChecked = !checkbox.isChecked
}
}
From a user experience point of view, I would question why you need both checkboxes. A checkbox is an on/off control, so you would normally have text like "Select really great option?" with a single checkbox for yes/no; checked is yes, unchecked is no.
I would move func buttonClicked(sender: UIButton) to the parent ViewController.
let siCheckBox = CheckBox()
let noCheckBox = CheckBox()
func checkBoxToggled(sender: AnyObject) {
noCheckbox.isChecked = !noCheckbox.isChecked
siCheckbox.isChecked = !siCheckbox.isChecked
}
This is only safe if you're sure at least 1 is always checked. Otherwise I would add an if statement to make sure at l is checked.
New to Swift. I am populating a series of UIViews from values in an Array. I am needing to pass the individual index values across multiple functions at diffrent states of longPress.
What is the best way way of setting?
I have found many examples, but most have to do with index.row values of UITableViews.
EDIT: I have included a slimmed down version of the relevant code.
func createBlock(title: String) -> UIView {
let block = UIView()
block.frame = CGRectMake(0, 0, 100, 100)
block.translatesAutoresizingMaskIntoConstraints = false
block.backgroundColor = UIColor.blackColor()
let longPressRec = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longPressed(_:)))
block.addGestureRecognizer(longPressRec)
return block
}
func longPressed(sender: UILongPressGestureRecognizer){
switch (sender.state) {
case UIGestureRecognizerState.Began:
startDrag(sender)
case UIGestureRecognizerState.Changed:
dragOn(sender)
case UIGestureRecognizerState.Ended:
stopDrag(sender)
default:
return
}
}
func startDrag(sender: UILongPressGestureRecognizer){
}
func dragOn(sender: UILongPressGestureRecognizer){
}
func stopDrag(sender: UILongPressGestureRecognizer){
}
Set the tag of the sender.
Add an extension:
extension UILongPressGestureRecognizer {
var tag: Int! {
get {
return 0
}
set(newValue) {
self.tag = newValue
}
}
}
Try this:
longPressRec.tag = indexPath.row
And then:
func longPressed(sender: UILongPressGestureRecognizer){
let tag = sender.tag
//Do something with tag
}
In my UITableViewController I have a custom cell which contains a switcher which is the following:
import Foundation
import UIKit
class SwitchCell: UITableViewCell {
#IBOutlet weak var label : UILabel!
#IBOutlet weak var switchEmail : UISwitch!
func setEditable(canEdit:Bool) {
if (canEdit) {
self.switchEmail.enabled = true
self.label.highlighted = false
}
else {
self.switchEmail.enabled = false
self.label.highlighted = true
}
}
func configureCellWithSwitch(labelText:String, switchValue:Bool, enabled:Bool) {
var labelFrame:CGRect = self.label.frame
labelFrame.size.height = Settings.labelHeight
self.label.frame = labelFrame
self.label.text = labelText
if (switchValue) {
self.switchEmail.setOn(true, animated: true)
}
else {
self.switchEmail.setOn(false, animated: true)
}
self.setEditable(enabled)
}
}
I would like to know how to implement a listener/delegate to the switcher in order to get its value from the UITableViewController. I was able to write delegate/listeners for a cell with UITextField and UITextView implementing the methods
func controller(controller: UITableViewCell, textViewDidEndEditing: String, atIndex: Int)
and
func controller(controller: UITableViewCell, textFieldDidEndEditingWithText: String, atIndex: Int)
but I don't know what I should implement the switcher.
UISwitch has no delegate protocol. You can listen to the status as follows:
ObjC:
// somewhere in your setup:
[self.mySwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
- (void)switchChanged:(UISwitch *)sender {
// Do something
BOOL value = sender.on;
}
Swift:
mySwitch.addTarget(self, action: "switchChanged:", forControlEvents: UIControlEvents.ValueChanged)
func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.on
// Do something
}
Swift3 :
mySwitch.addTarget(self, action: #selector(switchChanged), for: UIControlEvents.valueChanged)
func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
}
Swift4:
mySwitch.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged)
#objc func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
}
In Swift4.0
mySwitch.addTarget(self, action: #selector(valueChange), for:UIControlEvents.valueChanged)
#objc func valueChange(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
print("switch value changed \(value)")
}
Another (Swift 3 or 4) method is to use didSet observer and drastically reduce code, like so-
In the class declaration declare a variable like below:
var switchFlag: Bool = false {
didSet{ //This will fire everytime the value for switchFlag is set
print(switchFlag) //do something with the switchFlag variable
}
}
Then you can have an IBAction on the UISwitch like so
#IBAction func switchChanged(_ sender: Any) {
if self.mySwitch.isOn{
switchFlag = true
}else{
switchFlag = false
}
}
Swift 3:
Using Storyboard Autolayout:
Add Reference:
#IBOutlet weak var sampleSwitch: UISwitch!
Associate method:
#IBAction func sampleSwitchValueChanged(_ sender: Any) {
if sampleSwitch.isOn {
print("ON")
}
else {
print ("OFF")
}
}
Programatic way:
Adding Target:
sampleSwitch.addTarget(self, action: #selector(ViewController.sampleSwitchValueChanged(sender:)), for: UIControlEvents.valueChanged)
The method associated with the switch:
func sampleSwitchValueChanged(sender: UISwitch!)
{
if sender.isOn {
print("switch on")
} else {
}
}
In Swift 5
switchDemo.addTarget(self, action: #selector(didTapAdvertise), for:UIControl.Event.valueChanged)
#objc func didTapAdvertise(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
print("switch value changed \(value)")
}
Swift 3:
#IBOutlet weak var mySwitch: UISwitch!
mySwitch.addTarget(self, action: #selector(MyClass.switchChanged(_:)), for: UIControlEvents.valueChanged)
func switchChanged(_ mySwitch: UISwitch) {
if mySwitch.isOn {
// handle on
} else {
// handle off
}
}
I have the solution in objective-c, it is the method that I use regularly:
-The Action of the switch must be in tableviewcontroller and not on the cell
-When You tap on the switch inside the action can do this to find the correct cell, then you can easily find the index or any other value that you need ...
- (IBAction)switchValueChanged:(UISwitch *)sender
{
YourCellClass *cell = (YourCellClass *)[sender findSuperViewWithClass:[YourCellClass class]];
etc....
}
the method findSuperviewWithClass is a category on UIView
- (UIView *)findSuperViewWithClass:(Class)superViewClass
{
UIView *superView = self.superview;
UIView *foundSuperView = nil;
while (nil != superView && nil == foundSuperView)
{
if ([superView isKindOfClass:superViewClass])
{
foundSuperView = superView;
} else
{
superView = superView.superview;
}
}
return foundSuperView;
}