Skip to content

Commit

Permalink
feat: added KeyboardAwareScrollView (#296)
Browse files Browse the repository at this point in the history
## 📜 Description

Added `KeyboardAwareScrollView` as a component available from a library.

## 💡 Motivation and Context

I got asked many times times to export this component from the package
(now users had to copy the source code of this component into theirs
apps).

Even though this component is not perfect and contains some bugs in edge
cases I still think it's better to open-source it and fix reported bugs
later (rather than keep it just in example app and people will not be
aware about its existence).

## 📢 Changelog

### JS
- exported `KeyboardAwareScrollView` from the package;
- removed code from examples app and start to use a component provided
from the package;

### Docs
- added a page about new component;

## 🤔 How Has This Been Tested?

e2e tests, page preview.

## 📝 Checklist

- [x] CI successfully passed
  • Loading branch information
kirillzyusko committed Dec 14, 2023
1 parent a30e729 commit db5a741
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 457 deletions.
1 change: 0 additions & 1 deletion FabricExample/src/components/AwareScrollView/index.ts

This file was deleted.

This file was deleted.

23 changes: 0 additions & 23 deletions FabricExample/src/components/AwareScrollView/utils.ts

This file was deleted.

5 changes: 1 addition & 4 deletions FabricExample/src/screens/Examples/AwareScrollView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import React from 'react';
import { useResizeMode } from 'react-native-keyboard-controller';
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';

import KeyboardAwareScrollView from '../../../components/AwareScrollView';
import TextInput from '../../../components/TextInput';
import { styles } from './styles';

export default function AwareScrollView() {
useResizeMode();

return (
<KeyboardAwareScrollView testID='aware_scroll_view_container' bottomOffset={50} style={styles.container} contentContainerStyle={styles.content}>
{new Array(10).fill(0).map((_, i) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { LayoutChangeEvent, View, Text, Button } from 'react-native';
import { StackScreenProps } from '@react-navigation/stack';
import { useResizeMode, KeyboardStickyView } from 'react-native-keyboard-controller';
import { KeyboardAwareScrollView, KeyboardStickyView } from 'react-native-keyboard-controller';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { ExamplesStackParamList } from '../../../navigation/ExamplesStack';
import KeyboardAwareScrollView from '../../../components/AwareScrollView';
import TextInput from '../../../components/TextInput';
import { styles } from './styles';

Expand All @@ -15,8 +14,6 @@ const variants = ['v1', 'v2', 'v3'] as const;
type Variant = typeof variants[number];

export default function AwareScrollViewStickyFooter({ navigation }: Props) {
useResizeMode();

const { bottom } = useSafeAreaInsets();
const [footerHeight, setFooterHeight] = useState(0);
const [variant, setVariant] = useState<Variant>("v1");
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Keyboard manager which works in identical way on both iOS and Android.
- module for changing soft input mode on Android 🤔
- reanimated support 🚀
- interactive keyboard dismissing 👆📱
- prebuilt components (`KeyboardStickyView`, re-worked `KeyboardAvoidingView`) 📚
- prebuilt components (`KeyboardStickyView`, `KeyboardAwareScrollView`, re-worked `KeyboardAvoidingView`) 📚
- easy focused input information retrieval 📝 🔮
- works with any navigation library 🧭
- and more is coming... Stay tuned! 😊
Expand Down
110 changes: 110 additions & 0 deletions docs/docs/api/components/keyboard-aware-scroll-view.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
keywords: [react-native-keyboard-controller, KeyboardAwareScrollView, keyboard aware view, aware scroll view]
---

# KeyboardAwareScrollView

import Lottie from 'lottie-react';
import lottie from '../../../src/components/HomepageFeatures/text-inputs.lottie.json';

<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 20 }}>
<Lottie animationData={lottie} style={{ width: 400, height: 400 }} loop />
</div>

`ScrollView` that effortlessly handles keyboard appearance, automatically scrolls to focused `TextInput` and provides a native-like performance.

## Comparison

Current `react-native` ecosystem has a plenty of solutions that solves the problem of focused inputs being covered by keyboard. Each of them has its own advantages and disadvantages.

Below is a table with the most important functions and their support in various implementations:

||[react-native-avoid-soft-input](https://mateusz1913.github.io/react-native-avoid-softinput/)|[react-native-keyboard-aware-scroll-view](https://github.com/APSL/react-native-keyboard-aware-scroll-view)|[react-native-keyboard-manager](https://github.com/douglasjunior/react-native-keyboard-manager)|[react-native-keyboard-controller](./keyboard-aware-scroll-view.mdx)|
|-----|-----|-----|-----|-----|
|Respects keyboard animation|🟠 <sup><small>1</small></sup>||||
|JS implementation||||🟠 <sup><small>2</small></sup>|
|Reacts on focused input layout changes|||🟠 <sup><small>3</small></sup>||
|Reacts on focus changes|||||
|Auto-scroll when user is typing and input in non visible area|||🟠 <sup><small>3</small></sup>||
|Android support|||||
|Maintained|||||
|Support Fabric (new) architecture||🟠 <sup><small>4</small></sup>|||

> <sup>1</sup> <b>only</b> on <b>iOS</b>
> <sup>2</sup> <code>KeyboardAwareScrollView</code> is implemented in JS, but some hooks (<code>useKeyboardHandler</code>/<code>useReanimatedFocusedInput</code>/<code>useFocusedInputHandler</code>) exposed from native code
> <sup>3</sup> achievable with <code>KeyboardManager.reloadLayoutIfNeeded()</code> usage in appropriate <code>TextInput</code> callbacks (<code>onLayout</code>/<code>onChangeText</code>)
> <sup>4</sup> since it's JS based solution it supports new architecture, but it uses <b>deprecated</b> API.
## Props

### ScrollView Props

Inherits [ScrollView Props](https://reactnative.dev/docs/scrollview#props).

### `bottomOffset`

The distance between keyboard and focused `TextInput` when keyboard is shown.

## Example

```tsx
import React from 'react';
import { StyleSheet, TextInputProps, TextInput as TextInputRN } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';

const TextInput = (props: TextInputProps) => {
return (
<TextInputRN
placeholderTextColor="#6c6c6c"
style={styles.textInput}
multiline
numberOfLines={2}
testID={props.placeholder}
{...props}
placeholder={`${props.placeholder} (${props.keyboardType === 'default' ? 'text' : 'numeric'})`}
/>
);
};

export default function AwareScrollView() {
return (
<KeyboardAwareScrollView
bottomOffset={50}
style={styles.container}
contentContainerStyle={styles.content}
>
{new Array(10).fill(0).map((_, i) => (
<TextInput
key={i}
placeholder={`TextInput#${i}`}
keyboardType={i % 2 === 0 ? 'numeric' : 'default'}
/>
))}
</KeyboardAwareScrollView>
);
}

const styles = StyleSheet.create({
container: {
paddingHorizontal: 16,
},
content: {
paddingTop: 50,
},
textInput: {
width: '100%',
minHeight: 50,
maxHeight: 200,
marginBottom: 50,
borderColor: 'black',
borderWidth: 2,
marginRight: 160,
borderRadius: 10,
color: 'black',
paddingHorizontal: 12,
},
});
```
Loading

0 comments on commit db5a741

Please sign in to comment.