I have an old app source code that uses storyboard & xib without auto layout or size classes. Even though I am rewriting it from scratch, it would take some time as number of modules are too many. The immediate need is to fix the code that manually sets frame of UI elements by detecting screen size at runtime. So a code written this way places elements outside the safe area:
self.controlBarBkg568h.frame = CGRectMake(0, CGRectGetHeight(self.view.bounds) - tapBarBackgroundImage.size.height, CGRectGetWidth(self.view.bounds), tapBarBackgroundImage.size.height);
Since there are so many interface elements that are placed this way, I am wondering what is an easy way to fix the code that works on iPhone X?
Use the safeAreaInsets property on UIView. This is a UIEdgeInsets object that describes the safe area for the current view. (Documentation)
In your specific case, you should be able to change your code to something like this:
self.controlBarBkg568h.frame = CGRectMake(0, CGRectGetHeight(self.view.bounds) - tapBarBackgroundImage.size.height - self.view.safeAreaInsets.bottom, CGRectGetWidth(self.view.bounds), tapBarBackgroundImage.size.height);
If you have many views positioned this way, you are going to have to edit them all to respect the safe area. This is one of the downsides of manual layout — it's hard to change in the future (especially if there aren't any helper layout variables where you can edit many variables at once).
More documentation about positioning content relative to the safe area is available here: https://developer.apple.com/documentation/uikit/uiview/positioning_content_relative_to_the_safe_area
Related
So my view is pretty simple to setup but I can't figure out how to do a specific task.
So what I need to do is take in an array of strings, each one of these strings are a country ISO3 format code which in turn have a corresponding flag associated with it. Now after I add the flags to the view I need to be able to set all the constraints.
So first I add the imagesviews to the view, that works fine but now when I get to the updateConstraints method I am unsure how to proceed since I have an unknown amount of subviews.
So each subview will be placed about 5 spaces apart from the flag before it and the top of the image and bottom of the image should span the views height.
How can I write code that handles an arbitrary number of subviews?
So first i add the imagesviews to the view
As you do that, also add each view's constraints. Since you are looping through the flags / image views, you know whether there was a previous image view and if you've taken a little care, you have a reference to it. Thus, there is actually not a lot of code — it's a loop, and not a very long one — and it isn't at all difficult.
As an alternative, I suppose you could use a UIStackView (if you are not running on iOS 8). It will just take all the image views and space them out with constraints for you; all you have to do is decide on its size, which you can presumably do by counting the image views.
I'm an intermediate iOS developer who's trying to jump on the OSX side of things.
I've been struggling to create an accordion-like display of several views, where only one view at a time can be unfolded to occupy the whole parent's view's available space. In other words, click on a view's title bar, it will both open/unfold this view and close/fold the currently open view, with animations'n'all. Oh end, I need the views' contents to be scrollable.
I tried starting from Apple's NSStackView sample code, but first it is not quite what I want, and what's more, I can't figure out how to start from here to end up where I eventually want to be.
Then I tried to master the Auto-Layout facilities but with no success. Truth be told, this whole Auto-Layout thing still confuses me some.
Does any of you have clues as to how I should proceed? Sample code? Tutorials (I tried several Auto-Layout tutorial but at the end of the day they still leave me missing the tricks I'd need to figure...).
Thanks.
/Julian
Check out the sample code: InfoBarStackView. It creates an accordion-like interface, the one difference from what you're describing is it lets multiple views be revealed at the same time (although, that's a simple difference).
It uses NSStackView and autolayout constraints to create the interface and drive the reveal/hide animations.
The stack view could also be put into an NSScrollView to allow the content to be scrollable. (Something similar was done during a WWDC 2013 Cocoa Animation talk).
First time building a user interface, had a few general questions
1) Does it really matter if you drag and drop view objects into view controller.. or if you programmatically add subviews and specify frames and fonts? What's the better approach to take?
2) In the programmatic approach, I end up guessing frame values, (x,y) points, and then checking in simulator if I like it. Is this the right approach, or are there faster, better ways to build out the UI? Maybe methods I'm not aware of?
3) Any useful tutorials/pointers in the right direction on how to get started?
Thanks!
1) Both approaches are fine, but the Interface Builder is usually better if you have a more static UI. In a more dynamic app (where views appear and disappear, or if you use UIViewController containment), you need to add/show/hide some of the views in the code. Even in that case you can design individual views in the IB, to make sure they look good, and then instantiate and display them in the code.
2) If you design your views in the IB, then the problem of guessing the sizes largely disappears. In some cases it can be useful to have an empty view added in the IB, which acts as a placeholder for your dynamic content. Then, when you add a view to it in the code, you just use the superview's dimensions so your view fills the placeholder.
I am trying to create a view for a kind of brainstorming application like, for example, OmniGraffle, with elements that contain textviews and can be dragged around. (Also, the should be connectable with arrows, but that is not (yet) the problem)
I did my homework and searched via google and read books about cocoa, but there seems to be no similar example around.
Since I am also new to cocoa, I’m a bit helpless here.
The thing I am sure of is, that I need a custom view in which I can create my elements - what I tried until now to do that is:
First, I searched for the syntax to add subwindows to a window to create my elements. Subwindows, I imagined, would automatically be movable and come to front and so on.
The problem: As the experienced Cocoa-programmers of you probably are not surprised, I was stunned to find nothing about anything like that - this seems to be something, that is just not intended in Cocoa?!
Then I thought about creating subviews that contain a custom view for the title bar drawing (where the user can click to drag the element) and a NSTextView.
Problems:
I read, that it is not so clever to create dozens of subviews in a window because that would be very slow (or would that be not so bad in this case because all the subviews would be instances of always the same class?).
Also I can’t find out how to load a subview from a nib- or xib-file. Would I need a viewController? Or would that make the dozens-of-instances-problem even worse?
And Apple tells you not to overlap subviews (okay, that would be not so important, but I really wonder how the guys at OmniGroup made OmniGraffle...)
Because of that, I now wanted to do the title-bar-drawing in the surrounding custom view and create the textview programmatically (as I understand, a text-“view“ ist not really a view and takes its functionality from NSCell to reduce all the effort with the views?).
Problems:
Even that failed because I was not able to create a textview that doesn’t fill the complete window (the initWithFrame: of the [[NSScrollView alloc] initWithFrame: aRect] just seems to be ignored or do I get that wrong?).
Also, there should be some buttons on each element in the final application. I imagine that would be easier to accomplish with a subview from a nib-file for each element?
Well, now that nothing works and the more I read, the more problems seem to occur, I am pretty confused and frustrated.
How could I realize such a program? Could someone please push me in the right direction?
I created a class for the draggable elements where I save position, size and text in instance variables. In my view, every new element instance is added to an array (for now, this works without a controller). The array is used to draw all the elements in a loop in drawRect:. For the text of the element I just use a NSTextFieldCell which is set to the saved text from every element in the same loop.
That way it is also possible to overlap the elements.
I’m starting to develop my first full-blown Cocoa application containing a view which I would like to behave (and look) similar to Automator’s AMWorkflowView.
The basic features I’d like to achieve:
Positioning of subviews
Display of subviews in expanded / collapsed states
Multiple selection
Drag and drop
In order to get accustomed to Cocoa, I started with a custom NSView which mainly served as a container for the custom subviews and handled their positioning and multiple selection.
The subviews are also subclasses of NSView, and contain a variable amount of views themselves, like buttons, labels and popup menus, and therefore can have different heights.
This worked quite well, but before going on, I want to make sure to have everything neat and tidy according to the MVC pattern.
I suspect that there already is a class in Cocoa that facilitates the implementation of a view container, like maybe NSCollectionView.
It seems that there is no (easy) way to display differently sized views in an NSCollectionView, though. Should I continue implementing my custom NSView (probably using an NSArrayController for selection and sorting support), or are there better ways to go?
Any help is much appreciated
Unfortunately the answer is you'll have to roll your own. NSCollectionView does not allow for variable-sized items (which also rules out expanded/collapsed states).
For a limited number of items, you can accomplish this rather easily (you just need a container view that arranges the subviews properly when asked to layout, then you need to make sure you re-layout when things change). For many subviews, however, you'll need to take care to be as efficient as possible. This can start with laying out as little as possible (only those "after" the resized view, for example) and get as complex as caching a visual representation of a prototype view, drawing the cached images (fast!) for all but the view being edited, and only using/positioning a "real" view for the view being edited.
Drag and drop works the same as it always has, but none of the above accounts for the pretty animation NSCollectionView gives you. :-) It's fast and beautifully-animated precisely because all the subviews are uniform (so the layout calculations are fast and simple). Once you add irregular sizes, the problem becomes significantly more complicated.
The bottom line: If you need variably-sized views, NSCollectionView will not work and you'll need to roll your own or find someone else's shared code, but performance and beautiful animation will not be easy.