I have Two text field in my View. i am using picker view as input. when ever picker is enabled the keyboard is visible behind the picker.The other issue is when i use Resign First responder for the text field in the Action the first time it shows picker without the keyboard at behind.But the second time when i click the text field the KeyBoard appears instead of picker. Here is my code.
- (IBAction)selectService:(id)sender
{
[self createActionSheet];
//[selectServiceTextBox resignFirstResponder];
pickerType = #"servicePickerType";
servicePicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
pickerArray = [[NSArray alloc]initWithObjects:#"Money Transfer",#"Bill Payment", nil];
servicePicker.dataSource = self;
servicePicker.delegate = self;
servicePicker.showsSelectionIndicator = YES;
[actionSheet addSubview:servicePicker];
// rowIndex = [stateTextField.text intValue];
//[servicePicker selectRow:rowIndex inComponent:0 animated:NO];
}
- (IBAction)wayOfTransfer:(id)sender
{
if ([selectedItem isEqualToString:#""])
{
NSLog(#"empty selection");
}
else if ([selectServiceTextBox.text isEqualToString:#"Money Transfer"])
{
[self createActionSheet];
// [secondTextBox resignFirstResponder];
//[selectServiceTextBox resignFirstResponder];
pickerType = #"MoneyTransferMethod";
servicePicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
pickerArrayTwo = [[NSArray alloc]initWithObjects:#"Cash Pick-up",#"Bank Account",#"Zym Card", nil];
servicePicker.dataSource = self;
servicePicker.delegate = self;
servicePicker.showsSelectionIndicator = YES;
[actionSheet addSubview:servicePicker];
}
}
You have to make the picker and keyboard appear exclusive of each other so that both can gracefully be switched between each other.. One way to do it is make the picker hidden by default and then bring it on screen when the first textview is on focus using an animation... Similarly hide it while bringing keyboard on using the second textview.
I have made a sample project that does this and have tested it... I hope this is what you intend to do...
//ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextViewDelegate,UIPickerViewDataSource,UIPickerViewDelegate>
#property (weak, nonatomic) IBOutlet UITextView *firstTextView;
#property (weak, nonatomic) IBOutlet UITextView *secondTextView;
#property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
#end
//ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController{
NSMutableArray *pickerDataSource;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
pickerDataSource = [[NSMutableArray alloc] initWithObjects:#"data1",#"data2", nil];
self.pickerView.frame = CGRectMake(0, self.view.frame.size.height, 320, 162);
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
}
// Textview delegates
-(void)textViewDidBeginEditing:(UITextView *)textView{
if ([textView isEqual:self.firstTextView]) {
[textView resignFirstResponder];
if (self.pickerView.frame.origin.y >= self.view.frame.size.height) {
[self showPicker];
}else{
[self hidePicker];
}
}else{
[self hidePicker];
[self.secondTextView becomeFirstResponder];
}
}
-(void)showPicker{
[UIView animateWithDuration:0.2 animations:^{
self.pickerView.frame = CGRectMake(self.pickerView.frame.origin.x, self.pickerView.frame.origin.y - self.pickerView.frame.size.height, self.pickerView.frame.size.width, self.pickerView.frame.size.height);
}];
}
-(void)hidePicker{
[UIView animateWithDuration:0.2 animations:^{
self.pickerView.frame = CGRectMake(self.pickerView.frame.origin.x, self.pickerView.frame.origin.y + self.pickerView.frame.size.height, self.pickerView.frame.size.width, self.pickerView.frame.size.height);
}];
}
// Picker Delegates
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return pickerDataSource.count;
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.firstTextView.text = pickerDataSource[row];
}
-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [pickerDataSource objectAtIndex:row];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Please let me know if there is anything unclear.
i think you need hide keyboard behind picker view ... simple you put this code in your text click action method
UItextfield delegate method.....
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[text_box_variable resignFirstResponder];
}
Related
I am trying to use pure code to create UI practice block pass value between viewController. But the callback block didn't work. The NSLog method didn't print anything on debug area. Here's the code. Give me some tips, thank you.
VC.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (copy, nonatomic) void (^callBack)(NSString *text);
#end
VC.m
- (UITextField *)textField {
if (!_textField) {
_textField = [[UITextField alloc] init];
_textField.backgroundColor = [UIColor whiteColor];
}
return _textField;
}
- (UIButton *)button {
if (!_button) {
_button = [[UIButton alloc] init];
_button.backgroundColor = [UIColor blueColor];
[_button addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
- (void)setupUI {
[self.view addSubview:self.textField];
[self.view addSubview:self.button];
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view.mas_centerX);
make.centerY.mas_equalTo(self.view);
}];
[self.button mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view);
make.centerY.mas_equalTo(self.view).offset(100);
}];
}
- (void)buttonAction {
NSString *str = self.textField.text;
if (self.callBack != nil) {
self.callBack(str);
NSLog(#"This statement didnt print in log");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
}
update code
VC2.m
- (void)viewWillAppear:(BOOL)animated{
self.callBack = ^(NSString *text){
};
}
- (void)buttonAction {
if (self.callBack) {
NSLog(#"It worked on debug area %#", self.textField.text);
self.callBack(self.textField.text);
}
self.textField.text = #"";
}
VC1.m
- (void)viewDidLoad {
[super viewDidLoad];
_secondVc = [[SecondViewController alloc] init];
_secondVc.callBack = ^(NSString *str){
};
[self setupUI];
self.view.backgroundColor = [UIColor greenColor];
}
- (void)viewWillAppear:(BOOL)animated {
if (_secondVc.callBack != nil) {
NSLog(#"It wrked on debug screen");
_secondVc.callBack = ^(NSString *str){
NSLog(#"It didn't worked on debug screen");
//I want set my label.text = str;
};
};
}
The only way is that you property
#property (copy, nonatomic) void (^callBack)(NSString *text);
is empty. Try to put breakpoint in buttonAction method and look at the property.
As Sander and KrishnaCA mentioned your callBack is nil. I would suggest you create a definition of the block like this:
typedef void(^TextBlock)(NSString *text);
Then change your property to:
#property (copy, nonatomic) TextBlock callBack;
Create a copy of the block in your first view controller:
#interface FirstViewController()
#property (copy, nonatomic) TextBlock firstViewControllerCallBack;
#end
Initialize the callback copy (i.e. in viewDidLoad)
- (void)viewDidLoad {
[super viewDidLoad];
self.firstViewControllerCallBack = ^(NSString *text){
NSLog(#"Second view controller's button tapped!");
};
}
Assign the callback to the second view controller right before presenting/pushing it:
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.callBack = self.firstViewControllerCallBack; // Assign the callback
// ... Presenting the view controller
Clean up the completion block after you done with it (i.e. in viewWillDisappear):
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.firstViewControllerCallBack = nil;
}
In my app I want to programmatically add textfield below another if required on click of a button. I already had provided two textFields. if a user want to add another textfield he can do so by clicking a button. I have already written code to obtain the textfield but the problem is that it overlaps the already designed textFields. How can I do it?
Is there any way through which I can get the x and Y co-ordinates of already designed textfield so that I can place new textField relative to those co-ordinates.
This code add textField to view dynamically when every click action on button
ExampleViewController.h
#import <UIKit/UIKit.h>
#interface ExampleViewController :UIViewController<UITextFieldDelegate>
#property int positionY;
#property int fieldCount;
#property (strong,nonatomic) UIScrollView *scroll;
#end
ExampleViewController.m
#import "ExampleViewController.h"
#interface ExampleViewController ()
#end
#implementation ExampleViewController
#synthesize positionY;
#synthesize fieldCount;
#synthesize scroll;
- (void)viewDidLoad {
[super viewDidLoad];
scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.backgroundColor = [UIColor whiteColor];
[self.view addSubview:scroll];
UIButton *clickToCreateTextField = [[UIButton alloc] initWithFrame:CGRectMake(40, 80, self.view.frame.size.width-80, 75)];
[clickToCreateTextField setTitle:#"Create Text Field" forState:UIControlStateNormal];
[clickToCreateTextField addTarget:self action:#selector(clickedButton) forControlEvents:UIControlEventTouchUpInside];
[clickToCreateTextField setBackgroundColor:[UIColor blackColor]];
[scroll addSubview:clickToCreateTextField];
positionY = clickToCreateTextField.center.y;
fieldCount = 0;
// Do any additional setup after loading the view.
}
-(void) clickedButton{
//add text field programmitacally
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(40, positionY, self.view.frame.size.width-80, 75)];
textField.delegate = self;
//give a tag to determine the which textField tapped
textField.tag = fieldCount;
textField.placeholder = [NSString stringWithFormat:#"Your dynamically created textField: %d", fieldCount ];
[scroll addSubview:textField];
//check if the textFields bigger than view size set scroll size and offset
if (positionY>= self.view.frame.size.height) {
scroll.contentOffset = CGPointMake(0, positionY);
scroll.contentSize = CGSizeMake(scroll.frame.size.width, scroll.frame.size.height+positionY);
}
fieldCount++;
//increase the position with a blank place
positionY = positionY+textField.frame.size.height+20;
}
#pragma mark TextField Delegate Methods
-(void) textFieldDidBeginEditing:(UITextField *)textField{
//Do what ever you want
}
-(void) textFieldDidEndEditing:(UITextField *)textField{
[textField resignFirstResponder];
//do anything
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
You can do any additional changes on this code.
I think this example explain your answer.
Hope it helps.
Use a counter and calculate y like this counter*texfield.frame.size.height.
I'm wondering if there is a way to slide the first-responder keyboard to the left or to the right when the user press a button.
http://cl.ly/image/143K3t403d1m/1.png
I make the button as a keyboard-accessory view. When it's tapped the keyboard should slide to the left displaying another custom inputs panel.
Any ideas?
If you want a keyboard that can be selected from the system (using the globe key), you'll need to read this article about creating a Custom Keyboard App Extension for iOS 8.
If you just want to be able to switch between inputView objects, the following code will get you there:
// ViewController.m
#import "ViewController.h"
#interface ViewController () {
}
#pragma mark -
#pragma mark - UI Controls
#property (strong, nonatomic) UIInputView *inputView;
#property (strong, nonatomic) UITextField *textField;
#end
#implementation ViewController
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
#pragma mark -
#pragma mark - Keyboard switching
- (void)switchKeyboard {
// Simply toggle the "inputView" for self.textField
if (self.textField.inputView == nil) {
self.textField.inputView = self.inputView;
} else {
self.textField.inputView = nil;
}
[self.textField resignFirstResponder];
[self.textField becomeFirstResponder];
}
#pragma mark -
#pragma mark - UI Setup
// All of the code below here
// is for pure, in-code AutoLayout
- (void)setupUserInterface {
[self createControls];
[self setupControls];
[self layoutControls];
}
- (void)createControls {
self.textField = [[UITextField alloc] init];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.inputView = [[UIInputView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 216.0f)];
self.inputView.backgroundColor = [UIColor lightGrayColor];
}
- (void)setupControls {
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44.0f)];
toolbar.backgroundColor = [UIColor lightGrayColor];
// When the button is tapped, it'll execute "switchKeyboard" above
UIBarButtonItem *switchButton = [[UIBarButtonItem alloc] initWithTitle:#"Switch" style:UIBarButtonItemStyleDone target:self action:#selector(switchKeyboard)];
toolbar.items = #[switchButton];
self.textField.inputAccessoryView = toolbar;
[self.textField setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (void)layoutControls {
[self.view addSubview:self.textField];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[textfield]-|"
options:0
metrics:nil
views:#{#"textfield": self.textField}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(height)-[textfield(==height)]"
options:0
metrics:#{#"height" : #(40)}
views:#{#"textfield": self.textField}]];
}
#end
Caveat: You will need to do a lot of tweaking to make sure the user experience is good. In my testing, on the simulator (iPhone 4S), this works ok, but isn't the smoothest user experience.
In my app I've to create a custom alert view like the following:
So I followed this tutorial to create a custom alert view. I finished it but I'm getting issue in the following method:
- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
NSMutableArray *items = [[NSMutableArray alloc]init];
[items addObject:self.buttonOk];
[items addObject:self.buttonClose];
int buttonIndex = (tag == 1);
if (shouldRemove) {
[items removeObjectAtIndex:buttonIndex];
} else {
if (tag == 1) {
[items insertObject:self.buttonOk atIndex:buttonIndex];
} else {
[items insertObject:self.buttonClose atIndex:buttonIndex];
}
}
}
I edited it than the tutorial because I don't need a UIToolBar for buttons. When I run the app it says me that I can't insert a nil object in an NSMutableArray, but I don't understand what's wrong, I hope you can help me to fix this issue.
UPDATE
Here's all the class code I developed:
#import "CustomAlertViewController.h"
#define ANIMATION_DURATION 0.25
#interface CustomAlertViewController ()
- (IBAction)buttonOk:(UIButton *)sender;
- (IBAction)buttonCancel:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UIButton *buttonClose;
#property (weak, nonatomic) IBOutlet UIButton *buttonOk;
#property (strong, nonatomic) IBOutlet UIView *viewAlert;
-(void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove;
#end
#implementation CustomAlertViewController
- (id)init
{
self = [super init];
if (self) {
[self.viewAlert setFrame:CGRectMake(self.labelAlertView.frame.origin.x,
self.labelAlertView.frame.origin.y,
self.labelAlertView.frame.size.width,
self.viewAlert.frame.size.height)];
[self.buttonOk setTag:1];
[self.buttonClose setTag:0];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)showCustomAlertInView:(UIView *)targetView withMessage:(NSString *)message {
CGFloat statusBarOffset;
if (![[UIApplication sharedApplication] isStatusBarHidden]) {
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
if (statusBarSize.width < statusBarSize.height) {
statusBarOffset = statusBarSize.width;
} else {
statusBarOffset = statusBarSize.height;
}
} else {
statusBarOffset = 0.0;
}
CGFloat width, height, offsetX, offsetY;
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft ||
[[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
width = targetView.frame.size.width;
height = targetView.frame.size.height;
offsetX = 0.0;
offsetY = -statusBarOffset;
}
[self.view setFrame:CGRectMake(targetView.frame.origin.x, targetView.frame.origin.y, width, height)];
[self.view setFrame:CGRectOffset(self.view.frame, offsetX, offsetY)];
[targetView addSubview:self.view];
[self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:ANIMATION_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.viewAlert setFrame:CGRectMake(0.0, 0.0, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView commitAnimations];
[self.labelAlertView setText:#"CIAO"];
}
- (void)removeCustomAlertFromView {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:ANIMATION_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView commitAnimations];
[self.view performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:ANIMATION_DURATION];
}
- (void)removeCustomAlertFromViewInstantly {
[self.view removeFromSuperview];
}
- (BOOL)isOkayButtonRemoved {
if (self.buttonOk == nil) {
return YES;
} else {
return NO;
}
}
- (BOOL)isCancelButtonRemoved {
if (self.buttonClose == nil) {
return YES;
} else {
return NO;
}
}
- (void)removeOkayButton:(BOOL)shouldRemove {
if ([self isOkayButtonRemoved] != shouldRemove) {
[self addOrRemoveButtonWithTag:1 andActionToPerform:shouldRemove];
}
}
- (void)removeCancelButton:(BOOL)shouldRemove {
if ([self isCancelButtonRemoved] != shouldRemove) {
[self addOrRemoveButtonWithTag:0 andActionToPerform:shouldRemove];
}
}
- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
NSMutableArray *items = [[NSMutableArray alloc]init];
[items addObject:self.buttonOk];
[items addObject:self.buttonClose];
int buttonIndex = (tag == 1);
if (shouldRemove) {
[items removeObjectAtIndex:buttonIndex];
} else {
if (tag == 1) {
[items insertObject:self.buttonOk atIndex:buttonIndex];
} else {
[items insertObject:self.buttonClose atIndex:buttonIndex];
}
}
}
- (IBAction)buttonOk:(UIButton *)sender {
[self.delegate customAlertOk];
}
- (IBAction)buttonCancel:(UIButton *)sender {
[self.delegate customAlertCancel];
}
#end
UPDATE 2
Code in which I use the CustomAlertView:
#import "PromotionsViewController.h"
#import "CustomAlertViewController.h"
#interface PromotionsViewController () <CustomAlertViewControllerDelegate> {
BOOL isDeletingItem;
}
#property(nonatomic,strong) CustomAlertViewController *customAlert;
- (IBAction)buttonBack:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UIButton *buttonAlert;
- (IBAction)buttonAlert:(UIButton *)sender;
#end
#implementation PromotionsViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.buttonAlert setTitle:self.promotionSelected forState:UIControlStateNormal];
[self.customAlert setDelegate:self];
isDeletingItem = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonBack:(UIButton *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc]init];
[self.customAlert removeOkayButton:NO];
[self.customAlert removeCancelButton:NO];
NSString *message = [NSString stringWithFormat:#"La tua offerta %# del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
[self.customAlert showCustomAlertInView:self.view withMessage:message];
isDeletingItem = YES;
}
- (void)customAlertOk {
if (isDeletingItem) {
[self.customAlert removeCustomAlertFromViewInstantly];
} else {
[self.customAlert removeCustomAlertFromView];
}
}
- (void)customAlertCancel {
[self.customAlert removeCustomAlertFromView];
if (isDeletingItem) {
isDeletingItem = NO;
}
}
#end
Maybe you're calling addOrRemoveButtonWithTag:andActionToPerform: at a time where your UI is not fully created, since UI elements are created asynchronously. So if you call this method, right after custom alert view instanciation, you'll get your crash because the buttons in the view are not created.
To solve this issue, you need to call addOrRemoveButtonWithTag:andActionToPerform: only once your custom alert has been added to the view hierarchy.
EDIT :
With the example code you gave in edit 2, you call these lines :
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc]init];
[self.customAlert removeOkayButton:NO];
[self.customAlert removeCancelButton:NO];
}
but when you have just instantiated CustomAlertViewController, its 2 buttons are not yet created, so I suggest you add 2 properties hasOkButton and hasCancelButton and a new constructor to your custom class like this one :
- (instancetype) initWithOk:(BOOL)OkButton AndCancel:(BOOL) CancelButton
{
if(self = [super init])
{
hasOkButton = OkButton;
hasCancelButton = CancelButton;
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// At this time, the custom UI buttons will be created in the UI view hierarchy
[self removeOkayButton: hasOkButton];
[self removeOkayButton: hasCancelButton];
}
And in the caller you can use the following to display a custom alert View:
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc] initWithOk:NO AndCancel:NO];
// ...
}
EDIT #2
I tried your solution in a real project, I made it work by using these lines int the caller :
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [self.storyboard instantiateViewControllerWithIdentifier:#"customAlertView"];
self.customAlert.hasOK = NO;
self.customAlert.hasCancel = YES;
NSString *message = [NSString stringWithFormat:#"La tua offerta %# del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
[self.customAlert showCustomAlertInView:self.view withMessage:message];
isDeletingItem = YES;
}
In the CustomAlertViewController declare 2 visible properties hasOK and hasCancel in.h.
And modify your .m by adding method :
-(void)viewWillAppear:(BOOL)animated
{
[self removeOkayButton:self.hasOK];
[self removeCancelButton:self.hasCancel];
}
Be sure to modify your storyboard (if eligible) to have the "customAlertView" defined this way :
Don't forget also to bind your UIButton to the controller this can be a mistake too in your implementation :
Hope this will help you :)
I found on the web a tutorial to create custom alert view by using code, if you are interested you can go to this tutorial. I used it for my issue and it worked great! You have to fix a few things, because it uses deprecated command but it's easy to fix it.
If you are interested just take a look about this tutorial. I think you can integrate it in your app and after you can easily use for other stuff if it's necessary. I hope that my answer will help someone.
I have a Storyboard with a ViewController using a navigation controller and a TabBarController. I have been trying to resolve this for a few days now.
The problem:
Very often user I cannot interact with the view... that includes scrolling, tapping the text field and any buttons being pressed. Something is stopping me from interacting with the newly loaded UIView.
I have tried using the init method and tried using the init with frame method. The view is showing all the time though so maybe this is not the problem.
I have tried remaking the whole xib file, re-coding the .h and .m files and re-attaching all the outlets on the view.
I am stuck
In the view controller I am loading a UIView with separate .xib file and separate .h and .m file.
This is how I am doing it:
in my ViewController in the viewDidAppear method:
int startPos = self.navigationController.navigationBar.frame.size.height+20;
inviteFriendsView = [[InviteFriendsEmailAddressesView alloc] init];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"InviteFriendsEmailAddressesView" owner:self options:nil];
inviteFriendsView = (InviteFriendsEmailAddressesView*)[nib objectAtIndex:0];
[self.view addSubview:inviteFriendsView];
[inviteFriendsView setDelegate:self];
[inviteFriendsView setUserInteractionEnabled:YES];
[inviteFriendsView customizeView];
[inviteFriendsView setAlpha:0.0];
[inviteFriendsView setY:startPos];
IBAction method for showing the view:
- (IBAction)inviteFriendsButtonTapped:(id)sender {
[self.view bringSubviewToFront:inviteFriendsView];
[inviteFriendsView setUserInteractionEnabled:YES];
[inviteFriendsView animate];
}
Here is the .h and .m files which show how I am loading the view:
InviteFriendsEmailAddressesView.h
#import <UIKit/UIKit.h>
#import "InviteFriendsViewDelegate.h"
#import "InviteFriendsNetworkContollerDelegate.h"
#import "InviteFriendsNetworkController.h"
#interface InviteFriendsEmailAddressesView : UIView <UITextFieldDelegate, UITextViewDelegate, InviteFriendsNetworkContollerDelegate, UIGestureRecognizerDelegate>
- (void) customizeView;
- (void) animate;
#property BOOL visible;
#property int y;
#property id<InviteFriendsViewDelegate> delegate;
#property (strong, nonatomic) NSArray *emails;
#property int height;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
#property (weak, nonatomic) IBOutlet UILabel *inviteFriendsTitle;
#property (weak, nonatomic) IBOutlet UILabel *inviteFriendsDescription;
#property (weak, nonatomic) IBOutlet UITextField *userEmailTextField;
#property (weak, nonatomic) IBOutlet UIImageView *userEmailImageView;
#property (weak, nonatomic) IBOutlet UIButton *addFriendsButtonOutlet;
#property (weak, nonatomic) IBOutlet UILabel *emailAddressesDescription;
#property (weak, nonatomic) IBOutlet UIImageView *viewBackground;
#property (weak, nonatomic) IBOutlet UIView *emailAddressesCellBackground;
#property (weak, nonatomic) IBOutlet UILabel *emailAddressCellTextUILabel;
#property (weak, nonatomic) IBOutlet UIButton *emailAddressCancelButton;
#property (weak, nonatomic) IBOutlet UIView *emailAddressView;
#property (weak, nonatomic) IBOutlet UIButton *sendInviteButtonOutlet;
#property (weak, nonatomic) IBOutlet UIButton *progressSoFarButtonOutlet;
#property (weak, nonatomic) IBOutlet UIScrollView *viewScrollView;
#property (strong, nonatomic) InviteFriendsNetworkController *inviteFriendsNetworkController;
#pragma mark - UITextFieldDelegate Methods
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; // return NO to disallow editing.
- (void)textFieldDidBeginEditing:(UITextField *)textField; // became first responder
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField; // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
- (void)textFieldDidEndEditing:(UITextField *)textField; // may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
- (BOOL)textFieldShouldClear:(UITextField *)textField; // called when clear button pressed. return NO to ignore (no notifications)
- (BOOL)textFieldShouldReturn:(UITextField *)textField; // called when 'return' key pressed. return NO to ignore.
#end
InviteFriendsEmailAddressesView.m
#import "InviteFriendsEmailAddressesView.h"
#import "UIFont+Theme.h"
#import "UIColor+Theme.h"
#import "UIImage+Theme.h"
#implementation InviteFriendsEmailAddressesView
#synthesize emails;
#synthesize visible;
#synthesize y;
#synthesize delegate;
#synthesize height;
#synthesize inviteFriendsNetworkController;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"InviteFriendsEmailAddressesView" owner:self options:nil];
self = [nib objectAtIndex:0];
}
return self;
}
- (id) init {
// self = [[[NSBundle mainBundle] loadNibNamed:#"InviteFriendsEmailAddressesView" owner:self options:nil] objectAtIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(themeChanged)
name:#"New Theme Applied"
object:nil];
NSUserDefaults *properties = [NSUserDefaults standardUserDefaults];
if([properties objectForKey:#"emails"]){
emails = [properties objectForKey:#"emails"];
} else {
emails = [[NSArray alloc] init];
}
[self.viewScrollView setDelegate:self];
[self.activityIndicator setHidden:YES];
[self.viewScrollView setScrollEnabled:YES];
//CGRect newScrollViewFrame = self.viewScrollView.frame;
//newScrollViewFrame.origin.y = 0;
//newScrollViewFrame.size.height = keyWindowFrame.size.height;
//[self.viewScrollView setFrame:newScrollViewFrame];
// get the size of the screen and set the content size to the size of the screen plus the bottom bar.
CGRect screenRect = [[UIScreen mainScreen] bounds];
screenRect.size.height = screenRect.size.height-200;
[self.viewScrollView setContentSize:CGSizeMake(screenRect.size.width, 1200)];
[self.viewScrollView setFrame:screenRect];
[_viewScrollView setScrollEnabled:YES];
// 100 is the size of the tool bar.
[self updateEmailListView];
self.userEmailTextField.delegate = self;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[self.viewScrollView addGestureRecognizer:singleTap];
//reactionNetworkController
inviteFriendsNetworkController = [[InviteFriendsNetworkController alloc] init];
[inviteFriendsNetworkController setDelegate:self];
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (void) updateEmailListView {
// With some valid UIView *view:
for(UIView *subview in [self.emailAddressView subviews]) {
if([subview isHidden] == NO){
[subview removeFromSuperview];
}
}
// if we have email addresses in the email address list.
if([emails count] > 0){
// display and populate scrollview with email addresses.
for(int i =0; i < [emails count]; i++){
// every other view set it white so that it creates a grey, white, grey, white pattern.
if(i % 2 == 0){
[self.emailAddressesCellBackground setBackgroundColor:[UIColor whiteColor]];
} else {
[self.emailAddressesCellBackground setBackgroundColor:[UIColor grayColor]];
}
// generate our background
UIView *newBackground = [[UIView alloc] initWithFrame:CGRectMake(
self.emailAddressesCellBackground.frame.origin.x,
self.emailAddressesCellBackground.frame.origin.y+self.emailAddressesCellBackground.frame.size.height*i,
self.emailAddressesCellBackground.frame.size.width,
self.emailAddressesCellBackground.frame.size.height)];
[newBackground setTag:i];
// generate our email addresses label.
UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectMake(
self.emailAddressCellTextUILabel.frame.origin.x,
self.emailAddressCellTextUILabel.frame.origin.y+self.emailAddressesCellBackground.frame.size.height*i,
self.emailAddressCellTextUILabel.frame.size.width,
self.emailAddressCellTextUILabel.frame.size.height)];
[newLabel setTag:i];
[newLabel setText:[emails objectAtIndex:i]];
// generate the delete button and add a target for the selector when it is pressed.
UIButton *newButton = [[UIButton alloc] initWithFrame:CGRectMake(
self.emailAddressCancelButton.frame.origin.x,
self.emailAddressCancelButton.frame.origin.y+self.emailAddressCancelButton.frame.size.height*i,
self.emailAddressCancelButton.frame.size.width,
self.emailAddressCancelButton.frame.size.height)];
[newButton setTag:i];
[newButton addTarget:self action:#selector(deleteButtonPressed:) forControlEvents:UIControlEventTouchDown];
[newButton setImage:self.emailAddressCancelButton.imageView.image forState:UIControlStateNormal];
// attach the new views to the scrollview
[self.emailAddressView addSubview:newBackground];
[self.emailAddressView addSubview:newButton];
[self.emailAddressView addSubview:newLabel];
}
[self.emailAddressView setHidden:NO];
}
// if we do not have any emails added yet.
else {
[self.emailAddressView setHidden:YES];
}
}
- (void) deleteButtonPressed:(id)sender{
int tag = [sender tag];
NSLog(#"delete button pressed with sender tag: %i", [sender tag]);
NSMutableArray *mutableEmails = [emails mutableCopy];
[mutableEmails removeObjectAtIndex:tag];
emails = mutableEmails;
NSUserDefaults *properties = [NSUserDefaults standardUserDefaults];
[properties setObject:emails forKey:#"emails"];
[properties synchronize];
[self updateEmailListView];
}
- (void) customizeView{
[self.inviteFriendsTitle setFont:[UIFont themeFontNamed:#"viewTitleFont" ofSize:18]];
[self.viewBackground setImage:[UIImage themeImageNamed:#"backgroundImage"]];
[self.inviteFriendsDescription setFont:[UIFont themeFontNamed:#"normalTextFont" ofSize:13]];
[self.emailAddressesDescription setFont:[UIFont themeFontNamed:#"normalTextFont" ofSize:13]];
if(height == 0 &&[delegate respondsToSelector:#selector(getHeight)]){
height = [delegate getHeight];
[self setFrame:CGRectMake(0,
-height,
self.frame.size.width,
height)];
}
}
- (void) animate{
if(visible == YES){
[self slideOut];
visible = NO;
}
else{
[self customizeView];
[self slideIn];
visible = YES;
}
NSLog(#"is user interaction enabled in InviteFriendsView?: %hhd", self.isUserInteractionEnabled);
}
- (void) themeChanged {
[self customizeView];
}
- (void) slideIn {
NSLog(#"Slide in");
[[self superview] setUserInteractionEnabled:NO];
[self.activityIndicator setAlpha:1.0];
[self.activityIndicator startAnimating];
self.alpha = 1.0;
[UIView animateWithDuration:0.5
animations:^{
[self setFrame:CGRectMake(0,
y,
self.frame.size.width,
height)];
}
completion:^(BOOL finished) {
NSLog(#"DID finish slide in");
}];
}
- (void) slideOut{
NSLog(#"Slide out");
if([delegate respondsToSelector:#selector(getY)]){
y = [delegate getY];
}
[self setViewScrollView:self.viewScrollView];
[self setUserInteractionEnabled:YES];
[self.viewScrollView setUserInteractionEnabled:YES];
[self.viewScrollView setScrollEnabled:YES];
[self.viewScrollView setScrollsToTop:YES];
[UIView animateWithDuration:0.5
animations:^{
[self setFrame:CGRectMake(0,
-height+y,
self.frame.size.width,
height)];
}
completion:^(BOOL finished) {
self.alpha = 0.0;
[[self superview] setUserInteractionEnabled:YES];
}];
}
#pragma mark - UITextFieldDelegate Methods
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return true;
}
// return NO to disallow editing.
- (void)textFieldDidBeginEditing:(UITextField *)textField{
}
// became first responder
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
return true;
}
// return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
- (void)textFieldDidEndEditing:(UITextField *)textField{
}
// may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
return true;
}
// return NO to not change text
- (BOOL)textFieldShouldClear:(UITextField *)textField{
return true;
}
// called when clear button pressed. return NO to ignore (no notifications)
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[self addFriendToInviteButtonPressed:self];
[textField setText:#""];
return true;
}
// called when 'return' key pressed. return NO to ignore.
#pragma mark - Button Action Pressed Methods
- (IBAction)addFriendToInviteButtonPressed:(id)sender {
NSMutableArray *mutableEmails = [emails mutableCopy];
[mutableEmails addObject:self.userEmailTextField.text];
NSLog(#"mutableEmails: %#", mutableEmails);
NSUserDefaults *properties = [NSUserDefaults standardUserDefaults];
[properties setObject:mutableEmails forKey:#"emails"];
[properties synchronize];
emails = mutableEmails;
[self updateEmailListView];
[self.userEmailTextField setText:#""];
[self.userEmailTextField resignFirstResponder];
}
- (IBAction)sendInviteButtonPressed:(id)sender {
// send a POST request to the server with the emails.
NSString *stringEmails = [[emails valueForKey:#"description"] componentsJoinedByString:#""];
NSLog(#"stringEmails: %#", stringEmails);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int site = 0;
if([[defaults objectForKey:#"Theme"] isEqualToString:#"BOMG"]){
site = 1;
}
[self.inviteFriendsNetworkController inviteFriendsWithAddressList:emails AndSite:site];
}
- (IBAction)progressButtonPressed:(id)sender {
}
#pragma mark - InviteFriendsNetworkControllerDelegateMethods
- (void) didSendAddressList:(NSDictionary *)response{
}
- (void) failedTosendAddressList{
}
#pragma mark - UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
[self.userEmailTextField resignFirstResponder];
}
#end
This might be an issue with the frames, where the controls are rendered (partially) outside the superview frame. This can be caused by invalid autoresizing masks or autolayout constraints.
To debug this you can set 'clip subviews' to YES for the relavant controls. When you see some of the controls are not visible anymore (or just partially), check the frames and resizingmasks or constraints of the superview.
Check whether the view controller is added in the build phase compile source. If you not added the view controller in the compiler source (if its not added automatically) it will some effect in xib integration.
I found the answer. I had to comment out the line
[[self superview] setUserInteractionEnabled:NO];
inside slideIn(){..}
So disabling user interaction for the superview would of course stop all user interaction from happening in a subview (such as the scrollview).
Oh dear.
Thanks guys!