How to code a "numbers pad" like Call application - iphone

how can I do something like this in an iPhone app?
I need to input a number but I want something like this, not a simple UITextField.
How?
Thanks!

I Agree with Kevin. But if you decide to implement your own keyboard-like pad you may have to lose all those nice features provided by the original iOS keyboard.

You will have to create a custom UIView if you want it to look like what you sent. Basically add a set of subviews (UIButtons) for each control. Then create a delegate for the custom UIView that will notify of value changes. For example, here is some rough code to get you started:
// CustomNumbersView.m
- (void)button1DidClick:(id)sender
{
[self.delegate customNumbersView:self didSelectKeyWithValue:#"1"];
}
- (void)button2DidClick:(id)sender
{
[self.delegate customNumbersView:self didSelectKeyWithValue:#"2"];
}
// MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
CustomNumbersView *customNubmersView = [[CustomNumbersView alloc] initWithFrame:...];
customNumbersView.delegate = self;
}
- (void)customNumbersView:(CustomNumbersView *)customNumbersView didSelectKeyWithValue:(NSString *)value
{
self.mainTextField.text = [NSString stringWithFormat:#"%#%#", self.mainTextField.text, value];
}

As I need one in several situations in my programs, I wrote a delegate-driven KeyPad.

I've solved with new feature
UITextField.keyboardType = UIKeyboardTypeDecimalPad;

Related

textField should update as soon as a method is called

I am working on a project which deals with an examination paper. I display only 1 question at a time on the view. After the users answers the question a second question is displayed if the user swipes towards left hand side.
I have placed a textField to display the score at each point in time. I implemented it but my score gets updated only if the user navigates to the next question.
My requirement is that as soon as the question is answered the score should be updated in the textField.
scoreField.text=[NSString stringWithFormat:#"%d",currentScore];
Is there any technique to do so whenever a question is answered? My paper has 20 questions and has 20 submit buttons so I cannot place the above code at each and every submit button action method. It would be ugly and not effective programming.
Please help if there is any way to solve my case.
Thanks in advance
If you understand your problem correctly then you don't want to set scoreField.text in every submit button handler. I am assuming that you are setting this when navigating to next question. You only need to update this when currentScore is changed. So I think it's better to create a setter for currentScore and update scoreField.text from that. Something like this:
- (void)setCurrentScore:(NSInteger)newScore {
currentScore = newScore;
scoreField.text=[NSString stringWithFormat:#"%d",currentScore];
}
And call setCurrentScore whenever you need to change the score. Or even better, you can use a setter property and write your own setter implementation.
This can be made really simple, and elegant. With a few assumptions:
There is globally accessible model object that holds the score, for example +[Examination sharedExammination].
The model object has a KVO (Key-Value-Observing) compatible property like score.
You use a custom subclass of UILabel to display the score.
With these assumptions you can let your custom UILabel register for KVO changes to to the score property and update itself automatically. The implementation of the UILabel subclass would include something like this:
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[[Examination sharedExamination] addObserver:self
forKeyPath:#"currentScore"
options:0
context:NULL];
}
return self;
}
-(void)dealloc
{
[[Examination sharedExamination] removeObserver:self
forKeyPath:#"currentScore"];
[super dealloc];
}
-(void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context
{
if ([keyPath isEqualToString:#"currentScore"]) {
scoreField.text = [NSString stringWithFormat:
#"Score: %d", [object currentScore]];
} else {
[super observerValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
Try this:
[self.view setNeedsDisplay];

How can I set a maximum on the number of pages in a TTLauncherView?

I'm using TTLauncherView as a sort of home screen for my app and I only have one page's worth of icons. How can I make it so the TTLauncherView won't let you drag icons to "the next page"? I want to set a maximum number of pages (in this case one.)
(EDIT: long story short, I subclassed beginEditing, see the answer below.)
I see where why it adds an extra page when beginEditing is called, but I don't want to edit the framework code. (That makes it hard to update to newer versions.) I'd also prefer not to subclass and override that one method, if I have to rely on how it's implemented. (I'm not against subclassing or adding a category if it's clean.)
I tried setting scrollView.scrollEnabled to NO in the callback method launcherViewDidBeginEditing in my TTLauncherViewDelegate, but that doesn't work while it's in editing mode and I don't know why.
I tried adding a blocker UIView to the scrollview to intercept the touch events by setting userInteractionEnabled=NO, which works OK. I still have to disable the dragging of TTLauncherItems to the next page somehow.
I also tried setting the contentSize of the scrollview to it's bounds in launcherViewDidBeginEditing, but that didn't seem to work either.
Is there a better way?
Tried to block gestures:
- (void)setLauncherViewScrollEnabled:(BOOL)scrollEnabled {
if (scrollEnabled) {
[self.scrollViewTouchInterceptor removeFromSuperview];
self.scrollViewTouchInterceptor = nil;
} else {
// iter through the kids to get the scrollview, put a gesturerecognizer view in front of it
UIScrollView *scrollView = [launcherView scrollViewSubview];
self.scrollViewTouchInterceptor = [UIView viewWithFrame:scrollView.bounds]; // property retains it
UIView *blocker = self.scrollViewTouchInterceptor;
[scrollView addSubview:scrollViewTouchInterceptor];
[scrollView sendSubviewToBack:scrollViewTouchInterceptor];
scrollViewTouchInterceptor.userInteractionEnabled = NO;
}
}
For reference: TTLauncherView.m:
- (void)beginEditing {
_editing = YES;
_scrollView.delaysContentTouches = YES;
UIView* prompt = [self viewWithTag:kPromptTag];
[prompt removeFromSuperview];
for (NSArray* buttonPage in _buttons) {
for (TTLauncherButton* button in buttonPage) {
button.editing = YES;
[button.closeButton addTarget:self action:#selector(closeButtonTouchedUpInside:)
forControlEvents:UIControlEventTouchUpInside];
}
}
// Add a page at the end
[_pages addObject:[NSMutableArray array]];
[_buttons addObject:[NSMutableArray array]];
[self updateContentSize:_pages.count];
[self wobble];
if ([_delegate respondsToSelector:#selector(launcherViewDidBeginEditing:)]) {
[_delegate launcherViewDidBeginEditing:self];
}
}
I think overriding beginEditing in TTLauncherView is your best bet. Since you'd only really be touching one method (and only a few lines in that method), upgrading it when the time comes shouldn't be too bad. Since that method explicitly adds the extra page, I'm not sure how you'd get around it w/o editing that specific piece of code
As Andrew Flynn suggested in his answer, I was able to make it work by subclassing and overriding the beginEditing method to remove the extra page TTLauncherView adds when it goes into editing mode.
One problem I'm having is I can't figure out how to remove the warning I get for calling the (private) method updateContentSize on my subclass. I tried casting it to id, but that didn't remove the warning. Is it possible?
edit: I was able to remove the warning by using performSelector to send the message to the private class. (I had previously create a category method performSelector:withInt that wraps NSInvocation so that I can pass primitives via performSelector methods, which makes this very convenient.)
// MyLauncherView.h
#interface MyLauncherView : TTLauncherView {
NSInteger _maxPages;
}
#property (nonatomic) NSInteger maxPages;
#end
// MyLauncherView.m
#implementation MyLauncherView
#synthesize maxPages = _maxPages;
- (void)beginEditing {
[super beginEditing];
// ignore unset or negative number of pages
if (self.maxPages <= 0) {
return;
}
// if we've got the max number of pages, remove the extra "new page" that is added in [super beginEditing]
if ([_pages count] >= self.maxPages ) {
[_pages removeLastObject];
[self updateContentSize:_pages.count]; // this has a compiler warning
// I added this method to NSObject via a category so I can pass primitives with performSelector
// [self performSelector:#selector(updateContentSize:) withInt:_pages.count waitUntilDone:NO];
}
}

Setting a delegate using blocks in iPhone

On a view controller I have multiple textfields, which all use the same delegate. Now in the delegate the code gets really ugly since I have to differentiate between all the textfields (bunch of if/else-if or a switch statement). I came a cross this article:
Blocks in textfield delegates
But from this I still don't understand how this solves the problem? Doesn't this basically call one method and pass it the text and the method has no idea what textfield gave the string? You would still need to differentiate between the textfields, but this time inside the block (with the usual if(textfield == bazTextField)...).
I don't know that it exactly solves the problem so much as shifts it (and into viewDidLoad, which usually gets a bit of mush-mash in it anyway).
However in that example the block itself was being passed in the textfield to run comparisons with and "remembers" the values of all the instance variables as well (if it refers to them), so that's how it knows what text and text field is being dealt with.
I don't see how that code exactly is supposed to help though, since it assigns one block to the single delegate class to be used with all text field delegates - unless perhaps you were supposed to have one per text field, each with a different block. Then you have way more code than you'd have had with the if statements!
The article doesn't make it clear, but I believe the idea is to create one of these blocks (and block delegate objects) for each UITextField that you wish to have respond to textFieldShouldReturn.
hm, maybe I didn't completely understand the article, but I don't see the advantage of using blocks instead of selectors in that concrete example.
you could achieve something similar like this
#interface AlternativeTextFieldDelegate : NSObject <UITextFieldDelegate>
{
SEL selectorToCall;
id objectToCall;
}
- (void) setObjectToCall:(id)obj selector:(SEL)selector;
#end
#implementation AlternativeTextFieldDelegate
- (void) setObjectToCall:(id)obj selector:(SEL)selector
{
objectToCall = obj;
selectorToCall = selector;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[objectToCall performSelector:selectorToCall];
return YES;
}
#end
and the view controller
#interface ViewWithTextFieldsController : UIViewController
{
UITextField *tf1;
AlternativeTextFieldDelegate *delegateForTF1;
UITextField *tf2;
AlternativeTextFieldDelegate *delegateForTF2;
}
// ...IBOutlets and all that...
- (void) tf1ShouldReturn; // handles shouldReturn for tf1
- (void) tf2ShouldReturn; // handles shouldReturn for tf2
#end
#implementation ViewWithTextFieldsController
- (void) viewDidLoad // or wherever
{
delegateForTF1 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF1 setObjectToCall:self selector:#selector(tf1ShouldReturn)];
tf1.delegate = delegateForTF1;
delegateForTF2 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF2 setObjectToCall:self selector:#selector(tf2ShouldReturn)];
tf2.delegate = delegateForTF2;
}
// ...
#end
don't really know if that's any better than chaining if-elses though.
it seems to me that this complicates things more than the problem it solves.

objective-c delegates and events design (I don't get it)

I'm pretty new to the objective-c language (less than three months) but it is something that i really need to understand.
Suppose there is a controller (in a iOS environment) that manages a table view for input data from the user. The table must have editable cells and some features to make the value selection easier, for example a button that shows a popover with the possible values for a field.
Suppose there is a field to store country names. The popover first shows a list of continents; when the user selects a continent, the controller of the popover must show the countries of the previews selected continent.
Now, this popover appears in many places in the app so it will be nice if I can encapsulate it for later use. What i will expect for this popover is something like this:
...
#protocol MyPopoverDelegate<NSObject> {
-(void)didSelectCountry:(NSString *)countryName;
{
...
MyPopoverController *dataSelector = [[MyPopoverController] alloc] init];
dataSelector.dataType = CountryDataType;
dataSelector.delegate = self;
[dataSelector show];
[dataSelector release];
...
The problem here is the line [dataSelector release] because the code for managing the popover must stay alive until the country is selected. That's means the dataSelector variable must be a property of the caller class and that sucks.
The question then is:
How can i organize situations like this to have a reusable controller?
Thanks
Edited after vodkhang answer:
Ok, that's a good one, but dataSelector still is a property.
What if i do:
#implementation MyPopoverController
- (id)init {
...
[self retain];
...
}
- (void)popoverControllerDidDismissPopover: (UIPopoverController *)popoverController {
...
[delegate didFinishSelectingCountry:countryName];
[self release];
}
#end
I never see this behavior in objective-c, i feel that this is not the idea.
Why is it wrong?.
One of the way you can do for delegate method is to have:
MyPopOverDelegate
- (void)didFinishSelectingCountry:(NSString *)countryName popOver:(MyPopOver *)popOver;
Caller.m
// the caller
- (void)viewDidLoad {
MyPopoverController *dataSelector = [[MyPopoverController] alloc] init];
dataSelector.dataType = CountryDataType;
dataSelector.delegate = self;
[dataSelector show];
}
- (void)didFinishSelectingCountry:(NSString *)countryName popOver:(MyPopOver *)popOver {
// finish stuff
[popOver release];
}
This way is used a lot like NSUrlConnection, UIImagePickerController
If you want some unique object reusable across an entire app from anywhere in the view hierarchy, you can make it a property of the app delegate, and let the app delegate own it (retain it when live, release it during memory warnings, etc.).
A self retained object may eventually run into problems if you ever port your code to a garbage collected environment.

iPhone SDK: Can I nab in instance variable from one view and access it in another?

I'm pretty new to OOP in general and just really started working with Obj-c a few months back. So, please be gentle! I appreciate your help in advance. Now to the question!
I have 3 Text Fields where a user inputs name, phone, and email.
I collect and place them in a label using an NSString like this [this is the one for the name]:
- (IBAction)changeGreeting:(id)sender {
self.name = textInput.text;
NSString *nameString = name;
if([nameString length] == 0) {
nameString = #"I Forgot";
}
NSString *greeting = [[NSString alloc]
initWithFormat:#"Hello, my name is %#! Really!", nameString];
label.text = greeting;
[greeting release];
}
With this I have been able to place the text from text.input into my label (as stated in label.text = greeting;)
I have another view where I'd like to have someone review this information (view a label too). I need to have access to name or Textinput.text in that other view.
How can I accomplish this?
If you don't need to communicate changes between the two view controllers, you may want to pass it in using a custom init method. This may be best for a confirmation screen, where the prompt would make no sense without this string.
- (id)initWithFrame:(CGRect)aRect username:(NSString*)aName {
if((self = [super initWithFrame:aRect])) {
_myName = [aName retain];
}
return self
}
Another option is to implement a method on the first view controller and call it from the second.
- (NSString*)enteredUsername {
return _myName;
}