I would like to be able to interact with the UIControl I have made, and therefore want it in my ViewController.
What I tried
I subclassed UIControl (1).
Then I added a UIView to my View Controller and assigned it the new class (2).
But in Interface Builder I am not able to set my outlets to the buttons contained in the new class (1)?!
1:
2:
UIControl's documentation confirms that it is a subclass of UIView, and I should therefore be able to connect the outlets, right?
What am I missing here? :/
Off-course you can't add IBOutlet because buttons what you added to WeekdayControl are in UIViewController, you can't add Outlet to WeekdayControl, buttons only subviews of WeekdayControl, UIViewController is boss here, and you can add outlet only to UIViewController. (Sorry for my English)
Better create you buttons programatically in WeekdayControl.
Must read first:-
You cannot use the UIControl class directly to instantiate controls.
It instead defines the common interface and behavioral structure for
all its subclasses.
The main role of UIControl is to define an interface and base
implementation for preparing action messages and initially dispatching
them to their targets when certain events occur
So, you are doing wrong, if you really need to make a custom view or custom control then you can directly do it by creating a custom UIView and connecting the outlets directly with the view.
I think you missing the objective of subclassing a UIControl, it doesn't give rights to create outlets as it's a subclass of UIView,just read this lines what it is stated in the docs:-
Subclassing Notes
You may want to extend a UIControl subclass for either of two reasons:
To observe or modify the dispatch of action messages to targets for
particular events
To do this, override sendAction:to:forEvent:, evaluate the passed-in
selector, target object, or UIControlEvents bit mask, and proceed as
required.
To provide custom tracking behavior (for example, to change the
highlight appearance)
To do this, override one or all of the following methods:
beginTrackingWithTouch:withEvent:,
continueTrackingWithTouch:withEvent:, endTrackingWithTouch:withEvent:.
Related
I'm trying a storyboard-free approach, and attempted the following:
I created a FooView.xib to hold my layout. It has a few buttons and labels.
I created a FooView.swift to hold a FooView subclass of UIView. At the moment, it doesn't really do anything.
I created FooViewController.swift to manage my FooView instances. I call it to create FooViews as follows:
init() {
super.init(nibName: "FooView", bundle: nil)
}
I set the File Owner of FooView.xib to the FooView class
I set the custom class of the FooView view as FooView
I dragged some #IBAction outputs from the IB to the FooView implementation
When my actions fire, I get a runtime exception: "unrecognized selector sent to instance" that references the FooViewController(!). I double checked the File Owner and all the outputs, all references look correct.
It acts like it ignores the File Owner with respect to the event dispatch.
(It feels like I'm fighting the framework and really am expected to implement all my outputs/actions inside the controller, but from an architectural purity perspective (to enhance testing) I was leaning towards hiding the xib control details and making a more opaque view that didn't directly expose its inner controls to the controller, but instead had a protocol/delegate kind of contract.)
I have a sneaky suspicion that if I moved all the xib-loading logic into the UIView implementation that things would work, but that feels like a larger adventure. Is there an easy way to set up my FooView subclass to receive the events?
Another thing you could use is set the First Responder as the target for your action. Although you won't get the nice neat indicator in XCode that you IBAction is connected, it will pass the message to the first class in the responder chain that implements that method.
To set it up in interface builder, click on First Responder and open the Attributes inspector. Add your method to the User Defined list as someAction: (don't forget the colon). Then you can connect your button to the first responder and that method will be an available option for you to connect it.
Lastly you declare your IBAction just like normal in the view class you want to implement it.
I have created a custom view (Quantity View) with nib file in Swift. I have created some IBOutlets & IBActions (for buttons, labels etc.) in my custom view.
I tried to use this custom view (Quantity View) by assigning class name to a UIView in my storyboard.
It's showing me all the IBOutlets & IBActions in the Connections Inspector, as shown in this screenshot: .
I just want to show only delegate for the Custom view.
Possible Answer:
I thought I can use the -viewWithTag to get the views instead of Outlets.
But, I want to know if it's possible with having Outlets also or if there is much better way to do this?
What are the other possible ways (optimum) to handle this situation?
You can also consider the following solution:
You can take the subviews of your QuantityViews(custom view) and you can identify the specific views by its frame origin.
Note : you should know the customview subviews frame
Its not possible to hide IBOutlets from storyboard if you declare the class members as IBs (IBOutlets or IBActions).
The IBOutlets or the IBActions are just indicators to the interface builder so that it can show the names on it when you try to bind them it actually calls the setValue: forKey: method to set the view's reference to the IBOutlet property.
Now if you try to access an subview from the file's owner class without any IBoutlets you need to have a pointer to point it, so for that either you can get the reference using ObjectID which is assigned to the subview by the interface builder or you can get it using the viewWithTag: method.
The ObjectID you need to find all time when you add or replace a subview from the view, so better and convenient approach is to use tag property of UIView class.
So my conclusion to this problem is to access the views using the viewWithTag method you mentioned earlier.
I think your way is correct. But sometimes Xcode doesn't work correctly.
The following makes the IBOutlets and IBActions reappear and work properly:
Clean project your project in Xcode.
Quit Xcode completely.
Delete all contents of ~/Library/Developer/Xcode/DerivedData/.
Restart MacOS just in case.
I hope you will resolve that :)
Where should I customise my IBOutlets?
Say I have created a button with interface builder, created an IBOutlet for it and I would want to change a property during runtime (ex: background color or localized title).
I would think of adding it to the viewDidLoad method, but outlets aren't yet created.
I remember having nil outlets in viewDidLoad, but I might be wrong.
If I move it viewWillAppear, the code will be executed every time the view controller's view appears.
Is there any better place for my IBOutlet related code, so it's only executed once?
Obviously I can do just about any customization using only the interface builder and making use of the User defined runtime attributes or localized stroryboards, but I don't like that since it's much more tedious to change later.
From the Doc
Its clearly says about the Views loaded into the memory in the -viewDidLoad() delegate itself.
I would think of adding it to the viewDidLoad method, but outlets
aren't yet created.
It is a false statement, Because you only get the viewDidLoad: message after IBOutlets are created. So you can safely do any customization in viewDidLoad:
Let’s say you have a Button you want to customise. You put the button at the place where you want it to be and then open the “Identity Inspector” on the right.
There is a textfield for “Custom Class”:
I usually create a subclass of UIButton / NSButton (depending on iOS or OSX) and edit the behaviour, drawing methods and functionality in this class file. Then just add the name of this class in this textfield. Voila!
I have derived my own View class from UIView that handles gestures and drawing itself.
I use Interface Builder to place several instances of it on a View.
On certain events, I want to call several delegates in the UIViewController, just like an UIButton::onTouchUpInside event. I don't want to set up an interface protocol and connect an IBOutled id instance, like in (1).
I was looking all around documentation and also stack overflow, but I haven't found any clue about the syntax.
So, what is the syntax for that with Xcode 4.4 (just updated)?
Deployment Target will be IOS >=5.0 because of the custom properties I already use.
[EDIT]
Subclassing from UIControl does give indeed access to the standard UI events like TouchUpInside, but is it possible to add custom named events like "onSomethingElse"?
(1) Events for custom UIView
I'm not entirely sure exactly what you want from this view, but if you want to handle things like UIButton::onTouchUpInside event, then maybe you should look into subclassing UIControl instead of UIView. It gives you access to events, just like UIButton.
If you post a NSNotification of whatever custom event you define, you can have multiple listeners registered with the NSNotificationCenter to respond to the event.
You can see details by looking for addObserver:selector:name:object: and postNotificationName:object:.
In many iOS books and tutorials they demonstrate how in interface builder you can basically turn a UIView into a UIControl and have it inherit new higher level functionality to respond to clicks and behave like button for example. This is done simply by changing the class type in interface builder of a selected UIView.
This is often done to dismiss the keyboard when someone touches on the "background" or main view of a given view controller. Once a UIView's class is changed to a UIControl you just assign connect a new IBAction for when a TouchUpInside event occurs for example.
Now I understand this concept but it seams like a weird Xcode hack. The reason is, I don't see how I could accomplish the same thing programatically. Let me explain: If I create an instance of a UIView in code and I want it to behave like a UIControl how would I tell this UIView instance that I want it to inherit from UIControl. Now keep in mind I don't actually want to subclass UIControl because that would be jumping through more hoops and I don't think that is what Interface Builder is doing when you change that class type, or is it? Also, keep in mind UIControl is meant to be an abstract class and not to be used directly otherwise I would probably just do that.
Ultimately my question is, is there an equivalent way to accomplish the same thing in pure code and have a UIView become a UIControl such that I can assign the higher level events to it?
I hope this makes sense, if not I can elaborate.
UIControl inherits from UIView, so if you wanted to do this programmatically, you would just create an instance of UIControl instead. So if you were creating a view controller's view programmatically, for instance, you could do something like:
- (void)loadView
{
CGRect viewSize = /* some appropriate default size */
UIControl* myControlView = [[UIControl alloc] initWithFrame:viewSize];
// configure your control (e.g., set events, etc)
[self setView:myControlView];
[myControlView release]; // omit this line if using ARC
}
I created xib file. then new Objective c class file inherits from
UIView. i set xib class Objective c class, in interface builder and
then change super class of Objective c class to UIControl.