i added two custom view classes and the elements of that class are addede to viewcontroller class but i cannot accecssing 1st element but i can access second element
hear my code
1st class
class TextField: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let view=UIView(frame : CGRectMake(8,100,270,47))
let headerText=UILabel(frame : CGRectMake(0,0,view.bounds.width,16))
headerText.text="label"
headerText.textColor=UIColor.blackColor()
headerText.textAlignment=NSTextAlignment.Left
headerText.font = UIFont.systemFontOfSize(13.0)
headerText.numberOfLines = 0
view.addSubview(headerText)
let textField=UITextField(frame : CGRectMake(0,20,view.bounds.width,28))
textField.borderStyle=UITextBorderStyle.RoundedRect
textField.userInteractionEnabled=true
textField.keyboardType=UIKeyboardType.NamePhonePad
view.addSubview(textField)
self.addSubview(view)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
2nd class
protocol ElementDelegate {
func buttonClick(sender:UIButton)
}
class ButtonClass: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let button=UIButton(frame: CGRectMake(10,50,270,30))
button.setTitle("Click", forState: UIControlState.Normal)
button.backgroundColor=UIColor.blueColor()
button.userInteractionEnabled=true
button.addTarget(self, action: #selector(button_click(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(button)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func button_click(sender:UIButton){
delegate.buttonClick(sender)
}
}
my viewcontroller class
class ViewController: UIViewController,ElementDelegate {
override func viewDidLoad() {
let screenSize:CGRect=UIScreen.mainScreen().bounds
let date = TextField(frame: CGRectMake(0,10,screenSize.width,screenSize.height))
self.view.addSubview(date)
let element = Button(frame: CGRectMake(0,70,screenSize.width,screenSize.height))
element.delegate = self
self.view.addSubview(element)
}
}
when under running i added first textfield view second i added button view but when i click in textbox i cannot accessing it but button is working fine when i remove button textbox working fine why i cannot accessing both one after another
please help me.....
let date = TextField(frame: CGRectMake(0,10,screenSize.width,screenSize.height))
...
let element = Button(frame: CGRectMake(0,10,screenSize.width,screenSize.height))
You've created two subviews with exactly the same frame (size and position). The one you add second will be on top of the other, and will be taking the touch events, even if the button and textfield within them are in different places - a plain UIView will still take touch events.
Why are you making a view subclass that just holds another view inside it in a different position? Why not just position the button and textfield directly?
Related
I need UIButton to have the property bookId. I tried the following code but it's giving me the error Property 'self.bookId' not initialized at super.init call. I need the property to be able to query the database for that specific bookId when the button is clicked on.
import UIKit
class BookUIButton: UIButton {
var bookId: String
init(frame: CGRect, bookId: String) {
super.init(frame: frame);
self.bookId = bookId
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func awakeFromNib() {
super.awakeFromNib()
//TODO: Code for our button
}
}
Any help would be greatly appreciated!!!
swift enforces you to initialize every member var before it is ever/might ever be used. Since it can't be sure what happens when it is supers turn, it errors out: better safe than sorry!
Solution 1:
class BookUIButton: UIButton {
var bookId: String?
init(frame: CGRect, bookId: String) {
super.init(frame: frame);
self.bookId = bookId
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func awakeFromNib() {
super.awakeFromNib()
//TODO: Code for our button
}
}
Solution 2:
There is a better way to skip this error. So all you have to do is to initialize member after declaration:
class BookUIButton: UIButton {
var bookId: String = String()
init(frame: CGRect, bookId: String) {
super.init(frame: frame);
self.bookId = bookId
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func awakeFromNib() {
super.awakeFromNib()
//TODO: Code for our button
}
}
Is it important to have it named bookId? And is it important to be a string?
What if you just gave the UIButton a tag? (e.g. ButtonName.tag = Int)
Since you can always instantiate a button from storyboard, that button need to have a required init?(coder aDecoder: NSCoder). That method is required just for you to insert a button in the storyboard.
If the button is actually created via storyboard, than of course it won't have the id soon enough (at init time) for it not to be optional.
Since I assume that you will always instantiate the button programmatically, and not via storyboard, you can just implement your own init, with your params, and than, in the required init, just insert a fatalError.
That will compile as the fatalError returns Never (meaning it never returns), so the compiler can understand that bookId will never actually be nil.
Actually if you delete the required init Xcode will suggest you to insert the method with a fatalError and will autocomplete it for you if you want.
Of course, after that, if you put a button of this class in the storyboard, it will crash, so don't do that.
Adding a property to a button (or view in general) and force it to be created via some init and not via storyboard, in general, is perfectly fine if you don't intend to use the storyboard for that button (or view).
PS: after this brief on how to do what you want to do, I want to suggest you NOT to do it in THIS case, as it seems a bad idea for a button to hold any sort of data about some API you need to call. The button should just be a button and inform you when the user taps it. Then, when the button is pressed, some other class should handle what to do, using some other model to get the correspondent bookId for that button tap.
Completely different was if you would add some property that helped the button to look different, or add some other behavior specific to the use of the button (which is just be tappable and inform of taps)
I added a custom view, that has a button, to my viewController. I want to make an #IBAction from that button to my viewController.
I have following problems:
How do I make it show up in a storyboard? When I run the app it works fine.
How do I make an #IBAction from that button to my viewController?
class CustomCellView: UIView{
//MARK: Initializer
override func awakeFromNib() {
super.awakeFromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
}
//MARK: Functions
func commonInit(){
let customView = Bundle.main.loadNibNamed("customCellView", owner: self, options: nil)?.first as? UIView ?? UIView()
customView.frame = self.bounds
self.addSubview(customView)
}
}
Add #objc in your viewController where you added customView.
e.g.
#objc func actionCustom()
{
print("Click Added")
}
Use
func commonInit(){
let customView = Bundle.main.loadNibNamed("customCellView", owner: self, options: nil)?.first as? UIView ?? UIView()
customView.frame = self.bounds
self.addSubview(customView)
customView.button.addTarget(self, action: #selector(actionCustom), for: .touchUpInside) //Add click code here
}
my customView is not showing in storyboard but when I run the app it's ok
This is the expected behaviour with the custom views. You won't get to see how the view looks in the xib that you use the custom view only in the xib that you defined the view.
How make #IBAction from that button to my viewController.
You can't. Custom views don't make public the subviews in interface builder. The best thing you can do is to use the delegate pattern or as Bhavesh Sarsawa pointed out doing it programatically either by adding the vc as a target or by making an IBAction in the ccustom view which calls a closure that is sent by dependency injection.
customButton.setAction { code that gets called when the button is pressed }
I have created a viewcontroller which consists of two classes. These are displayed below:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var Viewholder: UIImageView!
var txt:String?
override func viewDidLoad() {
super.viewDidLoad()
let vv= TestView(frame: Viewholder.frame)
view.addSubview(vv)
txt= "hello"
let rr = TestView(frame: self.view.frame,textvalue:txt!)
rr.colour = "" // set value
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
class TestView: UIView {
var textvalue:String?
init(frame: CGRect,textvalue) {
self.textvalue= textvalue
super.init(frame: frame)
self.sharedLayout()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.frame = frame
self.setupPaths()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func sharedLayout() {
print(textvalue!) // works here
}
func setupPaths() {
print(textvalue!) // doesnt work here (displays nil)
}
How can I make it work so that the value of textvalue in "setupPaths" gives the correct value so that I can then changee the text of a label. I am having trouble getting the setuppath function to display the passed value as it is returning null. This is stopping me from editting the label with a passed value.
You can create a customView like this
class TestView: UIView {
var colour:String?
override init(frame: CGRect) {
super.init(frame: frame)
self.sharedLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.sharedLayout()
}
init(frame: CGRect,colour:String) {
self.colour = colour
super.init(frame: frame)
self.sharedLayout()
}
func sharedLayout() {
}
}
//
You can create it like this
let rr = TestView(frame: self.view.frame,colour:"test")
// rr.colour = "" // set value
You are badly confused about object-oriented programming. In your code:
let vv= TestView(frame: Viewholder.frame)
view.addSubview(vv)
txt= "hello"
let rr = TestView(frame: self.view.frame,textvalue:txt!)
The let vv line creates a TestView object and installs it as a subview of the view controller's content view.
Then the next 2 lines create a NEW instance of TestView and install text into that 2nd view. You then forget about this second view.
This is like buying a new car, setting the station on the radio of the new car, abandoning the new car, and then going home and wondering why the radio station on your existing car didn't change. The two objects are not the same object and settings in one instance of TestView have no effect on the other instance of TestView.
I need to open keyboard on button click for UIButton (not using/for UITextField). I have tried to create custom button by overriding variable canBecomeFirstResponder but it's not working.
Is there any other way to do so?
Note: I want to set UIPIckerView as an input view of UIButton in key board frame.
Here is my code.
class RespondingButton: UIButton {
override var canBecomeFirstResponder: Bool {
return true
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
// common init
}
}
In my view controller, I connected button action.
class TestViewController: UIViewController {
#IBAction func testBecomeFirstResponder(button: RespondingButton){
button.becomeFirstResponder() // Not working.
}
}
Here is what I would do.
Create transparent textField 1x1px, lets say it is myTextField.
Then add your desired button. In the button action make the myTextField.becomeFirstResponder().
Create view:
let pvBackground: UIView = {
let v = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
v.backgroundColor = .white
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
In viewDidLoad:
pvBackground.addSubview(yourPickerView)//add the picker into the pvBackground
myTextField.inputView = pvBackground
I added the pickerView into the another view to be able to customize it more.
Add conformance to UIKeyInput like this. It should work.
class RespondingButton: UIButton, UIKeyInput {
override var canBecomeFirstResponder: Bool {
return true
}
var hasText: Bool = true
func insertText(_ text: String) {}
func deleteBackward() {}
}
I'm making an iOS app with Xcode where all my buttons should have the same style. The only difference between these buttons are their height and width. Is there a way to save the first one I styled, and then use it again in the different view controllers, without copying? I'm thinking if this is possible it'll save me a lot of time.
Applying the same style to multiple instances of UIButton:
Strictly Programmatic route:
The first two methods are what I would do. The third is only to illustrate that it is possible to write an init that copies settings from another button.
Apply preset style with a sub class:
class StyledButton : UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.blackColor()
// more styling
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Apply preset style with an extension to UIButton:
extension UIButton {
func setCustomStyle1() {
self.backgroundColor = UIColor.blackColor()
// nore styling
}
}
Copy style with a convenience init in an extension to UIButton:
extension UIButton {
convenience init(styleFromButton button: UIButton, frame: CGRect) {
self.init(frame: frame)
self.backgroundColor = button.backgroundColor
}
}
Interface Builder solution:
Create a new Swift file:
Create a sub class of UIButton in the new file:
class StyledButton : UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
style()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
style()
}
private func style() {
self.backgroundColor = UIColor.blackColor()
// more styling
}
}
Go back to the Interface Builder and select a UIButton you want to style.
Select the third panel on the right, this is the identity inspector.
Select your sub class as the class for the UIButton.
Repeat for all buttons to style.
Or style the entire thing in IB and Alt-Drag to make a copy.