SwiftKickMobile/SwiftMessages

Overriding KeyboardTrackingView not useful since most functions and properties are private

mkoorn opened this issue · 7 comments

Hi,

I'm using SwiftMessages to show a popup with a form.
Since some of the inputs are pushed above the screen I am trying to override the KeyboardTrackingView so that I can calculate the topmargin myself to make sure each input is visible when it becomes first responder.

I'm most interested in
private func show(change: Change, _ notification: Notification)

Could you make this function open?

Since I am using this library in a podspec, it's not easy to make this change for myself.

That function is the core business logic of the component, so I wouldn't typically make that open. Instead, I'd prefer to add customization options. If I made the UI update anytime you change topMargin, would that solve your problem? If not, can you describe what you want to have happen in more detail?

Hi, thanks for your swift reply.

What I have tried now is override the topmargin property.

In the getter I now calculate the topmargin with:.

  • get the cell of the form which is firstresponder
  • calculate the frame of the cell in the form
  • calculate whether the cell will be offscreen by using the height of the KeyboardTrackingView
  • adjust the topmargin to the appropriate negative value to ensure the whole cell is still in view.

This works well for the first time the top cell becomes first responder.
If I switch between cells on the form this stops working since when getting the height of the trackingView it was adjusted by previous calls to the topmargin getter.

What I need is access to the new height of the trackingview before the topmargin is applied in

private func show(change: Change, _ notification: Notification) {
    ...
    let newHeight = max(0, thisRect.maxY - keyboardRect.minY) + topMargin
    ...
}

If I can get the correct height of the trackingView, based on the the keyboardRect (depending on the keyboard type) and then calculate the topmargin, I think I can solve my problem.

Just to throw in another option, add an open function which returns the topmargin

open func calulateTopMargin(newHeight: CGFloat) -> CGFloat

the default implementation would just return the topmargin property.

the override implementation could return my calculated topmargin if needed, otherwise return super.

This is probably too much tailored to my use-case. Therefore I was thinking of making the whole show function open, which would give complete control and access to the change and notification to any overriding class.

Can you take a look at the branch work/9.0.5?

I changed the timing of the following delegate method:

func keyboardTrackingViewWillChange(change: KeyboardTrackingView.Change, userInfo: [AnyHashable : Any])

Now it is called before the height is calculated, giving you an opportunity to update topMargin. I think this gives you what you need.

If you prefer to subclass KeyboardTrackingView, I added the following function as well:

/// Subclasses can override this to do something before the change.
open func willChange(
    change: KeyboardTrackingView.Change,
    userInfo: [AnyHashable : Any]
) {}

This works great for me.
Thanks for your work. Great lib.

@wtmoose could you please release this? Since I am using a podspec I cannot set a branch.

Done.