I have two classes and one of them I create a button which, I want to call a method in this class.
class blueFooterForImages: UIView{
//buttons for footer
let slideButton = UIButton()
let buttonOnFooter = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
//setting buttons
slideButton.frame = CGRectMake((self.frame.width / 2) - 10 , 10, 30, 30)
slideButton.addTarget(self, action: "animationFunction:", forControlEvents: UIControlEvents.TouchUpInside)
slideButton.setImage(imageForSlideButton,forState: .Normal)
self.addSubview(slideButton)}
}
internal func animationFunction(sender: UIButton!) {
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.frame.size.width -= 100
})
}
add this to your code, use singleton and send the instance
static var sharedInstance : blueFooterForImages?
override init(frame: CGRect) {
super.init(frame: frame)
blueFooterForImages.sharedInstance = self
//rest of init code....
}
in other class:
var button = UIButton(initParams...);
button.addTarget(blueFooterForImages.sharedInstance!,action:"animationFunction:", forControlEvents: UIControlEvents.TouchUpInside);
just make sure that blueFooterForImages.sharedInstance is not nil
(make sure that blueFooterForImages instance was created before you do this)
Related
I need to use custom views instead of views created with xib file.
How do I convert and use nib/xib file to programmatically view ?
class CustomCell: UITableViewCell {
var item: ViewModelItem? {
didSet {
titleLabel?.text = item?.title
}
}
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = .none
}
#IBOutlet weak var titleLabel: UILabel?
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
accessoryType = selected ? .checkmark : .none
}
}
I added it instead of xib. How should i send this?
I want the xib file to be programmatically added and controllable.
I want the xib file to be programmatically added and controllable.
class CustomCellView: UIView {
convenience init(frame: CGRect,checkboxTag:Int?) {
self.init(frame: frame)
self.addCustomView(checkboxTag: checkboxTag)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView(checkboxTag : Int?) {
var checkbox: UIButton = ClickingCheckbox()
if((checkboxTag) != nil)
{
checkbox.tag = checkboxTag!
}
self.addSubview(checkbox)
}
}
class ClickingCheckbox: UIButton {
convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
self.setImage(UIImage(named: "unfilled.png"), for: UIControlState.selected)
self.setImage(UIImage(named: "filled.png"), for: UIControlState.normal)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc private func buttonTapped() {
self.isSelected = !self.isSelected
}
}
When you are using view from Nib, it calls AwakeFromNib() method, custom views from code are using Init() methods.
To convert you Xib to programmatically code you need to setup all UI inside Init() method and move all initialConfiguration methods from AwakeFromNib() to Init()
I made a custom UIView() and i'm trying to add a okButton to it.
However. I have added the button but when showing my UIView in one of my ViewControllers, But the button won't work. This is my code:
class Luna: UIView {
let luna = UIView()
let okButton = UIButton()
typealias completionHandler = (_ success:Bool) -> Void
// Not yet implemented
open var touchOutsideToHide: Bool = true;
private var screenWidth: CGFloat {
return UIScreen.main.bounds.width
}
override init(frame: CGRect) {
super.init(frame: frame)
okButton.setTitleColor(.blue, for: .normal)
okButton.setTitle("Okay", for: .normal)
okButton.titleLabel?.font = UIFont(name: "avenirnext-demibold", size: 16)
let gesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.pressButton(_:)))
okButton.addGestureRecognizer(gesture)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
//The target function
#objc func pressButton(_ sender: UIButton){ //<- needs `#objc`
// .. //
print("btn hit")
}
I do not get btn hit in the console and the tap isn't registered
the button is visible, it's added as a subview:
Screenshot
Button have default touch gesture, you don't need to add it. just add target as follow to fix your issue. Create protocol of your customer class and declare delegate for it in same class as follow.
protocol LunaDelegate: class {
func okButtonTapped(sender: UIButton)
}
class Luna: UIView {
let luna = UIView()
let okButton = UIButton()
typealias completionHandler = (_ success:Bool) -> Void
weak var delegate: LunaDelegate?
// Not yet implemented
open var touchOutsideToHide: Bool = true;
private var screenWidth: CGFloat {
return UIScreen.main.bounds.width
}
override init(frame: CGRect) {
super.init(frame: frame)
okButton.setTitleColor(.blue, for: .normal)
okButton.setTitle("Okay", for: .normal)
okButton.titleLabel?.font = UIFont(name: "avenirnext-demibold", size: 16)
okButton.addTarget(self, action: #selector(pressButton(sender:)), for: .touchUpInside)
}
#IBAction func pressButton(sender: UIButton) {
if let selfDelegate = self.delegate {
selfDelegate.okButtonTapped(sender: sender)
}
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Then after implement your code as follow to use your custom view. When your button will pressed then delegate method will be call in your view controller.
Usage:
class LunaViewController: UIViewController, LunaDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let luna = Luna(frame: CGRect.init(x: 100, y: 100, width: 100, height: 40))
luna.delegate = self
self.view.addSubview(luna)
}
// MARK:- Luna Delegate
func okButtonTapped(sender: UIButton) {
print("OK Button Pressed From Luna View")
}
}
This is the proper solution which I have already using in my current project. I hope this will help you.
This question already has answers here:
Expected declaration error for making high score [duplicate]
(2 answers)
Closed 4 years ago.
I'm trying to create a UIButton in Swift 4 but I keep getting a "Expected declaration" error in the "MyView" class when I try to call the addTarget function. I've done this same code in other classes and have never gotten the error. Am I missing something? Thanks.
import Foundation
import UIKit
protocol MyDelegate: class {
func onButtonTapped()
}
class OtherViewController: UIViewController {
}
class MyViewController: UIViewController, MyDelegate {
func onButtonTapped() {
let nextViewController = OtherViewController()
navigationController?.pushViewController(nextViewController, animated: false)
}
var myView: MyView!
override func viewDidLoad() {
super.viewDidLoad()
myView.delegate = self
}
}
class MyView: UIView {
weak var delegate: MyDelegate?
let button = UIButton()
button.addTarget(self, action: #selector(buttonTapped),for: .touchUpInside)
func buttonTapped() {
self.delegate?.onButtonTapped()
}
}
you cannot addTarget or call any method in the class space , this space is for declartion as the error suggests .
to fix this you can do either this
let button:UIButton =
{
let btn = UIButton()
btn.addTarget(self, action: #selector(buttonTapped),for: .touchUpInside)
return btn
}()
Or
let button:UIButton = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
button.addTarget(self, action: #selector(buttonTapped),for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
in both cases you must add #objc annotation to the buttonTapped function because selectors must refer to an #objc function .
so it will be like this
#objc func buttonTapped(){}
Also you need to add this button to the view on order for it to be drawn to the screen .
view.addSubView(button)
Although I could create a func setImages () in my CustomView class and call this after initializing myCustomView, I would like to understand if there's a cleaner way to set a view's delegate so that it is accessible when being initialized.
My main ViewController contains
class Main: UIViewController, CustomViewDelegate {
var imagesArray:[UIImage] = [Image1,Image2,Image3,Image4,Image5]
var myCustomView = CustomView()
override func viewDidLoad() {
super.viewDidLoad()
myCustomView.delegate = self
myCustomView = CustomView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
//this causes init of CustomView, but delegate is now nil and button images don't load
}
}
My CustomView file contains
var buttonsArray = [Button1,Button2,Button3,Button4,Button5]
override init(frame: CGRect) {
super.init(frame : frame)
for n in 0..< buttonsArray.count {
buttonsArray[n].setImage(delegate?.imagesArray[n], for: .normal)
}
}
You can create a new initializer which takes a frame and a delegate type and set the delegate before you set images to buttons
init(frame: CGRect,sender: CustomViewDelegate) {
super.init(frame : frame)
self.delegate = sender
for n in 0..< buttonsArray.count {
buttonsArray[n].setImage(delegate?.imagesArray[n], for: .normal)
}
}
For that, you have to confirm your viewController for the delegate(obviously).Call your customView like this in viewController:
class ViewController: UIViewController, CustomViewDelegate {
var myCustomView: CustomView!
override func viewDidLoad() {
myCustomView = CustomView(frame: self.view.bounds, sender: self)
}
}
hope it helps!
I have a custom view with a button.
When adding the view in storyboard i get an error:
failed to render instance of the agent
When i debug the view from interface builder it crashes when it sets the image of the button.
CODE:
#IBDesignable
class UIHeader: UIView {
private lazy var backButton: UIButton = {
let btn = UIButton()
btn.tintColor = UIColor.lightGrayColor()
btn.translatesAutoresizingMaskIntoConstraints = false
//CRASH HERE//
btn.setImage(UIImage(named: "prev")!.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
btn.addTarget(self, action: #selector(UIHeader.OnBackButtonClickLister(_:)), forControlEvents: .TouchUpInside)
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
}
extension UIHeader {
#IBInspectable
var backButtonImage: UIImage? {
get {
return backButton.imageForState(.Normal)
}
set (newImage) {
backButton.setImage(newImage?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
}
}
extension UIHeader {
private func setupView() {
translatesAutoresizingMaskIntoConstraints = false
addSubview(backButton)
}
}