Subclassing an NSScrollView's DocumentView - objective-c

How can one subclass an NSScrollView's DocumentView in order to do some custom drawing? I need to do some work with NSShadow inside of the scroll view.

The document view is just a normal view (subclass of NSView,) so all you have to do is to create a view, either programmatically or in Interface Builder, and set the scroll view's documentView property to the new view.
You can set the property in a suitable awakeFromNib method, for instance.

Related

How to store orginal frame of UIView subclass loaded from storyboard automatically

I have a subclass of UIView which is has a property called originalFrame.
I want this class to store the original it's original frame value after it loaded from the storyboard it is apart of.
I have overridden the awakeFromNib method:
-(void)awakeFromNib
{
self.originalFrame = self.frame;
}
This works if the view of the view controller it is apart of is not resized right after to fit the screen size.
However, the view controllers in my storyboard are all for the iPhone 4-inch screen, so when the app runs on an iPhone 3.5 inch screen, awakeFromNib is called before the view controller's view is resized to fit the 3.5 inch screen. If my subview is not anchored to the top, then the originalFrame property won't reflect its frame after the resize.
I was able to override layoutSubviews to get the frame property after the view controller's view was resized, but this method is called other times too and I have no way of knowing if it is for the initial resize to fit screen, or something else.
Is there any way to do this without having to set this property manually on a case by case basis in the viewDidLoad method of the view controller?
You can check if the value is already set if you set it in awakeFormNib to CGRectZero and check in layoutSubviews if it is CGRectZero. Only set the frame in layoutSubviews if it is CGRectSubviews.

Static UITableView not fullscreen

For my registration form, I am currently using a UITableView which isn't fullscreen and I add cells programmatically through hardcoding the datasource methods. By the time the whole class got very complex and huge.
Pastebin link
The cells are custom and have a UILabel and a UITextfield. Now one of the cells should have a button instead of the textfield. This would make the whole thing more complex then it should be, in my opinion. So my thought was using the static feature of the tableview in the storyboard. But this requiers a UITableViewController, if I use one the TableView is always fullscreen. Is there a way to se the static feature without a fullscreen TableView??
If you have a fixed number of cells, the static table view controller is a good option. Instead of implementing the datasource methods, as you mentioned, you can include each input field as an IB outlet.
If you want a static table view controller that is not full-width, embed the table view controller inside a container view.
For example, create a new view controller, add a container view object w/ the desired width in this new view controller, and then connect your static table view controller to the container view.
Note that the static table view controller becomes a childViewController of the enclosing view controller. You can facilitate access to the textFields from the enclosing view controller w/ a weak property to the textFields w/in the child view controller.
- (UITextField *)surnameTextField
{
UITextField *textField;
// reference childController that is initiated via containerView
if ([[self.childViewControllers lastObject] isKindOfClass:[NameViewController class]])
{
NameViewController *nameVC = [self.childViewControllers lastObject];
textField = nameVC.surnameTextField;
}
return textField;
}
You do not need to use a UITableViewController. Just drag and drop a table view from the control palette onto a UIViewController in your storyboard. Size and position it how you want to and add any other controls to the UIViewController that you need.
In the property sheet for the UITableView set the content type to 'Static Cells' then define your cells how you want them.

Change self.view's class type

I have a app out for testing right now that's almost completely done - just a few bug fixes left. Unfortunately, the customer decided that they'd like the entire main page of the app to be inside of a scroll view (so that there's more room for the table at the bottom). I already have everything set up and I don't really want to move everything and change references. Is there an easy way to change the class of the main view to a scroll view? I've already tried changing the class in IB and setting the class type in the init method. If there isn't I'll probably just throw the top section of the view into a nib file and load it as a custom cell.
-EDIT- I ended up changing the class type in IB and then doing
[(UIScrollView *) self.view setScrollEnabled:YES];
[(UIScrollView *) self.view setContentSize:CGSizeMake(0,2000)];
in viewDidLoad. Thanks for the help, wish I could accept all your answers.
When you are referring to [self view], I am going to assume you mean in a view controller. The view of a view controller can be any view that derives from UIView. Thus a scrollview is completely acceptable.
I don't really want to move everything and change references.
what would you have to move? why would you have to change references? Only thing you should need to do is add a scroll view to your view controller, set the view controllers view to it, and add the current view as a subview to the new scroll view. No references need to be changed, nothing has to be moved.
Refer to loadView method in documentation of view controller.
Here is a simple (untested!) example
- (void)loadView {
UIScrollView *scrollView = [[UIScrollView alloc] init] autorelease];
//Set the properties of scrollview appropriately....
self.view = scrollView;
}
Now the root view of your view controller will be a scroll view.
Note
- As the documentation states, do not do this if you are using interface builder to initialize your views/view controller. I could not tell from your description if this was the case or not. If it is, you should be able to change the view type in interface builder.
You need to set the contentSize property of your scrollview.
Since you are using IB, the easiest way to do this is to put all your UI elements into a view and add this single view to your scroll view. In the viewDidLoad method, set the content size of the scrollview to be the same size as the view that contains all your UI.
As an aside, there are much easier ways to reference views than walking down the view hierarchy, as you seem to be doing. viewcontroller.view.something.tableview. Add a connection to the tableview from your view controller in IB and it doesn't matter where that tableview is in the view hierarchy. You'll always be able to reach it from viewcontroller.tableview, no matter how you rearrange your nibs.
I think you have to use a pointer with proper type. Example for Google Maps: let's say you changed you base view's class to GMSMapView.
MapViewController.h
#property GMSMapView *mapView;
MapViewController.m
-(void)awakeFromNib{
[super awakeFromNib];
self.mapView = (GMSMapView*)self.view;
// ... etc.
}

iOS: how do I dynamically change a uiscrollview's minZoom every time its bounds are changed?

I suppose I could subclass it and override minZoom's getter method but is there a simpler way to do this?
In your view controller override this -
- (void)viewWillLayoutSubviews
When a view’s bounds change, the view adjusts the position of its subviews. Your view controller can override this method to make changes before the view lays out its subviews.
if this is too soon theres a viewDidLayoutSubviews
Change your scrolllviews zoom there.

Highlighting selected item in a NSCollectionView using NSBox

How do I make the NSCollectionView update to show the currently selected item using an NSBox? Displaying selection in a list seems like a basic thing, but I'm having all kinds of trouble with this.
I've read this question and also looked at the sample code from Apple. There seems to be several ways to do this.
Using a subclasses of NSCollectionViewItem and special "prototype view".
Using a NSBox.
I wish to use the NSBox way since it seems simples and is also used in the official code sample.
It's apparently done as described in the following quote by alternegro:
If a different background color will suffice as a highlight, you could
simply use an NSBox as the root item for you collection item view.
Fill the NSBox with the highlight color of your choice. Set the NSBox
to Custom so the fill will work. Set the NSBox to transparent.
Bind the transparency attribute of the NSBox to the selected attribute
of File Owner(Collection Item) Set the value transformer for the
transparent binding to NSNegateBoolean.
I'm stuck at the very first part: "use an NSBox as the root item for you (sic) collection item view". I've tried to change the "Custom Class" to a FoobarBox that inherits from NSBox, but it doesnt seems to help as I cannot change the background color to blue nor can I bind the transparency. Any pointers on how to make the selection display in my NSCollectionVuew would be appreciated.
First, create a class for your ListView that inherits from NSBox
#interface MyListViewBox : NSBox
#property (unsafe_unretained) IBOutlet NSCollectionViewItem *controller;
#end
Then, in Interface Builder, specify your class name as "Custom class" property as shown on my screenshot
Then you will realize IB does not show NSBox properties or binding in the GUI (at least with version 4.5.2), so I decided to change the properties programmatically.
Create an outlet for NSCollectionViewItem in your NSBox subclass (as seen above)
Use IB to link the outlet to your NSCollectionItemView
in -(void)awakeFromNib for your NSBox subclass, add the following code
-(void)awakeFromNib {
//properties are not showing up in XCode Inspector IB view
//configuring the box here :-(
self.boxType = NSBoxCustom;
self.borderType = NSLineBorder;
self.fillColor = [NSColor selectedControlColor];
//bind the "transparent" property of NSBox to the "selected" property of NSCollectionViewItem controller
//controller is bound as IBOutlet in IB
NSValueTransformer* transformer = [NSValueTransformer valueTransformerForName:NSNegateBooleanTransformerName];
[self bind:#"transparent"
toObject:self.controller
withKeyPath:#"selected"
options:[NSDictionary dictionaryWithObjectsAndKeys:transformer, NSValueTransformerBindingOption, nil]];
}
In XCode 4.5.2, you can just delete the NSView that comes automatically with the NSColletionView and drag in an NSBox (which will have all the appropriate bindings available). Make sure you re-bind the CollectionView to your new Box.