I am trying to skip over text fields that are disabled when a user navigates through my tableview. However, when they reach the bounds of the visible cells, everything gets out of whack because I am trying to detect if a text field is disabled, and if so, then recursively call my method again to navigate one more time. ie. if user presses a button to navigate to the right, and that text field is disabled, recursively call a right press again.
It seems, any text fields in cells outside what is visible are disabled. once the user reaches the edges of the table I go into infinite loops, or things just break.
here is my section of code where I make my enabled check and if not make my recursive call. This really shouldn't be that complicated. Logically all I want to do is detect if the text field we just moved to is disabled and if so, just initiate the same button press again. Nothing fancy.
edit with some playtesting it has become apparent that the nextTextFieldSelection is coming back as null, although the destinationIndexPath and newTag values are correct. Is it possible requesting an indexPath not visible is causing a null return?
//logic to move to next text field and manually scroll the tableViewbased on button input is here
nextTextFieldSelection = (UITextField *)[[_tableView cellForRowAtIndexPath:destinationIndexPath] viewWithTag:newTag];
if (nextTextFieldSelection.userInteractionEnabled == NO) {
switch (arrowButton.tag) {
case NumericKeyboardViewLeftArrow:
currentTextField = nextTextFieldSelection;
[self numericKeyboardView:(VS_NumericKeyboardView *)numericKeyboardView DidSelectArrowButton:(UIButton *)arrowButton];
return;
case NumericKeyboardViewRightArrow:
currentTextField = nextTextFieldSelection;
[self numericKeyboardView:(VS_NumericKeyboardView *)numericKeyboardView DidSelectArrowButton:(UIButton *)arrowButton];
return;
default:
break;
}
}
cellForRowAtIndexPath returns nil for not visible cells. Thats probably why you are getting into that infinite loop.
See: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006943-CH3-SW16
Related
I'm using UIWebView to display formatted content. However, I need to replace the default keyboard for UITextViews/UITextFields with our own.
I can use grotesque methods to hide the default keyboard when it appears, but I can't find the text field to direct input to. UITextFieldTextDidBeginEditingNotification or UITextViewTextDidBeginEditingNotification is never fired off. I do see UIKeyboardWillShowNotification etc properly emitted.
It is important that the final result be App Store approved.
EDIT:
When the keyboard notification comes, note which HTML element is focused. Then make your view controller first responder.
[self becomeFirstResponder];
Your view controller should become first responder and return your custom input view.
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (UIView*)inputView {
return _customInputView;
}
When your custom input view gets input, you can pass it to the HTML element.
NSString* script = [NSString stringWithFormat:#"element.value += '%#';", input];
[_webView stringByEvaluatingJavascriptFromString:script];
I got a UIButton with style "Info Dark" set up in interface builder in my iPhone 4 app. One of the properties of the button is "Highlighted", which displays a white highlight around the button.
I would like to toggle this white highlight on and off, indicating if the button function is active or not.
The button is linked for "Touch up inside" event in the interface builder with this callback:
infoButton.highlighted = !infoButton.highlighted;
After the first touch, the highlight disappears and does not toggle as I expect it to. What else do I need to do to make the highlight toggle and display the state of the button?
Thank you!
Update:
When loaded from the interface builder, the button stays highlighted, even as the view appears/disappears. What causes this to happen is the "shows touch on highlight" interface builder property. If I assign the code above to another button, the info button highlights on and off as expected. However, the touches of the info button itself interfere with the above code, causing the button to lose the "touch" highlight
Update 2: I added another info button, directly below the first info button, in the interface builder and made it glow permanently. To create the appearance of the toggle, I hide and unhide the glowInfoButton below the real one. This works as expected:
infoButton.highlighted = NO;
glowInfoButton.highlighted = YES;
glowInfoButton.enabled = NO;
glowInfoButton.hidden = YES;
- (IBAction)toggleInfoMode:(id)sender {
// infoButton.selected = !infoButton.selected;
glowInfoButton.hidden = !glowInfoButton.hidden;
}
The Highlighted image is what displays when the UIButton is being pressed, and is controlled within the UIButton itself.
You're looking for the Selected property. You can set a Selected Image in IB, and then put a infoButton.selected = !infoButton.isSelected; in your TouchUpInside callback.
The highlighted property doesn't work like that, buttons aren't toggles.
It's just to know if the button is being pressed, if I'm correct.
If you want to implement that functionality, I recommend you subclass UIButton or UIControl.
Now that I see what you really were after I would advise subclass UIButton and check for a call to an event then toggle highlight state accordingly. You can do this without adding the dummy button.
in a custom button class implementation file place the following code, or similar:
#import "HighlightedButton.h"
#implementation HighlightedButton
BOOL currentHighlightState;
-(void)toggleHighlight:(id)sender {
self.highlighted = currentHighlightState;
}
-(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
//get the string indicating the action called
NSString *actionString = NSStringFromSelector(action);
//get the string for the action that you want to check for
NSString *touchUpInsideMethodName = [[self actionsForTarget:target forControlEvent:UIControlEventTouchUpInside] lastObject];
if ([touchUpInsideMethodName isEqualToString:actionString]){
//toggle variable
currentHighlightState = !currentHighlightState;
//allow the call to pass through
[super sendAction:action to:target forEvent:event];
//toggle the property after a delay (to make sure the event has processed)
[self performSelector:#selector(toggleHighlight:) withObject:nil afterDelay:.2];
} else {
//not an event we are interested in, allow it pass through with no additional action
[super sendAction:action to:target forEvent:event];
}
}
#end
That was a quick run at a proper solution, there is a flicker on toggle that you may not like. I am sure if you play around with some changes that can be corrected. I tried it and actually like it for your stated case.
The highlighted state of a UIButton is simply setting the button's alpha to 0.5f. So if you set the button to not change on highlight, then just toggle the alpha between 0.1 and 0.5.
For example:
- (void)buttonPressed:(id)sender {
if((((UIButton*)sender).alpha) != 1.0f){
[((UIButton*)sender) setAlpha:1.0f];
} else {
[((UIButton*)sender) setAlpha:0.5f];
}
}
Perhaps what you really want is
infoButton.enabled = NO;
This will dim the button and disable touches when set to no, allow normal operation when set to YES.
or in your case:
infoButton.enabled = !infoButton.isEnabled;
to toggle the availability of same.
If you put this in your touchupinside event, of course it will work only the first time. After that is disabled and does not receive touch events. You would put it in another method that decides whether or not the button should be enabled.
If you truly want it to change each time it is pressed then you probably should use a switch or you may look at the -imageForState, -setTitle:forState and/or -setTitleColor:forState methods. If you want to toggle the appearance each time it is touched, you could change these.
I am implementing an a UITableView and have the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method implemented and within that method I have if loops (below):
NSInteger row = [indexPath row];
if (self.someDetailViewController == nil) {
if (row==0) {
OneTableViewController *aDetail = [[OneTableViewController alloc] initWithNibName:#"OneDetail" bundle:nil];
self.oneDetailViewController = aDetail;
[aDetail release];
} else if (row==1) {
OneTableViewController *aDetail = [[OneTableViewController alloc] initWithNibName:#"TwoDetail" bundle:nil];
self.oneDetailViewController = aDetail;
[aDetail release];
}
}
However each time I select something in my table view (let's say row 0) I am taken to the secondary view (OneDetail) and then when I go back and select another row (row 1) and I expect to go to the other view (TwoDetail) however I am taken to OneDetail (to original row that was selected first) - how can this be when the user taps another row they are taken to the first row's secondary view that was originally tapped. This also happens vice versa (i.e. selecting row 1 and being taken to TwoDetail and then going back and selecting row 0 and also being taken to TwoDetail not OneDetail...
I was wondering if anyone knew how to 'restart' an if loop when the user presses the back button or how to overcome my issue in some other fashion. Thanks so much in advance!
I suspect that the second time you enter the method, this check is returning false:
if (self.someDetailViewController == nil)
Thus, you never get into the part where you check which row you're on, and you're permanently stuck with whichever one you set first.
This is not a loop.
You store your detail view controller in the instance variable oneDetailViewController.
Only if that someDetailViewController is nil, which is the case most probably only when the method is executed for the first time, you will assign a value.
A view controller that is initialized with "oneDetail".
Unfortunately you do not show the remaining code to us. I assume that you do not have a statement
self.someDetailViewController = nil;
further down in the method.
Why do yo do that == nil thing anyway? What is the detail view controller good for in the further processing? Just release it at the end of didSelectRowAtIndexPath and create a new one next time it is executed. There is no need for an instance variable saving it.
Hoever, if you have good reasons for this unusual piece of code, which you did not share with us, then we could certainly make a suggestion on how to achieve that - if you let us know :)
I am developing a project in which the user can add the object to favorite list that is table View. here I adding the object through rightBarButtonItem. I wanna show a message if User tap the right BarButton more than one. message is nothing but a UILabel that contains text like "Object already exist". please help me to solve this problem. thanks....
You might have a method that is executed when the button is tapped where you add the item to your table view. Lets say the method is called didClickButton. Have a Bool variable say isItemAdded indicating the status of the item. Set it to NO initially. when button is pressed check if its NO. If NO then proceed and set it to YES else display "Alert already added"
-(void)didClickButton
{
if(!isItemAdded)
{
//code to add to tableview
isItemAdded = YES;
}
else
{
//code to show message or alert
}
}
Initiaize a global counter and use it to count the taps by incrimienting it inside the method that is called by your rightBarButtonItem.
int tapsCtr = 0;
Put this code inside your method:
tapsCtr++;
if(tapsCtr > 1){
NSLog(#"User tapped more than once");
tapsCtr = 0;
}
I have a view where a UITextView always has focus. What I want to do is extend the built-in undo/redo behavior to support undo/redo for when I programmatically set the text (e.g., for when I clear it, by setting it to #"").
Since only the firstResponder gets undo/redo events, I thought I'd simply use the UITextView's undoManager property to create my invocations. e.g.,
// Before clearing the text...
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:self.myTextView.text];
[self.myTextView.undoManager setActionName:#"Clear"];
// ...
-(void)undoClear:(NSString *)textToRestore
{
self.myTextView.text = textToRestore;
if ([self.myTextView.undoManager isUndoing])
{
// Prepare the redo.
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:#""];
}
}
Unfortunately, this is not working. It:
Introduces an empty item into the undo stack ("Undo")
The "Undo Clear" gets added after that item (if I tap "Undo", I see "Undo Clear")
Undo Clear and Redo Clear work, however, then I see "Undo Clear" again and it doesn't work from there on.
Any ideas? Am I approaching this wrong?
Update: It seems like I've figured out the empty undo item issue: it happens when I set the text of the UITextView after I've called prepareWithInvocationTarget. If I call it before, it doesn't happen. Funny thing is, the empty item isn't pushed onto the undo stack if I don't call prepareWithInvocationTarget (i.e., normally, when I set the text of a UITextView).
OK, figured it out:
The issue with #1 is as outlined in the update to my original post.
Issues #2 and #3 were just me using the NSUndoManager incorrectly. My final unClear method (which gets called on undos is as follows:
-(void)undoClear:(NSString *)textToRestore
{
NSString *textBackup = [self.myTextView.text copy];
self.myTextView.text = textToRestore;
if ([self.myTextView.undoManager isUndoing])
{
// Prepare the redo.
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:#""];
}
else if ([self.myTextView.undoManager isRedoing])
{
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:textBackup];
}
[textBackup release];
}
It's working as it should now.
You can change your textview to whatever text you want and preserve undo and redo manager's memory stacks. self.content is UITextView.
-(void) yourClearAllButtonIsPressed
{
[[self.content.undoManager prepareWithInvocationTarget:self] undoClear:self.content.text];
[self.content setText:#""];//Or something else you want to change your textview to
}
}
//just one, my method I created
-(void) undoClearBlablabla:(NSString*) text
{
[[self.content.undoManager prepareWithInvocationTarget:self] undoClear:self.content.text];
[self.content setText:text];
}
I'm not sue how many Text Fields you are working with, though textBackup is not getting retained by prepareWithInvocationTarget: How is it still in the Undo Stack several clear's later? Seems like it might still be there after the first one, though not after the 2nd one or after the Autorelease pool flushes.