6

I am trying to implement PullDown To Search feature in my app. To implement this i just modified bit EGOTableViewPullRefresh it is working good except an issue.

Issue

When user opens the application following screen shall appear. initially the UICollectionView's contentoffset shall be (0,0) enter image description here

If user pulls down the collection view the following screen shall appear at this point the contentoffset of UICollectionView shall be (0,-60) enter image description here

User can search by entering their text in the above screen. My issue is occurring in this screen as soon as user taps the UITextField to enter text contentoffset of UICollectionView changes (0,-60) to (0,-110) and UI loosks like bellow screen. I am not sure why this change occurs can you please guide me to resolve this?

enter image description here

BaSha
  • 2,260
  • 3
  • 18
  • 37
thavasidurai
  • 1,934
  • 1
  • 25
  • 47

5 Answers5

2

Had the same issue. Overriding viewWillAppear:, viewDidLoad: and other methods as told in documentation had no effect, TPKeyboardAvoidingScrollView didn't help either. After struggling with collection view for over 2 days I've come to a really bad workaround. The idea is to lock scrolling up when keyboard is about to appear, so your collection view will not move anywhere, and unlock scroll after keyboard ends animation. To do so you should subclass UICollectionView to add a flag that locks scroll, subscribe to keyboard notifications and set this flag properly.

Before you implement this workaround, I must warn you that this is a VERY bad idea, and you should try everything else before doing that. Still, this works...

So here is what you do:

  1. In viewWillAppear of your viewController subscribe for keyboard notifications:

    - (void)viewWillAppear:(BOOL)animated
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardDidShow:)
                                                     name:UIKeyboardDidShowNotification
                                                   object:nil];
        // you custom code here
    }
    

You will handle notifications later

  1. Don't forget to unsubscribe from notifications:

    - (void)viewWillDisappear:(BOOL)animated
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        // your custom code
    }
    
  2. Subclass UICollectionView and add flag:

    @property (nonatomic, getter=isLocked) BOOL locked;
    
  3. Override setContentOffset: in your collection view:

    - (void)setContentOffset:(CGPoint)contentOffset
    {
        if (contentOffset.y < self.contentOffset.y && self.isLocked) // user scrolls up
            contentOffset.y = self.contentOffset.y; // ignore new Y coordinate, so collection view will not scroll up
        [super setContentOffset:contentOffset];
    }
    
  4. In your viewController create methods for keyboard handling to lock and unlock scroll:

    - (void)keyboardWillShow:(NSNotification *)aNotification
    {
        [(LockableCollectionView *)self.collectionView setLocked:YES];
    }
    
    - (void)keyboardDidShow:(NSNotification *)aNotification
    {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [(LockableCollectionView *)self.collectionView setLocked:NO];
        });
    }
    

Warning! Here is a little clarification about dispatch_after in keyboardDidShow: If you unlock scroll right after keyboard did show, locking will be ignored and collection view will scroll up. Wrap it into dispatch_after to run this code after 0.3 seconds and it works well. This is probably related with run loops and should be tested on real devices, not in simulator.

AnKh
  • 31
  • 3
  • It doesn't really work if u click again on UITextfield, when keyboard is already on the screen. – Zaporozhchenko Oleksandr Nov 12 '15 at 08:59
  • I think may be more right to not override - (void)setContentOffset:(CGPoint)contentOffset and override another method: -(void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated – Sound Blaster Nov 12 '15 at 10:43
  • FWIW - I discovered this behavior occurs if you use the keyboard avoidance code in Apple's example as is. I had to modify it to take into account the offset of the table view at the time the keyboard appears. – David U Nov 19 '15 at 16:47
1

I had an UITableView inside an UICollectionView and got weird scrolling. Inspired by @AnkH I override my UICollectionView and added this into the constructor:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow),
            name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide),
            name: NSNotification.Name.UIKeyboardDidHide, object: nil)

Override contentOffset too and blocked all modifications of contentOffset while the keyboard was visible. Done. The problem is that UITableView already triggers the correct contentOffset setting on itself, but then the parent UICollectionView adds its own contentOffset, resulting in disastrous behaviour. First it was scrolling too far up, then too far down. Now it works flawlessly!

Jan
  • 687
  • 7
  • 18
0

also not a beautiful solution to handle this

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIKeyboardWillShowNotification, object: nil)

 

func keyboardWillShow()  {
    let offset = self.collectionView!.contentOffset;
    self.collectionView!.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right:0 )
    self.collectionView!.contentOffset = offset

    let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
    dispatch_after(delayTime, dispatch_get_main_queue()) {
        let offset = self.collectionView!.contentOffset;
        self.collectionView!.contentInset = UIEdgeInsets(top: 60, left: 0, bottom: 0, right:0 )
        self.collectionView!.contentOffset = offset
    }
}
Eli Sadoff
  • 6,628
  • 6
  • 29
  • 54
Onnmir
  • 1,022
  • 13
  • 16
0

The easiest alternative is to use a UIViewController and add your own UICollectionView. The amount of crazy hacks needed to disable all the undesired behavior of the keyboard is just insane.

noobular
  • 3,191
  • 2
  • 22
  • 19
0

problem solve! changing my UICollectionViewController by a UIViewController and make my UICollectionView a subView of my ViewController.view.

r0d0
  • 1
  • 1
  • for some reason the UICollectionViewController add an scrollview as top view in the hierarchy. That was the view that get modified when keyboard appear. – r0d0 Jun 20 '17 at 15:09
  • It doesn't work for me... I'm experience this problem while using UIViewController with UICollectionView. – Radek Wilczak Jul 20 '17 at 12:30