Vertically add elements to a scrollview: diffs between Java and iPhone SDK? - iphone

Folks,
coming from the Java/Swing world, I am sometimes puzzled by the UI programming on the iPhone. I've spent the last hours with Googling for information but it seems that I asked the wrong questions by thinking too much in Java. Could you please point me to resources to get more familiar with the GUI concepts to be able to achive the following functionality:
Basically, I want to create a vertically scrollable view that represents structured text (for example, a recipe). Each step consists of a title and a textual description. As I want to fold and unfold such steps, the title would be somehow interactive and by clicking it the description would be displayed or hidden.
In Java, I would create a component that renders one such section. The layout manager would compute the components preferred height (with or without description being displayed).
Then, in Java, I would create a panel with a vertical layout manager and sequentially add my components. This panel would be placed in a scroll pane; the scroll pane would ask the panel to layout itself and then show a viewport on it, if for example the height is bigger than the scroll pane's height.
What Java provides me is:
layouting of elements (computing their preferred height and width), thus no need to deal with coordinates and dimensions
dynamic creation of UIs by creating and adding components during runtime
What I understood on the iPhone:
I can dynamically add views as subview to a view, e.g. a scrollview by calling addSubview
I can even remove that stuff using removeFromSubview (as explained here Clear content of UIScrollView)
What I don't understand on the iPhone:
does one view always correspond to a visible screen (I did use tab and navbar navigation so far and there whenever I set a new view, it fills the current visible screen minus the space needed for the two bars)?
or is it possible to define a view that contains a label on top ("north") and a text in center; if so, could such a view automatically determine its height?
can I realize my example in a similar way like in Java or would I need to calculate all dimensions and coordinates of the individual components on my own? (This example seems to touch on that topic: iPhone scrollView add elements dynamically with id)
Alternatively, could I use a WebView and render my stuff as local HTML using JavaScript to show or hide nodes?
Thanks for any hint or link!

There are no layout managers in Cocoa, views are being reposition according to their struts and springs settings. For information on that read the documentation: http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/IB_UserGuide/Layout/Layout.html
To create a "view that contains a label on top and a text in center" you create a view with subviews - one being a label at the top, second the textview in center. If you configure struts/springs for all of subviews properly, they will autoresize when the container view is resized.
You should also get accustomed to Interface Builder, creating views in code is real pain in the ass.

Related

Available height to position UI elements assuming keyboard always shows

I am encountering a problem that I'm not sure how to solve. If you look at the screenshot below, you'll see that the UI is laid out so that it neatly fits into the space between the safe area layout guide's top anchor and the top of the keyboard.
The keyboard will ALWAYS be shown in this view controller. But I need a way of knowing what the height of the keyboard is so that I can do some math to figure out how to tall to make the UITextView (the red box).
I tried the approach of registering for notifications on when the keyboard will show, but that is too late.
I need a way of knowing the height of the keyboard before the view renders so that I can configure the height of each of the elements in the UI.
Is there a way to do this?
Thank you!
One option would be to capture the dimensions of the Keyboard when it IS presented then pass those dimensions into this view.
However, you will also want to make sure that you are handling cases such as the split keyboard on an iPad and things of that nature.
For that you might choose to look at the documentation on using the keyboardLayoutGuide and use it with some constraints.
https://developer.apple.com/documentation/uikit/keyboards_and_input/adjusting_your_layout_with_keyboard_layout_guide

What should I look out for when combining Autolayout and positioning in iOS?

I am working on an iOS project that uses auto layout to set up a view with a scroll view and a stack as the scroll view's content.
All works well, and I can add UIViews until the cows come home to the stack and it does what is expected.
However the question now arises when I am about to implement the user-definable layouts for the reporting view.
The stack holds a view dedicated to user defined layouts.
The user will define the data output (for example "benefits") and the origin (top left corner) and that view will be placed there. They can place as many or as few views and pieces of data that are made available to them in this manner. They will have no understanding of auto layout and hence will solely rely on the exact positioning of these views via the top left corner and their size.
Is there anything I should be aware of before starting this phase of the project? My concern is the mixing/matching of auto layout in the global layout and exact positioning inside this one specific view.
Looking for input on caveats, code that I MUST include (for example any flags that should be set) and so forth.
Thanks for any sort of help,
D
Thanks for all the suggestions.
My concept was a little to involved for the suggestions given, however I did develop a solution that allowed the user to position the widgets by origin (top left corner) while still using AutoLayout.
For those interested, I created a "dummy" UIView to hold all of the user positioned widgets and then created Autolayout constraints based on the top and left anchors of this view.
Since the widgets are created by reading the layout from a Dictionary, if they make changes to the layout, I simply remove/refresh the layout if they make a change.
Thanks once again for the nuggets, without which I would not have thought of this solution.
D

NSOutlineView disclosure triangle vertically off center

I'm working with an NSOutlineView on a macOS app and it provides disclosure triangles for items that can be expanded.
I'm also creating custom NSTableCellView items rather than using basic cell items. This allows me to create the cell how I want visually.
My issue is that when they're displayed, the disclosure triangle on the left is not centered vertically.
Notice how the disclosure triangles are not aligned properly. They're a bit lower than they should be. If you scroll away and come back, sometimes, they automatically align themselves correctly. Has anyone been able to fix this issue before?
For what it's worth, I'm using the following code as well for the cells.
self.outlineView.rowHeight = CGFloat(integerLiteral: 66)
self.outlineView.usesAutomaticRowHeights = true
It's hard to figure out what the problem is without seeing how you've set up your project, but I'm going to give it shot.
First, when usesAutomaticRowHeights is set to true, the outline view uses Auto Layout to position the cell views. Thus, you need to be utilizing constraints in your Storyboard or Nib file, or things will behave strangely (see: your picture). If I had to guess, the prototype cell view you set up in Interface Builder is having its autoresizingMask translated into Auto Layout constraints (which, generally, causes a boatload of problems).
What I would do is this:
Open up the Storyboard or Nib document containing the outline view.
Locate the prototype NSTableCellView instance that contains the street name text field in the Document Outline to the left of the canvas. (If you don't see the Document Outline, you can open it by clicking the item at Editor » Show Document Outline in the main menu).
Next, see if you have any constraints in place. If you do, remove them by selecting Editor » Resolve Auto Layout Issues » Clear Constraints under the menu item "section" that's titled All Views in ${YOUR_SCENE}.
Now, depending on what you're going for, there are different ways to go about setting up constraints, but here's what I would suggest. Assuming you want the street name to be centered vertically with the disclosure triangle, I would add a vertical constraint between the text field and its parent cell view like so:
With the text field selected in the Document Outline, click the Align icon in the lower right-hand corner of Interface Builder's main canvas area (see image).
In the popover that appears, check the checkbox next to Vertically in Container.
In the text field on the right side of the popover, enter a value of “0”.
Finally, click the “Add 1 Constraint” button.
You’ll probably see a red error (or yellow warning) sign show up, as the view has now opted into Auto Layout, but it only has a metric for its vertical position. So we now need to add some constraints to describe where the text field should be positioned on the x axis. Like before, we’ll define the constraints using the popover buttons on the lower right-hand side of the canvas:
Click the Add New Constraints button (the one to the right of the Align button).
On the diagram at the top of the popover, click the faint red lines on the left and right side of the white rectangle. This is telling Interface Builder we want to add leading and trailing constraints.
Now, enter the desired padding you want on each side of the text field. In the example image, I went with “4” points on both sides, but obviously, you can use whatever value(s) you think works best with your layout.
Finally, click the “Add 2 Constraints” button.
Any warning(s) that were present should now disappear, as we've added enough constraints to describe the position of the text field. In theory, you should now be able to build and run your project, and the text fields should be aligned with the disclosure triangles. With that said, there are plenty of other reasons a layout can get finicky, and considering usesAutomaticRowHeights is a new API in macOS High Sierra (and Steve Jobs is no longer there to beat it into Apple developers to make everything Just Work™), there could be issues that I'm unaware of.
Alternatively, you can set usesAutomaticRowHeights to false and have some object (e.g. a view controller, a NSObject subclass, etc.) conform to the NSOutlineViewDelegate protocol and implement the outlineView(_:heightOfRowByItem:) method to return any arbitrary height you want for different rows. The nice thing about sizing rows this way is that you can allow certain rows to be larger or smaller, depending on the role of the corresponding item. There are lots of tutorials on this, so I won't regurgitate a half-baked explanation here, but feel free to Google “Conforming to NSOutlineViewDelegate protocol” for more info.
Anyway, try the steps above, and see if they do anything for you, and if they don't, let me know. I can go as deep into the rabbit hole with you as you need, so just ask. Good luck!
For those like me who stumbled upon this issue many years later, here's the fix that worked for me, and requires a lot less work.
NSOutlineView has a function frameOfOutlineCell(atRow:) and the documentation states: You can override this method in a subclass to return a custom frame for the outline button cell
You can override the method in order to provide a frame that's actually in the vertical center of the row. And an important point that I learned from trial and error, is that you don't even need to provide that updated frame. Not sure if this is a bug or what, but for me, just calling super.frameOfOutlineCell(atRow: row) in the function override was enough to make the disclosure indicator appear in the correct location.
So my subclass of NSOutlineView is this:
class MyOutlineView: NSOutlineView {
override func frameOfOutlineCell(atRow row: Int) -> NSRect {
super.frameOfOutlineCell(atRow: row)
}
}
That's all. Hopefully that works for others as well!

Steps for creating a custom view

How can I create a custom view with a custom style? I have many TextView's in my layout and its kind of difficult to manage all of them. I want to group them in a custom view with custom look (a box with rounded corners) and in my code just give the values to the custom view code to handle it itself.
What I am looking after is something like:
Can someone plesae tell me the steps to create such custom view with rounded box and few TextView's inside it?
Two approaches:
You can create a layout for your view. You need to take different layout widgets like textviews etc. and assign them values.
You can use canvas to draw such view.
The proper way is to inherit from View. Either programatically or in designer You assign any layout to this view. To the layout You assign Your elements ( TextViews, whatever ).
Create methods in the derived View class which fill the inner elements, something like getters/setters, like properties in c#. Those are public.
Then place Your custom compound control onto Your main view.
I for myself created a column orientated tablecontrol with custom scrollbar this way ( but pure via code ) and it works very well. Ah, and additionally You can draw shapes on Your derived view, which allow You relatively simple to apply round corners, and even color transitions.
I'm assuming you're using eclipse to create your android project.
Go to your src file and create a new layout (relative layout works best here). There is a visual representation of the layout you're creating so you should be able to play around with it. Drag and drop the textviews where you want them and give them unique names. Then in your java code, call the textviews like:
TextView text = (TextView) findViewById(R.id.textview_name_here);
text.setText("Your Text Here");
There are plenty of examples online.

XCode 4 Interface Builder: A better way to work with lots of overlapping views

In IB I have quite a few views that are shown. Many of them are hidden when the app loads, but are shown later when buttons are pressed. This is all fine, but when building this layout in IB it is extremely difficult to layout anything because there are so many overlapping views, some of which are partially transparent (ones that are set to hidden) and other are completely overlapping and covering others. This makes layout very hard.
What is the best method when laying out lots of views like this? Is there another way to break things up? Or better yet, can I hide a a view completely (like in photoshop) so that I can edit the ones underneath, then turn that layer back on?
Another option when trying to select a view that is obscured by another is the shortcut:
'ctrl' + 'shift' and click
It displays a list of all the views under the cursor.
I'm not aware of any way to hide objects in the canvas, but a useful trick for complex layouts is to double-click an item in the document tree to the left - this selects the item and puts focus on the canvas, you can the use the cursor keys to nudge it about.
This doesnt solve the problem of not being able to see things because there are, for example, five or six labels occupying the same space, but if that is the situation it may be a better idea to have a single label and change its contents in code.
I ran into this issue for an app I'm building that has an arial-view image of a park with clickable hotspots. When a hotspot is clicked a popup UIview is displayed with information about that spot in the park. I use the same VC/XIB for three parks. This makes the XIB really busy and hard to work with (i.e the same issue that you have) The detail UIViews make it hard to work with the views underneath. My workaround was to pick each detailed UIView that was hiding the part of the XIB I wanted to work on, and add 1000 to the UIView origin.x in the size inspector. This moved those UIViews enough out of the way for me to do what I needed to with the XIB. Then when I was done, I moved them back by x 1000. (I just needed to move them out horizontally to do what I needed to)
I know its clunky but given that XCode does not have a convenient way to hide portions of an XIB - it was the quickest approach I could think of!
One approach to handling overlapping items in IB is:
Ensure the groups of items that you want to hide are grouped into Views.
Give these Views names: e.g. ViewOptionA, ViewOptionB and ViewOptionC.
Can do this by clicking on name of view in the tree while it is selected and then typing new name.
When you want to hide one of those groups of items:
a) Select the View by either:
i) Clicking on it in the tree at the left or
ii) Ctrl-Shift Clicking in the layout editor and then select the view from the list.
b) In the Attributes Inspector set Alpha to 0.
When you want to unhide one of those groups of items:
As for 2) but set Alpha back to 1
[You do need to remember to unhide all views before you publish!
If you are forgetful like me then perhaps you could subclass UIView and set Alpha to 1. I haven't tried this subclassing idea yet.]