SwiftKickMobile / SwiftMessages

A very flexible message bar for UIKit and SwiftUI.
MIT License
7.32k stars 746 forks source link

Overriding KeyboardTrackingView not useful since most functions and properties are private #482

Closed mkoorn closed 2 years ago

mkoorn commented 3 years ago

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.

wtmoose commented 3 years ago

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?

mkoorn commented 3 years ago

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:.

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.

mkoorn commented 3 years ago

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.

wtmoose commented 3 years ago

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]
) {}
mkoorn commented 3 years ago

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

mkoorn commented 3 years ago

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

wtmoose commented 2 years ago

Done.