Skip to content
This repository was archived by the owner on Oct 30, 2018. It is now read-only.

Implements an alternative technique for dragging the keyboard on iOS 9 #355

Closed
wants to merge 11 commits into from

Conversation

dzenbot
Copy link

@dzenbot dzenbot commented Jan 13, 2016

Because the keyboard is on its own view hierarchy since iOS 9, we needed to lookup for its view so we could move the keyboard view following the text input using a panning gesture, using private APIs. We no longer use private APIs, but we needed this feature back.

This is an alternative technique, working in the following way:

  • Whenever the panning gesture recogniser changes state to Began, we take a snapshot of the keyboard window and add it as a subview of the textInputbar, just below, at the same position the keyboard is.
  • We then hide the window keyboard since it overlaps the app's window.
  • Then, when dragging the textInputbar, the user will have the impression the keyboard is following, accomplishing the effect we wanted. After all, we don't need interactivity on the keyboard.
  • Whenever the panning gesture recogniser changes states to either Possible, Cancelled, Ended or Failed, we remove the keyboard mockup and unhide the keyboard window, going back to the original layout.

This works great on iPhone and iPad. It is not needed on iOS 8 and 7, since we are able to access the keyboard view like we use to, without any private API usage.

Here's the result:
keyboard_panning2

}
}

- (UIWindow *)keyboardWindow
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crazy idea. Have you tried grabbing the keyWindow from the UIApplication after the keyboard notification event has fired?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Unfortunately, the key window doesn't change. It's always the app window.

The keyboard window should always be above any other window from the view hiearchy, since it needs to overlap any piece of UI. But still, this could eventually break on future iOS releases. It is not reliable, but so far, the best way to access its view "legally".

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@rounak
Copy link
Contributor

rounak commented Jan 14, 2016

Why not create an input accessory view of the same height as the text view, and get its frame and move the actual text view?

@dzenbot
Copy link
Author

dzenbot commented Jan 14, 2016

We used to do that, some time ago. We moved away from that approach since it wasn't satisfactory enough (dragging lags, UI issues, firing more keyboard notifications than expected, etc.).
See #243

On iOS 7 and 8, it seemed more reliable to be able to drag the keyboard view guaranteeing the sticky effect of the text input. We never anticipated that huge change on iOS 9. Moving back to the old approach would mean a huge refactor.

@rounak
Copy link
Contributor

rounak commented Jan 15, 2016

@dzenbot how do you think the other people (FB, Insta etc.) do it?

@dzenbot
Copy link
Author

dzenbot commented Jan 15, 2016

I sincerely have no clue.
I know that the Telegram app used to access the keyboard's window using the same technique we did, just camouflaging the private class names by encoding them, and decoding when needed.

@iosdeveloper
Copy link

Why don't you use keyboardDismissMode set to interactive to achieve this?

@dzenbot
Copy link
Author

dzenbot commented Jan 20, 2016

@iosdeveloper please see #361 (comment)

@dzenbot
Copy link
Author

dzenbot commented Feb 6, 2016

Closing/Reopening to run tests again.

@dzenbot dzenbot closed this Feb 6, 2016
@dzenbot dzenbot reopened this Feb 6, 2016
@dzenbot dzenbot force-pushed the keyboard-panning-v2 branch from f49bf06 to 6f6227a Compare February 6, 2016 17:17
@dzenbot dzenbot added this to the v2 milestone Feb 12, 2016
@dzenbot dzenbot force-pushed the keyboard-panning-v2 branch from 6f6227a to b7e7745 Compare February 14, 2016 20:53
Ignacio Romero Zurbuchen added 9 commits February 16, 2016 13:41
…d up on iOS 9, without using any private APIs
…th the mockup. Reproducible by scrolling up very quickly, while the keyboard is visible.

This is a temporary fix, since it comes with a side effect too.
… keyboard snapshot/swap whenever the finger touches the input bar (much more reliable)
@dzenbot dzenbot force-pushed the keyboard-panning-v2 branch from b7e7745 to f3f31a7 Compare February 16, 2016 23:45
Ignacio Romero Zurbuchen added 2 commits February 16, 2016 17:22
…and tweaks the internals to work in other edge cases.
…This helps avoiding a lag when dragging the text input bar while the keyboard placeholder isn't yet shown. Still needs tweaks.
@aryaxt
Copy link
Contributor

aryaxt commented Mar 16, 2016

I Might be a little late but, this can be done by setting an invisible view as an InputAccessoryView of the textView, and then using KVO to observe frame and center changes.
https://github.com/aryaxt/TextInputBar/blob/master/TextInputBar/Source/TextInputAccessoryView.swift

The only challenge I had with this solution was handling and calculating offsets when running in a modal form-sheet in an iPad landscape mode. I believe SlackTextViewController has this issue as well

@dzenbot
Copy link
Author

dzenbot commented Mar 16, 2016

That is exactly what we used to do before. It's a well known and clean technique.
Problem is that it didn't work on iOS 9, thus we started using private APIs to access the keyboard's window to be able to listen to the center property's update.

On iOS 9, this call will never work:

for path in keyPathsToObserve {
    newSuperview?.addObserver(self, forKeyPath: path, options: .New, context: myContext)
}

https://github.com/aryaxt/TextInputBar/blob/master/TextInputBar/Source/TextInputAccessoryView.swift#L67-L77

@aryaxt
Copy link
Contributor

aryaxt commented Mar 16, 2016

@dzenbot Not quite sure what the issue is. I'm currently using this technique in production with no issues on iOS9. I just tested and verified (iOS 9.2.1) that willMoveToSuperview get's called and sets the observer, and as I'm pulling the keyboard down observeValueForKeyPath is called.

the one thing I noticed is that only center is called, and not frame

willMoveToSuperview
addObserver:forKeyPath frame
addObserver:forKeyPath center
observeValueForKeyPath Optional("center")

@dzenbot
Copy link
Author

dzenbot commented Mar 16, 2016

What is newSuperview for you, on iOS 9?

@aryaxt
Copy link
Contributor

aryaxt commented Mar 16, 2016

it returns <UIInputSetHostView: 0x129431860; frame = (0 667; 375 0); layer = <CALayer: 0x129414d30>)

@dzenbot
Copy link
Author

dzenbot commented Mar 16, 2016

I will give it a try to https://github.com/aryaxt/TextInputBar/ but it might just not apply much for this project, since we don't layout the textInput as a text input accessory view any more. Switching back will mean a huge refactor.

@aryaxt
Copy link
Contributor

aryaxt commented Mar 16, 2016

@dzenbot 👍
FYI: my input bar is not set as an accessoryView, it's added as a view of the controller. The accessoryView is TextInputAccessoryView which is just a hidden view is only used for tracking the movement of the keyboard

@ashare80
Copy link

@dzenbot Man I feel your pain here haha.

Did you every try using the accessoryView and overriding addConstraint: to capture and modify the height constraint? If so any issues?

I'm using the auto-created height constraint to update the height of the accessoryView to allow for the interactive dismiss to still work. Since that internal constraint is not animatable, I animate the content to the new height before setting the internal constraint.

Check out my project here https://github.com/ashare80/ASTextInputAccessoryView

@dzenbot
Copy link
Author

dzenbot commented Apr 13, 2016

That looks very interesting! Will have a look real soon.

@dzenbot dzenbot mentioned this pull request Apr 17, 2016
@AYastrebov
Copy link

@dzenbot thanks for this solution!
Will it be merged in nearest release?
When should we expect this fix in master?

Thanks!

@dzenbot
Copy link
Author

dzenbot commented Jul 20, 2016

We will eventually revisit this solution with a different approach after all.

@dzenbot dzenbot closed this Jul 20, 2016
@dzenbot dzenbot deleted the keyboard-panning-v2 branch October 4, 2016 01:23
@felixchan
Copy link

felixchan commented Nov 17, 2016

Has this issue been abandoned? How do we enable this behavior?

@joihelgi
Copy link

joihelgi commented Jul 9, 2017

@dzenbot Is this still a problem? or what do you use in slack today to achieve keyboard dragging?

@christiansoe
Copy link

@aryaxt's solution worked for me!

@hipwelljo
Copy link
Contributor

Super interested in the different approach, keyboard panning to dismiss is sorely missed.

@diegogarciar
Copy link

tableView.keyboardDismissMode = .onDrag does the trick

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.