Getting NSTableCellView inside tableView(_:heightOfRow:) - cocoa

I understand that you cannot call view(atColumn:row:makeIfNecssary:) from within tableView(_:heightRow:).
Ideally I'd like to derive height based on a button state within the NSTableCellView. I can think of a couple ways to work around this.
Use objectValue in my custom NSTableCellView to keep track of the state of the button.
Only enable buttons on selected row items and maintain a list of the selected NSTableCellView.
Are these recommended or is there another recommended way to handle this.
Also, is it recommended for a NSTableCellView to know what row/col it belongs too? Or is this something that also should be maintained in objectValue?
My use case is will have a disclosure arrow to expand the cell. I've tested it out and it works, however at this point, I'm using a test flag variable to control the height values not the actual button state.

Related

What is the appropriate UI set up for messaging functionality?

I have an app which allows users to send messages to each. The process is accomplished by saving the sent messages in a local SQLite database, while actually sending the messages to a database and using push notifications to send the message to the recipient's SQLite database. The set up I have works fine. However, what I am confused about is how to set up the actual interactive UI for the user (I am using XCode). I figured it should be a UITableView with each table cell representing a message. However, with this approach I run into a few requirements:
Variable TextView Sizes
Just as with regular iOS messaging, the TextView's size needs to be variable, adjusting its dimensions to fit all of the text in each message. I do not know how to accomplish this. I have a general understanding of how to generally vary sizes, but no clue how to dynamically have it based on the text within that view.
Variable TextView Positions
Again, just as with regular iOS messaging, the textview needs to be offset to either the right or left side depending on whether the sender was the user or who the are conversing with, respectively. I also do not know how to do this, because it changes the center of the textview.
Non-selectability
Xcode allows cells to be pressed. Handling what happens after this selection can be achieved by the didSelectRowatIndexPath tableView function. I can simply not implement this, but clicking on the cell causes it to turn darker to indicate it has been pressed. I would like to eliminate this while retaining the ability to, say, select some of the text and copy and paste it or whatever (just like messaging works normally on your phone).
Other Approaches?
This is the real meat of the question. I have considered the above approach because that is all that I have been able to come up with based on my limited experience with XCode UI elements. If there is a better approach (perhaps even a pod or framework) for this purpose I would love to hear it. I do not need the messaging UI to look amazing, just clean and crisp.
I suggest the following:
Variable TextView Sizes:
I assume you do use auto layout. If you don’t yet, please consider using it since it make life much easier!
If you use a UITableView, you can adjust the height of its UITableViewCells dynamically, depending on the actual content by using self-sizing cells. You can find a tutorial how to do this here.
Variable TextView Positions:
I assume you have a UITextView within a table view cell. In this case, you have to set auto layout constraints to the borders of the cell’s contentView. If you define a custom subclass of a UITableViewCell, you can define in this class 2 IBOutlet properties that are linked to say the left and the right layout constraints (e.g. var leftLayoutConstraint: NSLayoutConstraint). Then, you can set the constraint’s constant property as required when the cell is laid out, i.e. in the layoutSubviews function of the custom table view cell.
Non-selectability:
I am not sure what you mean by „I can simply not implement this“. Please make sure that you set the delegate property of the UITableView to the view controller where you want to handle cell selection. Selecting a cell changes the cells color by default, but you can change this: In the storyboard, select your table view’s prototype cell, and open Xcode’s utility pane (top rightmost button). Under „Table view cell“ you find „Selection“ that you can set to „None“.
I hope this helps!

Tabbing between NSTextFields with nextKeyView

I have a single NSViewController with the following layout, set using a storyboard:
The nextKeyView outlet of each of the NSTextFields is configured to be the next NSTextField in the order presented on the screenshot. For example, I chose the server NSTextField in IB and dragged from the nextKeyView outlet in Connectivity inspector to the login NSTextField, and did the same for the rest of the fields.
When the app is launched, any tab press on any of the field moves the selection to the first NSTextField. How do I achieve the desired tabbing between the fields?
I tried this in the respective WindowController, but to no avail:
- (void)windowDidLoad {
[super windowDidLoad];
self.window.initialFirstResponder = self.serverTextField;
}
This seems to be the most detailed answer, from Justin Bur posted to cocoa-dev mailing list (31 Jan 2007).
On several occasions over the years, people have asked why their key
view loop doesn't work properly. Most of these queries never get
answered on the list. After failing to find help for my key view loop
problems either on this list or on web sites, I did some
experimenting.
The key view loop can be problematic to deal with. It is designed to
just work magically, so in most cases it's not an issue. But if it
doesn't work, it's pretty difficult to figure out why not. Here are
some guidelines for getting a working key view loop.
Consider whether you can settle for an automatically generated key view loop. Each responder's top left corner determines its placement
in the loop. The loop proceeds from upper left to lower right, row by
row (at least for left-to-right scripts). This is by far the easiest
solution. To enable this, make sure the window's initialFirstResponder
is nil. See also -[NSWindow recalculateKeyViewLoop].
If the automatic key view loop is not suitable, set up your own key view loop using Interface Builder as much as possible. The window's
initialFirstResponder outlet must be set, in order to disable
automatic key loop generation. From that responder around the loop,
set the nextKeyView outlet of each item in the loop. (If desired, the
last item's nextKeyView can be set to the first item, thus closing the
loop.) For any view with scrollbars (NSTextView, NSTableView, etc.),
you should use the enclosing NSScrollView when setting nextKeyView.
If you have any responders created in code, splice them into the key view loop early (preferably in awakeFromNib
or maybe -[NSWindowController windowDidLoad]).
For each (sequence of) new item(s), you must use call -[NSView setNextKeyView:] thus: once to make
the previous item point to the (first) new one, (calls to make each
new item point to the next), and finally to make the (last) new item
point to its successor.
If your window has a toolbar, toolbar items that are interested in becoming key view will automatically add and remove themselves as the
toolbar is shown or hidden. The toolbar does not take into account the
return value of -[NSWindow autorecalculatesKeyViewLoop]. Toolbar items
are always placed in the loop before the top leftmost item. There is
no easy way to change this.
Once the window has been displayed, it can be extremely difficult to modify the key view loop - in particular if you are using
NSScrollView or NSTabView. These (and others?) are special cases
because they insert their contained views into the loop automatically.
For information on the initialFirstResponder and key view loop of an
NSTabViewItem, see the AppKit release notes for OS X 10.1
.
If you have items that should sometimes be in the loop and other times not, it is not advisable to attempt to splice them in and out of
the loop. Instead, subclass -[NSResponder acceptsFirstResponder] for
these items. If an item returns NO from this method, it will be left
out of the loop (temporarily); if it returns YES, it will come back
into the loop. Alternately, if the item is derived from NSControl (it
probably is), you can call setRefusesFirstResponder: on it.
If you make a mistake, your key view loop will cease to function, either in one direction or in both. Once it breaks it stays broken. To
debug, comment out calls to setNextKeyView: or
setInitialFirstResponder: until it works again. The offending call is
likely trying to modify the key view loop in the presence of
NSScrollView or NSTabView, after these objects have already done their
behind-the-scenes loop-munging. Move the calls to an earlier point, or
do without. (If you have no calls to setNextKeyView:, then check your
nib - make sure the window's initialFirstResponder is set and that
nextKeyView outlets are chained together the way you want.)
In System Preferences/Keyboard & Mouse/Keyboard Shortcuts, at the bottom of the pane under "Full keyboard access", you can control
whether key view loops include all controls or only text fields and
scrolling lists (^F7 to toggle). You should test your key view loops
with this setting in each state.
These guidelines were determined by experiment and may not be entirely
accurate. Corrections and further explanations are most welcome.
Set the window's initialFirstResponder in windowDidLoad of the window controller or viewWillAppear of the view controller. If initialFirstResponder isn't set before the window's makeKeyAndOrderFront, recalculateKeyViewLoop is called.

IOS Swift how can stop re-creating cells on drag or scroling in tableview

I am Creating a tableview using custom cell with textfield. When i enter text in tableviewcell textfield and when i scroll the tableview the data is changing . Means re painting cells . How can i stop reloading cell on drag or scroll in IOS 8 swift
Thanks
If your want your cell not re-used, try to make it a subclass of UITableViewCell with a unique identifier, and do not use the identifier with other cells. I haven't test it yet, just hope it will solve your problem.
Ps. If the textfield's text is still overwritten, make a check at the cell's class file (like making an if-else statement checking if the textfield's text is empty).
Detailed workflow:
In cellForRowAtIndexPath(), after you dequeue the cell, normally you will set some property of your custom cell to refresh the data it holds. To implement this, you need to add a didSet observer on the property at the cell's class file. To achieve the goal you want, you can also add the checking code in the didSet observer.
In Your case. You need to customize your keyboard.
Add [Prev][Next] buttons on top of the keyboard and avoid scrolling.
Basically this idea is useful in form based app. May be your doing that kind.
And yes, Stop relaoding of cells is not good to app. If you will implement this. Apple will not approve your app. So avoid this kind of stuffs.
This is how cells work in a UITableView. The standard implementation of the cellForRowAtIndexPath: method dequeues cells and reuses them.
And ideally your app should save the text from the text fields and change the correct text in the cells depending on their indexPath in the same method's implementation.
If you do not want to do that, a dirty workaround would be to create a new cell every time in the cellForRowAtIndexPath: method instead of dequeuing rows.*
*Do not do this unless absolutely necessary. This is very bad coding practice

Validating a drag to an NSCollectionView isn't reflected visually

I have an NSCollectionView that I want to accept items dragged from elsewhere in my application.
I implement collectionView:validateDrop:proposedIndex:dropOperation: and collectionView:acceptDrop:index:dropOperation: in the collectionview's delegate and register for the appropriate dragged types. Both methods get called fine when I drag the appropriate types, but I don't get a blue focus ring over the collectionview indicating a valid drag.
Have tried both the collection view and its containing scroll view on Default and External settings for the focus ring. Both are just the standard non-derived Cocoa classes. Wondered if there was anything else I should try. Surely it isn't necessary to subclass NSCollectionView for this?
Thanks
Chris
Focus rings are not typically the correct way to provide feedback about drag destinations. Every view does it slightly differently. NSTextView shows the insertion bar. NSTableView shows a blue line in between rows for Before drop operations, and shows a bezel around the row for On drop operations. (See NSTableViewDropOperation)
NSCollectionView shows a "gap" between existing subviews to show where the items will be dropped for Before drop operations, and it will set the selected property on NSCollectionViewItem to YES for On drop operations. (Note: NSCollectionViewItem doesn't do anything by default to visibly represent the selected property. You must implement that yourself.)
Since NSCollectionView's feedback uses existing subviews only, it appears there isn't any feedback at all for empty NSCollectionView's. You would need to subclass to provide this behavior yourself. You could also file a bug to request that NSCollectionView do this itself.

Sizing a control to fit its container in Interface Builder

Let's say I have a split view, and I want to fill half of it with a table view (a fairly common use case, I would think). Is there any way to tell the table view to size itself to fit the split view or do I really have to size it manually?
I've done this, the way Jon Hess mentions first. Assuming you're using Interface Builder version 3:
Drag and resize your GUI (tableview from what I understand?) component to fit into the enclosing area the way you want it.
Click it to select it.
Press Command-Shift-I to open the inspector window for this GUI component. The inspector window should now actually show that you've selected a "Scroll View".
Click the "ruler" heading to be able to set the sizing. You'll see to the right an animated representation of how your GUI component will behave within its enclosing GUI component, and to the left another represenation of the same, without animation, but with four springs and two struts that you can turn on or off.
Turn all six things on, making them red.
Voilà :-)
It's generally easier to create the subviews first, then use the Layout/Embed Objects In/Split View menu item to create the split view around them.
As far as I know, doing it manually is the only way to go. However, if you turn on "snap to cocoa guidelines", the inner view will snap to the edges of the enclosing view as you drag towards them. This makes it easier than having to manually mouse the edges into place, or manually edit the sizes to match.
You can set all of the springs and struts of the table view to "on" in the size inspector and that will cause the table view to fill the split view. Alternatively, you can use the outline view in the main document window to place the tableview's enclosing scroll view directly into the splitview instead of in an intermediary custom view.

Resources