I want to make a panel in Interface Builder with buttons and stuff on it. Then I want to programmatically clone it and reposition the clones with affine transforms.
I'm thinking of something like a MovieClip from Flash.
And it isn't sufficient to just render the same UI element multiple times. For example, it should be possible to type something different in each text box.
Any ideas?
Create a new NIB file that contains your custom view.
Create a UINib instance from that NIB file with +[UINib nibWithNibName:bundle:].
Whenever you want to create a new view, call -[UINib instantiateWithOwner:options:]. The array that this method returns contains all top-level objects of your NIB. So if the NIB file you created only consists of a view, the array contains this view as its only element. Make sure to retain the objects in the array.
Related
I'm just learning about nibs and swift and am curious about something. I know that if you have a main.storyboard file, that a nib is loaded first fir the root view controller, then for any views that may exist hierarchically under that view controller, however... I'm wondering something.
When they say a nib is 'loaded' does that mean that, a single function CALLS instances of the ui objects that you would like to load, based on the storyboard that you have built in the interface builder?
If not, what is the right way of looking at this? I'm trying to collect an easy to understand, accurate mental model of what happens.
Thanks!
What exactly does a nib file look like if you were to look inside?
Go right ahead and look inside and see! It's just an XML file; perfectly readable by a human.
I know that if you have a main.storyboard file, that a nib is loaded first fir the root view controller, then for any views that may exist hierarchically under that view controller
Correct! To be more precise, think of every "scene" in the storyboard as comprising two nibs, one containing the view controller, the other containing its view, the view's subviews, and everything else constituting that scene.
When they say a nib is 'loaded' does that mean that, a single function CALLS instances of the ui objects that you would like to load, based on the storyboard that you have built in the interface builder?
Think a nib as just a bunch of potential object instances. Loading the nib turns those potential objects into actual instances. Loading a nib is thus just another way of instantiating and configuring objects. A nib being "loaded" simply means that the nib is read and the objects it describes are instantiated and retrieved. That is why you can load the same nib multiple times to get multiple instances of those objects.
So I've got a table view which display a number of dots depending on some other data. Each cell in the table view contains a different number, and needs to display a certain number of dots according to that number. So for example, cell 1 corresponds to 5 dots, cell 2 corresponds to 3 dots, so on.
Since all the cells contain at least one dot, I have created a prototype cell which contains a single dot (called a dotView, which is a custom View that I am using).
I would like to basically duplicate the dot several times to match the number that I need.
The dots are aligned and positioned vertically, so I just need to copy and paste the dotView above itself, but treat it as a separate view so I can access its' members without altering any of the other dotViews.
If successful, will I need to set the auto layout parameters myself? Or will it inherit some of the prototypes values?
You can certainly do it if you're just designing things in the nib (storyboard). Any view you see in Interface Builder can be duplicated; just say Duplicate (or Option-drag). You will then have to configure the new copy completely.
You cannot, however, magically "copy and paste" an existing view in the interface in code, while the app is running. The standard way to do this sort of thing in code is to design the custom view in a .xib file. Then, whenever you need a new copy of this view, you load the nib and retrieve it. This is basically just an elaborate way of making a new but completely configured instance of this view (and all its subviews, settings in the nib, etc.). You will then need to insert the newly instantiated dot view manually (i.e. in code) into the interface wherever it is needed. Positioning it is up to you, and if it needs constraints, you will have to add them as well.
I have one xib file for a custom UIView subclass. Works fine. I'm able to load the correct nib and create an instance of my class and it contains all the subviews I added to the xib file.
However, I have also subclassed this view, but I can't figure out how to create an instance of this class and get it to use the xib file used by the parent class. Is this even possible? I don't want to create a new xib file for my subclass, since the view hierarchy, subviews and GUI looks the same, it's just the code that differs.
Can I load a nib and "connect" it to another class than the one specified as the "Custom class" in the xib settings? Or can I create a new instance of a view and tell it to use a xib of a certain name?
You can try to write something really weird with -awakeAfterUsingCoder: to substitute created object, but this is really shaky and a few can get it right.
The thing is that .xib file stores set of serialised objects, when this set is loaded, information about each object, i.e. it's class, size, other attributes, parent object, constraints are as well deserialised and applied. So, xib files store which class should receive +alloc and other messages and, consequently, which objects will then receive all the attributes via KVC (-setValue:forKey:). So, no, you can't just configure some class to load some xib, because xib file tells which class should be loaded.
As a soulution I'd suggest to refactor your code, (for example) incapsulate different subclasses logic to some other object. So, before you had multiple subclasses with different logic, then, you'll have single class, loadable from xib, but you have to set some MyDifferentLogicVariant1Implamentor entity to preserve different logic for 'different' classes.
Superclass - Subclass1 - Subclass2
vs
Superclass.differentLogic = DifferentLogicImplementor1
Superclass.differentLogic = DifferentLogicImplementor2
I'm learning about xib files and just starting to understand why people use them as well as or instead of storyboards. My question is about how and when it's appropriate to use the xib as a "template".
Let's say I have a xib mapped to my custom UIView subclass - I know how to set that up in IB - and my xib has a UILabel subview. This is a very simplified example just for the purposes of the question, but basically I'm trying to create a view that can be reused for each screen of an iOS "introduction" walkthru, like the panels of https://github.com/MatthewYork/MYBlurIntroductionView
So I want to set most of what's in the view up at design time, and most of it will be common to each instance. The text I want to put in the UILabel is going to be static (i.e. I know it now at design-time) but each instance of the view will have different text. So let's say that I want to position the UILabel in different places in each instance, depending on how much text is in it etc and whether it's covering something else important. Now, I know I could do this programmatically, i.e. have the label as a #property linked up in IB and then set frame position in the code, but as far as I understand it the beauty of using xibs is that you can do known things like this at design-time.
As far as I can see my options are:
Load new instances of the xib and set the position etc programmatically as mentioned above (would rather not if possible)
Create my template xib, setting all the common stuff, and then make copies of it "CustomView1.xib", "CustomView2.xib", etc. (a bit yuck but not too bad)
After creating my template xib, use the storyboard to drag in new UIViews and somehow set each to be linked to my one "CustomView.xib", and then somehow do my static repositioning of the subview UILabel within each of those UIView instances on the storyboard. Is that possible? If so that'd be great. Obviously I know I can set each of those UIViews to be instances of my UIView subclass, but I'm just missing the link between doing that and customising each instance. Does the file's owner have something to do with it?
Do I need to create a custom view (i.e., a subclass of a UIView where I override drawRect) in order to eventually make an array containing those custom views? Because I ultimately want to make a scrollView that implements page control and displays a number of views (i.e., the array of custom views) on separate pages. The views are just an UIImage above three buttons. And the image for one view is different for each other view (e.g., electronic flash cards).
It doesn't look like you need a custom view to override drawRect: since you are looking to build a collection view using a single image view and three buttons. However it will not hurt to create one so that accessing the sub views can be done via named properties. For example, customObject.imageView and customObject.firstButton. As a unit it makes sense to create one as it will be messy to keep track of all the image views and buttons you would end up adding to the scroll view otherwise.