I can't get the UI Text View Keybord to disappear - xcode

Hi this is my code i am trying to get the UI text view keyboard to disappear. I have 2 text fields the second one is text view. I try and drag the action but it wont let me. Please help!!!!!
- (IBAction)dismiss1:(id)sender{
[sender resignFirstResponder];
}
- (IBAction)dismiss2:(id)sender2{
[field2 resignFirstResponder];
}

UITextView doesn't have event actions.
Import <UITableViewDelegate, UITableViewDataSource> in header file and use below code to disapear keyboard when click on return button.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text isEqualToString:#"\n"]) {
[self.textView resignFirstResponder];
// Return FALSE so that the final '\n' character doesn't get added
return NO;
}
// For any other character return TRUE so that the text gets added to the view
return YES;
}

Related

Create a selectable square button, that open with double click in Xcode (Cocoa)

How to create a Square Button, that once clicked on once it gets selected (focus ring) and once its clicked on twice it performs an action.
Is it possible to do that in XIB file?
In AppDelegate(or some other class):
#property BOOL alreadyClickedButton;
Then initialize the property:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setAlreadyClickedButton:NO];
}
Then in an action:
-(IBAction)onclickButton:(id)sender {
if ([self alreadyClickedButton] ) {
NSLog(#"Do something...");
[self setAlreadyClickedButton:NO]; //Reset the button to initial state?
}
else {
[[self window] makeFirstResponder:sender];
[self setAlreadyClickedButton:YES];
}
}
Every two clicks of that button, you will see the message.

How to deal with first responder and a NSPopover

I’m trying to replicate the behaviour of the search field in iTunes, for looking up stock symbols and names. Specifically, as you start typing in the search field a popover appears with the filtered items. For the most part I have this working however what I can’t replicate is the way it handles first responder
I have my popover appear after three characters are entered. At this point the NSSearchField would lose first responder status and therefore I could no longer continue typing. The behaviour I would like is
the ability to continue typing after the popover appears
if scrolling through the items with the arrow keys, and then resume typing, you would continue from the last character in the Search field.
What I tried is subclassing NSTextView (use this as the custom field editor for the NSSearchField) and overriding
- (BOOL)resignFirstResponder
By simply returning NO, I can continue typing once the popover appears, but obviously I can’t select any of the items in the popover. So i tried the following, which returns YES if the down arrow or a mousedown event occurs.
#interface SBCustomFieldEditor ()
{
BOOL resignFirstRepond;
}
#end
#implementation SBCustomFieldEditor
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
resignFirstRepond = NO;
}
return self;
}
- (BOOL)resignFirstResponder
{
return resignFirstRepond;
}
- (void)keyDown:(NSEvent *)theEvent
{
if ([theEvent keyCode] == 125) {
resignFirstRepond = YES;
[self resignFirstResponder];
}
[super keyDown:theEvent];
}
- (void)mouseDown:(NSEvent *)theEvent
{
resignFirstRepond = YES;
[self resignFirstResponder];
}
This works for the mousedown event, but not the keydown event, furthermore this doesn’t address the issue, when the user resumes typing.
Any suggestions?
In the meantime I found an easy fix. Subclass your text view and implement - (BOOL)canBecomeKeyView. Always return NO there. It will be called only once when the popover is shown. You can work with the text view any time still.

Hide show/hide button in source list ( a view based outline view)

how to hide show /hide button (edited as expand here). even i set it as empty string ,the border for the data cell shrinks as shown in image. previously i used the method - (BOOL)outlineView:(NSOutlineView *)outlineView shouldShowOutlineCellForItem:(id)item , it hiding the show/hide string and working perfectly. but the problem is the outlineview allows only expanding not collapsing. i want to expand only one parent at a time by clicking the corresponding parent node.
Use this method from NSOutlineViewDelegate method :
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldShowOutlineCellForItem:(id)item;
Finally solved it, this code helped me.
- (NSRect)frameOfOutlineCellAtRow:(NSInteger)rowIndex
{
NSRect superFrame = [super frameOfOutlineCellAtRow:rowIndex];
// Return NSZeroRect if the row is a group row
if ([[self delegate] respondsToSelector:#selector(outlineView:isGroupItem:)]) {
if ([[self delegate] outlineView:self isGroupItem:[self itemAtRow:rowIndex]]) {
return NSZeroRect;
}
}
return superFrame;
}

NSTableView & NSOutlineView editing on tab key

My app has an NSOutlineView and an NSTableView, and I'm having the same problem with both. With a row in either selected, pressing the tab key puts the first column into edit mode instead of making the next key view first responder. To get to the next key view, you need to tab through all of the columns.
Also, shift-tabbing into either view results in the last column going into edit mode, necessitating more shift-tabs to get into its previous key view.
In case it matters, I'm using the autocalculated key view loop, not my own, with my NSWindow set to autorecalculatesKeyViewLoop = YES. I would like tabbing between the columns once the user elects to edit a column, but I don't think it's standard behavior for the tab key to trigger edit mode.
Update
Thanks to the helpful responses below, I worked it out. Basically, I override -keyDown in my custom table view class, which handles tabbing and shift-tabbing out of the table view. It was tougher to solve shift-tabbing into the table view, however. I set a boolean property to YES in the custom table view's -acceptsFirstResponder if it's accepting control from another view.
The delegate's -tableView:shouldEditTableColumn:row checks for that when the current event is a shift-tab keyDown event. -tableView:shouldEditTableColumn:row is called and it's not a shift-tab event, it sets the table view's property back to NO so it can still be edited as usual.
I've pasted the full solution below.
/* CustomTableView.h */
#interface CustomTableView : NSTableView {}
#property (assign) BOOL justFocused;
#end
/* CustomTableView.m */
#implementation CustomTableView
#synthesize justFocused;
- (BOOL)acceptsFirstResponder {
if ([[self window] firstResponder] != self) {
justFocused = YES;
}
return YES;
}
- (void)keyDown:(NSEvent *)theEvent
{
// Handle the Tab key
if ([[theEvent characters] characterAtIndex:0] == NSTabCharacter) {
if (([theEvent modifierFlags] & NSShiftKeyMask) != NSShiftKeyMask) {
[[self window] selectKeyViewFollowingView:self];
} else {
[[self window] selectKeyViewPrecedingView:self];
}
}
else {
[super keyDown:theEvent];
}
}
#end
/* TableViewDelegate.m */
. . .
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
{
NSEvent *event = [NSApp currentEvent];
BOOL shiftTabbedIn = ([event type] == NSKeyDown
&& [[event characters] characterAtIndex:0] == NSBackTabCharacter);
if (shiftTabbedIn && ((CustomTableView *)tableView).justFocused == YES) {
return NO;
} else {
((CustomTableView *)tableView).justFocused = NO;
}
return YES;
}
. . .
This is the default behavior. If there's no row selected, the table view as a whole has focus, and the Tab key switches to the next key view. If there is a row selected, the table view begins editing or moves to the next cell if already editing.
From AppKit Release Notes:
Tables now support inter-cell
navigation as follows:
Tabbing forward to a table focuses the entire table.
Hitting Space will attempt to 'performClick:' on a NSButtonCell in
the selected row, if there is only one
instance in that row.
Tabbing again focuses the first "focusable" (1) cell, if there is one.
If the newly focused cell can be edited, editing will begin.
Hitting Space calls 'performClick:' on the cell and sets the datasource
value afterwards, if changed. (2)
If a text cell is editing, hitting Enter will commit editing and focus
will be returned to the tableview, and
Tab/Shift-tab will commit the editing
and then perform the new tab-loop
behavior.
Tabbing will only tab through a single row
Once the last cell in a row is reached, tab will take the focus to
the next focusable control.
Back tabbing into a table will select the last focusable cell.
If you want to change this behavior, the delegate method tableView:shouldEditTableColumn:row: may be helpful. You may also have to subclass NSTableView if you really want to affect only the behavior of the Tab key.
The solution using keyDown didn't work for me. Perhaps because it is for cell-based table view.
My solution for a view-based table view, in Swift, looks like this:
extension MyTableView: NSTextFieldDelegate {
func controlTextDidEndEditing(_ obj: Notification) {
guard
let view = obj.object as? NSView,
let textMovementInt = obj.userInfo?["NSTextMovement"] as? Int,
let textMovement = NSTextMovement(rawValue: textMovementInt) else { return }
let columnIndex = column(for: view)
let rowIndex = row(for: view)
let newRowIndex: Int
switch textMovement {
case .tab:
newRowIndex = rowIndex + 1
if newRowIndex >= numberOfRows { return }
case .backtab:
newRowIndex = rowIndex - 1
if newRowIndex < 0 { return }
default: return
}
DispatchQueue.main.async {
self.editColumn(columnIndex, row: newRowIndex, with: nil, select: true)
}
}
}
You also need to set the cell.textField.delegate so that the implementation works.
My blog post on this tricky workaround: https://samwize.com/2018/11/13/how-to-tab-to-next-row-in-nstableview-view-based-solution/
I've had to deal with this before as well. My solution was to subclass NSTableView or NSOutlineView and override keyDown: to catch the tab key presses there, then act on them.
How convenient! I was just looking at this myself yesterday, and it's good to see some confirmation of the approach I took - keyDown: handling.
However, I have one small possible refinement to your approach: I worked out that the method triggering editing on shift-tabbing back to the table was the becomeFirstResponder call. So what I did on a NSTableView subclass was:
Add a synthesized property to control whether tab-editing behaviour was disabled
On keydown, check the first character (also check for [[theEvent characters] length] to avoid exceptions for dead keys!) for tab; if tab editing is disabled, move on to the next/previous view, as per your code sample.
Override becomeFirstResponder:
- (BOOL)becomeFirstResponder {
if (tabEditingDisabled) {
[self display];
return YES;
}
return [super becomeFirstResponder];
}
This keeps all the code in the tableview subclass, keeping the delegate cleaner :)
The only danger is I don't know what else NSTableView does in becomeFirstResponder; I didn't notice anything breaking, but...
This worked for me:
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSEvent *e = [NSApp currentEvent];
if (e.type == NSKeyDown && e.keyCode == 48) return NO;
return YES;
}

How to force NSToolBar validation?

I'm geting this strange behavior. I'm using a panel with text to show to the user when the app is waiting for some info. This panel is show modally to prevent the user to click something.
When the loading panel is hidden all the items on the toolbar are disabled and the validateToolbarItem method is not called.
I'm showing the panel in this way:
- (void)showInWindow:(NSWindow *)mainWindow {
sheetWindow = [self window];
[self sheetWillShow];
[NSApp beginSheet:sheetWindow modalForWindow:mainWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
[NSApp runModalForWindow:sheetWindow];
[NSApp endSheet:sheetWindow];
[sheetWindow orderOut:self];
}
- (void)dismissModal {
[sheetWindow close];
[NSApp stopModal];
}
How can I force the toolbar to validate in this case?
Edit after comment:
I have already tried:
[[[NSApp mainWindow] toolbar] validateVisibleItems]
[[NSApp mainWindow] update];
[NSApp updateWindows];
[NSApp setWindowsNeedUpdate:YES];
All after call dismissModal. I'm thinking that the problem is elsewhere....
The problem is that NSToolbar only sends validation messages to NSToolbarItem's that are of Image type, which none of mine were. In order to validate any or all NSToolbarItems's, create a custom subclass of NSToolBar and override the validateVisibleItems: method. This will send validation messages to ALL visible NSToolbarItem's. The only real difference is that instead of having the Toolbar class enable or disable the item with the returned BOOL, you need to enable or disable the item in the validation method itself.
#interface CustomToolbar : NSToolbar
#end
#implementation CustomToolbar
-(void)validateVisibleItems
{
for (NSToolbarItem *toolbarItem in self.visibleItems)
{
NSResponder *responder = toolbarItem.view;
while ((responder = [responder nextResponder]))
{
if ([responder respondsToSelector:toolbarItem.action])
{
[responder performSelector:#selector(validateToolbarItem:) withObject:toolbarItem];
}
}
}
}
#end
Now, assume you have a controller with an IBAction method that handles Actions for a NSSegmentedControl in your toolbar:
- (IBAction)backButton:(NSSegmentedControl*)sender
{
NSInteger segment = sender.selectedSegment;
if (segment == 0)
{
// Action for first button segment
}
else if (segment == 1)
{
// Action for second button segment
}
}
Place the following in the same controller that handles the toolbar item's Action:
-(BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
{
SEL theAction = [toolbarItem action];
if (theAction == #selector(backButton:))
{
[toolbarItem setEnabled:YES];
NSSegmentedControl *backToolbarButton = (NSSegmentedControl *)toolbarItem.view;
[backToolbarButton setEnabled:YES forSegment:0];
[backToolbarButton setEnabled:NO forSegment:1];
}
return NO;
}
The result is that you have complete control over which segments are enabled or disabled.
This technique should be applicable to almost any other type of NSToolbarItem as long as the item's Received Action is being handled by a controller in the responder chain.
I hope this helps.
NSToolbar *toolbar; //Get this somewhere. If you have the window it is in, call [window toolbar];
[toolbar validateVisibleItems];

Resources