NSOutlineView disclosure triangle vertically off center - swift

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!

Related

How can I make a NSTextfield with left or right indicator for validation?

I need to make a custom NSTextField with an indicator like this:
https://i.stack.imgur.com/LAhfA.png
On the right side, you could see an indicator icon.
What code I need to make this?
Thanks for all.
EDIT
The text never could be overlap the icon. The icon is not always displayed, but it can be shown when it is being written and when the text is correct, this text must also occupy the position of the icon.
A text field control is a view where the drawing is all done with an NSTextFieldCell. What you'd need to do is subclass NSTextFieldCell, and customize the drawing. Look at NSCell's API and you'll see there's a drawWithFrame:inView: method which is what does all of the drawing for the entire field. Various other methods of NSCell are used in this process.
Unfortunately some of how the drawing is done is a bit private and not eeeasily fiddled with, but the main thing is drawWithFrame:inView: will draw the background and then call drawInteriorWithFrame:inView: to draw the text. Off the top of my head, I can't remember if NSTextFieldCell uses titleRectForBounds: to determine what the text's bounds are, but I'm pretty sure it is. So you could override that to return a narrower rectangle, leaving room to either draw the validation icon with the cell itself, or use a subview.
Additionally, you'll need to adjust the bounds in which the NSTextView field editor draws and edits the text, otherwise when you view the field while it is not first responder it will look fine, but when you edit the field's text it will overlap the icon. For that you may need to adjust the frame given to editWithFrame:inView:editor:delegate:event:.
It's always a bit finicky to tweak text fields because it takes a while to find all the methods and code paths involved, but that's the gist of what you need to do.

ios autolayout constraints to resize view for screen size

I am new to ios development and still trying to get hang of autolayout. The problem that I am facing can be better explained with images below
Now I am removing the "Login with a social network" on iphone 4. What I want is how to center the google plus icon between the "OR Label" and "Start without registering" button
and it should also resize to fit between them.
what kind of constraints does it need to achieve that. If someone can point me in the right direction that would be great help. I have been breaking my head over this entire day. Thanks.
to center [g+] between [or] and [start ..] buttons:
you need to do two things.. on the storyboard:
select [g+] and [or]
select editor->pin vertical spacing
and then
select [g+] and [start]
select editor->pin vertical spacing
you should see a vertical line show up between the two objects each time. This is to indicate that that space will always be the same weather on a 3.5" or a 4" iPhone display.
I don't see why you want the g+ button to resize.. that actually goes agains the UI guidelines which instruct that different users shouldn't have different user experiences (see the reason behind why there isn't a replacement for the iOS 7.0 deprecated sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: method)
The same logic that discourages changing font sizes on labels/buttons depending on form factor etc resulting in different users having different experiences, is the same logic that would discourage you from scaling up or down your [g+] button depending on form factor circumstances as well.
If you're just trying to get the "g+" graphic centered between the "OR" label and the "Start without registering" label, you can:
Add a view (that you won't really see because you'll make it transparent, but it's useful for alignment purposes) whose top constraint is linked to the "OR" label and whose bottom constraint is linked to the "Start without registering" label:
Then put the "g+" graphic inside that view, aligning its center vertical and horizontal constraints with its superview's.
If you do that, the "g+" button will stay in the middle between those two labels (assuming, of course, that the "Start without registering" label has a bottom constraint to its superview, i.e. It's pinned to the bottom of the view).
In terms of resizing that button, I'd personally advise against that, if you wanted, you could, for example, remove that transparent view we created above, and just do that trick with the "g+" image/button itself. You will want to set the content size of that imageview to be "Aspect Fit" (so it doesn't get distorted).
Again, I really don't like that latter approach, but you can do it.
I gather that you want to remove the "Log in with social network" label at runtime. There are two approaches for that:
A simple approach is to create an IBOutlet for the height constraint for that label, e.g., logInWithSocialNetworkHeightConstraint and then you can do:
self.logInWithSocialNetwork.text = nil;
self.logInWithSocialNetworkHeightConstraint.constant = nil;
[self.view layoutIfNeeded];
The alternative is to define a constraint between the "OR" label and the "g+" graphic's appropriate view. This, itself, has two possible approaches:
You could define this in IB, but define it with a priority less than 1000. Because the constraints for the "Login with ..." label will have higher priority, when that label is there, those constraints will take precedence. If you you remove the label:
[self.logInWithSocialNetwork removeFromSuperview];
[self.view layoutIfNeeded];
Then the new constraint you defined will then come into play.
You could alternatively remove the "Login with ..." label and then programmatically add a new constraint between the "OR" button and the "g+" graphic's view.

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.]

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

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.

distribute option in interface builder of iPhone

i have following buttons in my application.
Now i want to set equal spacing among all buttons.
Suppose If I am using corelDraw or Photoshop, there is always an option for align & distribute.
Here I need to distribute my objects vertically.
How is that possible in interface builder of iPhone?
Sample image is given below, in which distribution is required.
alt text http://img268.imageshack.us/img268/4146/problem13.png
I know this post is ages ago, but for the sake of simplicity (maybe) and to avoid using table views (for sure)...
In your example, if you select the first UIButton, keyword, and press option key, interface builder shows you the relative distance from the center to any other object you hover with the mouse. So if you decide the optimal distance is the one between keyword and category buttons, you can apply that distance for the rest of objects simply adding or substracting the appropriate amount of pixels from the button size inspector.
Hope it helps!
Depending on the type of object, you might do this.
Select all implied objects.
Select Editor->Embed in->Matrix;
this will place the objects regularly.
Then select the option Editor->Unembed
and the objects will keep their new positions. Hope this helps!
I dont think there an option to do it automatically, you can do some math though and get them to have equal spacing by setting their frames...
Another option is to place all of these in a table (since they look like table view cells anyway), and adjust an empty footer view height to get the spacing you want between elements.
Of course that means you don't get to view the layout in IB.
It's even simpler - Simply drag a "Flexible Space Bar Button Item" from the Object Library in Xcode into each gap. It will automatically expand to equispace your other items.
&