I am new in Ios and i am having hard time wrapping my head around protocols and delegates concept. I am implementing a library called BEMCheckBox https://github.com/Boris-Em/BEMCheckBox or https://cocoapods.org/pods/BEMCheckBox for implementing radio buttons. Its documentation is pretty descriptive using which i have successfully added checkboxes, grouped them together to work as radio boxes.
#IBOutlet var inarelashipcb: BEMCheckBox!
#IBOutlet var complicatedcb: BEMCheckBox!
#IBOutlet var singlecb: BEMCheckBox!
var groupbx:BEMCheckBoxGroup!
func initialize(){
groupbx = BEMCheckBoxGroup(checkBoxes: [inarelashipcb,
complicatedcb, singlecb])
groupbx.selectedCheckBox = singlecb
groupbx.mustHaveSelection = true
}
Now i want to use didTapCheckBox method but i donot understand how. The documentation is blurry there no snippets for that. For the record this is what the documentation states
"BEMCheckBox uses a delegate to receive check box events. The delegate object must conform to the BEMCheckBoxDelegate protocol, which is composed of two optional methods:
didTapCheckBox:
Sent to the delegate every time the check box gets tapped, after its properties are updated (on), but before the animations are completed."
Any snippets to help me use delgate so i can implement didTapCheckBox method?
func initialize(){
groupbx = BEMCheckBoxGroup(checkBoxes: [inarelashipcb,
complicatedcb, singlecb])
groupbx.selectedCheckBox = singlecb
groupbx.mustHaveSelection = true
for checkbox in groupbx {
checkbox.delegate = self
}
}
must call initialize in viewDidLoad of the viewController
override func viewDidLoad() {
// Do your work
initialize()
}
compiler will show you an error, error will be gone if you add this codes
extension ViewController : BEMCheckBoxDelegate {
func didTap(_ checkBox: BEMCheckBox) {
//do your work
// if you have multiple checkboxes, then do like that
//if checkBox == checkBox1 {
//do work for checkbox1
//} else if {
// ..
//}
}
}
Don't forget to add the following line
import BEMCheckBox
The outlet checkbox you have declared, set delegate to self.
For eg, if your checkbox outlet is checkbox1 set its delegate as
checkbox1.delegate = self
I solve it.
using this code
func initialize(){
groupbx = BEMCheckBoxGroup(checkBoxes: [inarelashipcb,
complicatedcb, singlecb])
groupbx.selectedCheckBox = singlecb
groupbx.mustHaveSelection = true
inarelashipcb.delegate = self
complicatedcb.delegate = self
singlecb.delegate = self
}
func didTap(_ checkBox: BEMCheckBox) {
print("here hello")
}
Also my uiviewcontroller inherited from BEMCheckBoxDelegate
Related
I needed to delegate a click action for my UIView class to my UIViewController class since Swift does not support multiple class inheritance. So i wanted it such that once a button is clicked on my subview, a function in my BrowserViewController class is called.
I am using a protocol to achieve this, but on the function does not triggered when the button is tapped. Please help me out.
View Controller
class BrowseViewController: UIViewController {
var categoryItem: CategoryItem! = CategoryItem() //Category Item
private func setupExplore() {
//assign delegate of category item to controller
self.categoryItem.delegate = self
}
}
// delegate function to be called
extension BrowseViewController: ExploreDelegate {
func categoryClicked(category: ProductCategory) {
print("clicked")
let categoryView = ProductByCategoryView()
categoryView.category = category
categoryView.modalPresentationStyle = .overCurrentContext
self.navigationController?.pushViewController(categoryView, animated: true)
}
}
Explore.swift (subview)
import UIKit
protocol ExploreDelegate: UIViewController {
func categoryClicked(category: ProductCategory)
}
class Explore: UIView {
var delegate: ExploreDelegate?
class CategoryItem: UIView {
var delegate: ExploreDelegate?
var category: ProductCategory? {
didSet {
self.configure()
}
}
var tapped: ((_ category: ProductCategory?) -> Void)?
func configure() {
self.layer.cornerRadius = 6
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.categoryTapped)))
self.layoutIfNeeded()
}
#objc func categoryTapped(_ sender: UIGestureRecognizer) {
delegate?.categoryClicked(category: ProductCategory.everything)
self.tapped?(self.category)
}
}
}
Simply add a print statement inside categoryTapped.
You will then know if it is actually being tapped.
A million things could go wrong, for example, you may have forget to set the UIView to allow intertaction.
After checking that. Next add another print statement inside categoryTapped which shows you whether or not the delegate variable is null.
You'll quickly discover the problem using simple print statements.
print("I got to here!")
It's that easy.
And what about
if delegate == nil { print("it is nil!! oh no!" }
else { print("phew. it is NOT nil.") }
Debugging is really that easy at this level.
Next add a print statement inside setupExplore()
func setupExplore() {
print("setup explore was called")
....
See what happens.
I don't see any piece of code which sets the delegate.
First of all, define delegate as a property inside CategoryItem class, Then you must set the current instance of BrowseViewController to the delegate variable of CategoryItem. Now you can expect your method being called.
There are a few things that could cause the delegate method to not be triggered in this code:
Ensure that isUserInteractionEnabled = true on your CategoryItem. This is probably best done in either the configure() function in the CategoryItem or in the setupExplore() function of the BrowseViewController.
Make sure that the setupExplore() function on the BrowseViewController is being called, and that the category is being set on the CategoryItem to trigger the configure function. Otherwise, either the delegate or the gesture recognizer might not being set.
Side Note - weak vs strong delegate
On a side note, it is usually best practice to make your delegate properties weak var rather that having them be a strong reference, as this makes them prone to strong retain cycles.
Therefore, you might want to consider making the var delegate: ExploreDelegate? on your CategoryItem into weak var delegate: ExploreDelegate?. For more information on this problem, view this post.
I'm trying to add accessibility to a simple UISlider. I read the Apples adjustable document and saw that I need to implement two functions from the UIAccessibilityAction protocol; accessibilityIncrement() and accessibilityDecrement().
The problem I'm having is that even if I set the slider to be an accessibility element in viewDidLoad and setting slider.accessibilityTraits = .adjustable, the two override functions aren't called even if I change the values.
I also tried to set slider.accessibilityLabel = "test", but it's still not reading the label. Only how far the slider has come. For instance "80%".
Any idea on how I can make this work? I also read these two posts on stackOverflow, but none of them worked for me. accessibilityIncrement / Decrement not called and Accessibility accessibilityDecrement() not getting called
I can also mention that I also tried setting breakpoints at the accessibilityIncrement() and accessibilityDecrement(), but nothing happened.
My code
override func viewDidLoad() {
super.viewDidLoad()
slider.isAccessibilityElement = true
slider.accessibilityLabel = "test"
slider.accessibilityTraits = .adjustable
}
override func accessibilityIncrement() {
slider.accessibilityValue = textField.text!
}
override func accessibilityDecrement() {
slider.accessibilityValue = textField.text!
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
guard let unit = question?.unit else { return }
let currentValue = Int(sender.value + 0.5)
textField.text = "\(currentValue) \(unit)"
slider.accessibilityLabel = textField.text!
}
You implement the accessibilityIncrement() and accessibilityDecrement() methods in your view controller but they should belong to the created slider whose trait should be .adjustable.
I suggest you take a look at this accessibility site where a complete example about adjustable values with code snippets and illustrations is provided for both ObjC and Swift.
Following this example will allow to call the accessibilityIncrement() and accessibilityDecrement() methods with your slider.
thanks for all help:)! fixed it using iboutlet collection and add properies on viewDidLoad
I'm trying to add properties to keyboard keys like layer.shadowColor or layer.shadowRadius.
I got an error
'Value of type '(UIButton)' -> () has no member 'layer'
how to fix this ?
this is my code keyboardViewController.swift
import UIKit
class KeyboardViewController: UIInputViewController {
var newKeyboardView: UIView!
#IBAction func keyPressed(sender: UIButton) {
}
#IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
}
func loadInterface() {
// load the nib file
let keyboardNib = UINib(nibName: "newKeyboard", bundle: nil)
// instantiate the view
newKeyboardView = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// add the interface to the main view
view.addSubview(newKeyboardView)
// copy the background color
view.backgroundColor = newKeyboardView.backgroundColor
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
textColor = UIColor.whiteColor()
} else {
textColor = UIColor.blackColor()
}
self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
}
}
I think that in order to apply some style to the button, you need an outlet to this button.
Right now, from what I can understand, you are trying to apply styles to the button from the #IBAction to the sender, which is not the proper way to do it.
Try to make an outlet to the button in the view controller and then to apply the styles from within the viewDidLoad method.
I hope this is clear, but if you want a more specific answer you need to show us what you tried, for example pasting the code you have in the view controller
EDIT:
Based on the code you post, the keyboard is a Nib you instantiate from loadInterface(). I don't have a clear vision of the whole thing with only this piece of code, but it seems to me that you are trying to apply some styles to every key button of a keyboard view. Unfortunately this really depends on how the keyboard is implemented, can you provide some more details?
Anyway, from what I see I think you didn't write this code: probably you are following a tutorial or maintaining someone else's code. That's ok, but I suggest you to follow a an introduction course to iOS development with Swift, like the Udacity's one, which is fantastic IMHO (https://www.udacity.com/course/intro-to-ios-app-development-with-swift--ud585)
If you try to format your UIButton with QuartzCore framework, you'll need to import it first:
import QuartzCore
Then you will be able to access those members.
For example (latest swift3 code):
#IBAction func keyPressed(sender: UIButton) {
let button = sender as UIButton!
button?.backgroundColor = UIColor.red
button?.layer.shadowColor = UIColor.black.cgColor
button?.layer.shadowRadius = 1.0
button?.layer.cornerRadius = 4.0
}
In case you need to apply your styles sooner, try to consider to put this code into viewDidLoad or viewDidAppear methods:
self.nextKeyboardButton.backgroundColor = UIColor.red
self.nextKeyboardButton.layer.shadowColor = UIColor.black.cgColor
self.nextKeyboardButton.layer.shadowRadius = 1.0
self.nextKeyboardButton.layer.cornerRadius = 4.0
Seems like you're trying to "add property" not to a button, but rather to a closure which accepts a button as an argument.
Make it like this:
nextKeyboardButton.layer.shadowColor = UIColor.redColor.cgColor
nextKeyboardButton.layer.shadowRadius = 5.0
So while I do see other examples of this online. None of them seem to work for me. I am trying to unhide my PinPadView class by calling it from the ViewController. Any suggestions would be greatly appreciated.
class ViewController: UIViewController, UIWebViewDelegate {
func initPinLogin() {
//Display the Pin Pad object in App
PinPadView.loadPinPad()
}
}
class PinPadView: UIView {
class func loadPinPad() {
let pinPad:PinPadView = PinPadView()
pinPad.hidden = false
}
}
Edit:
I have answered my question below. It was a newbie mistake, but for those who are having similar issues and want to see what I did, it is there.
You are creating a new instance of the object
let pinPad:PinPadView = PinPadView()
which you are un-hiding.
Instead reference the object which you want to hide from your VC class.
Thanks to everyone for the input. I have figured out what I was trying to do. I did not have to call the function from another class but rather create an outlet in the ViewController
#IBOutlet weak var pinPad: PinPadView!
after I did that, I was very easily able to do this
func initPinLogin() {
//Display the Pin Pad object in App
pinPad.hidden = false
}
Try tis:
class ViewController: UIViewController, UIWebViewDelegate {
func initPinLogin() {
let pinPad:PinPadView = PinPadView()
pinPad.loadPinPad()
}
}
class PinPadView: UIView {
class func loadPinPad() {
self.hidden = false
}
}
I want to update the label in the DetailViewController everytime I selected a tableRow in the MasterViewController. To achieve this, I designed a delegate, which I have in the MasterVC
protocol TestTableViewControllerDelegate {
func selectedRow(selectedCar : Car)
}
class TestTableViewController: UITableViewController {
...
var delegate : TestTableViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = DetailViewController()
The delegate works just fine, (it is implemented correctly in the DetailVC), it can pass values from TestTableVC to DetailVC and also correctly do println(), which prints a new Car.model String to the console every time I select a row in the TTVC.
The DetailVC looks like this (shortened):
class DetailViewController: UIViewController, TestTableViewControllerDelegate {
#IBOutlet var textLabel: UILabel!
var theCar : Car? {
didSet(newCar) {
refreshUI()
}
}
override func viewDidLoad() {
super.viewDidLoad()
refreshUI()
}
func selectedRow(selectedCar : Car) {
theCar = selectedCar
refreshUI()
}
func refreshUI() {
textLabel?.text = theCar!.model
}
}
I can achieve any kind of action with my delegate, expect for refreshing the UI. I have tried numerous ways, this is my latest attempt. Before that, I tried setting the textLabel's text property directly within the delegate method, didn't work. This problem only occurs when working with the UI-elements. I know it has something to do with the view not being loaded yet, but why does my refreshUI() function not work at all?
I am still a beginner, so any tip or help would be much appreciated!
A workaround I've used is to cerate a properly in the delegate and pass the value to it instead of the UI element. When the view loads I update the label's text properly with the value of the delegates property. I would think there's a better way to do this (I'm new to programming) but this is the best soultion I've come up with so far. Will update with sample code soon.