How do I prevent text entry in a UITextView? - iphone

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.

Related

Move View When Keyboard Appears - Only Upon Editing?

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

UIBarButtonItem - Invalid tap glow size

I have a strange problem with glow that appears when pressing on a UIBarButtonItem in the UIToolbar control. When I set ImageInsets property to 4,0,0,0 the glow gets smaller every time I tap on it. Here is an illustration:
The problem doesn't appear if I don't set imageInsets. The problem appears for all buttons in the UIToolbar. I don't have tap handlers. Making bigger inset (e.g. 8,0,0,0) produces the same result faster.
I appreciate any suggestions on how to solve the problem.
EDIT: Changed the code to Objective-C since the problem reproduces without MonoTouch as well.
It's default single view project. I added a toolbar and a UIBarButtonItem into it using storyboard designer. Created an outlet for the button.
#import "ViewController.h"
#implementation ViewController
#synthesize testBtn;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 0, 0, 0);
[testBtn setImageInsets:insets];
}
- (void)viewDidUnload
{
[self setTestBtn:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
It is hard to see what the problem is without code. Would you mind posting the relevant parts of your code up? I am thinking it has something to do with you repeatedly incrementing the top inset by 4... I will edit my answer once I see the relevant code.
EDIT: So I am not familiar with Monotouch... and from the code you pasted I am assuming the constructor does indeed get called once. I am thinking there may be a bug in the Monotouch framework which is causing the imageinsets to be shifted by the specified amount (down 4) every time the button is tapped. I would check in the following order:
That the delegate method tied to the button is not pointing to the constructor.
Change the inset to (8,0,0,0) and in 5 taps do you see the same image as above (10x). If so it may be an issue with the monotouch framework or with how you hooked up your delegate method.
Sorry but I am unfamiliar with monotouch so I can't provide much more assistance. Unless you are locked into using Monotouch, I would strongly recommend you learn native Objective-C and program natively to avoid small pitfalls and headaches such as this. Objective-C and the iOS SDK is pretty elegant.
Finally, I asked designer to adjust image size and thus get rid of the imageSize property use.

Why calling [self becomeFirstResponder] caused so many problems?

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;
}

Edit a UIViewController

I can't seem to find any information on what should be a simple issue. I have a table which contains a series of cells. When you tap on the cell it shows the information of that object in detail. I know it is possible to have a button which places all of the data on the screen in EDIT mode. Any tutorials or advice as how to do this (properly/ with best practices)?
Just to be clear this is for iPhone/ Objective-C/ Cocoa.
Thanks,
EDIT 1
Sorry. I know how to put the button there. But how do make the labels editable?
You are confusing two states:
Putting the tableView into editing mode - this is for deleting, or moving cells around in the table, regardless of the cell content. This is controlled by the UITableView.editing property.
and
Putting the tableViewCell into some sort of editing state. There is no official editing state for the cell (i.e. there is no single flag to set to make all UILabels in a cell into editable textFields.) You need to implement all of this logic yourself. If you're using .xibs, a good practice here is to have a different .xib for your cell's editing mode.
You cannot have editable labels. However, you can replace the label with a textfield when the button is pressed, and then update the label once finished.
One way to do this is the following. Create a textfield in the same location as the label and initially set textField.hidden = YES;. Then implement something along these lines:
-(IBAction)editMyCell:(id)sender {
textField.text = cellLabel.text;
cellLabel.hidden = YES;
textField.hidden = NO;
[textField becomeFirstResponder];
}
and when the editing has finished, restore with
-(void)textFieldDidEndEditing:(UITextField *)textField {
cellLabel.text = textField.text;
textField.hidden = YES;
cellLabel.hidden = NO;
[textField resignFirstResponder];
}
You'll probably want to tweak this idea a bit for your situation, but it's probably the simplest thing to implement that achieves what you're after.
There is nothing in the base sdk associated with editing a UIViewController. Normally that kind of logic is defined by the programmer. But I could see someone writing a function that turns all of your UILabels in your UIView into UITextViews so the user can edit the text.
There might be sample code out there but this seems like custom code to me.

Disable Magnifying Glass in UITextField

Is there a way to prevent the user from moving the cursor in a UITextField? I'd like it to stay at the end of the string.
This is an old question, but I was looking for an answer to the same question, and found a solution.
It is actually quite simple to prevent the user from moving the cursor. Just subclass UITextField and provide the following implementation of caretRectForPosition:
- (CGRect)caretRectForPosition:(UITextPosition *)position
{
return [super caretRectForPosition:self.endOfDocument];
}
NO SUBCLASS needed.
You Could use UITextFieldDelegate. It will make disable magnifying glass & text selection.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
textField.userInteractionEnabled = NO;
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
textField.userInteractionEnabled = YES;
}
NB: This is just a bypass.
There's no way to prevent them from moving the cursor. You can, however, prevent them from editing the text except at the end by implementing the
– textField:shouldChangeCharactersInRange:replacementString:
method in your text field's delegate.
Edit: you can also set userInteractionEnabled to NO so that the user can't tap the field. Call becomeFirstResponder manually so that the field gets focus since the user can't tap to focus.
I'd suggest to check the gestureRecognizers property.
You will find a lot of them in the array and might want to either remove them all or to find the ones that triggers the event you want to intercept and remove/replace it.
I used it to remove copy/paste and magnifying glass functionalities from an UITextField
I haven't check if you can disable the magnifying glass, but the recommended way to selectively disable editing behavior in a UIResponder (and thus a UITextField) is to implement canPerformAction:withSender of UIResponder.
See UIResponder documentation.
Maybe if you return "NO" for the select and selectAll action you can disable it.
Another, more brutal, way is to intercept any touch event and reset the cursor to the end.