Scroll textview when selecting text cover whole textview's screen area - ios

In my application there is one UIScrollView having UITextView.
if the UITextView has 200 lines and user will select the first line and drag the last end point of selected text and user will drag that point to select more lines.
then, in a screen whatever the text seen, the user can select but the scroll view isn't automatic scrolling to select another text line.
may be it's quite confusing to understand but i don't know exactly what to ask for this question.
for understanding i am putting image here. in image that blue colored last end point will drag down then UITextView should scroll. that functionality i want in my application.
any types of idea, code,link will be great help...
EDIT :
The text view is fit to 200 lines.
means the text height is that much that 200 lines of text having.
so i have to scroll the scroll view and for that need any event will call on drag down the end point.

Write this And all the problem will resolve Bro ..... Do it
UITextView *lblNews=[[UITextView alloc]init];
lblNews.textColor = [UIColor blackColor];
lblNews.userInteractionEnabled=YES;
lblNews.scrollEnabled=YES;
lblNews.editable=NO;
lblNews.dataDetectorTypes = UIDataDetectorTypeAll;
lblNews.contentInset = UIEdgeInsetsMake(20.0, 0.0, 20.0, 0.0);
[self.view addSubView:lblNews];

It may be that UIScrollView is intercepting the touch when you drag your finger over it.
For a test, I would try setting the UIScrollView userInteractionEnabled = NO, and see if that allows the auto scrolling of the UITextView.
If it does then I would make a delegate for the UITextView which for delegate method textViewDidBeginEditing sets UIScrollView userInteractionEnabled = NO;
and for delegate method
textViewDidEndEditing sets UIScrollView userInteractionEnabled = YES;
similarly, for the UITextView you can try setting exclusiveTouch = YES and back to NO in the delegates, and see if that helps.

Related

iMessage Extension: UITextView in Child View Controller, scrolling behaviour has multiple issues

I have a very basic view controller in an iMessage Extension. (Expanded view of course). I am aware that you can not have keyboard input int the Compact view...
The UITextView is constrained to the Element above it, and below it. It has a set height and width. The constraints are all in order, and are not broken.
All the options on the textview in interface builder have been left as DEFAULTS.
The following problems occur with the UITextView:
When I begin editing, the cursor is barely visible. (on the bottom of the field, half way cut off vertically).
Typing the first letter brings the cursor to the vertical centre of the Text View.
Putting a new line and then a character, puts the cursor back down again.
Then typing subsequent characters after that will bring the cursor to the Vertical Centre again. And every other character scrolls the whole text view to the bottom again. So you get this weird bounce up and down behaviour with every key stroke.
The Scroll Bar visual hint on the right side does not reflect the proper height of the text view, when I scroll. (The scroll bar only goes down half way - of the text view's height.)
I expect the UITextView to work like this by default:
Cursor should go to the TOP of the text view, when activated and editing.
Text View should not jump when typing keys after a new line.
Vertical Scroll Bar indicator should show the full range of the text field, and not half of it.
So, obviously the internal Scroll View inside the Text View has a problem figuring out the sizes of things.
Does anyone know, if this is an iMessage specific issue, or whether anyone has had this problem outside of iMessage as well, and how to fix?
My IB constraints (The second view down is the text view):
Video Demo of the problem:
https://youtu.be/1bkvHnkXLWM
UPDATE: I am using Child View Controllers to embed my View Controller inside the Root Controller. I have tried a blank Hello World application, and the UITextView works normally by default. So the issue, therefore is related to the way i'm embedding a Child View Controller.
This is the code I'm using to embed my Child View Controller:
- (void)showViewController:(UIViewController*)vcToShow isPop:(BOOL)isPop
{
NSLog(#"Presenting Controller: %#", vcToShow);
[self.activeVC willMoveToParentViewController:nil];
[self addChildViewController:vcToShow];
vcToShow.view.translatesAutoresizingMaskIntoConstraints = NO;
vcToShow.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.rootView addControls:#[vcToShow.view]
align:VerticalAlignStretchToFullHeight];
UIViewController* currentVC = self.activeVC;
self.activeVC = vcToShow;
vcToShow.view.alpha = 0.0f;
[self transitionFromViewController:currentVC
toViewController:vcToShow
duration:0.3
options:UIViewAnimationOptionTransitionNone
animations:^{
vcToShow.view.alpha = 1.0f;
}
completion:^(BOOL finished) {
[currentVC removeFromParentViewController];
[vcToShow didMoveToParentViewController:self];
[self updateScreenState];
if (isPop) {
[self removeReferenceToController:currentVC];
}
}];
}
I have a solution.
Instead of using Interface Builder to place my UITextView, I used my own programmatic constraint generation method to create and place the UITextView, only after ViewDidAppear.
My suspicion is that at the time Interface builder rendered the Child VC's view, it did not have everything populated that the UITextView's internal scroll view needed. So the scroll view got initialized with wrong dimension values, and therefore would glitch out on anything scrolling related. After doing everything in viewDidAppear programmatically (in the Child VC), the text view now scrolls properly, and the cursor is always at the beginning, working as expected.
The update code:
Took UITextView out of interface builder completely.
Added it programmatically (called from viewDidAppear):
self.textView = [[UITextView alloc] init];
self.textView.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat topPadding = self.instructionLabel.frame.origin.y + self.instructionLabel.frame.size.height + TEXT_VIEW_TOP_PADDING;
// This custom method generates Visual Constraint format for me
// so i don't have to write manual individual constraint syntax.
[self.rootView addControls:#[self.textView]
align:VerticalAlignTop
withHeight:TEXT_VIEW_HEIGHT
verticalPadding: 0
horizontalPadding: 20
topPadding: topPadding];

How to prevent iOS from resizing your UIViewController's view after return from background

I have a UIViewController that displays a form with several text fields. In order to prevent the text fields from getting blocked by the keyboard, I resize the controller's view when the keyboard appears and disappears.
However, when the keyboard is up, the user presses the home button, and then returns to the app, the controller's view will be resized again to the size it was before the keyboard was up and the keyboard will still be showing.
What's causing my controller's view to be resized on return from background, and how can I prevent it?
Maybe you need to nest a UIView,for example
_backgroundView = [UIView new];
_backgroundView.backgroundColor = [UIColor whiteColor];
_backgroundView.frame = CGRectZero;
[self.view addSubview:_backgroundView];
[_backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.mas_equalTo(self.view);
make.height.mas_equalTo(self.view.mas_height);
}];
then you need add your custom UIView to this backgroundView.
as you said,UIViewController's view will be resized after return from background. so you can nest a UIView of the same size as self.view,and add your custom UIView to this UIView.
In order to prevent the text fields from getting blocked by the keyboard, you can resize this backgroundView when the keyboard appears and disappears. and this time when you click the home button to enter the background or return from background,self.view won't be resized and backgroundView won't be resized too.
Although it is a bit of a hassle, this will solve your problem and will not affect the user experience anymore. And if you have a better solution, please let me know
It sounds like you are setting the frame and not using autolayout. When the view reappears viewDidLayoutSubviews gets called and your frame gets recalculated obliterating your previous change. You can either:
1) Move your frame to viewDidLayoutSubviews and change its size only if the keyboard is showing.
2) Use autolayout and simply pull up your bottom constraint .constant by an amount equal to your keyboard height.
In both cases you should call layoutIfNeeded to trigger autolayout/viewDidLayoutSubviews when the keyboard appears/disappears. This behavior is a good example of why you should not manipulate your frames outside of viewDidLayoutSubviews except for transitory animations.

Make UITextView parent be its own inputAccessoryView

I'm trying to achieve a similar keyboard interaction that Messages has in iOS 7. I have a UIView which contains a UITextView, and when the user selects it to start typing, I want to make this UIView the inputAccessoryView. This would take care of the animation for me, as well as the new UIScrollView keyboard dismiss interaction in iOS 7.
When the UITextView begins editing, I'm trying to set its inputAccessoryView to its parent UIView (which is already in the view hierarchy). The keyboard appears but not with an accessory view.
I've read some people are using a duo of UITextFields to make this work, but that seems like a bad way to achieve this.
Any suggestions?
A much easier solution is to make your input field the input accessory view of your view controller:
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (UIView *)inputAccessoryView
{
return self.yourInputField;
}
The view will be on screen at the bottom of the screen and when it becomes first responder in response to a user tapping it, the keyboard will be presented. The view will be animated such that it remains immediately above the keyboard.
The only way to get this to work is via a second text field. The idea is to make it a subview but not visible (due to crazy rect). You then switch firstResponder back and forth between it and the real text field while its getting delegate methods. I created a some one viewController test project and did this (you can copy paste and verify behavior with about 2 minutes of time):
#implementation ViewController
{
UITextField *field;
UITextField *dummyView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
field = [[UITextField alloc] initWithFrame:CGRectMake(0, 460, 320, 20)];
field.borderStyle = UITextBorderStyleRoundedRect;
field.delegate = self;
//field.inputAccessoryView = field;
field.text = #"FOO";
[self.view addSubview:field];
dummyView = [[UITextField alloc] initWithFrame:CGRectMake(0, 40000, 320, 20)];
dummyView.delegate = self;
[self.view addSubview:dummyView];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField == field && textField.superview == self.view) {
[field removeFromSuperview];
dummyView.inputAccessoryView = field;
[dummyView becomeFirstResponder];
}
return YES;
}
#end
I should add I've used this technique in shipping apps since iOS 4.
EDIT: So a couple of other ideas:
1) To make the glitch when the keyboard starts moving look a little better, you could take a snapshot of your textView, put that into a UIImageView, and when you remove the textView from the primary view, replace it with the UIImageView. Now the appearance is the same. Add an animation for the image so that noting happens for 50 ms, then the alpha goes to 0. Add a similar animation to your real textview, so that it has an alpha of 0 for 50 ms, then it goes to 1. You may be able to tweak this so the transition is good (but not great).
2) The way apple probably does this is to get the animation curve and timing from the keyboard moving notification. In this case they would add a accessory view with 0 height at first, and animate the textField so its tracking the keyboard, but above it. Both moving same distance at the same time. At the end of the animation, the textField is pulled out of self.view, the accessory view has its frame changed to have the height of the textField, and the textField is placed as a subview of the accessory container view. This should work but yeah, its a bit complex to do. If you want someone to code it for you offer a 100 pt bounty. You still need the dummy text field for when you go and move the textField at the end, since when you take it out of its containing view it will resign first responder. So at the end, you make the dummy field the first responder, move the textfield, then make the real textfield the first responder again.
This actually works best if you don't use .inputAccessoryView at all and instead just animate the position of the parent UIView as the keyboard opens and closes. Here is an answer describing the process step-by-step with all the code.

only Scrolling programmatically?

I don't know if this makes sense at all. I have UIScrollView from interface builder hooked it up as an outlet on top of my UIScrollView I have a UIImage view which holds an image called Scroll Background it is an extra half in screen real estate - my app is landscape and the image is an about half the screen taller. The image is hooked up as an outlet too. I have a button on a toolbar that brings up the keyboard when the button is pressed I'd like to programmatically scroll to the bottom of the UIImage view and when it is resigned I'd like to programmatically scroll to the top. I don't want the user to be able to scroll just for the app to scroll programmatically.
I can't seem to get this method to work and I'm not sure why :/
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
scrollRectToVisible:animated: is a non-intuative method to use in my opinion. In order to accomplish what you are after you should be able to set userInteractionEnabled to NO on the UIScrollView that will prevent users from scrolling.
Then in order to scroll the view programmatically you can call scrollRectToVisible but you need to give it a CGRect that is representative of the area you want to show. So in your case to scroll to the top:
CGRect visibleFrame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds) , CGRectGetHeight(self.view.bounds));
[self.myScrollView scrollRectToVisible:visibleFrame animated:YES];
Hope this helps!

center title and button in a custom sized UIAlertView iOS

I am working with alertViews to load to them different objects, such as textFields and others.
With textFields there is no problem. I have successfully added a UIPickerView as a subview of my alertView and I had resized the alertView.frame to hold the pickerView properly, but then the title and the button in the alertView are not centered.
I tried with many of the options [alertView …function…] but none seems to work with this issue. This looks bad in a custom sized alertView. Any suggestions?
Thanks folks!
to solve the Title issue, I got inspiration from this post: Custom AlertView With Background
First of all, when the App presents the alertView, I called a NSLog to get:
the pickerView's (my subview) width
the _titleLabel's width
the _titleLabel's starting position (MinX and MinY)
then I resized the _titleLabel frame and that was all!
textAlignment is Center by default so all I had to do was resize the label frame. other possible method is to use
[theTitle CGAffineTransformMakeTranslation(newXValue, 0];
Y value is 0 because I didn't want it to move vertically. But the described method is cleaner to me.
so what I added to the method that creates&presents my alertView was this:
NOTE: this code HAS to go BEFORE the addition of any additional view to the alertView!
//... alertView creation and display
//create a title object to edit titleLable properties
UILabel *theTitle = [pickers valueForKey:#"_titleLabel"];
// set frame for titleLabel to begin where it currently begins in both X and Y, set its width to the width of th e picker +/- the difference in X in case they don't have the same MinX value, and set the height it already has
theTitle.frame = CGRectMake(CGRectGetMinX(theTitle.frame), CGRectGetMinY(theTitle.frame), CGRectGetWidth(pkPais.frame)+6, CGRectGetHeight(theTitle.frame));
//...add subviews and set its frames (in my case, a pickerView)
as for the button, i found in the UIAlertView.h file that buttons cannot be customized...so if someone has any tip on this issue, any help will be appreciated.
hope this helps someone else!
UPDATE: As I mentioned, Apple said buttons in alertViews cannot be customized, so there are two alternatives: create a custom button and add it as subview or have no button at all. In my case I did so, and called [myAlertView dismissWithClickedButtonIndex:-1 animated:YES] in the didSelectRow...inComponent part of the pickerView code.
This worked for me just fine, but I am open to new ideas!!
See ya!

Resources