Scrolling UITextView programmatically - iphone

I'm implementing some simple text chatting capabilities in my app and I'm having issues with scrolling the UITextView programmatically. I'm using a UITextView created in Interface Builder that appends a new line and some text to the preexisting text. When the new text is added it should scroll to the bottom.
I built a test application to nail down the concept before adding it to my app. The text in the UITextView updates with the text from a UITextField, however no scrolling occurs.
- (IBAction)enteredText {
CGPoint currentPosition = [textWindow contentOffset];
[textWindow setText:[NSString stringWithFormat:#"%#\n%#", textWindow.text, textInput.text]];
[textWindow setContentOffset:currentPosition animated:NO];
[textWindow scrollRangeToVisible:NSMakeRange([textWindow.text length], 0)];
[textInput setText:#""];
[textInput becomeFirstResponder];
}
I remember implementing a very similar feature in another application I developed a while ago andfrom what I remember the code is similar. The only difference is that the earlier application was for iPhone OS 2 but this one is for 3.0. I read in some forums that the 3.0 beta had some issues with scrolling when the UITextView was created in Interface Builder. I checked the current release notes and I didn't see anything indicating that.
Edit: The IB action is called because text is updated in the UITextView. And "Cancellable Content Touches" is checked.
Edit: Confirmed that the same code works on 2.2.1 but not 3.0

I found that after the user has tapped on the UITextView the scrolling begins to work. So after I loaded this particular view I temporarily set the UITextView as FirstResponder, then the UITextField as FirstResponder:
[myChatRoomViewController.chatWindow becomeFirstResponder];
[myChatRoomViewController.input becomeFirstResponder];
The scrolling then happened automatically, albeit it seemed less smoother than what I remembered in iPhone OS 2.

Are you sure the IBAction is getting called? If so, try making sure that “Cancellable Content Touches” is checked in Interface Builder. This should solve the problem you hinted about in your post.

Related

Large Text Being Cut Off in UITextView That is Inside UIScrollView

I'm having a serious problem that I just can't seem to fix and it's driving me insane for the last two days. I have searched far and wide and I can't find a solution, even though I have tried many.
I have a UITextView inside a UIScrollView. I am able to dynamically resize the UITextView inside the scrollview to display the text. But when the UITextView contains very large text it gets cut off when I scroll almost to the end. However, the UIScrollView's frame is still being sized correctly.
I read these posts: this this and many similar ones.
The UIScrollview and UITextview are both created in the xib using AutoLayout.
Here is my current code and a screenshot as you can see the blank spot in the screenshot should be filled with text. please help.
- (void)viewDidAppear:(BOOL)animated
{
CGRect frame = self.longDescField.frame;
frame.size.height = self.longDescField.contentSize.height;
self.longDescField.frame = frame;
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.longDescField.contentSize.height + 200);
self.scrollView.scrollEnabled = YES;
[self.scrollView flashScrollIndicators];
}
This issue has existed since iOS 7 and is still present in iOS 12.
However, I wasn't able to keep the normal scrolling behaviour by setting scrollEnabled = NO before the resize, as #igz recommended. Instead I switched scrolling on and off after the resize
// Resize text view here
textView.scrollEnabled = NO;
textView.scrollEnabled = YES;
This forced the cut off text to render correctly.
Thanks everyone for your help. This is ultimately what ended up working for me in iOS7.
I had to disable auto layout for this particular xib.
Then did the following:
[textView setScrollEnabled:YES];
[textView setText:text];
[textView sizeToFit];
[textView setScrollEnabled:NO];
For me the solution was to put sizeToFit after customizing the textView
[self.yourTextView sizeToFit];
This should be the last thing you do when manipulating the textview, should not be before you populate the content text.
This issue can be fixed by setting the contiguous layout property to false.
textView.layoutManager.allowsNonContiguousLayout = false
Although the documentation says that the default value is false, it is actually set to true for a UITextView.
Definitely iOS7. I had this same problem applying to all UITextViews that were resized, both xib and code generated. I found the textContainer.size needed adjusting after UITextView frame was changed.
I created this category code to adjust the textContainer.size but it also seems to need adjusting after setting the text value as well, so I have to call adjustAfterFrameChange after any text changes if they are not followed by setting the frame size.
This code makes the assumption that UITextView is not doing anything with setFrame: itself so take out setFrame: and call adjustAfterFrameChange manually if you want to avoid that risk
Edit: changed
self.textContainer.size = self.frame.size; // fix for cut off text
to
self.textContainer.size = self.contentSize; // fix for cut off text
#interface UITextView(Extras)
- (void)adjustAfterFrameChange;
#end
#implementation UITextView(Extras)
- (void)adjustAfterFrameChange {
#if defined(__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
if ([self respondsToSelector:#selector(textContainer)])
self.textContainer.size = self.contentSize; // fix for cut off text
#endif
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self adjustAfterFrameChange];
}
#end
Try this
[self.textView setContentInset:UIEdgeInsetsMake(-8.0, 0, -8.0, 0)];
It work for the cut off text display in the UITextView.
I had a similar issue, wherein long text was getting cut off after a resize of the text view.
Turning off scrollingEnabled before the resize seemed to fix it. Sure seems like an IOS 7 bug.
We had the same problem, except the left half or right half of the UITextView was getting cut off. Happened on both iOS 7 and iOS 6, on a variety of phones. Calling:
myTextView.scrollEnabled = NO;
in viewWillAppear worked around the problem.
Just try this.
In IOS 8 and Xcode 6.3,
textview.scrollEnabled=YES;
[self.textview setContentInset:UIEdgeInsetsMake(-10.0, 0, -5.0, 0)];
We had an issue like this with the rollout of iOS7. When we called setText which added a new line (or lines) to our UITextView, the textview wasn't using the correct new height for its redrawing. The setNeedsDisplay, setNeedsLayout, redrawing layers, redrawing the entire view, etc all didn't work. Finally we forced a loss and gain of focus:
[textView resignFirstResponder];
[textView becomeFirstResponder];
This forced the height recalculation and correct redraw. Thankfully it does not cause the keyboard to pop out and in, but it's worth regression testing that on any iOS versions your app supports.
This happens all the way, from in Interface Builder too.
When text view selected, in Utilities Inspector uncheck the option Shows Vertical Indicator. The cropped text appears now.
None of these answers worked for me.
I was fooling with the storyboard and somehow it's working now. It still looks wrong in the storyboard but on the device it's now displaying fine.
I did various things, including toggling many of the options for the textfield.
I think what fixed it for me was making the view larger, building, and making it the right size again.
My apologies for a vague uncertain answer, but maybe it helps. This project was originally written for iOS 5, and the text view may not have been messed with much since then.
I have the same Problem for a textview (without a scrollview). Solved this (Xcode 7.3.1, iOS 9.3) just by unchecking "Scrolling Enabled" in the Attributes Inspector.
I may be wrong but I do not understand your problem thoroughly but what is the use of using a UIScrollView since with the UITextView class implements the behavior for a scrollable, multiline text region ?
You should discard the UIScrollView.
I am facing the same situation. I have to disable the UITextView's scrolling and doing that causes the last line is cliped. Here is my solution:
//In the UITextView subClass, override "gestureRecognizerShouldBegin" and let the scrolling of UITextView remain on.
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && gestureRecognizer.view == self){
return NO;
}
return [super gestureRecognizerShouldBegin:gestureRecognizer];
}
In Swift I fixed this issue by simply setting the textContainerInset of my UITextView:
textView.textContainerInset = UIEdgeInsets(top: 0.0, left: 0.0,
bottom: 50.0, right: 0.0)
This worked for me:
textView.scrollEnabled = NO;
//resize here
textView.scrollEnabled=YES;

Phonegap: completely removing the black bar from the iPhone keyboard

We're using Phonegap to develop our mobile app, and we borrowed code from here to remove the black next/prev/done bar from the keyboard:
https://stackoverflow.com/a/9276023/35364
What that code does is it finds the black bar, as a UIView object, and calls 'removeFromSuperview' on it.
We're not familiar with the iOS SDK/API. So while we can look at the code and get an idea of what it's doing, we can't tell if it's doing it properly, or how to improve it.
The specific problem we're running into:
We have a text field for writing a message, and we're manually controlling the placement of this field to be exactly above the keyboard, similar to the native sms app. In other words, we're putting it where the black bar was supposed to be.
When we focus/type in the message field, the system pushes the view up. It seems like this is a mechanism to make sure the text field is not invisible when the user types in it.
This is happening even though the text field is visible.
I noticed that by putting the input field right above where the black bar would normally be (as oppose to behind it), the view doesn't scroll.
So it seems the system somehow thinks the black bar is still there!
(To double check: when the black bar is not removed, and we put the text field right above it, we can focus and type in it, and the view would not scroll).
So the question is:
Why does the "system" push the content up when editing a text-field that's place right "behind" where the black bar is supposed to be? Is it because the black bar is not completely removed yet? Do we need to do something to "completely" remove the black bar? Do we need to force iOS to recalculate the size of the keyboard? or what exactly?
Is this mechanism (pushing up the view) implemented by iOS's UIWebView, or by Phonegap?
Is there any phonegap app that has solved this problem?
replace
[subviewWhichIsPossibleFormView removeFromSuperview];
with
UIScrollView *webScroll = [webView.subviews lastObject];
CGRect newFrame = webScroll.frame;
float accesssoryHeight = subviewWhichIsPossibleFormView.frame.size.height;
newFrame.size.height += accesssoryHeight;
[subviewWhichIsPossibleFormView removeFromSuperview];
[webScroll setFrame:newFrame];
it resize the content scroll view for the amount of missing accessory space. It is as far using "private API" as the other code. In detail it isn't using private API directly but if Apple decide to change how a view appears (in this case Keyboard and WebView) then it will crash.
For example if they rename UIWebFormAccessory, your code will not work anymore.
EDIT:
on iOS 5.0+ you can call webView.scrollView directly. So you can split the code to have a pre iOS 5 fallback:
UIScrollView *webScroll;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
webScroll = webView.scrollView;
} else {
webScroll = [webView.subviews lastObject]; // iOS 2.x (?) - 4.x
// make sure this code runs appropriate on older SDKs
}
This worked for me: https://github.com/don/KeyboardToolbarRemover
You will have to know though, there is no Cordova.plist file as of Phonegap 2.3.0 - instead edit your config XML file with the following:
<plugin name="KeyboardToolbarRemover" value="KeyboardToolbarRemover" />
in the branch

iPhone/iPad Keyboard Dimming

I am writing a universal app that will be used primarily at night. I will need to display a keyboard but do not want the light colors of the keyboard to blind the user and/or spoil their night vision. I do not want to have to go through the trouble to creating a custom keyboard so I thought a solution might be to place a UIView over the keyboard and give it a black background color with an alpha of 0.5 or something however, I can not figure out how to get a UIView to cover the keyboard. Does anyone know how to do this? Does Apple allow this?
The keyboard is found as a subview of a new window that is added when it appears. Finding it is a little hacky and fragile (will need checking at new iOS versions, as it has changed before) but it does work and it is allowed (I do exactly this for a night mode in an app that is on the app store).
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1]; // This assumes you aren't adding any new windows yourself
for(UIView *keyboard in tempWindow.subviews)
{
if([[keyboard description] hasPrefix:#"<UIPeripheralHost"] == YES) // This was different in an earlier version of iOS, and may well change again in the future!
{
[keyboard addSubview:maskView];
break;
}
}
This is done inside the method that responds to the UIKeyboardDidShowNotification object. I've not tried it on the iPad, this is iPhone code only.
The mask view is, as you say, just a plain view with a black background and some transparency. You can also use the alert keyboard style which gives a black space in between the keys.
This method does not prevent the little key flashes (the larger keys that pop up when you tap a key) from being at full brightness, unfortunately.
try applying the required changes on inputView property of UITextFiled/UITextArea (the one being used).

Show iPhone soft keyboard even though a hardware keyboard is connected

My iPad app uses an external "device" that acts as a hardware keyboard. But, at some point in the settings, I need to input text and I can't use the "device" ("device" is not a keyboard).
So, is there any way to force pop the soft keyboard even thought I have a hardware keyboard connected?
Yes. We've done this in a few of our apps for when the user has a Bluetooth scanner "keyboard" paired with the device. What you can do is make sure your textField has an inputAccessoryView and then force the frame of the inputAccessoryView yourself. This will cause the keyboard to display on screen.
We added the following two functions to our AppDelegate. The 'inputAccessoryView' variable is a UIView* we have declared in our app delegate:
//This function responds to all textFieldBegan editing
// we need to add an accessory view and use that to force the keyboards frame
// this way the keyboard appears when the scanner is attached
-(void) textFieldBegan: (NSNotification *) theNotification
{
UITextField *theTextField = [theNotification object];
// NSLog(#"textFieldBegan: %#", theTextField);
if (!inputAccessoryView) {
inputAccessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, navigationController.view.frame.size.width, 1)];
}
theTextField.inputAccessoryView = inputAccessoryView;
[self performSelector:#selector(forceKeyboard) withObject:nil afterDelay:0];
}
//Change the inputAccessoryView frame - this is correct for portrait, use a different
// frame for landscape
-(void) forceKeyboard
{
inputAccessoryView.superview.frame = CGRectMake(0, 759, 768, 265);
}
Then in our applicationDidFinishLaunching we added this notification observer so we would get an event anytime a text field began editing
//Setup the textFieldNotifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textFieldBegan:) name:UITextFieldTextDidBeginEditingNotification object:nil];
Hope that helps!
There’s no way to do this with the current SDK. Please let Apple know via the Bug Reporter.
The solutions here didn't work on iOS 13 or aren't App Store compatible so I solved the problem by creating my own soft keyboard. It is pretty basic but works. Feel free to contribute!
Project on Github
All you have to do is add SoftKeyboardView.swift to your project and somewhere (e.g. appDidFinishLaunching) hit the singleton:
Usage:
SoftKeyboardManager.shared.disabled = false
Since I have the same problem, the closest solution I have found is to use Erica Sadun's app called KeysPlease which is available via cydia and modmyi. It's description is "Use soft kb even when connected to a BT kb.".
Additionally I have found that if you have a physical keyboard also attached, in my case via the iPad keyboard doc, you can bring up the keyboard using a key which seems to map to the eject key on a bluetooth keyboard. Perhaps there is a way to inject this key as if it was pressed on an attached keyboard?
I really wish there was a more official coding solution to this.
When my app connect bluetooth device, keyboard wouldn't show.I try set force the frame of the inputAccessoryView as Brian Robbins say. It didn't work.
Then I use a stupid way to solve.I found when I click textfield or textview one more time, keyboard will show.
So I just need to simulate touch in textfield or textview once , it works.
If you want to do some simulate touch, check this.
https://github.com/HUYU2048/PTFakeTouch

iphone UITextView does not support data detectors when the text view is editable

I am getting an interesting warning at build time (iPhone simulator) that gives the following:
EditView.xib:35:0 UITextView does not support data detectors when the text view is editable.
This is basically non existent on google and I would like to remove it.
My editview.xib has a textview where I write notes into it. Is there any more info that is needed?
I have four different Xibs with similar TextViews that are used for notes as well. I was getting the same warnings. The suggestion to disable the "Detects Phone Numbers" and "Detects Links" does removes the warnings. However, I wanted my users to still have the ability to use the detectors in my notes.
This is how I solved the issue in my app:
In IB: I deselected the two properties for the TextView. -(which does stop the build warnings).
In my - (void)viewDidLoad { I set the properties of the textView to the following:
myTextView.dataDetectorTypes = UIDataDetectorTypeAll; which enables the data detectors of all types (phone numbers and url addresses).
In my View Controller's: -(void)textViewDidBeginEditing:(UITextView *)sender {
method, I turned the data detectors back OFF using: myTextView.dataDetectorTypes = UIDataDetectorTypeNone
Then taking advantage of the -(void)textViewDidEndEditing:(UITextView *)sender {
method, I turned them back ON using: myTextView.dataDetectorTypes = UIDataDetectorTypeAll;
This method disables the data detectors when the user is editing the UITextView and turns the data detectors back ON when the user is finished editing. This Fix allowed for selection of the phone numbers and URL from within the textView, so that I did not loose the function.
I found the following in the Apple Docs on the DataDetectors for UITextView: after playing around with the UITextView for a while, hope it helps.
UIDataDetectorTypes:
Defines the types of information that can be detected in text-based content.
Types:
UIDataDetectorTypePhoneNumber;
UIDataDetectorTypeLink;
UIDataDetectorTypeNone;
UIDataDetectorTypeAll;
Update: 11-5-2010;
Extra Note:
Data detectors are not permitted if UITextView is "Editable", because there would be too many variables to track users changes to text as well as touches with trying to execute phone call or links.
Solution:
Load the TextView with self.textView.editable = NO; and set you UIDataDetector's based on the types I listed above. This way if the user wants to "select" web address or phone number etc, the delegate can handle. When you need your user to edit the textView, then turn ON the self.textView.editing = YES; & remove your UIDataDetectors accordingly. This should assure no errors or warnings during compiling.
Special Consideration:
Be sure to first remove the datadectors when re-enabling, then enable "editing = YES;"...The order is important no to enable editing if UIdatadetectors are still assigned.
Therefore, the sequence order should be something like this...
To Edit textView: 1. remove data detectors, 2. then enable editing = YES.
To Use DataDetectors: 1. Disable Editing = NO; 2. then add data detectors.
I was seeing this warning as well. Here's how I fixed it:
In the xib file in Interface Builder, select your text view, and bring up the attributes inspector. Make sure that "Detects Phone numbers" and "Detects Links" are both UNCHECKED.
I had "Detects Links" checked, and turns out that's what was causing the warning. Basically, if the textview is editable, you don't want these auto-detect features turned on.
So Wordy!
textView.editable = NO;
textView.dataDetectorTypes = UIDataDetectorTypeAll;
the URL address must start with "http://", otherwise the textview cannot detect it.
I thought about trying to use a Tap-Gesture-Recognizer with "delaysTouchesBegan = YES" and "cancelsTouchesInView = NO"
It is still quite easy to solve!
Load view with editable disabled as well as UIDataDetectorTypeAll or the types of links you want to detect. Then add a GestureRecognizer:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(editTextRecognizerTabbed:)];
recognizer.delegate = self;
recognizer.numberOfTapsRequired = 1;
[self.textViewNotes addGestureRecognizer:recognizer];
So you can change settings within this method:
- (void) editTextRecognizerTabbed:(UITapGestureRecognizer *) aRecognizer;
{
self.textViewNotes.dataDetectorTypes = UIDataDetectorTypeNone;
self.textViewNotes.editable = YES;
[self.textViewNotes becomeFirstResponder];
}
And at least you have to change the edit and detections settings back after user has finished the text input:
- (void)textViewDidEndEditing:(UITextView *)textView;
{
self.textViewNotes.editable = YES;
self.textViewNotes.dataDetectorTypes = UIDataDetectorTypeAll;
}
works lika a charm!
Data detectors for the UITextView would be for copy and paste. Since you are setting it as editable, copy/paste shouldn't be allowed where you think paste should, but copy shouldn't.
Simplenote somehow does this on iOS 4. (There's a free/lite version in case you wanna try.)
It acts a little bit different:
When tapping on one of the highlighted parts, it still starts the editing, and won't follow the link.
But when you tap-and-hold on a detected dataTpye, it shows yout the menu for calling, open the link or whatever.
Also, when tapping inside the text the editing really starts at the place you tapped.
So they somehow remove the dataDectectors, enable editing AND get the touches forwarded to the editable UITextview AFTER the tap is recognized.
Any ideas how to do that?
I thought about trying to use a Tap-Gesture-Recognizer with "delaysTouchesBegan = YES" and "cancelsTouchesInView = NO"
So I can remove the dataConnectorTypes and set it editable on the action method of the recognizer,
and hopefully the touches to the UITextview are delivered AFTER that.
But haven't had time to test it so far.