So i've created a custom TableViewCell, and in the nib I put a UISwitch. Before I had even hooked it up to anything, if I ran it in the simulator and clicked on it, it would switch from off to on with the animation and such.
I'm trying to add a feature where the user is only allowed to change from off to on when a certain condition is true. I want it so, when the user touches the switch, it checks if the condition is true, and if it isn't it the switch doesn't move.
I've set up an IBAction where if the user Touches Up Inside, it'll run my function. My function is this:
if([on_switch isOn])
{
if([my_switch canSwitchOn])
{
NSLog(#"SWITCHED ON SUCCESSFULLY");
[on_switch setOn:TRUE animated:TRUE];
}
else
{
NSLog(#"SWITCHED ON UNSUCCESSFULLY");
//Put in popup here
}
}
else
{
[[ClassesSingleton sharedSingleton] classSwitchedOff:cell_index];
[on_switch setOn:FALSE animated:TRUE];
}
However, no matter what I do, that switch will flip, even though I gave it no directions to do so. I'm pretty sure it's the auto-flip that cause it to do so even before I'd hooked anything up to it. Is there a way to turn that off?
Thanks!
What you need to do is set userInteractionEnabled property to False on your UISwitch.
If you had allready made the connection in Interface Builder to an IBOutlet you delared in your owning class, you would be able to set it in code like this:
mySwitch.userInteractionEnabled = NO;
You could also set the property directly in Interface Builder by selecting the checkbox, as shown below (However in your app, you are going to need to wire the button up to an IBOutlet anyway to implement your conditional logic.)
alt text http://www.clixtr.com/photo/ef06c1f7-8cca-40cd-a454-5ca534ceb9fe
I think you will need something like the following:
// Somewhere just after the creation of _switch
[_switch addTarget:self action:#selector(switchValueDidChange:) forControlEvents:UIControlEventValueChanged];
// Target/Action method
- (void)switchValueDidChange:(UISwitch *)sender {
if(sender.on && [self canSwitchOn] == NO){
[sender setOn:NO animated:YES];
// Popup
}
}
Problem you're having is that the switch has already committed it's on state on touch up. When that's not the case (I'm not sure, never tested) you have to check whether the switch is currently not on. This bit of code will revert the state when the user was not allowed to switch the switch.
A better way is to disable the control, but maybe that's not what you want in this case.
Related
I have used the demonstration code Apple has in their docs here:
http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html#//apple_ref/doc/uid/TP40009542-CH5-SW7
To have my view move accordingly depending on which textField is being edited. It works great, my view moves as I expect, except for one thing.
My issue is, I can select a textField and it will only move the view up when I begin typing and not when I actually select the textField.
I am literally using identical code as in the docs (follow the link above). Quite frustrating, I can't see what would cause this. Thanks.
Here is The Logic See.
1)You need a Flag Value Set TRUE initially in ViewDidLoad or viewWillAPpear.
suppose isNeedToMove is that Flag value.
you need to Implement these methods in Your Code,for using them don't forget to Adopt the protocol UITextFieldDelegate in your UIViewcontroller.h class.
EDIT:Here I have Chnaged The Code AS you mentioned in yOur Comment You needed to move That UIView on just Touching the TextFIeld.See Here below Is The Logic With SOme Code.
addTarget To the TextField in ViewDiodiLoad
- (void)viewDidload
{
[touchyTextField addTarget:self
action:#selector(yourDesiredMethod)
forControlEvents:UIControlEventTouchDown];
}
-(void)yourDesiredMethod
{
if(isNeedToMove)//this Flag Avoid The unnecessary move call.
{
//here call the method which Move The UIview
}
}
- (BOOL)textFieldShouldReturn:(UITextField*)textField
{
[textField resignFirstResponder];
//here call the method which move UIView to its actual position.
isNeedToMove= TRUE;
return YES;
}
I hope you may get Some idea .
I had this trouble too. In keyboardWasShown, the Apple documentation says:
if (!CGRectContainsPoint(aRect, activeField.frame.origin)
I used:
if (activeField == myTextField)
Here's the long version of the answer: moving content located under the keyboard
For the past few extremely frustrating days of my life, I've been trying to figure out what's wrong with me code. In a certain page, if I put UITextViews or UITextFields or a MFMailComposer or a MessageComposer or anything with fields that require editing, the fields just wouldn't respond to touches. I couldn't edit anything when I ran the app. I couldn't edit text views or email fields or anything. I tried everything, but nothing worked. It turns out that on the main page (MainVC) that leads to the page where fields don't respond (GiftVC), in the viewDidAppear method (in the MainVC), I say: [self becomeFirstResponder];.
Now I'm not really sure why I put that there, but it turns out that commenting that line out fixes everything and makes all the fields and textviews and email composers and everything work just fine again.
I also have this in the MainVC page:
-(BOOL)canBecomeFirstResponder {
return YES;
}
and commenting that out fixes the problem as well.
The weird part is that even with the [self becomeFirstResponder] line, everything worked just fine in the new iOS 5 (simulator and device), but in iOS 4 (simulator and device), it wouldn't work at all with that line. Now that I've removed it, it works fine in both cases.
If you have the following in your UIViewController subclass
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.view.window) {
[self becomeFirstResponder];
}
}
then you probably intended to allow that subclass to handle motion events (shaking) or something similar. So that's probably why it's there.
If you weren't able to edit UITextFields then this subclass was probably becoming the first responder and not forwarding the event to the actual UITextField. When a UIViewController subclass calls overrides canBecomeFirstResponder to return YES and makes them self the first responder (ie [self becomeFirstResponder], if you want don't want that custom class to handle the touch events for the UITextField, then you should override the nextResponder method.
An example from my own product -- Essentially I have a UIViewController subclass that does two things: 1) it handles shake events and 2) it displays another view modally when some button is tapped. On the modal view there are some UITextFields. To allow my UIViewController subclass to forward the touch events to my modal view, I added the following:
- (UIResponder *)nextResponder
{
if (!self.view.window) {
// If the modal view is being displayed, forward events to it.
return self.modalViewController;
} else {
// Allow the superclass to handle event.
return [super nextResponder];
}
}
This will work on iOS 4 and 5, with either sdk.
Now, in your case you obviously didn't remember adding the code to become first responder in the first place, so you don't need the above hooks. However, it's good to know for the future.
Back to your actual question -- once you updated your SDK to 5, why wouldn't things work on iOS 4, but they would work on iOS 5? iOS 5 is doing some of the event forwarding for you which is why it works there. It should have never worked on iOS 4 in the beginning. Apple fixed some bugs that allowed it to work on 4, which is why it no longer works on 4.
I know the question had already accepted an accepted answer; I just wanted to clear up any confusion out there.
Check if MainVC has a method called canResignFirstResponder that returns NO (at least sometimes). If so, then once it becomes first responder, it won't let anything else become first responder, until it returns YES from that method. (All the UITextViews, etc. have to become first responder to be edited.)
Actually just look everywhere in all your code for canResignFirstResponder, in case it's in a superclass or something.
Otherwise the only thing that would stop the text fields and views from being editable would probably be if they got set userInteractionEnabled = NO, but since it hinges on the becomeFirstResponder statement, it is more likely to do with canResignFirstResponder.
In iOS 4, a subclass must override canBecomeFirstResponder in order to be able to become first responder. Maybe this is different for iOS 5 or it's a bug.
Try this,
Make sure you have added the uiTextViewDelegate and
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
NSLog(#"textViewShouldBeginEditing:");
return YES;
}
For some reason, resignFirstResponder is not working. I am not sure why? I have tried to call it from textFieldDidEndEditing and nothing happens. A NIB is being used and each's delegate is pointing to files owner.
What needs to be done to get the keyboard to dismiss?
Thanks.
Don't use -textFieldDidEndEditing. That's called after the text field resigns firstResponder status, which is what you're trying to use it as a hook to make happen. Cart before horse, chicken-and-egg kind of problem.
Instead use -textFieldShouldReturn to get triggered when the return key is pressed (and remember to return YES; from that.) Also float a clear custom button behind the elements of the view and handle a "background tap" that goes through all the text fields on your view and resigns first responder on the lot of them.
actually you should return NO so that the text field does not begin editing at all. If it does, the firstresponder gets set and the keyboard pops up again.
Make sure your setting your delegates for the textfield.
myTextField.delegTe = self;
And you are using in your header:
<UITextFieldDelegate>
EDIT:
Try:
if(textField == myTextField){
[textField resignFirstResponder];
}
Is there an iPhone equivalent for the NSResponder methods -selectNextKeyView or -nextValidKeyView from Mac OS X? I know about the -becomeFirstResponder method, but finding out which view to call that on is not very pretty when view hierarchies get more complicated.
There must be some kind of way to find this out as when I press tab when in the iPhone Simulator, focus does properly go to the next UITextField. This made me wonder what exactly happens when I press tab. Any ideas?
Update: This does exactly what I want, but _nextKeyResponder is private API, so a no-no. Is there any way to do a 'fake' tab key press without using private API?
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Try to find next responder
UIView *nextResponder = (UIView *)[self.view _nextKeyResponder];
if (nextResponder) {
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
[self.tableView scrollRectToVisible:[self.tableView convertRect:[nextResponder frame] fromView:nextResponder] animated:YES];
} else {
// Not found, so remove keyboard.
[textField resignFirstResponder];
}
return NO; // We do not want UITextField to insert line-breaks.
}
There is not a public iOS equivalent for NSResponder's -selectKeyView or -nextValidKeyView.
When the first responder is an instance of UITextField, pressing tab instantiates a private subclass of UIEvent which is passed to -[UIApplication sendEvent:], which in turn calls -[UIView _nextKeyResponder].
-[UIView _nextKeyResponder] doesn't work quite the way you think it does. It treats the key view chain as a loop, so your else block will never be reached. For the same reason, even if there was a public API for synthesizing keyboard events, you probably wouldn't want to use it.
Instead, you probably want something more like UIWebView's UIToolbar-based form input accessory. Its buttons can be enabled and disabled when appropriate, and its delegate handles the actual button press actions.
To implement such a delegate in a general way, however, it might be helpful to look at how -[UIView _nextKeyResponder] is implemented.
In the UITextField delegate -textFieldDidEndEditing:, switch between the various text fields (for example, by testing the text field's tag property).
When you match one text field, set another text field or other control to become the next responder.
I'm surprised nobody else appears to have solved this on iOS.
I devised a solution that handles both Tab and Shift+Tab to go forward and backward to any field you want on iOS, and doesn't use any private APIs.
Here is the write-up: http://weaklyreferenced.wordpress.com/2012/11/13/responding-to-the-tab-and-shift-tab-keys-on-ios-5-ios-6-with-an-external-keyboard/
I have a text field entry in my view that I would like to block access to during a background operation. I've tried using the editable property, which successfully blocks access during the background operation, but the moment I set editable to YES, the keyboard comes up and the textfield becomes the first responder. Dismissing the keyboard just after changing editable doesn't do anything:
// Broken code
textView.editable = YES;
[textView resignFirstResponder];
I've thought about adding a clear UIView that just blocks access to the UITextView after dismissing the keyboard, but that seems like overkill. Is there a correct way to handle this?
Just so people don't have to read farther than the selected answer: It turns out that this is a "known issue" in the SDK, and you can find it listed in the release notes. Using userInteractionEnabled performs the same function, as long as you make sure to dismiss the keyboard yourself.
Try textView.userInteractionEnabled = NO;
Put a UIView in front of the UITextView with a dark (or white) background color and alpha set low (like 5%) sized to fully cover the textview. Default it to hidden.
When you want the textinput disabled, send it a resignFirstResponder then show the hidden layer on top. It intercepts user inputs (and ignores it). The alpha color will make it look 'dimmed.' Once your background operation is done just set the cover view to hidden and you're good to go. If you want to get fancy you can do UIView alpha fade animations.
I'm not sure of a "correct way" but I'd probably do the transparent view solution... I agree that it seems like overkill but the simple solution is often a good answer.
Since the view gets focus upon changing the editable properties this would be easier.
the other solution that I can think of is to derive a custom UITextView and recode the editable property (or make a new method) that can accomplish what you are trying to do. This is a good object oriented solution but this could be come cumbersome.
You might also consider using a Category to add the functionality. But for either of these solutions, are still back to square one of how to accomplish what you need...
Thank god someone came up with a better response. I originally built it with the following blocker, but the userInteractionEnabled BOOL is much easier.
It turns out that the problem is a known issue with UITextView. My workaround:
#import <UIKit/UIKit.h>
/**
God damn SDK bug means that you can't use editable to enable/disable a
UITextView (It brings up the keyboard when re-enabling)
*/
#interface StupidF_ingTextViewBlocker : UIView {
}
#end
#implementation StupidF_ingTextViewBlocker
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
Then in place of the code I've placed above (instead of using editable). To disable (assuming I have an iVar called blocker):
// Put this in a lazy loading property or in loadView
blocker = [[StupidF_ingTextViewBlocker alloc] initWithFrame:writeView.frame];
// The blocker code ~= textView.editable = NO
[self.view addSubview:blocker];
// Removing the blocker ~= textView.editable = YES
[blocker removeFromSuperView];
Subclass UITextView, and implement a single method:
- (BOOL) canBecomeFirstResponder { return NO; }
Use the UITextViewDelegate. You'll need to swap out the delegate object depending on the current state.
If in the blocked state, then you'll use a delegate where textViewShouldBeginEditing returns NO.
the other delegate's textViewShouldBeginEditing would return YES.