{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf410 {\fonttbl\f0\froman\fcharset77 Times-Roman;\f1\fswiss\fcharset77 Helvetica-Bold;\f2\froman\fcharset77 Times-Bold; \f3\fnil\fcharset77 Monaco;\f4\froman\fcharset77 Times-Italic;\f5\fswiss\fcharset77 Helvetica; } {\colortbl;\red255\green255\blue255;\red0\green0\blue255;} \pard\ql\qnatural \f0\fs24 \cf0 Version 1.1.4 Copyright \'a92004-2006 by Rainer Brockerhoff. Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.\ \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \f1\b\fs72 \cf0 RBSplitView\ \f0\b0\fs28 \ \f2\b\fs36 Basics\ \f0\b0\fs28 \ An RBSplitView object stacks several subviews within one view so that the user can change their relative sizes. By default, the split bars (called dividers) between the views are vertical, so the views are side-by-side. To have horizontal dividers (so the views are on top of each other), use the method \f3\fs22 \cf2 setVertical: \f0\fs28 \cf0 . The rest of this section assumes you have vertical dividers and gives information on horizontal dividers in parentheses.\ \ Although for the user RBSplitViews can behave very similarly to Cocoa\'d5s standard NSSplitViews, they\'d5re quite different as far as the programmer is concerned. RBSplitView is \f4\i not \f0\i0 a drop-in replacement for NSSplitView. By default, RBSplitViews follow the expected user interface conventions, although you can make it look and behave differently if you really wish to do so.\ \ All direct subviews of a RBSplitView \f4\i must \f0\i0 be RBSplitSubview objects. If you add another type of view directly to RBSplitView (by using one of the \f3\fs22 \cf2 addSubview: \f0\fs28 \cf0 methods), an intermediate RBSplitSubview will automatically be generated and your view will be set to resize along with it. RBSplitView is itself a subclass of RBSplitSubview, so you can easily nest RBSplitViews.\ \ A RBSplitView\'d5s subviews are arranged left to right (or top to bottom), with their positions counting from zero. The RBSplitSubviews are always set to completely cover the RBSplitView\'d5s height (or width), while the RBSplitView\'d5s width (or height), called here its main axis or dimension, is completely covered by the subviews and by the dividers between them. Here\'d5s an example RBSplitView with 3 subviews running in Interface Builder\'d5s test mode:\ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f5\fs24 \cf0 {{\NeXTGraphic Pasted Graphic.tiff \width7520 \height4240 }¬}\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs28 \cf0 \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \cf0 Interface Builder shows each subview\'d5s dimension for easier tuning. In this case, the dividers are vertical, so the vertical dimension isn\'d5t interesting; the subviews cover the RBSplitView entirely in the vertical axis. The dividers use the default 8x8-pixel \'d2dimple\'d3 image in the middle, and the user can drag the divider with the mouse along its entire length.\ \ Here\'d5s the Interface Builder inspector panel for the same example:\ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f5\fs24 \cf0 {{\NeXTGraphic 1__#$!@%!#__Pasted Graphic.tiff \width5480 \height8600 }¬}\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs28 \cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural \cf0 And here\'d5s the inspector panel for the first subview:\ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f5\fs24 \cf0 {{\NeXTGraphic Pasted Graphic 1.tiff \width5480 \height8600 }¬}\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs28 \cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural \cf0 Some of these attributes will be explained below.\ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \cf0 \ The most complex part of how a RBSplitView and its RBSplitSubviews work together is resizing. Usually, a RBSplitView would cover a significant part of a window and be resized along with it; indeed, when you drag a RBSplitView into a view from the palette its resizing springs come already set to do so.\ \ Let\'d5s suppose the window is widened by 50 pixels. When that happens, the RBSplitView\'d5s frame is also widened by 50 pixels. Its \f3\fs22 \cf2 setFrame: \f0\fs28 \cf0 method, beyond doing the expected resizing, will also set a flag indicating that the subviews have to be adjusted accordingly. It will then call the \f3\fs22 \cf2 adjustSubviews \f0\fs28 \cf0 method where all the heavy lifting is done. The normal subview resizing mechanism is turned off; RBSplitView\'d5s \f3\fs22 \cf2 autoresizesSubviews \f0\fs28 \cf0 method will always return NO, and the subview\'d5s autoresizingMasks are ignored. Instead, the subview\'d5s dimensions are changed by various alternate mechanisms, and then the \f3\fs22 \cf2 adjustSubviews \f0\fs28 \cf0 method will be called \'d1 either explicitly or automatically just before display \'d1 and resize them to keep everything consistent.To return to our example, if the RBSplitView is widened by 50 pixels, this increase will be distributed proportionally between all three subviews. As 50 isn\'d5t evenly divisible by 3, and subviews will always have integer dimensions, the increments will be rounded appropriately and the fractional increase will be stored for later calculations. So if the RBSplitView is later shrunk by 50 pixels again, the subviews should return to their exact former sizes.\ \ The user can also drag one of the dividers to resize the two adjacent subviews. In that case, of course, the other dividers won\'d5t move and only those two subviews will be resized appropriately. The cursor will change while over a divider, and again while it is being dragged.\ \ Things become more complex when some RBSplitSubviews have their attributes changed. You can set a minimum size, a maximum size, or both. You can also set a flag to indicate if the subview can be collapsed. A collapsed subview appears shrunk to zero dimension:\ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f5\fs24 \cf0 {{\NeXTGraphic Pasted Graphic 3.tiff \width7520 \height4240 }¬}\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs28 \cf0 \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \cf0 so that the adjacent dividers are next to each other. These attributes interact in several ways. Basically, the \f3\fs22 \cf2 adjustSubviews \f0\fs28 \cf0 method will go to great lengths to always keep all subviews within the minimum and maximum dimensions. (The default minimum is 1 pixel \'d1 you can\'d5t set it to zero \'d1 and the default maximum is a very large number).) You should always set a minimum dimension for a RBSplitSubview if you have one or more subviews inside it that should keep their relative positions, or maintain a certain minimum size. The tip here is to experimentally resize each subview to the smallest dimension you consider tenable, then click on the \'d2Current\'d3 button next to the minimum size field in the inspector panel to set the minimum to that dimension.\ \ If you turn on the \'d2Can Collapse\'d3 check box for a subview, it will be collapsed under several circumstances. If the user moves an adjacent divider more than half into it, it will collapse \'d1 but it will also expand again when the divider is moved a similar amount into the opposite direction. Subviews can also be collapsed or expanded programmatically, or by double-clicking on the divider. The \f3\fs22 \cf2 adjustSubviews \f0\fs28 \cf0 method can also collapse or expand views if that\'d5s the only way to keep other subviews within their limits. However, the algorithm may get confused if you set limits on all subviews and don\'d5t take care to ensure the RBSplitView\'d5s size will always accomodate these limits.\ \ All these resizing mechanisms are quite different from the ones normally used for views, as sibling RBSplitSubviews are interdependent. So you never should call \f3\fs22 \cf2 setFrame: \f0\fs28 \cf0 or \f3\fs22 \cf2 setFrameSize: \f0\fs28 \cf0 on a RBSplitSubview; use \f3\fs22 \cf2 setDimension: \f0\fs28 \cf0 if necessary, or rely on the automatic resizing whenever possible.\ \ You may have noticed that it\'d5s not easy to work with nested views in Interface Builder. So I suggest that you work in outline view at all times. Double-click any item in the outline view to select and edit it; clicking directly in the window may select the wrong subview. Click in an empty area of your window to deselect everything else before adjusting sizes, dividers or before dropping anything into a RBSplitView. To drag a divider in Interface Builder, click outside to deselect the RBSplitView, then double-click-and-hold on the divider you want to drag. When the cursor turns into the closed hand, drag the divider to the desired position, then click outside again to redraw all subviews. This will work in all cases. Most RBSplitView behavior can be verified from Interface Builder\'d5s simulator mode. Use it especially if you set minimum and maximum dimensions.\ \ \f2\b\fs36 Miscellaneous Tips & Tricks\ \f0\b0\fs28 \ - If you include the library in your project, you must reference the RBSplitView class in some way from one of your source files, otherwise the library may get stripped out of your deployment build and you\'d5ll get a runtime exception when loading the nib file. This happens automatically if you implement one of the delegate methods, or subclass. If you\'d5re just using RBSplitView in your nib files and nowhere else, call \f3\fs22 \cf2 [RBSplitView class] \f0\fs28 \cf0 once anywhere - for instance, inside your app delegate\'d5s \f3\fs22 \cf2 applicationDidFinishLaunching \f0\fs28 \cf0 method. \ - If you have several UI elements inside the same RBSplitSubview, you usually should set the subview\'d5s minimum size to the smallest value that still keeps all interface elements visible and correctly sized. If you neglect to do this, or set the minimum too small, collapsing and reexpanding will jumble up your subviews.\ - Avoid setting minimum and maximum dimensions for \f4\i all \f0\i0 subviews. If you absolutely have to, set appropriate minimum or maximum sizes for the containing window, to avoid getting into situations where the constraints can\'d5t be satisfied.\ - If you want one single subview to stay the same size, and all others to be resized when resizing your window, implement \f3\fs22 \cf2 splitView:wasResizedFrom:to: \f0\fs28 \cf0 in your delegate, and call \f3\fs22 \cf2 adjustSubviewsExcepting: \f0\fs28 \cf0 on the RBSplitView there.\ - If you want all subviews except one to stay the same size, and only that one to resize when resizing your window, implement \f3\fs22 \cf2 splitView:wasResizedFrom:to: \f0\fs28 \cf0 in your delegate, and call \f3\fs22 \cf2 changeDimensionBy:mayCollapse:move: \f0\fs28 \cf0 on that subview.\ - If you want RBSplitView state to be saved between application runs, set an autosaveName for the top-level RBSplitView in IB, then call \f3\fs22 \cf2 restoreState: \f0\fs28 \cf0 on it just after restoring the window frame. If you have multiple document windows, set the autosaveName just before calling \f3\fs22 \cf2 restoreState: \f0\fs28 \cf0 instead of in IB.\ - If you want to collapse a subview and make its divider disappear, call \f3\fs22 \cf2 setHidden:YES \f0\fs28 \cf0 on it. Then later, call \f3\fs22 \cf2 setHidden:NO \f0\fs28 \cf0 to restore it in the same position and size as before. If you want to use animation, call \f3\fs22 \cf2 collapseWithAnimation \f0\fs28 \cf0 , then from inside the \f3\fs22 \cf2 splitView:didCollapse: \f0\fs28 \cf0 delegate method schedule another method to call \f3\fs22 \cf2 setHidden:YES \f0\fs28 \cf0 later in your main event loop (using \f3\fs22 \cf2 performSelector:withObject:afterDelay: \f0\fs28 \cf0 ).\ - If you want dividers to collapse or expand with animation on a double-click, implement \f3\fs22 \cf2 splitView:shouldHandleEvent:inDivider:betweenView:andView: \f0\fs28 \cf0 in your delegate, start the animation there, and return NO.\ - If you want to draw a frame inside some specific subview, implement \f3\fs22 \cf2 splitView:willDrawSubview:inRect: \f0\fs28 \cf0 in your delegate, and draw it there.\ - Check out the sample app\'d5s main.m source file to see most of these delegate methods in action.\ - Normally you almost never need to call \f3\fs22 \cf2 adjustSubviews \f0\fs28 \cf0 yourself; do this only if you notice incorrect redrawing behavior.\ }