Programmatically resizing NSSplitView - objective-c

I used to use and love RBSplitView, however I failed at reimplementing it programmatically as a certain version of xcode does not support IB plugins anymore.
Therefore I went back to using NSSplitView. NSSplitView is fine for what I need, the thing is that the autoSave of NSSplitView is broken. So I decided to implement it myself.
The thing I am doing at the moment is resizing 1 of the subviews of the NSSplitView.
What is the proper way of resizing an NSSplitView? - setPositionOfDivider:itIndex: should be the way to go ( haven't tried it ), however I do not know how to get the current position of the divider.
-- thanks in advance

In my experience, NSSplitView hates you and wishes you harm. RBSplitView is so much better, it is worth IMO the headache of programatic layout (and I've been so burned with the ShortcutRecorder IB plugins that I will never go back to IB plugins).
That said....
The only way that I know of to determine the current position of the divider is to look at the subviews, find the divider's view, take it's frame, and work out its position keeping in mind the dividerThickness. It is insane that you have to write that code, but the code isn't that incredibly difficult, and you can put it in a category.
Or go back to RBSplitView while you still can, if your needs are ever going to be complicated.

I'm using Swift here but the same method should exist in Objective C:
mySplitter.setPosition(123, ofDividerAtIndex: 0)

Related

Major NSTextView Rotation Problems

Bear with me on this one, as it's been frustrating me for a few days. This seems like it should be really simple, but for some reason I keep running into a series of frustrating problems. I've done more work on iOS in the past, and never had these kinds of problems that I'm having on OS X. I'm wondering if I'm not understanding something fundamental about the view architecture in AppKit. In particular, I am not very familar with the interaction between layer-backed views and plain views as I have not needed to animate anything on OS X before (and because iOS makes all views layer-backed by default).
Anyway, I'm having some major problems with trying to rotate an NSTextView object by 45 degrees. The text is for some labels that get placed in a larger custom NSView subclass, but most of that seems irrelevant to this specific problem. I'll go through what I've tried and the problems I had. The position of the labels is basically static, so I don't care about whether or not they are animatable or not. The labels need to be created and placed programmatically, not from IB, as their size and position is dependent on dynamically generated data. If it matters, the NSTextViews are using attributed strings.
1) I first did this the way that seemed most straightforward to me, which was simply to set frames for the NSTextView labels, added them as subviews to the graph object, and then called [labelTextView setFrameRotation:45] on them. This worked perfectly on Mountain Lion, but when I tested it on Lion the label height that gets drawn on screen gets increased mysteriously (even though when I log the frame afterwards it is unchanged). That isn't acceptable because I need it to draw a background color for the label so that it looks readable when overlaid onto the graph. So on Lion there is a bug or something in setFrameRotation as applied to NSTextView (or so it would seem). Does anyone know what is going on with that? It's very annoying that it works correctly on 10.8 but not on 10.7. SetFrameCenterRotation has the same problem. Making the view layer-backed, or not, seems to make no difference.
2) I next tried to do this using CATransform3DMakeRotation, after making the parent view and the NSTextView layer-backed. I used the line labelTextView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1.0);, but the text view doesn't rotate when I do this. As a test, I tried the same thing using a plain NSView with a colored background, and it does rotate correctly. Does anyone know possible reasons why this wouldn't work with an NSTextView?
3) I tried enclosing the NSTextView in a NSView container and then calling setFrameRotation on that. This does rotate it correctly, but somehow triggers an infinite recursion in Core Animation that quickly consumes gigabytes of RAM unless I kill the process! Again, any ideas about what's going on there?!?
4) I tried all of this using Autolayout to position the labels AND positioning them manually by setting their frames. No differences in results either way.
5) I could do this using completely custom drawing, but that would be a LOT of work in this particular case. I'd rather not do that just to support 10.7. I also could try NSTextField to see if it suffers from the same thing in part 1), but that would be annoying because I want some of the features of NSTextView (this isn't just a single line blob of text).
What am I doing wrong here? I never imagined something this simple being this difficult to get working correctly on 10.7 + 10.8.
UPDATE:
I tried substituting NSTextField for NSTextView and the problem in 3) goes away (the paragraph styling isn't exactly how I want it yet, but I can possibly fix that). Any ideas on why NSTextView has such problems with being rotated where NSTextField apparently doesn't? That seems insane to me. I'll try NSTextField without the container next to see if it also suffers from the drawing glitch on Lion.
UPDATE 2:
I tried just using an NSTextField instead of an NSTextView and rotating it, and that also worked completely fine on both Lion and Mountain Lion. The visual glitch where the size of the text view changes after rotation also disappears. So I guess the answer is that NSTextView is just totally incapable of having its frame rotated without triggering multiple bugs (especially on older versions of OS X). If that's the case, and NSTextView isn't intended to be used that way, Apple's docs should probably say so. Can anyone confirm that that is the case?

Infinite UIScrollView

I would like to implement a timeline, much like one you can find in iMovie or Final Cut, which you can scroll in either direction. Scrolling to the left would go back in time ( months ) and scrolling to the right would go forward in time, creating a smooth continues path.
What would be the best way to implement this?
Do tricky things with UIScrollView
Subclass UIView and try to re-create inertial scrolling
A disadvantage of recreating the inertial scrolling is if Apple ever decides to change it that my app will feel weird. I personally do not like it when an app does not feel system integrated, this includes games like tower madness where they made their own scrollview which works really bad and feels wrong.
Apple has and example project featuring infinite scrolling it's called StreetScroller, the description says:
Demonstrates how a UIScrollView subclass can scroll infinitely in the
horizontal direction.
I hope this helps you.
StreetScroller can only support no paging mode. I wrote a class based on the StreetScroller and support paging & no paging at the same time.
https://github.com/hellohalo/InfiniteScrollView

Is using autosizing or autoresizingMask on desktop projects bad?

Being a somewhat proficient iOS developer, I have just started working on a desktop OSX project in Cocoa and I'm running into issues that I just can't grasp. So this question is for the OSX developers out there.
I don't like the Interface Builder much, so I tend to write my views in code. The most prominent method I write my view layout code in is a view controller's loadView method, and at least on iOS I use autoresizingMasks for everything. Try out the view small, large, rotated landscape and portrait and if all is dandy, I continue with the next item on my list. Now on the desktop, the autoresizingMask works (or just looks) a little bit different. First of all the properties have different names, but their behavior also seems weird or unexpected.
When I ran into the issue below, I thought it must be my code was wrong, so after trying out long enough I re-created it with Interface Builder just for confirmation's sake, and guess what: I got the exact same result. Take a view with four vertically stacked subviews. Set the middle two to have flexible heights, the outer ones to be fixed. When you run it, size it down and back up again, I get two completely different layouts before and after the resize. See image:
Now I can follow why this happens from a mathematical standpoint between run loops, but from the point of an 'autosizing' or 'autoresizing' feature, this makes absolutely no sense.
Before I try to write the mother-of-all-resizing-topics here, might I ask you these questions? Feel free to elaborate some more on the resizing topic if you feel it adds to the post.
Am I a fool for not wanting to use the Interface Builder on desktop projects?
Should I depend on the autoresizingMask less than I would on iOS projects?
What are decent alternatives to making sure your layout lives up to standards without Interface Builder?
Cheers!
Yes, in my opinion. :)
You should depend on it when it does what you need. When it's insufficient, override resizeSubviewsWithOldSize: and/or resizeWithOldSuperviewSize: (or see below).
???
If you can target 10.7, look at the new constraint-based layout system. Check out the Cocoa Autolayout video from WWDC 2011.
You could also set minSize on your NSWindow to something large enough to prevent the singularity.
I'm not sure I'd say "fool," but refusing to use Interface Builder on the Mac is a very…avante-garde choice.
You should definitely use autosizing on your views.
Be maniacally attentive and spend lots of time making sure everything is right. (This is why I don't recommend going without Interface Builder. In general, what you get is a lot of wasted time that you could have spent doing something else.)
In this case, I think the best approach would be to set a sensible minimum height for the window. Don't let it get too small to display what it needs to display.

Recreate the BookCase in iBooks

I just wanted to know how you could implement a bookcase, like in iBooks, into your iPhone app.
I presume you would need to use a UIScrollView, but then I read somewhere that you need to use a UITableView. Which is it?!
You'd use code that others have already written, such as AQGridView.
I'm not sure if there's a better way, but you could create multiple small views or images (these would represent each book) then add these small views/images to the subview of a larger view in a linear format (leaving a space between each element). Then just set the background of your larger view as an image of a bookcase. Sorry I don't know of a better way.
And for the above solution I would use a UIScrollView.
You can implement it anyway you like, but it seems to me that a UITableView would be the easiest (which will scroll anyway). All of the magic will happen in your UITableViewDataSource, which is where you will decide what books are placed on what row.
Once you have decided which books to display you will have create a custom tableview cell that draws the appropriate objects.
To be honest, while not too difficult of a task, it will take a lot of effort to get looking right. If you are not comfortable with custom drawing then be prepared to spend time learning about the various image/graphic APIs.

Cocoa + CoreAnimation: Animated List of Custom Subviews

I've been trying to get this right for weeks now, and though I've learned a lot through my misfires, at this point, I just need a solution. The issue is with unpacking the seemingly overlapping graphics and UI APIs included in Cocoa, many of which produce similar effects, but feature unique limitations that I've often discovered only after investing many hours into an implementation.
I'm new to Cocoa, but not to programming, and I'm trying to create a Mac app with a very customized UI – think Capo, Garageband, or Billings. One view in my window will display an ordered list of subviews, each of which does a lot of custom drawing, and each must support a "selected" state and drag-reordering. The subviews do not need to support being dragged outside of their superview.
Ideally, a drag will give animated feedback as it happens, pushing neighboring sibling views to make space, e.g. toolbar icons or the Safari bookmarks bar. The trouble is, I can't seem to land on the right pack of technologies to get this right. I've done the subviews as NSView subclasses in an NSCollectionView and also as CALayers in a custom CollectionView-like NSView, and neither seems to offer the perfect solution. That said, the first option seems the better of the two for its superior handling of mouse events.
I've not yet tried doing this as a TableView, and I don't want to go down that path without some indication I'm on the right track. Extensive Googling has shown only that there aren't any up-to-date resources on CoreAnimation-enabled reordering or dragging. As such a standard feature of the OS X UI, I feel like this should be easier!
Any help from anyone on what the right tools are for this job would be greatly appreciated. TIA.