I would like to start by saying that I am fairly new to iOS programming, so excuse my ignorance.
I have three UITextFields in my CustomLayout. I am asking users to fill in their name, age and sex. I would like two things, if possible. First I would like, as soon as a user hits the return button from the keyboard, the input string to be stored in an NSArray. In addition, the secondary objective is to iterate through the UITextFields when the user hits the same button.
// CustomLayout.h
#interface CustomLayout : UIView {
UITextField *nameField;
UITextField *ageField;
UITextField *sexField;
UILabel *nameLabel;
UILabel *ageLabel;
UILabel *sexLabel;
UIButton *startButton;
}
#property (nonatomic, strong) UITextField *nameField;
#property (nonatomic, strong) UITextField *ageField;
#property (nonatomic, strong) UITextField *sexField;
#property (nonatomic, strong) UILabel *nameLabel;
#property (nonatomic, strong) UILabel *ageLabel;
#property (nonatomic, strong) UILabel *sexLabel;
#property (nonatomic, strong) UIButton *startButton;
-(void)textFieldShouldReturn:(UITextField*)textField;
#end
In the implementation file
//CustomLayout.m
#implementation CustomLayout
#synthesize nameField, ageField, sexField;
#synthesize nameLabel, ageLabel, sexLabel;
#synthesize startButton;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[tkStyle viewBackgroundColor]];
NSString *startButtonLabel = #"Start Experiment";
//alocate and position views
CGRect viewRect;//placeholder rect, reused for each view
//nameLabel and nameField
nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(120, 95, 150, 40)];
nameLabel.textColor = [UIColor colorWithRed:106/256.0 green:180/256.0 blue:150/256.0 alpha:1.0];
nameLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:25];
nameLabel.backgroundColor=[tkStyle viewBackgroundColor];
nameLabel.text=#"Enter Name:";
nameField = [[UITextField alloc] initWithFrame:CGRectMake(280, 90, 200, 40)];
nameField.textColor = [UIColor colorWithRed:0/256.0 green:84/256.0 blue:129/256.0 alpha:1.0];
nameField.font = [UIFont fontWithName:#"Helvetica-Bold" size:25];
nameField.borderStyle = UITextBorderStyleRoundedRect;
nameField.backgroundColor=[tkStyle viewBackgroundColor];
textFieldShouldReturn:nameField.text;
// same for ageField and sexField
//startButton
viewRect = CGRectMake(250, sexField.frame.origin.y+75, 200, 40);
startButton = [[UIButton alloc] initWithFrame:viewRect];
[startButton setTitle:startButtonLabel forState:UIControlStateNormal];
[startButton setTitleEdgeInsets:UIEdgeInsetsMake(4, 0, 0, 0)];
[startButton setButtonIsActive:true];
//[startButton setOSCAddress:OSCStopPressedString];
[startButton addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchDown];
//and so on adjust your view size according to your needs
[self addSubview:nameField];
[self addSubview:ageField];
[self addSubview:sexField];
[self addSubview:nameLabel];
[self addSubview:ageLabel];
[self addSubview:sexLabel];
[self addSubview:startButton];
}
return self;
}
// that should allow for users to hit 'return' button to move through textfields
-(void)textFieldShouldReturn:(UITextField*)textField;
{
//[(NSArray *) userInfoArray addObject:textField.text];
}
// that should change Views as soon as the user presses 'Start Experiment'
-(void)buttonAction:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"startTest" object:self];
}
#end
Any help would be appreciated.
NSDictionary will be a good approach. you can have unique key for each textfield value.
-(void)textFieldShouldReturn:(UITextField*)textField;
should be:
- (BOOL)textFieldShouldReturn:(UITextField*)textField;
Also, don't forget to return TRUE or FALSE (or YES or NO).
To make this work, implement the UITextFieldDelegate protocol in your class.
Put the following line of code in your .m file, above the #implementation:
#interface CustomLayout () <UITextFieldDelegate>
#end
then, set the delegate in your UITextFields with:
nameField.delegate = self;
ageField.delegate = self;
sexField.delegate = self;
This way the textFieldShouldReturn: method will be called when the user presses 'enter'
A couple of things:
Given your delegate methods, I assume you've actually specified the delegate for your three UITextField controls to be the object in which you've implemented these various delegate methods.
If you want to control the behavior of the return key, implement the textFieldShouldReturn method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.nameField) {
[self.ageField becomeFirstResponder];
} else if (textField == self.ageField) {
[self.sexField becomeFirstResponder];
} else if (textField == self.sexField) {
[textField resignFirstResponder];
[self saveResults];
}
return NO;
}
I'd generally be inclined to do something like the above, where pressing return takes me to the next field, and pressing return on the last one dismisses the keyboard and tries to save the results.
BTW, in IB, I'd make sure that the "return key" setting for the first two control would be "Next", and for the last one, either "Go" or "Done".
Your save routine would simply populate an object with the contents of the three controls:
- (void)saveResults
{
Person *person = [[Person alloc] init];
person.name = self.nameField.text;
if (self.ageField.text) {
person.age = #([self.ageField.text integerValue]);
}
person.sex = self.sexField.text;
// now do whatever you want with this object
}
This obviously assumes that you have a Person class:
#interface Person : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) NSNumber *age;
#property (nonatomic, copy) NSString *sex;
#end
#implementation Person
#end
If you'd rather use a NSDictionary or NSArray, that's fine, too (make sure you check the text fields are not nil, though), though I personally prefer a well-defined model object like above.
As a refinement, you might want to make sure you only enter numeric values for age (if that's how you want to store the age):
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.ageField) {
NSCharacterSet *invalid = [[NSCharacterSet characterSetWithCharactersInString:#"1234567890"] invertedSet];
NSRange range = [string rangeOfCharacterFromSet:invalid];
return range.location == NSNotFound; // if non-numeric character not found, return true
}
return YES;
}
Related
I am new in iOS and I am facing problem regarding to get the value from custom table view cell to view controller. I am using rate view for rating and I am checking if value of rate is less then 3 then it show have to enter text in the text view and I want to get value in view controller
My code is like this
CustomTableviewcell.h
#interface NextTableview : UITableViewCell<RateViewDelegate,UITextViewDelegate>
{
NSString *StatusValue;
UILabel *lbl;
}
#property(nonatomic,strong) IBOutlet UILabel *staticlbl;
#property(nonatomic,strong) IBOutlet UITextView *commenttxtview;
#property(nonatomic,strong) IBOutlet UILabel *Kpiidlbl;
#property (weak, nonatomic) IBOutlet RateView *rateView;
#property (weak, nonatomic) IBOutlet UILabel *statusLabel;
#end
CustomTableviewcell.m
#synthesize rateView,staticlbl,statusLabel,commenttxtview,Kpiidlbl;
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
commenttxtview.layer.borderWidth = 0.70f;
commenttxtview.layer.borderColor = [[UIColor blackColor] CGColor];
commenttxtview.delegate=self;
UIToolbar* doneToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
doneToolbar.barStyle = UIBarStyleBlackTranslucent;
doneToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(doneButtonClickedDismissKeyboard)],
nil];
[doneToolbar sizeToFit];
commenttxtview.inputAccessoryView = doneToolbar;
lbl = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0,90.0, 34.0)];
[lbl setText:#"Enter Text"];
[lbl setFont:[UIFont systemFontOfSize:12]];
[lbl setBackgroundColor:[UIColor clearColor]];
[lbl setTextColor:[UIColor lightGrayColor]];
commenttxtview.delegate = self;
[commenttxtview addSubview:lbl];
statusLabel.hidden=YES;
commenttxtview.hidden=YES;
// Do any additional setup after loading the view from its nib.
self.rateView.notSelectedImage = [UIImage imageNamed:#"not_selected_star#2x.png"];
self.rateView.halfSelectedImage = [UIImage imageNamed:#"half_selected_star#2x.png"];
self.rateView.fullSelectedImage = [UIImage imageNamed:#"selected_star#2x.png"];
self.rateView.rating = 0;
self.rateView.editable = YES;
self.rateView.maxRating = 5;
self.rateView.delegate = self;
Kpiidlbl.hidden=YES;
}
-(void)doneButtonClickedDismissKeyboard
{
[commenttxtview resignFirstResponder];
// commenttxtview.hidden=YES;
}
- (void)textViewDidEndEditing:(UITextView *)theTextView
{
if (![commenttxtview hasText]) {
lbl.hidden = NO;
}
}
- (void) textViewDidChange:(UITextView *)textView
{
if(![commenttxtview hasText]) {
lbl.hidden = NO;
}
else{
lbl.hidden = YES;
}
}
- (void)rateView:(RateView *)rateView ratingDidChange:(int)rating {
self.statusLabel.text = [NSString stringWithFormat:#"%d", rating];
NSLog(#"Rating value =%#",self.statusLabel.text);
StatusValue=statusLabel.text;
NSLog(#"Status Value String =%#",StatusValue);
// Hear I am getting value of rating..in StatusValue..
int status=[StatusValue intValue];
if(status<=3)
{
commenttxtview.hidden=NO;
}
else{
commenttxtview.hidden=YES;
}
}
How can I get label and textview value in viewcontroller and I want to set rate view value to rate view after reload table.
Hear in the Image i am getting five star and If I click on less then 3 star it should have to write comment.I am taking rate value in the label.How can I get both label and textvalue in view controller.Please tell me to update question if you want more data.Thanks in Advance!
So write this in your CustomTableViewCell.h
#property(nonatomic,assign)NSInteger selectedRating;
everytime when the rating is updated in the Cell, you have to change the value of this variable.
In the viewController it depends on when you want to get the value of this cell. For example in this method:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CustomTableViewCell *yourCell = (CustomerTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
NSLog(#"%lu",yourCell.selectedRating);
}
Let me know if this was helpful!
Another way without a variable is to read the NSString in the statusLabel and change the string to a NSInteger variable...
If you are using your delegate...
Then implement the delegate RateViewDelegatein the viewController. The delegate is called in the class to which it is assigned...
Try this
You have to add the #property (nonatomic, weak) NSObject<RateViewDelegate>* delegate;
to the header file of your CustomTableViewCell.h in the method
-(UITableViewCell) cellForRowAtIndexPath....
you have to assign the delegate like this
cell.delegate = self;
Now modify your cell delegate method to this
- (void)rateView:(RateView *)rateView ratingDidChange:(int)rating {
self.statusLabel.text = [NSString stringWithFormat:#"%d", rating];
NSLog(#"Rating value =%#",self.statusLabel.text);
StatusValue=statusLabel.text;
NSLog(#"Status Value String =%#",StatusValue);
// Hear I am getting value of rating..in StatusValue..
int status=[StatusValue intValue];
if(status<=3)
{
commenttxtview.hidden=NO;
}
else{
commenttxtview.hidden=YES;
}
if([self.delegate respondsToSelector:#selector(rateView:ratingDidChange:)]){
[self.delegate rateView:rateView ratingDidChange:rating];
}
}
I'm using a contact picker to grab a string, then pass that string to another view controller, however the UILabel is not updating with the data (or any other string).
In the SlingViewController.m logs below, _taggedFriendsNames is being passed successfully.
Perhaps the issue is because the receiving view controller is trying to update the label on another (SlingshotView) view? I don't think that's the case as I've been updating labels in this way in other methods.
The answer is likely related to updating UILabels in general, but I've had no luck after searching.
Things I've checked with no success:
Updating from the main thread asynchronously
#synthesize the label in SlingshotView
calling setDisplay
Included potentially relevant code below. Thanks in advance for any tips!
SlingViewController.m
-(void)updateFriendsPickedLabel:(id)sender {
NSLog(#"updateFriendsPickedLabel: %#", _taggedFriendsNames); // i see this
slingshotView.friendsPickedLabel.text = #"any string"; // i don't see this
}
SlingViewController.h
#class TBMultiselectController;
#class SlingshotView;
#interface SlingViewController : UIViewController
#property (nonatomic, readonly) SlingshotView *slingshotView;
#property(nonatomic) NSString *taggedFriendsNames;
//for friend picker
-(void)updateFriendsPickedLabel:(id)sender;
#end
MultiSelectViewController.m
- (IBAction) sendButton: (id) sender {
NSMutableString *myString = [[NSMutableString alloc]initWithString:#""];
for (int i=0; i < self.selectedContacts.count; i++) {
Contact *myContact = self.selectedContacts[i];
[myString appendString:[NSString stringWithFormat:#"%# %# ", myContact.firstName, myContact.lastName]];
}
SlingViewController *svc = [[SlingViewController alloc] init];
svc.taggedFriendsNames = myString;
[svc updateFriendsPickedLabel:self];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
MultiSelectViewController.h
#protocol TBMultiselectControllerDelegate;
#class SlingViewController;
#interface TBMultiselectController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, TBContactsGrabberDelegate>
#property (nonatomic, assign) id<TBMultiselectControllerDelegate> delegate;
- (IBAction)sendButton: (id) sender;
#end
#protocol TBMultiselectControllerDelegate <NSObject>
-(void)updateFriendsPickedLabel:(id)sender;
#end
SlingshotView.h
#property (strong, nonatomic) UILabel *friendsPickedLabel;
SlingshotView.m
#synthesize friendsPickedLabel;
...
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect imageFrame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
contentView = [[UIView alloc] initWithFrame:frame];
[contentView setBackgroundColor:[UIColor whiteColor]];
[contentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[self addSubview:contentView];
self.friendsPickedLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, screenRect.size.height/2-100, screenRect.size.width-20, 200)];
self.friendsPickedLabel.shadowColor = [UIColor darkGrayColor];
self.friendsPickedLabel.numberOfLines = 0;
self.friendsPickedLabel.shadowOffset = CGSizeMake(0.5, 0.5);
self.friendsPickedLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.0];
[self.friendsPickedLabel setTextAlignment:NSTextAlignmentLeft];
self.friendsPickedLabel.textColor = [UIColor whiteColor];
self.friendsPickedLabel.font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:24];
[contentView addSubview:self.friendsPickedLabel];
You are reallocating this..
SlingViewController *svc = [[SlingViewController alloc] init];
svc.taggedFriendsNames = myString;
[svc updateFriendsPickedLabel:self];
Meaning your
slingshotView.friendsPickedLabel becomes nil..
And you are calling/using the delegate the wrong way, i think it suppose to be
[self.delegate updateFriendsPickedLabel:#"YourData To be Passed"];
From your code you are using the -(void)updateFriendsPickedLabel:(id)sender; inside SlingViewController and not the delegate, you are not implementing the delegate either..
Yes the -(void)updateFriendsPickedLabel:(id)sender; method is called, bacause you are calling it directly from the class..
SlingViewController.h
#interface SlingViewController : UIViewController < TBMultiselectControllerDelegate > // for delegate implementation
#property (nonatomic, readonly) SlingshotView *slingshotView;
#property(nonatomic) NSString *taggedFriendsNames;
//for friend picker
//-(void)updateFriendsPickedLabel:(id)sender;
#end
MultiSelectViewController.m
- (IBAction) sendButton: (id) sender {
NSMutableString *myString = [[NSMutableString alloc]initWithString:#""];
for (int i=0; i < self.selectedContacts.count; i++) {
Contact *myContact = self.selectedContacts[i];
[myString appendString:[NSString stringWithFormat:#"%# %# ", myContact.firstName, myContact.lastName]];
}
/*
SlingViewController *svc = [[SlingViewController alloc] init];
svc.taggedFriendsNames = myString;
[svc updateFriendsPickedLabel:self];
*/
[self.delegate updateFriendsPickedLabel:#"YourString"];
// this will call the method in your implementation class
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
Hmm.. I Think you have implemented the delegates the wrong way.
This is suppose to be a comment but its too long..
I have been working on this for a long time.
I need to expand and collapse the UILabel text on click of a button located at the end of text of UILabel.
Thinks I have tried
I have use VSWordDetector to detect which word of UILabel get tapped but it not gave correct word tapped.
I suggest you just use UIButton without visible frame with titleLabel.text #"..." or #"▼".
So, for example, you have a string #"Some long long, really long string which couldn't be presented in one line". Then take a substring for UILabel text, and put a button described above on the right from your label. Add an action for ▼-buuton to update label.text and hide button.
Code snippet:
#interface YourClass
#property (strong, nonatomic) UILabel* longStringLabel;
#property (strong, nonatomic) UIButton* moreButton;
#property (strong, nonatomic) NSString* text;
#end
#implementation YourClass
// Some method, where you add subviews, for example viewDidLoad
{
// ...
self.longStringLabel.frame = CGRectMake(0, 0, 100, 44);
[self addSubview:self.longStringLabel];
self.moreButton.frame = CGRectMake(CGRectGetMaxX(self.longStringLabel.frame), 0, 20, 44);
[self addSubview:self.moreButton];
// ...
}
- (UILabel*)longStringLabel
{
if (!_longStringLabel)
{
_longStringLabel = [UILabel new];
_longStringLabel.lineBreakMode = NSLineBreakByTruncatingTail;
}
return _longStringLabel;
}
- (UIButton*)moreButton
{
if (!_moreButton)
{
_moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
_moreButton.titleLabel.text = #"▼";
[_moreButton addTarget:self action:#selector(moreButtonDidTap:) forControlEvents:UIControlEventTouchUpInside];
}
return _moreButton;
}
- (void)moreButtonDidTap:(UIButton*)sender
{
self.longStringLabel.frame = [self.text boundingRectWithSize:CGSizeMake(self.longStringLabel.frame.size.width + self.moreButton.frame.size.width, 100)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName : self.longStringLabel.font }
context:nil];
self.longStringLabel.text = self.text;
self.moreButton.hidden = YES;
}
#end
I have a problem with one of my views retaining its subviews. The main view displays 'tables' in a restaurant, and loads a subview to display this 'table'.
When the main view is deallocated, the tables seem to remain allocated to memory. I have searched everywhere to try and find a solution to this as I just can't seem to fix it myself.
Firstly the code for the 'table' view:
#protocol tableDelegate <NSObject>
#required
- (void)tablePress:(id)sender;
- (void)tableSelect:(id)sender;
#end
#interface tablevw : UIView
{
CGPoint currentPoint;
}
-(void)changeOrderImage;
-(id)initWithFrame:(CGRect)frame teststring:(NSString *)ts;
#property (nonatomic, weak) IBOutlet UIView *view;
#property (nonatomic, weak) IBOutlet UILabel *numberLabel;
#property (nonatomic, weak) IBOutlet UILabel *nameLabel;
#property (nonatomic) BOOL isEdit;
#property (nonatomic) BOOL hasOrder;
#property (nonatomic, strong) NSMutableDictionary * orderNumbers;
#property (nonatomic) int orderNumber;
#property (nonatomic, strong) NSString *teststring;
#property (nonatomic, weak) IBOutlet UIImageView *tableImage;
#property (nonatomic, weak) id<tableDelegate> delegate;
#end
And the init method for the view:
- (id)initWithFrame:(CGRect)frame teststring:(NSString *)ts{
self = [super initWithFrame:frame];
if (self) {
orderNumbers = [[NSMutableDictionary alloc]init];
isRemote = FALSE;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"tabletopRound" ofType:#"png"];
UIImageView * iV =[[UIImageView alloc] initWithImage:[[UIImage alloc] initWithContentsOfFile:filePath]];
self.tableImage= iV;
tableImage.frame = CGRectMake(0, 0, 121, 121);
locked = FALSE;
[self addSubview:tableImage];
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTap)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTapGestureRecognizer];
UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(35, 50, 48, 20)];
numberLabel = label;
[numberLabel setTextColor:[UIColor blackColor]];
[numberLabel setBackgroundColor:[UIColor clearColor]];
[numberLabel setText:ts];
[self addSubview:numberLabel];
UILabel * labelTwo = [[UILabel alloc] initWithFrame:CGRectMake(24, 123, 70, 20)];
nameLabel = labelTwo;
[nameLabel setTextColor:[UIColor whiteColor]];
[nameLabel setBackgroundColor:[UIColor clearColor]];
[self addSubview:nameLabel];
self.userInteractionEnabled = YES;
self.tag = [ts intValue];
}
return self;
}
Finally, in the 'main' view the tables are added like so:
NSString *myString = [results stringForColumn:#"table_number"];
tablevw * tableView = [[tablevw alloc] initWithFrame:CGRectMake(x-60.5, y-60.5, 121, 121) teststring:myString];
tableView.delegate = self;
[self.view addSubview: tableView];
The delegate is set to Nil when the main view is dealloced. I have over ridden the dealloc method to log the dealloc calls to me - it is being called on the 'main' view but not on the 'table' view.
Thanks for your help
In the dealloc method try
for (UIView *view in [self.view subviews]) {
[view removeFromSuperview];
}
It would be even better if u can try
[tablevw removeFromSuperview], tablevw = nil;
I can see that your tablevw has a week reference to his delegate and that should be enough for to release the parent, but just for argue sake trie to nil tablevws delegate. Create an array of tablevw instances you created (or tag them as already suggested), then before you release parent remove them from superview, set their delegate to nil and kill the array. See what happenes, maybe that will help...
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!