Obj-C UIDownpicker 将在滚动期间用另一个值填充另一个文本字段

Posted

技术标签:

【中文标题】Obj-C UIDownpicker 将在滚动期间用另一个值填充另一个文本字段【英文标题】:Obj-C UIDownpicker will fill another textfield with another value during scrolls 【发布时间】:2018-11-19 03:26:30 【问题描述】:

我下面的代码将从服务器获取国家名称和国家代码并存储到2 NSMutablleMArraycountryMArraycodeMArraycode。当用户点击txtCountry UITextField时,它会调用down picker,当用户选择国家并点击完成时,它将根据索引获取Country Code from codeMArray并将代码放入txtCode UITexField

我想知道如何在滚动down picker 时立即填充txtCode UITextfield,而不是这种方式。有点像下面的图片。而不是让用户完成。当用户滚动down picker Country Name 时,txtCode UITexField 将自动填充为Code。有没有办法做到这一点。

在*中添加如下代码

我添加了 downpicker.m 和 downpicker.h 以及 * 中的代码,但它永远不会触发。请帮忙,谢谢。

RootViewController.h

#import <UIKit/UIKit.h>
#import "LoginViewController.h"
#import <DownPicker/UIDownPicker.h>

@protocol LoginViewProtocol <NSObject>

- (void)dismissAndLoginView;

@end

@interface RootViewController : UIViewController     <UITextFieldDelegate,UITableViewDelegate>
@property (strong, nonatomic) IBOutlet UITextField *txtCountry;
@property (weak, nonatomic) IBOutlet UIDownPicker *downCountry;
@property (strong, nonatomic) IBOutlet UITextField *txtCode;
@property (strong, nonatomic) IBOutlet UITextField *txtPhone;
@property (strong, nonatomic) NSMutableArray *countryMArray;
@property (strong, nonatomic) NSMutableArray *codeMArray;
@property (nonatomic) DownPicker *pickerCountry;

@end

RootViewController.m

#import "RootViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface RootViewController ()
    NSString *sURL,*sResponseData, *sRemaining;
    NSString *sCode;


@end

@implementation RootViewController

@synthesize loginView;
@synthesize txtCountry,txtCode,txtPhone;
@synthesize countryMArray;
@synthesize codeMArray;

- (void)viewDidLoad

    [super viewDidLoad];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];

    [self.view addGestureRecognizer:tap];

    //=== Initiallize the Mutable Array
    countryMArray = [[NSMutableArray alloc] init];
    codeMArray = [[NSMutableArray alloc] init];

    //=== Initialize the responseData Mutable Data
    self.responseData = [NSMutableData data];

    //=== Pass the string to server to get the return Country response.write
    appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    sURL = @"https://www.share-fitness.com";
    sURL = [sURL stringByAppendingString:@"/apps/getcountry.asp?"];

    NSURLRequest *requestCountry = [NSURLRequest requestWithURL:[NSURL URLWithString:sURL]];

    (void) [[NSURLConnection alloc] initWithRequest:requestCountry delegate:self];

    //=== Pass the string to server to get the return CountryCode
    sURL = @"https://www.share-fitness.com";
    sURL = [sURL stringByAppendingString:@"/apps/getctcode.asp?"];

    NSURLRequest *requestCode = [NSURLRequest requestWithURL:[NSURL URLWithString:sURL]];

    (void) [[NSURLConnection alloc] initWithRequest:requestCode delegate:self];

    //=== Initialie the picker ====
    self.pickerCountry = [[DownPicker alloc] initWithTextField:self.txtCountry withData:countryMArray];

    [self.pickerCountry addTarget:self
                       action:@selector(pickerClicked:)
             forControlEvents:UIControlEventValueChanged];



//**** ADDED the following but will never trigger ?
 - (void)pickerView:(UIDownPicker *)pickerCountry didSelectRow:(NSInteger)row inComponent:(NSInteger)component

    sCode = [codeMArray objectAtIndex:row];
    txtCode.text = [@"+"stringByAppendingString:sCode];

//**********************
 //=== Pick the countryCode, when Country is selected based on Array Index
 -(void)pickerClicked:(id)dp 

    NSString* selectedValue = [self.pickerCountry text];

    for ( int i = 0 ; i < countryMArray.count; i++) 

        NSString*item = [countryMArray objectAtIndex:i];

        if([item isEqualToString:selectedValue])
        
            sCode = [codeMArray objectAtIndex:i];
            txtCode.text = [@"+"stringByAppendingString:sCode];

            break;
        

    

Downpicker.h

#import <UIKit/UIKit.h>

@interface DownPicker : UIControl<UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate>

    UIPickerView* pickerView;
    IBOutlet UITextField* textField;
    NSArray* dataArray;
    NSString* placeholder;
    NSString* placeholderWhileSelecting;
    NSString* toolbarDoneButtonText;
    NSString* toolbarCancelButtonText;
    UIBarStyle toolbarStyle;


@property (nonatomic) NSString* text;
@property (nonatomic) NSInteger selectedIndex;

-(id)initWithTextField:(UITextField *)tf;
-(id)initWithTextField:(UITextField *)tf withData:(NSArray*) data;

@property (nonatomic) BOOL shouldDisplayCancelButton;

/**
Sets an alternative image to be show to the right part of the textbox (assuming that showArrowImage is set to TRUE).
 @param image
 A valid UIImage
*/
-(void) setArrowImage:(UIImage*)image;

-(void) setData:(NSArray*) data;
-(void) setPlaceholder:(NSString*)str;
-(void) setPlaceholderWhileSelecting:(NSString*)str;
-(void) setAttributedPlaceholder:(NSAttributedString *)attributedString;
-(void) setToolbarDoneButtonText:(NSString*)str;
-(void) setToolbarCancelButtonText:(NSString*)str;
-(void) setToolbarStyle:(UIBarStyle)style;

/**
 TRUE to show the rightmost arrow image, FALSE to hide it.
 @param b
 TRUE to show the rightmost arrow image, FALSE to hide it.
*/
-(void) showArrowImage:(BOOL)b;

-(UIPickerView*) getPickerView;
-(UITextField*) getTextField;

/**
Retrieves the string value at the specified index.
@return
The value at the given index or NIL if nothing has been selected yet.
*/
-(NSString*) getValueAtIndex:(NSInteger)index;

/**
Sets the zero-based index of the selected item: -1 can be used to clear        selection.
@return
The value at the given index or NIL if nothing has been selected yet.
*/
-(void) setValueAtIndex:(NSInteger)index;
@end

Downpicker.m

#import "DownPicker.h"

@implementation DownPicker

    NSString* _previousSelectedString;


-(id)initWithTextField:(UITextField *)tf

    return [self initWithTextField:tf withData:nil];


-(id)initWithTextField:(UITextField *)tf withData:(NSArray*) data

     self = [super init];
     if (self) 
        self->textField = tf;
        self->textField.delegate = self;

        // set UI defaults
        self->toolbarStyle = UIBarStyleDefault;

        // set language defaults
        self->placeholder = @"Tap to choose...";
        self->placeholderWhileSelecting = @"Pick an option...";
        self->toolbarDoneButtonText = @"Done";
        self->toolbarCancelButtonText = @"Cancel";

        // hide the caret and its blinking
        [[textField valueForKey:@"textInputTraits"]
         setValue:[UIColor clearColor]
         forKey:@"insertionPointColor"];

        // set the placeholder
        self->textField.placeholder = self->placeholder;

        // setup the arrow image
        UIImage* img = [UIImage imageNamed:@"downArrow.png"];   // non-CocoaPods
        if (img == nil) img = [UIImage imageNamed:@"DownPicker.bundle/downArrow.png"]; // CocoaPods
        if (img != nil) self->textField.rightView = [[UIImageView alloc] initWithImage:img];
        self->textField.rightView.contentMode = UIViewContentModeScaleAspectFit;
        self->textField.rightView.clipsToBounds = YES;

        // show the arrow image by default
        [self showArrowImage:YES];

        // set the data array (if present)
        if (data != nil) 
            [self setData: data];
        

        self.shouldDisplayCancelButton = YES;
    
    return self;


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    return (interfaceOrientation == UIInterfaceOrientationPortrait);


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;

    return 1;


- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

    self->textField.text = [dataArray objectAtIndex:row];


 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
 
    return [dataArray count];
 

 - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
 
    return [dataArray objectAtIndex:row];
 

 -(void)doneClicked:(id) sender
 
    //hides the pickerView
    [textField resignFirstResponder];

    if (self->textField.text.length == 0 || ![self->dataArray containsObject:self->textField.text]) 
        // self->textField.text = [dataArray objectAtIndex:0];
        [self setValueAtIndex:-1];
        self->textField.placeholder = self->placeholder;
    
    /*
    else 
        if (![self->textField.text isEqualToString:_previousSelectedString])   
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        
    
    */
    [self sendActionsForControlEvents:UIControlEventValueChanged];


-(void)cancelClicked:(id)sender

    [textField resignFirstResponder]; //hides the pickerView
    if (_previousSelectedString.length == 0 || ![self->dataArray containsObject:_previousSelectedString]) 
        self->textField.placeholder = self->placeholder;
    
    self->textField.text = _previousSelectedString;


- (IBAction)showPicker:(id)sender

    _previousSelectedString = self->textField.text;

    pickerView = [[UIPickerView alloc] init];
    pickerView.showsSelectionIndicator = YES;
    pickerView.dataSource = self;
    pickerView.delegate = self;

    //If the text field is empty show the place holder otherwise show the last selected option
    if (self->textField.text.length == 0 || ![self->dataArray containsObject:self->textField.text])
    
        if (self->placeholderWhileSelecting) 
            self->textField.placeholder = self->placeholderWhileSelecting;
        
         // 0.1.31 patch: auto-select first item: it basically makes placeholderWhileSelecting useless, but
         // it solves the "first item cannot be selected" bug due to how the pickerView works.
        [self setSelectedIndex:0];
    
     else
    
        if ([self->dataArray containsObject:self->textField.text]) 
            [self->pickerView selectRow:[self->dataArray indexOfObject:self->textField.text] inComponent:0 animated:YES];
        
    

    UIToolbar* toolbar = [[UIToolbar alloc] init];
    toolbar.barStyle = self->toolbarStyle;
    [toolbar sizeToFit];

    //space between buttons
    UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                                                               target:nil
                                                                               action:nil];

    UIBarButtonItem* doneButton = [[UIBarButtonItem alloc]
                               initWithTitle:self->toolbarDoneButtonText
                               style:UIBarButtonItemStyleDone
                               target:self
                               action:@selector(doneClicked:)];

    if (self.shouldDisplayCancelButton) 
        UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
                                     initWithTitle:self->toolbarCancelButtonText
                                     style:UIBarButtonItemStylePlain
                                     target:self
                                     action:@selector(cancelClicked:)];

        [toolbar setItems:[NSArray arrayWithObjects:cancelButton, flexibleSpace, doneButton, nil]];
     else 
        [toolbar setItems:[NSArray arrayWithObjects:flexibleSpace, doneButton, nil]];
    

    //custom input view
    textField.inputView = pickerView;
    textField.inputAccessoryView = toolbar;  


- (BOOL)textFieldShouldBeginEditing:(UITextField *)aTextField

    if ([self->dataArray count] > 0) 
        [self showPicker:aTextField];
        return YES;
    
    return NO;


- (void)textFieldDidEndEditing:(UITextField *)aTextField 
    // [self doneClicked:aTextField];
    aTextField.userInteractionEnabled = YES;


- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:  (NSRange)range replacementString:(NSString *)string

    return NO;


-(void) setData:(NSArray*) data

    dataArray = data;
    NSLog(@" This is the data : %@ ", dataArray);


-(void) showArrowImage:(BOOL)b  

    if (b == YES) 
      // set the DownPicker arrow to the right (you can replace it with any 32x24 px transparent image: changing size might give different results)
    self->textField.rightViewMode = UITextFieldViewModeAlways;
    
    else 
        self->textField.rightViewMode = UITextFieldViewModeNever;
    


-(void) setArrowImage:(UIImage*)image

    [(UIImageView*)self->textField.rightView setImage:image];


-(void) setPlaceholder:(NSString*)str

    self->placeholder = str;
    self->textField.placeholder = self->placeholder;


-(void) setPlaceholderWhileSelecting:(NSString*)str

    self->placeholderWhileSelecting = str;


-(void) setAttributedPlaceholder:(NSAttributedString *)attributedString

    self->textField.attributedPlaceholder = attributedString;


-(void) setToolbarDoneButtonText:(NSString*)str

    self->toolbarDoneButtonText = str;


-(void) setToolbarCancelButtonText:(NSString*)str

    self->toolbarCancelButtonText = str;


-(void) setToolbarStyle:(UIBarStyle)style;

    self->toolbarStyle = style;


-(UIPickerView*) getPickerView

    return self->pickerView;


-(UITextField*) getTextField

    return self->textField;


-(NSString*) getValueAtIndex:(NSInteger)index

    return (self->dataArray.count > index) ? [self->dataArray    objectAtIndex:index] : nil;


-(void) setValueAtIndex:(NSInteger)index

    if (index >= 0) [self pickerView:nil didSelectRow:index inComponent:0];
    else [self setText:nil];


/**
 Getter for text property.
 @return
 The value of the selected item or NIL NIL if nothing has been selected yet.
 */
- (NSString*) text 
    return self->textField.text;


/**
 Setter for text property.
 @param txt
 The value of the item to select or NIL to clear selection.
 */
- (void) setText:(NSString*)txt 
    if (txt != nil) 
        NSInteger index = [self->dataArray indexOfObject:txt];
        if (index != NSNotFound) [self setValueAtIndex:index];
    
    else 
        self->textField.text = txt;
    


/**
 Getter for selectedIndex property.
 @return
 The zero-based index of the selected item or -1 if nothing has been selected yet.
 */
- (NSInteger)selectedIndex 
    NSInteger index = [self->dataArray indexOfObject:self->textField.text];
    return (index != NSNotFound) ? (NSInteger)index : -1;


/**
 Setter for selectedIndex property.
 @param index
 Sets the zero-based index of the selected item using the setValueAtIndex method:    -1 can be used to clear selection.
 */
- (void)setSelectedIndex:(NSInteger)index 
    [self setValueAtIndex:(NSInteger)index];


@end

【问题讨论】:

【参考方案1】:

也许你的 Downpicker 是 UIPickerView 的子类,你应该实现它的委托方法,命名为:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component __TVOS_PROHIBITED;

可以解决你的问题。

【讨论】:

【参考方案2】:

首先我建议您使用 NSDictionary 而不是两个数组:您可以将字典的键设置为国家短,将值设置为电话并将其用作:

NSString *phoneCode = self.codeDict[@"en"];

其次,为 DownPicker 创建一个类别并覆盖 [pickerView:didSelectRow:inComponent]。从那里您可以发布用于完成操作的相同通知,或者您可以为此创建协议。

【讨论】:

【参考方案3】:

正如前面提到的其他答案,这里的关键应该在 pickerView:didSelectRow:inComponent 委托方法中。

您似乎已将其添加到您的 RootViewController,但 RootViewController 不是 UIPickerViewDelegate(您的 UIPickerView 的子类是)。为了解决这个问题,您需要将 RootViewController 调整为 UIPickerViewDelegate,并将您的 pickerView 代理实例设置为 RootViewController:

@interface RootViewController : UIViewController

@interface RootViewController : UIViewController     <UITextFieldDelegate,UITableViewDelegate, UIPickerViewDelegate>

...

然后在 rootViewController 的 viewDidLoad 中将选取器视图的委托设置为 self:

self.pickerCountry.delegate = self

【讨论】:

以上是关于Obj-C UIDownpicker 将在滚动期间用另一个值填充另一个文本字段的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C:点击 UIDownPicker 并获取 UITextfield 的值

在swift或obj-c中的uitextview末尾添加一个视图

OBJ-C:核心绘图 XY 轴固定

如何从 obj-c / ios 中的堆栈跟踪中获取源代码行

iOS/Obj-C UIScrollView 视图未正确添加

基于尺寸元素的设备旋转期间的动画更改将在旋转完成后进行