iOS Accessing scrollView inside of a textView delegate

1458279

Suspended
Original poster
May 1, 2010
1,601
1,521
California
I have a UIScrollView and contextView. I add UITextViews to it and set the delegate to self so that I can use the textViewShouldBeginEditing method. The textViewShouldBeginEditing is inside the same ViewController.m file, so the VC should be the delegate.

The textViewShouldBeginEditing method gets called and I want to check if the keyboard is blocking the textView and scroll it up if it's being blocked.

I want to call: [scrollView setContentOffset:CGPointMake(x, y) animated:YES]; However scrollView is not seen in textViewShouldBeginEditing.

I've seen where KVO can be used, but I want to use the delegate methods.

How can I gain access to the scrollView that the textView is on?
Code:
- (void)viewDidLoad {

    [superviewDidLoad];
   UIScrollView *scrollView;
    scrollView=[[UIScrollViewalloc]initWithFrame:CGRectMake(0,0,320,480)];
    scrollView.showsVerticalScrollIndicator=YES;
    scrollView.scrollEnabled=YES;
    scrollView.userInteractionEnabled=YES;
    scrollView.contentSize = CGSizeMake(320, 1200);
    scrollView.backgroundColor = [UIColorgrayColor];
    [self.viewaddSubview:scrollView];
    UIView *contentView;
    contentView=[[UIViewalloc]initWithFrame:CGRectMake(0,0,320,480)];
    contentView.userInteractionEnabled=YES;
    [scrollView addSubview:contentView];

       UITextView *myNewText = [UITextViewnew];
       myNewText.delegate = (id)self;
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
    NSLog(@"BeginEditing");

// This is what I want to do, it doesn't show up in Xcode, but I'm in the same module and the VC is the delegate, because this method is being called.
// I just need to access the scrollView from in here to make it scroll.
    //[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
    //[scrollView.contentOffset.x +320];
    //scroll the view up if needed
    returnYES;
}
I didn't want to create a subclass of UITextView or use KVO.
 

AxoNeuron

macrumors 65816
Apr 22, 2012
1,240
847
The Left Coast
You're creating the text view but you don't seem to be adding it in to the scrollview.

You need to set the frame of the scroll view, then use the addSubview() method of the UIScrollView.

Another piece of advise: I don't add subviews directly to the scrollview. Instead, I add a regular UIView to the scroll view, and I call it the 'contentView'. I then add everything in to that. If you are doing things visually in the storyboard this makes it significantly easier to use auto layout.

Objective-C
Code:
    UITextView *textView = [[UITextView alloc] init];
    textView.delegate = self;
    textView.frame = CGRectMake(20, 20, self.scrollView.frame.size.width - 40, self.scrollView.frame.size.width - 40);
    scrollView.addSubview(textView);
Swift
Code:
    let textView = UITextView();
    textView.delegate = self;
    textView.frame = CGRectMake(20, 20, self.scrollView.frame.size.width - 40, self.scrollView.frame.size.width - 40);
    scrollView.addSubview(textView);
 

1458279

Suspended
Original poster
May 1, 2010
1,601
1,521
California
You're creating the text view but you don't seem to be adding it in to the scrollview.

You need to set the frame of the scroll view, then use the addSubview() method of the UIScrollView.

Another piece of advise: I don't add subviews directly to the scrollview. Instead, I add a regular UIView to the scroll view, and I call it the 'contentView'. I then add everything in to that. If you are doing things visually in the storyboard this makes it significantly easier to use auto layout.

Objective-C
Code:
    UITextView *textView = [[UITextView alloc] init];
    textView.delegate = self;
    textView.frame = CGRectMake(20, 20, self.scrollView.frame.size.width - 40, self.scrollView.frame.size.width - 40);
    scrollView.addSubview(textView);
Swift
Code:
    let textView = UITextView();
    textView.delegate = self;
    textView.frame = CGRectMake(20, 20, self.scrollView.frame.size.width - 40, self.scrollView.frame.size.width - 40);
    scrollView.addSubview(textView);
Ok, I didn't post all the code.

Code:
- (void)viewDidLoad {
    [superviewDidLoad];
    // make a scrollView
    UIScrollView *scrollView;
    scrollView=[[UIScrollViewalloc]initWithFrame:CGRectMake(0,0,320,480)];
    scrollView.showsVerticalScrollIndicator=YES;
    scrollView.scrollEnabled=YES;
    scrollView.userInteractionEnabled=YES;
    scrollView.contentSize = CGSizeMake(320, 1200);
    scrollView.backgroundColor = [UIColorgrayColor];
    [self.viewaddSubview:scrollView];
    // make a UIView
    UIView *contentView;
    contentView=[[UIViewalloc]initWithFrame:CGRectMake(0,0,320,480)];
    contentView.userInteractionEnabled=YES;
    [scrollView addSubview:contentView];
    NSMutableArray *dataArray = [NSMutableArrayarray];
    NSMutableArray *labelArray = [NSMutableArrayarray];
    int leftData = 125;
    int leftLabel = 20;
    int height = 30;
    int length = 170;
    int labelLength = 90;
    int startTop = 0;
    int spacer = 15;
    for (int i = 0; i<30; i++){
        UITextView *myNewText = [UITextViewnew];
        startTop = startTop + height + spacer;
        myNewText.frame = CGRectMake(leftData, startTop, length, height);
        myNewText.text = [NSStringstringWithFormat:@"Item # %d StartTop: %d", i, startTop];

        // set the delegate so that we can control the keyboard events
        myNewText.delegate = (id)self;
        [dataArray addObject:myNewText];
        // make the label
        UILabel *myNewLabel = [UILabelnew];
        myNewLabel.frame = CGRectMake(leftLabel, startTop, labelLength, height);
        myNewLabel.text = [NSStringstringWithFormat:@"Item # %d StartTop: %d", i, startTop];
        [labelArray addObject:myNewLabel];
    }

    for (int i = 0; i<30; i++){
        [contentView addSubview:labelArray[i]];
        [contentView addSubview:dataArray[i]];
    }
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
    NSLog(@"BeginEditing");
/*

this method is called
However, I can't call the scrollView or contentView

*/

    //[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
    //[scrollView.contentOffset.x +320];
    //scroll the view up if needed
    return YES;
}


- (BOOL)textViewShouldEndEditing:(UITextView *)textView{
    NSLog(@"EndEditing");
    //hide the keyboard
    return YES;
}
The two methods (textvView delegates) but I can't call scrollView or contentView.

You should be able to put all this code into one VC and run it. I'm pretty sure it has to do with adding on an interface from the VC into the textView.

Mine are standard:
Code:
@interfaceViewController ()

@end

@implementation ViewController
Wouldn't I need to tell the VC that it can get messages back from the textView delegates?
[doublepost=1460605401][/doublepost]Here's a link to what someone else did to handle this problem. He uses NSNotifications, but some say that's not the best approach. Delegates are supposed to be the proper way to do it.

https://spin.atomicobject.com/2014/...cial&utm_campaign=uiscrollview-autolayout-ios

I'll also need to kill the keyboard afterwards.

The behavior I'm looking for is the same as seen in Apple's "contacts" app.

SO has a solution, but it still doesn't use delegates.

http://stackoverflow.com/questions/...ew-up-when-keyboard-appears/26237038#26237038

This is really an object (instance) visibility issue. I can's see the object that's created inside the same module. That should mean it has to go thru the proper channels (interface / protocol). Just not sure how to set it up.

Here's one SO member's suggestion. It looks good, but requires a pretty high version of iOS and still doesn't answer my question.
https://github.com/hackiftekhar/IQKeyboardManager
 
Last edited:

1458279

Suspended
Original poster
May 1, 2010
1,601
1,521
California
Ok, well it looks like I found a cheap work around.

I don't think it's the right way to do it, but it does work.

I changed the scope of the subview and now the delegate can see it using _scrollView.

There has to be a better way.

Code:
@interface ViewController()
@property UIScrollView *scrollView;
 

AxoNeuron

macrumors 65816
Apr 22, 2012
1,240
847
The Left Coast
Ok, well it looks like I found a cheap work around.

I don't think it's the right way to do it, but it does work.

I changed the scope of the subview and now the delegate can see it using _scrollView.

There has to be a better way.

Code:
@interface ViewController()
@property UIScrollView *scrollView;
It could be because you're not maintaining a strong reference to the text view and it might be getting deallocated along with its delegate property.
 

1458279

Suspended
Original poster
May 1, 2010
1,601
1,521
California
It could be because you're not maintaining a strong reference to the text view and it might be getting deallocated along with its delegate property.
Ok, that sound reasonable. The scrollview, contextview, and textviews were all created on the fly, so they probably default to weak and can't be seen after control leaves the method.

So I don't know how to make a var strong without putting in the @Property and that seemed to fix it.

So as far as scope goes, if it's in the @Property of the .m, it's private to the methods in that .m. If it's in the @Property of the .h, it's public to all that create an instance.

If that's the case, it's my fault for screwing up the scope.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.