How do I open an NSSheet in Mavericks? - cocoa

In Mavericks, the methods to open and close NSSheets has changed. And to make it tougher, the Release Notes do not match the current documentation (see below).
I'm trying to do this:
MainSheetController (NSWindowController):
-(IBAction)callSheet:(id)sender {
[sheetController openSheet];
}
SheetController (NSObject):
(void)openSheet {
[[NSBundle mainBundle] loadNibNamed:sheetName owner:self topLevelObjects:nil];
NSLog(#"1");
[self.mainWindowController.window beginSheet:self.sheet completionHandler:nil];
NSLog(#"2");
}
I get to 2, with no errors or warnings, but no sheet..
Current Documentation:
#if NS_BLOCKS_AVAILABLE
- (void)beginSheet:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
- (void)beginCriticalSheet:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
#endif

- (IBAction)userButtonPressed:(id)sender {
UserLoginWindowController * wc = [UserLoginWindowController new];
// we keep a reference, so the WC doesn't deallocate
self.modalWindowController = wc;
[[self window] beginSheet:[wc window] completionHandler:^(NSModalResponse returnCode) {
self.modalWindowController = nil;
}];
}
in the UserLoginWindowController
- (IBAction)cancelButtonPressed:(id)sender {
[[[self window] sheetParent] endSheet:[self window] returnCode:NSModalResponseCancel];
}

- (IBAction)showSheet:(id)sender
{
if (_windowController == nil)
{
_windowController = [MyWindowController new];
}
[[self window] beginSheet:[_windowController window] completionHandler:^(NSModalResponse returnCode)
{
}];
}
// And inside your MyWindowController class:
- (id)init
{
self = [super initWithWindowNibName:#"MyWindowNibName"]; // TODO: Change the name of your NIB
return self;
}
In your nib file, make sure the "Visible At Launch" flag is unticked for the window.

I figured out how to do this. Hope it's ok to post..
MainWindow.h
#interface MainWindowController : NSWindowController {
NSString *sheetName;
IBOutlet NSWindow *sheet;
id result1;
id result2;
...
id resultn;
}
#property (strong) NSString *sheetName;
#property (strong, nonatomic) IBOutlet NSWindow *sheet;
-(IBAction)callSheet0:(id)sender;
-(IBAction)callSheet1:(id)sender;
-(IBAction)callSheetn:(id)sender;
- (void)openSheet;
- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;
MainWindow.m
- (void)windowDidLoad
{
NSLog(#"%s", __FUNCTION__);
[super windowDidLoad];
sheetName = [[NSString alloc] init];
}
-(IBAction)callSheet0:(id)sender {
NSLog(#"%s", __FUNCTION__);
sheetName = #"Sheet0";
[self openSheet];
}
....
-(IBAction)callSheetn:(id)sender {
NSLog(#"%s", __FUNCTION__);
sheetName = #"Sheetn";
[self openSheet];
- (void)openSheet {
NSLog(#"%s", __FUNCTION__);
NSLog(#"sheetName: %#",sheetName );
[[NSBundle mainBundle] loadNibNamed:sheetName owner:self topLevelObjects:nil];
[self.window beginSheet:self.sheet completionHandler:nil];
}
- (void)save:(NSButton*)sender {
switch ([sender tag]) {
case 0:
[self doSave1];
result = #"1";
break;
case 1:
[self doSave2];
result = #"2";
break;
case n:
[self doSaven];
result = #"x";
break;
}
[self endSheet:self.sheet returnCode:result];
}
- (IBAction)cancel:(id)sender {
NSLog(#"%s", __FUNCTION__);
result = #"0";
[self endSheet:self.sheet returnCode:result];
// returnCode is optional
}
//endSheet:(NSWindow *)sheetWindow {
- (void)endSheet:(NSWindow *)sheetWindow returnCode:returnCode {
//NSLog(#"%s", __FUNCTION__);
[sheetWindow orderOut:self];
}
- (void)save:(NSButton*)sender {
switch ([sender tag]) {
case 0:
[self doSave1];
result = #"1";
break;
case n:
[self doSave3];
result = #"3";
break;
}
[self endSheet:self.sheet returnCode:result];
}
With this method, new in 10.9,I don't need a special sheet controller, and control remains quote local.

Related

mouseExited is no longer called after mouseDown in NSButton subclass

In building a custom NSButton, I've run into a problem handling highlight behavior. After clicking down on the button, holding, and dragging the cursor outside the button's bounds, mouseExited: and mouseEntered: events are not delivered. I understand the reason why, because in mouseDown: calling [super mouseDown:event]; will block until the click is released.
In researching this I came across this Stack Overflow post which describes the same problem. The solution noted is to add NSTrackingEnabledDuringMouseDrag to the NSTrackingArea options, which I have done, yet I continue to see this problem. I tried the other proposed solution with handling the next events in a loop, but this resulted in odd behavior. The button text color turns black on mouse down instead of highlighting the dimmed color, and it doesn't unhighlight upon releasing the mouse, it remains black.
I am using Xcode 9.3, running on macOS 10.13.4.
Here is my NSButton subclass:
#interface BorderlessButton : NSButton {
NSColor *_tempColor;
}
#property (strong, nonatomic) NSColor *color;
#end
#interface BorderlessButton ()
#property (nonatomic) BOOL pressed;
#end
#implementation BorderlessButton
- (id)init {
if (self = [super init]) {
[self setUp];
}
return self;
}
- (id)initWithFrame:(NSRect)frameRect {
if (self = [super initWithFrame:frameRect]) {
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self setUp];
}
return self;
}
- (void)setUp {
_color = [NSColor redColor];
[self setTitle:self.title];
[self setButtonType:NSButtonTypeMomentaryChange];
[self setBordered:NO];
NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:self.bounds
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag
owner:self
userInfo:nil];
[self addTrackingArea:area];
}
- (void)setTitle:(NSString *)title {
[super setTitle:title];
NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
[colorTitle addAttributes:#{NSFontAttributeName: self.font, NSForegroundColorAttributeName: self.color} range:NSMakeRange(0, [colorTitle length])];
[self setAttributedTitle:colorTitle];
}
- (void)setColor:(NSColor *)color {
_color = color;
[self setTitle:self.title];
}
- (void)mouseDown:(NSEvent *)event {
self.pressed = YES;
[self highlight:YES];
[super mouseDown:event]; // this blocks until released
[self mouseUp:event];
}
- (void)mouseUp:(NSEvent *)event {
self.pressed = NO;
[self highlight:NO];
[super mouseUp:event];
}
//FIXME: Not called after mouse press down and hold then exit
- (void)mouseExited:(NSEvent *)event {
if (self.pressed) {
[self highlight:NO];
}
[super mouseExited:event];
}
- (void)mouseEntered:(NSEvent *)event {
if (self.pressed) {
[self highlight:YES];
}
[super mouseEntered:event];
}
- (void)highlight:(BOOL)flag {
if (flag) {
if (self.isEnabled) {
NSColor *dimmedColor = [self dimmedColor];
_tempColor = _color;
self.color = dimmedColor;
[self setTitle:self.title];
}
} else {
if (self.isEnabled) {
self.color = _tempColor;
[self setTitle:self.title];
}
}
}
- (NSColor *)dimmedColor {
return [self.color colorWithAlphaComponent:0.5];
}
#end

Subviews out of bounds of NSScrollView respond to mouse event

My problem is that the subviews of my scrollView respond to mouse event even if they are not visible (out of the bounds of the visible part of the scrollView).
I've got this architecture :
CustomView *view01 = [[CustomView alloc] init];
CustomView *view02 = [[CustomView alloc] init];
NSView *contentView = [[NSView alloc] init];
[contentView addSubview:view01];
[contentView addSubview:view02];
NSSCrollView *scrollView = [[NSScrollView alloc] init];
scrollView setDocumentView:contentView];
With the CustomView implementation :
#import "CustomView.h"
#interface CustomView ()
{
NSTrackingArea *trackingArea;
}
#end
#implementation CustomView
-(id)initWithFrame:(NSRect)contentRect
{
if(self = [super initWithFrame:(NSRect)contentRect])
{
[self setFrame:contentRect];
}
return self;
}
- (void)mouseDown: (NSEvent*)event
{
NSLog(#"mouseDown:");
[NSApp preventWindowOrdering];
}
- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)evt
{
return YES;
}
-(BOOL)acceptsFirstResponder
{
return YES;
}
-(void)updateTrackingAreas
{
if(trackingArea != nil)
{
[self removeTrackingArea:trackingArea];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
NSLog(#"mouseEntered:");
}
- (void)mouseExited:(NSEvent *)theEvent
{
NSLog(#"mouseExited:");
}
- (NSView *)hitTest:(NSPoint)aPoint
{
return NSPointInRect(aPoint, self.frame) ? self : nil;
}
#end
I finally found the problem.
I needed to add the option NSTrackingInVisibleRect in the method :
-(void)updateTrackingAreas
{
if(trackingArea != nil)
{
[self removeTrackingArea:trackingArea];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways| NSTrackingInVisibleRect);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
Then, when a part of the CustomView are outside the scrollView, it doesn't respond to mouseEntered and mouseExited.

How to hide custom tab bar controller on a perticular screen?

I am using this code from the link...Which is the best approach for creating custom tab bar controller?
now I need to hide tabbar inbetween a page. and on the next page it will appear as usual. how to do it if any one can please help me with some useable link or codes
#import "MyTabBarController.h"
#interface MyTabBarController ()
#property (strong, nonatomic) UIButton *btn1;
#property (strong, nonatomic) UIButton *btn2;
#property (strong, nonatomic) UIButton *btn3;
#property (strong, nonatomic) UIButton *btn4;
#property (weak, nonatomic) UIButton *lastSender;
#property (strong, nonatomic) UIView *tabbarView;
#end
#implementation MyTabBarController
-(id)init
{
if (self=[super init]) {
[self setUP];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if (self=[super initWithCoder:aDecoder]) {
[self setUP];
}
return self;
}
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
[self setUP];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
_tabbarView = [[[NSBundle mainBundle] loadNibNamed:#"MyTabBarController" owner:nil options:nil] lastObject];
_tabbarView.frame = CGRectMake(0.0,
[[UIScreen mainScreen] bounds].size.height-70,
[[UIScreen mainScreen] bounds].size.width,70); // make it overlay your actual tab bar
[self.view addSubview:_tabbarView];
_btn1 = (UIButton *)[_tabbarView viewWithTag:1];
[_btn1 addTarget:self action:#selector(processBtn:) forControlEvents:UIControlEventTouchUpInside];
_btn2 = (UIButton *)[_tabbarView viewWithTag:2];
[_btn2 addTarget:self action:#selector(processBtn:) forControlEvents:UIControlEventTouchUpInside];
_btn3 = (UIButton *)[_tabbarView viewWithTag:3];
[_btn3 addTarget:self action:#selector(processBtn:) forControlEvents:UIControlEventTouchUpInside];
_btn4 = (UIButton *)[_tabbarView viewWithTag:4];
[_btn4 addTarget:self action:#selector(processBtn:) forControlEvents:UIControlEventTouchUpInside];
_lastSender = _btn4;
[self setSelectedViewController:self.viewControllers[3]];
}
-(void)processBtn:(id)sender
{
_lastSender =(UIButton*) sender;
[self setSelectedViewController:[self.viewControllers objectAtIndex:_lastSender.tag - 1]];
}
- (void)setSelectedViewController:(UIViewController *)selectedViewController
{
if ([self.viewControllers indexOfObject:selectedViewController] == 0)
{
if (self.selectedViewController == selectedViewController)
{
[(UINavigationController *)self.selectedViewController popToRootViewControllerAnimated:YES]; // pop to root if tapped the same controller twice
}
[super setSelectedViewController:selectedViewController];
}else if ([self.viewControllers indexOfObject:selectedViewController] == 1)
{
if (self.selectedViewController == selectedViewController)
{
[(UINavigationController *)self.selectedViewController popToRootViewControllerAnimated:YES]; // pop to root if tapped the same controller twice
}
[super setSelectedViewController:selectedViewController];
}else if ([self.viewControllers indexOfObject:selectedViewController] == 2)
{
if (self.selectedViewController == selectedViewController)
{
[(UINavigationController *)self.selectedViewController popToRootViewControllerAnimated:YES]; // pop to root if tapped the same controller twice
}
[super setSelectedViewController:selectedViewController];
}else if ([self.viewControllers indexOfObject:selectedViewController] == 3)
{
if (self.selectedViewController == selectedViewController)
{
[(UINavigationController *)self.selectedViewController popToRootViewControllerAnimated:YES]; // pop to root if tapped the same controller twice
}
[super setSelectedViewController:selectedViewController];
}
NSLog(#"%#",[_tabbarView subviews]);
for (UIButton *btn in [_tabbarView subviews])
{
if ([btn isKindOfClass:[UIButton class]])
{
if (btn == _lastSender)
{
NSString *strImageName=#"";
switch (btn.tag)
{
case 1:
strImageName=#"settings_icon_hover.png";
break;
case 2:
strImageName=#"garage_icon_hover.png";
break;
case 3:
strImageName=#"help_icon_hover.png";
break;
case 4:
strImageName=#"new_test_hover.png";
break;
default:
break;
}
btn.selected = YES;
UIImageView *imgSelected=(UIImageView*)[_tabbarView viewWithTag:btn.tag*10];
[imgSelected setImage:[UIImage imageNamed:strImageName]];
UILabel *lblSelected=(UILabel*)[_tabbarView viewWithTag:btn.tag*100];
[lblSelected setTextColor:[UIColor colorWithRed:82.0f/255.0f green:160.0f/255.0f blue:205.0f/255.0f alpha:1.0f]];
}
else
{
btn.selected = NO;
NSString *strImageName=#"";
switch (btn.tag)
{
case 1:
strImageName=#"settings_icon.png";
break;
case 2:
strImageName=#"garage_icon.png";
break;
case 3:
strImageName=#"help_icon.png";
break;
case 4:
strImageName=#"new_test.png";
break;
default:
break;
}
UIImageView *imgNonSelected=(UIImageView*)[_tabbarView viewWithTag:btn.tag*10];
[imgNonSelected setImage:[UIImage imageNamed:strImageName]];
UILabel *lblSelected=(UILabel*)[_tabbarView viewWithTag:btn.tag*100];
[lblSelected setTextColor:[UIColor grayColor]];
}
}
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)setUP
{
NSMutableArray *viewControllers = [NSMutableArray array];
UIStoryboard *storyBoard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navControllerSettings=[storyBoard instantiateViewControllerWithIdentifier:#"settings"];
[viewControllers addObject:navControllerSettings];
UINavigationController *navControllerGarage=[storyBoard instantiateViewControllerWithIdentifier:#"garage"];
[viewControllers addObject:navControllerGarage];
UINavigationController *navControllerHelp=[storyBoard instantiateViewControllerWithIdentifier:#"help"];
[viewControllers addObject:navControllerHelp];
UINavigationController *navControllerNewTest=[storyBoard instantiateViewControllerWithIdentifier:#"newtest"];
[viewControllers addObject:navControllerNewTest];
self.viewControllers = viewControllers;
}
#end

Cocoa: Making NSTextField editable after a click and short delay (like renaming in Finder)

I cannot find a simple example of how to use an NSTextField to edit it's contents in place.
Exactly like in the Finder - you're able to click, and with a short delay the text field becomes editable.
It seems like it's some combination of the textField, it's cell, and the fieldEditor? Problem is I can't find the most basic example of how to do it.
I've tried subclassing NSTextField with a couple different tests but it hasn't worked:
#import "GWTextField.h"
#implementation GWTextField
- (id) initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
return self;
}
- (void) mouseDown:(NSEvent *)theEvent {
[super mouseDown:theEvent];
[self.cell editWithFrame:self.frame inView:self.superview editor:[self.cell fieldEditorForView:self] delegate:self event:theEvent];
//[self setEditable:TRUE];
//[self setSelectable:TRUE];
//[self selectText:nil];
[NSTimer scheduledTimerWithTimeInterval:.3 target:self selector:#selector(edit:) userInfo:nil repeats:FALSE];
}
- (void) edit:(id) sende {
NSLog(#"edit");
[[NSApplication sharedApplication].mainWindow makeFirstResponder:self];
[self selectText:nil];
}
#end
Any ideas?
Here's another solution with no NSCell - one user pointed out that NSCell is deprecated and will at some point be gone.
#import <Cocoa/Cocoa.h>
#interface EditTextField : NSTextField <NSTextDelegate,NSTextViewDelegate,NSTextFieldDelegate>
#property BOOL isEditing;
#property BOOL commitChangesOnEscapeKey;
#property BOOL editAfterDelay;
#property CGFloat delay;
#end
----
#import "EditTextField.h"
#interface EditTextField ()
#property NSObject <NSTextFieldDelegate,NSTextViewDelegate> * userDelegate;
#property NSString * originalStringValue;
#property NSTimer * editTimer;
#property NSTrackingArea * editTrackingArea;
#end
#implementation EditTextField
- (id) initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
[self defaultInit];
return self;
}
- (id) initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
[self defaultInit];
return self;
}
- (id) init {
self = [super init];
[self defaultInit];
return self;
}
- (void) defaultInit {
self.delay = .8;
}
- (void) mouseDown:(NSEvent *) theEvent {
if(theEvent.clickCount == 2) {
[self startEditing];
} else {
[super mouseDown:theEvent];
if(self.editAfterDelay) {
[self startTracking];
self.editTimer = [NSTimer scheduledTimerWithTimeInterval:.8 target:self selector:#selector(startEditing) userInfo:nil repeats:FALSE];
}
}
}
- (void) startTracking {
if(!self.editTrackingArea) {
self.editTrackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveInActiveApp|NSTrackingAssumeInside|NSTrackingInVisibleRect owner:self userInfo:nil];
}
[self addTrackingArea:self.editTrackingArea];
}
- (void) mouseExited:(NSEvent *)theEvent {
[self.editTimer invalidate];
self.editTimer = nil;
}
- (void) mouseMoved:(NSEvent *) theEvent {
[self.editTimer invalidate];
self.editTimer = nil;
}
- (void) startEditing {
id firstResponder = self.window.firstResponder;
if([firstResponder isKindOfClass:[NSTextView class]]) {
NSTextView * tv = (NSTextView *)firstResponder;
if(tv.delegate && [tv.delegate isKindOfClass:[EditTextField class]]) {
EditTextField * fr = (EditTextField *)tv.delegate;
[fr stopEditingCommitChanges:FALSE clearFirstResponder:FALSE];
}
}
if(self.delegate != self) {
self.userDelegate = (NSObject <NSTextFieldDelegate,NSTextViewDelegate> *)self.delegate;
}
self.isEditing = TRUE;
self.delegate = self;
self.editable = TRUE;
self.originalStringValue = self.stringValue;
[self.window makeFirstResponder:self];
}
- (void) stopEditingCommitChanges:(BOOL) commitChanges clearFirstResponder:(BOOL) clearFirstResponder {
self.editable = FALSE;
self.isEditing = FALSE;
self.delegate = nil;
[self removeTrackingArea:self.editTrackingArea];
if(!commitChanges) {
self.stringValue = self.originalStringValue;
}
if(clearFirstResponder) {
[self.window makeFirstResponder:nil];
}
}
- (void) cancelOperation:(id) sender {
if(self.commitChangesOnEscapeKey) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
} else {
[self stopEditingCommitChanges:FALSE clearFirstResponder:TRUE];
}
}
- (BOOL) textView:(NSTextView *) textView doCommandBySelector:(SEL) commandSelector {
BOOL handlesCommand = FALSE;
NSString * selector = NSStringFromSelector(commandSelector);
if(self.userDelegate) {
if([self.userDelegate respondsToSelector:#selector(control:textView:doCommandBySelector:)]) {
handlesCommand = [self.userDelegate control:self textView:textView doCommandBySelector:commandSelector];
} else if([self.userDelegate respondsToSelector:#selector(textView:doCommandBySelector:)]) {
handlesCommand = [self.userDelegate textView:textView doCommandBySelector:commandSelector];
}
if(!handlesCommand) {
if([selector isEqualToString:#"insertNewline:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
handlesCommand = TRUE;
}
if([selector isEqualToString:#"insertTab:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:FALSE];
handlesCommand = FALSE;
}
}
} else {
if([selector isEqualToString:#"insertNewline:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
handlesCommand = TRUE;
}
if([selector isEqualToString:#"insertTab:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:FALSE];
handlesCommand = FALSE;
}
}
return handlesCommand;
}
#end
I built a re-usable NSTextField subclass you can use for edit in place functionality. http://pastebin.com/QymunMYB
I came up with a better solution to the edit in place problem. I believe this is how to properly do edit in place with NSCell. Please show and tell if this is wrong.
#import <Cocoa/Cocoa.h>
#interface EditTextField : NSTextField <NSTextDelegate>
#end
---
#import "EditTextField.h"
#implementation EditTextField
- (void) mouseDown:(NSEvent *)theEvent {
if(theEvent.clickCount == 2) {
self.editable = TRUE;
NSText * fieldEditor = [self.window fieldEditor:TRUE forObject:self];
[self.cell editWithFrame:self.bounds inView:self editor:fieldEditor delegate:self event:theEvent];
} else {
[super mouseDown:theEvent];
}
}
- (void) cancelOperation:(id)sender {
[self.cell endEditing:nil];
self.editable = FALSE;
}
- (BOOL) textView:(NSTextView *) textView doCommandBySelector:(SEL) commandSelector {
NSString * selector = NSStringFromSelector(commandSelector);
if([selector isEqualToString:#"insertNewline:"]) {
NSText * fieldEditor = [self.window fieldEditor:TRUE forObject:self];
[self.cell endEditing:fieldEditor];
self.editable = FALSE;
return TRUE;
}
return FALSE;
}
#end
In my application I have two text fields - one non editable, and second, hidden, editable, and activates title editing by calling:
[self addSubview:windowTitle];
[windowTitleLabel removeFromSuperview];
[self.window makeFirstResponder:windowTitle];
This is called from mouseUp: on view behind the label.
I don't remember why I needed to have two text fields (i didn't know Cocoa good that time), probably it will work even without label swapping.

multiple uitextfields in one view with different input (keyboard/picker)

I have a form-like view in my application which contains 8 textfields. Two of them are to be filled in by pickers, and the rest by normal heyboard typing. When picker-row is selected or when return button is pressed, the corresponding text should be entered into the textfield.
Could you please give some advice how to implement this properly? Also so that pickers/keyboards are dismissed after selection made/return pressed.
I found an answer to something similar here. ANd I managed to get the 2 picker-textfields working, but now I cannot make the keyboard appear for the rest. I guess it's because I'm overriding the textFieldShouldBegineEditing method. Any ideas to get round that? Can I somehow call the default method from inside textFieldShouldBeginEditing?? Note, if I uncomment my last lines of textFieldShouldBeginEditing I get a crash...
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
currentTextField = textField;
if (textField == self.pickerField1) {
currentArray = self.array1;
[pickerView reloadAllComponents];
pickerView.hidden = NO;
[self animatePickerViewIn];
return NO;
}
if (textField == self.pickerField2){
currentArray = self.array2;
[pickerView reloadAllComponents];
pickerView.hidden = NO;
[self animatePickerViewIn];
return NO;
}
// else {
// [currentTextField becomeFirstResponder];
// return NO;
// }
- (void)pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
[currentTextField setText:[currentArray objectAtIndex:row]];
[currentTextField resignFirstResponder];
pickerView.hidden = YES;
}
Thanks!
Adding this for anyone that needs more information - here's how I got it work using user2135738's provided code:
MyViewController.h
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController <UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate>
#property (weak, nonatomic) IBOutlet UITextField *aTextField;
#property (weak, nonatomic) IBOutlet UITextField *bTextField;
#end
MyViewController.m
#import "MyViewController.h"
#interface MyViewController ()
#end
#implementation MyViewController {
NSArray *aArray,
*bArray,
*currentArray;
UITextField *currentTextField;
UIPickerView *pickerView;
}
- (void)viewDidLoad {
aArray = [NSArray arrayWithObjects: #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, nil];
bArray = [NSArray arrayWithObjects:#"aString", #"bString", nil];
[super viewDidLoad];
pickerView = [[UIPickerView alloc] init];
pickerView.dataSource = self;
pickerView.delegate = self;
self.aTextField.delegate = self;
self.bTextField.delegate = self;
self.aTextField.inputView = pickerView;
self.bTextField.inputView = pickerView;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
currentTextField = textField;
if (textField == self.aTextField) {
currentArray = aArray;
[pickerView reloadAllComponents];
pickerView.hidden = NO;
return YES;
} else if (textField == self.bTextField){
currentArray = bArray;
[pickerView reloadAllComponents];
pickerView.hidden = NO;
return YES;
} else {
[currentTextField becomeFirstResponder];
return NO;
}
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [currentArray count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [NSString stringWithFormat:#"%#",[currentArray objectAtIndex:row]];
}
#end

Resources