Open Isaccobosio opened 1 week ago
Inside node_modules/react-native-keyboard-controller/src/components/KeyboardAwareScrollView/index.tsx
there is this piece of code:
const view = useAnimatedStyle(
() =>
enabled
? {
// animations become choppy when scrolling to the end of the `ScrollView` (when the last input is focused)
// this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
// by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
// from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
// re-calculation on every animation frame and it helps to achieve smooth animation.
// see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
paddingBottom: currentKeyboardFrameHeight.value + 1,
}
: {},
[enabled],
);
return (
<ScrollViewComponent
ref={onRef}
{...rest}
scrollEventThrottle={16}
onLayout={onScrollViewLayout}
>
{children}
<Reanimated.View style={view} />
</ScrollViewComponent>
);
The <Reanimated.View style={view} />
is the problem I think. But there is no way to style it and there is also no way to delete it.
Hi @Isaccobosio
Thank you for raising this problem π I'll split my answer in two parts:
<Reanimated.View style={view} />
is needed?<Reanimated.View style={view} />
is needed to add empty space to make sure you can scroll down and the content will be shown above the keyboard (even if keyboard is shown).
And of course, since I'm placing an additional view it'll affect the layout of your component.
As you pointed out above - you can add a view with flex: 1
or you can wrap your two view inside additional view and specify minHeight
:
<KeyboardAwareScrollView
style={{ backgroundColor: "green" }}
contentContainerStyle={{
flexGrow: 1,
backgroundColor: "blue",
justifyContent: "space-between",
}}
>
<View style={{minHeight: screenHeight- safeArea.top - headerHeight}}>
<View style={{ height: 100, backgroundColor: "red" }} />
<View style={{ height: 100, backgroundColor: "red" }} />
</View>
</KeyboardAwareScrollView>
I haven't tested code above - just wanted to show the idea.
Version from APSL was relying on contentInset
implementation. This code can add spacing without affecting the YOGA-layout.
Ideally I also would like to re-use the implementation of contentInset
, but the problem is that it's only iOS specific property and it doesn't have any effect on Android π So on Android I still would have to use the code that I'm using at the moment.
So I thought that cross-platform standart is more important in this library and decided to use cross-platform code everywhere (so the bug will be present everywhere as well, not only on Android or iOS).
Do you have any ideas on how to fix this problem in your project? Given the fact, that it's impossible to remove that view (I explained above why).
Hi @kirillzyusko , thank you very much for the answer!
The situation is clear. I understand that the Reanimated.View is essential for the purpose of this library. At this moment I don't have any solutions beside the one with the View and flex: 1.
What about to set the Reanimated.View with an initial height of 0? I haven't test it but it may helps.
Anyway, with <View style={{ flex: 1 }} />
the problem is solved.
My problem is that I'm using your component as a LayoutComponent and I'm currently passing a children.
Putting a <View style={{ flex: 1 }} />
seems like a workaround.
What about to set the Reanimated.View with an initial height of 0? I haven't test it but it may helps.
Do you want it to be like currentKeyboardFrameHeight.value === 0 ? 0 : currentKeyboardFrameHeight.value + 1
?
Putting a <View style={{ flex: 1 }} /> seems like a workaround.
Well, definitely yes π Can you try to use the code that I gave to you (where you specify minHeight
for container)? In this case (if it works) you can pass children as you did before π
Do you want it to be like currentKeyboardFrameHeight.value === 0 ? 0 : currentKeyboardFrameHeight.value + 1?
I don't know if this might be a solution. I need to try it. I can try it later and I'll let you know for sure!
Can you try to use the code that I gave to you (where you specify minHeight for container)?
It could work! I can try this as well ππ»
Yeah, please test and let me know how it works π
Hey @kirillzyusko
Sorry for the late answer but it was a hard week. So, I did some test.
minHeight
strategy.Code
const LoginScreen: React.FC = () => {
const screenHeight = Dimensions.get("window").height;
const headerHeight = useHeaderHeight();
const safeArea = useSafeAreaInsets();
return (
<KeyboardAwareScrollView
style={{ backgroundColor: "purple" }}
contentContainerStyle={{
flexGrow: 1,
backgroundColor: "blue",
// justifyContent: "space-between", // not needed anymore
paddingBottom: safeArea.bottom,
}}
>
<View
style={{
minHeight: screenHeight - safeArea.bottom - headerHeight,
backgroundColor: "yellow",
justifyContent: "space-between",
}}
>
<View style={{ height: 100, backgroundColor: "red" }} />
<View style={{ height: 100, backgroundColor: "green" }} />
</View>
</KeyboardAwareScrollView>
);
}
Result
https://github.com/user-attachments/assets/d563cf2f-36e3-4d27-8a4d-242a26c86ee9
This is working as expected, that means that it could be a solution. But I had to add some more style to the wrapper View.
You suggested to put <View style={{minHeight: screenHeight- safeArea.top - headerHeight}}>
and I edited that with this:
<View
style={{
minHeight: screenHeight - safeArea.bottom - headerHeight,
backgroundColor: "yellow",
justifyContent: "space-between",
}}
>
{...}
</View>
I had to do like that because without justifyContent: "space-between"
the childrens are not in the correct position.
So basically the justifyContent: "space-between"
inside the contentContainerStyle
is no more needed.
without the space between | with the space between |
---|---|
What I found is that setting the height of the Reanimated View based on currentKeyboardFrameHeight
value has no effect.
Even if a View has a height set to 0, it is part of the parent View.
So I tried something like this
const view = useAnimatedStyle(
() =>
enabled
? {
// animations become choppy when scrolling to the end of the `ScrollView` (when the last input is focused)
// this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
// by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
// from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
// re-calculation on every animation frame and it helps to achieve smooth animation.
// see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
paddingBottom: currentKeyboardFrameHeight.value + 1,
display: currentKeyboardFrameHeight.value === 0 ? "none" : "flex",
}
: {},
[enabled],
);
return (
<ScrollViewComponent
ref={onRef}
{...rest}
scrollEventThrottle={16}
onLayout={onScrollViewLayout}
>
{children}
<Reanimated.View style={view} />
</ScrollViewComponent>
);
With this approach it works because it effectively dismount the reanimated view. But as soon as the keyboard is presented it "flicker". Video down below
https://github.com/user-attachments/assets/067b6120-c446-4217-84d9-ae53fdca6887
I don't know how to handle this situation and which is the best solution. I hope that you have better ideas!
cheers!
Sorry for a late response @Isaccobosio
So it looks like first approach is actually working for you? π€
Regarding second solution - I think you can interpolate paddingBottom
to have a smooth transition without a flicker, i. e.:
const keyboardFrame = interpolate(
e.height,
[0, keyboardHeight.value],
[0, keyboardHeight.value + extraKeyboardSpace + 1],
);
currentKeyboardFrameHeight.value = keyboardFrame;
Would you mind to check that solution? I think it shouldn't hurt performance a lot (let me know if this solution works for you and then I can check on a low end device the FPS) π
Describe the bug Configuring the property
contentContainerStyle
forKeyboardAwareScrollView
withjustifyContent: "space-between"
does not work as expected. If I do the same thing withScrollView
it works fine.Code snippet
Expected behavior As a Scrollview, I expect that the two
View
inside theKeyboardAwareScrollView
is positioned with a space between them. What I am trying to create is a screen in the upper part of which there is a login form and in the lower part buttons for logging in with the various societies. If the screen size is not large enough, the two main components will have to scroll.Smartphone
Additional context I also tried to put a
View
between the two main Views like this:But this is the result:
As you can see in the bottom of the screen there is a little blue space (maybe a pixel). This means that the two Views are not displayed correctly. Is like a ghost View is displayed: