I'm relatively new to Cocoa programming, but I've managed to figure a fair amount out. One thing I haven't been able to figure out yet is how to have an element that is visible over all views. Like a volume control that is always visible just above the tab bar at the bottom of the screen.
How should I go about doing that?
If you just need to bring a view to the front, you can use bringSubviewToFront:, like so:
[self.view bringSubviewToFront:yourSubview];
If you need to position subviews so that they overlap in a certain way, you'll want to make use of CALayer. Just be aware that overlapping UIControl elements goes against Apple's Human Interface guidelines.
Related
I have a cocoa application that has a dozen scrollViews. I love the elasticity, especially in some cases where I'd actually put some kind of "Easter egg" (kinda like the apple logo in the books app. you scroll down, you see an apple logo.)
My problem is, that I need to limit the amount of exposed content beyond the actual content area. When I scroll with the magic mouse, especially, the elasticity causes the whole scroll content to disappear! Until you release the scroll, it moves back in.
Now, I would like to limit the elasticity to a specific margin. how?
NSScrollView manages a view which has a "canvas" bigger than what is/can be display at any one time. So if you want a different behaviour:
Check (void)setHorizontalScrollElasticity: but that doesn't quite do what you want. (you want to allow a fixed amount of elasticity)
Subclass NSScrollView to implement the behaviour you want.
Create your own class from scratch (well... Anything inheriting from NSResponder since you want to handle events).
For example, I once wrote a world-map program but needed the map to loop forever on the horizontal axis. I just manually managed the scrolling with a subclassed NSView. (don't have access to code currently)
Something to ponder about: I understand your reasons but just wanted to mention it. The behaviour should be expected by the user. If it looks like a button, it should act like out. Currently, scrollviews have the elasticity so that when they scroll via momentum (user is no longer touching), it doesn't stop suddenly once it reaches the end... which would be jarring for users.
Example
If subclassing NSScrollview, I would try overriding - (void)scrollWheel:(NSEvent *) and detect what are the bounds of the contentView and cap it at a certain value. Something around the lines of:
- (void)scrollWheel:(NSEvent *)event
{
[super scrollWheel:event];
if (self.contentView.bounds.origin.y > SomeConstant)
/* cap the value */
}
How could I move a subview to the front of the stack when the LevelMeter detects a certain amount of decibels? I want LevelMetering to be active in real time without a record play function.
Ultimately, I'm trying to animate a mouth to open and close based on sound.
To make a view topmost in the view order, you just have to send a -bringSubviewToFront: to the view that contains it. From a view controller, you might do something like:
[self.view bringSubviewToFront:levelMeterView];
If that doesn't answer your question, perhaps you can expand a bit on what you're asking?
In order to categorize a wide variety of unique views, I have an elaborate setup: main categories are selected via a toolbar, and then specific panes are selected in a category's NSScrollView. This looks like: window -> NSViewController controlling five views -> sub-NSViewController for each view controlling X views -> each view contains a core-plot graph. In short, nested NSViewControllers with a core-plot CPLayerHostingView at the end of nearly every path.
Before I even get to my question, feel free to point out that this is a poor implementation. In terms of user-friendliness, I think it makes sense, but the sheer number of nested objects makes me wonder if there's a better way.
Now then, assuming I've designed it the best possible way, the question itself: suppose I have selected a category and then a sub-item within, and am looking at a rendered graph. I desire the graph to resize appropriately if the window is resized. In Interface Builder I have done everything necessary to make this happen: everything from the CPLayerHostingView to the NSView in the main window have been set to autosize in all directions. Despite this, if I resize at runtime, the graph stays still and does not resize or move. In a design with zero or one NSView tiers this would be much simpler to debug, but I'm out of ideas in this scenario.
What tricks, programmatic or IB-based, can I use to make sure an NSView resizes according to a window resize many, many levels up?
Not only do you need to set the springs and struts, but you also need to make sure "Autoresizes Subviews" is checked.
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.
Is there a simple way to create a selectable NSRect in Cocoa? In need a rectangle that can be selected and stays selected after a mouse click.
Thanks.
NSRect is just a struct with a position and size. It's not an object that can actually do anything or have any properties other than a width and height. It sounds like what you want is to create an NSView that can be selected. (Here's Apple's Guide on the subject.)
Though not as immediate as you would like, you may be interested in the management of tracking rectangles and tracking areas performed by NSView class.
This mechanism allows you to define specific areas of your custom view. Then, an event is generated whenever the cursor enters or leaves the area, or a mouse button is pressed in this area (-mouseEntered:, -mouseExited:, -mouseDown:, -mouseUp:, -mouseDragged:, ... of NSResponder class). This up to you to define what you want your application do in response to these events (set the rectangle as selected and display it accordingly).
For an example implementation of this, take a look at the Sketch example included with the Apple developer tools (look in /Developer/Examples/AppKit). Sketch allows the user to create new graphics (including rectangles, but also ovals, lines, and text), select them, move them around in the document, etc. In particular, you'll probably want to look at the SKTGraphic class, which represents a single graphic object in the document, and the SKTGraphicView class, which is an NSView subclass that perform the actual layout and drawing, handling mouse events for dragging views around, etc.