How do I disable the autoscroll in a NSScrollView as I'm filling it with content?
I have subclassed it in my own class but I don't find an appropriate method to override.
There's probably more than one way to go about this, but take a look at -[NSClipView constrainScrollPoint:]. It's not meant to be called directly, rather to be overridden in an NSClipView subclass. NSClipView is the class that actually does the real work of scrolling the content of an NSScrollView.
You should be able to override it to simply return the document view's current origin point when you don't want scrolling to happen. It's worth noting that this will also disable scrolling via the user-visible interface, so you should only do it while you're filling the view with content. Otherwise, return the result of a call to the superclass's implementation.
Related
I am building a 3rd party library that I plan to integrate on different projects, so I need this to be as modular and have a non-destructive nature as possible. I need to "hook on" frame changes of UIViews. I am building a category and from that category method, I need to hook on that view's (it can be any regular UIView or subclass) frame change, and perform my additional logic. I've looked at KVO but as seen here https://stackoverflow.com/a/19701380/811405 it's not a safe approach.
How can I hook on frame change of a UIView? I can override setFrame: in my category, but I know that it is the single worst thing an Objective-C programmer can make: overriding a default method in a category. How do I achieve this?
UPDATE: I'm currently working on a really ugly (but working) solution:
I've created an invisible (empty drawRect:) UIView subclass.
I'm instantiating and adding it to the view of which I want to be notified of frame changes.
I'm setting that view's (the "superview") autoresizesSubviews to YES.
I'm setting my "invisible" view's autoresizing mask to both flexible width and height.
I'm overriding my "invisible" view's setFrame: to notify the appropriate object via delegation.
Because the superview will set frame of all subviews with flexible autoresizing mask when autoresizesSubviews is YES, this works, but it involves adding a hidden view inside a view, which is a bit hacky and may create problems in some scenarios (though most are corner cases). I'm still searching for a more suitable/less hacky solution.
I want to implement my own custom drawer completely by subclassing NSView and doing all my view drawing in that. I've created a custom NSView class that does hardly anything apart from implement initWithFrame: and drawRect: which I've got logging the frame/bounds of the NSView (which is reporting correctly). I've also instantiated this view and added it to the NSDrawer object in my application using setContentView: so that it uses my custom NSView.
However, this still draws a default drawer layout attached to the edge of my applications NSWindow. How do I override this default style so that I can draw my own drawer (!) in my custom, subclassed NSView without anything default being drawn by the OS? (So that I can control the design and size of the drawer myself, to basically emulate a tab bar that won't act strictly as a traditional drawer.)
I made a custom drawer by subclassing NSWindow rather than NSDrawer. It was a lot of work. There is a private object, NSThemeFrame, that sits between a NSWindow and its contentView. To avoid using private API, you have to make a transparent window and let its contentView act like a NSThemeFrame. Matt Gallagher shows how: http://cocoawithlove.com/2008/12/drawing-custom-window-on-mac-os-x.html
That frame is being drawn by the drawer's frame view. To do this, you need to use some private methods, and the easiest way is probably to use a custom subclass of NSDrawer. I do not know the specific methods used for drawers, but you can get a header for the class including private methods using class-dump.
Edit: This is what NSDrawer actually does.
NSDrawer is an opaque object that manages other objects. It creates a window using the private NSDrawerWindow class. Setting its content view sets the window's content view. The NSDrawerWindow class uses the private NSDrawerFrame class, which is a subclass of the private NSFrameView class, as its background and displays its content view inside that.
To change the frame, you need a way to change the frame view in the window. The easiest thing to do would be to get a header for NSDrawerWindow and add a category that overrides +frameViewClassForStyleMask: to return the class for your custom view. Your custom view should be a subclass of NSFrameView, which means you also need a header for that class.
I was wondering how to take care that my NSScrollView is not editable by the user, but i didn't find a way, there is no option in IB, nor do I find an appropriate method of the NSSCrollView class.
A previous post suggested to implement a delegate method
- (BOOL)textShouldBeginEditing:(NSText *)aTextObject
to return false, but this didn't work for me yet.
No solution was given on the previous question.
(I also tried selecting the TextView everything it doesn't display an option 'editable' i just downloaded the new Xcode so the version shouldn't be a problem)
You can't make NSScrollView non-editable. You can hide scrollers with setHasVerical/HorizontalScroller: that would prevent user from scrolling.
If you have NSTextView and want to make it non-editable just send setEditable:NO to it, not the scroll view. For that you obviously need a reference to the NSTextView or use NSScrollViews -documentView.
what is inside the scrollView that you want to prevent editing of?
what views have you got embedded in the scrollView? you need to find the view embedded in the scrollView that you want to prevent editing on, and call setEditable:NO on it.
So, I developed a kind of drop down button class.
Let's call it DDButton.
I mainly export one function :
-(void) addButtonWithImage:(UIImage*)image andTarget:(id)target andSelector:(SEL)selector
which lets the user add another button to the drop down.
I will need to use DDButton in different screens of my app.
I would like to use it like:
DDButton* ddb = [[DDButton alloc] initWithFrame:rect];
[ddb addButtonWithImage....]
[ddb addButtonWithImage....]
My question is since I never subclassed UIView before how should I implement it, and how should I use it later ?
Do I use IB and create a stub UIView which I'll connect to the DDButton in the Identity Pane ?
if so , how exactly I instantiate the view later on.
Or,
Do I subclass UIView ? if so , what methods I should override ? Do you I setup my buttons in the initializer ? in LayoutSubView ? In drawRect ?
I would love to hear the best approach here.
Thanks!
Edit
Let's say I choose the IB way : I have a main button which I set regardless of the
addButtonWithImage() calls, actually all calls to addButtonWithImage just "append" to that button. I want to main button to be the size of the view, until other buttons are added and then the view grows appropriately. However, I want the size of the view to be chosen by the user at first...using setFrame I guess.
Meaning in the awakeFromNib I can't count on the frame size yet (it only take the xib size I assume). So where would I setup my main button ? LayoutSubView ? setFrame ? I'm not sure.
Add your view to the interface in IB as a UIView, then change the class in the identity pane. If you need to do initialization in code, use a -(void)awakeFromNib method. I would suggest setting up the buttons when they are added in addButtonWithImage....
I'd probably do a subclass, building views in code is a good thing to learn.
Override drawrect: to do any custom drawing you need to do, if you're just adding a UIImageview or something and doing positioning you could just override initWith...: and do your custom initialisations.
I subclassed UIScrollView (IPhone SDK) and overrode the (void)layoutSubviews; method.
I noticed that each time the scrollView is scrolled, this method is called.
Is that the correct behaviour or do I have mistakes in my code? If it is the default behaviour, isn't this a performance killer?
Sincerely,
heinrich
It is the correct behaviour and it should be used to get a custom layout of your subviews. I have used it several times and haven't had any performance issues eaven with hundreds of items added.
A cut-out from the documentation on that topic:
Subclasses can also be containers for
other views. In this case, just
override the designated initializer,
initWithFrame:, to create a view
hierarchy. If you want to
programmatically force the layout of
subviews before drawing, send
setNeedsLayout to the view. Then when
layoutIfNeeded is invoked, the
layoutSubviews method is invoked just
before displaying. Subclasses should
override layoutSubviews to perform
any custom arrangement of subviews.