Animate search bar with keyboard
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import Input from 'components/Input';
|
import Input from 'components/Input';
|
||||||
import { ActivityIndicator, SafeAreaView, View } from 'react-native';
|
import { ActivityIndicator, Animated, SafeAreaView, View } from 'react-native';
|
||||||
import styled from 'styled-components/native';
|
import styled from 'styled-components/native';
|
||||||
import { useTypedSelector } from 'store';
|
import { useTypedSelector } from 'store';
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
@@ -21,6 +21,7 @@ import DownloadIcon from 'components/DownloadIcon';
|
|||||||
import ChevronRight from 'assets/icons/chevron-right.svg';
|
import ChevronRight from 'assets/icons/chevron-right.svg';
|
||||||
import SearchIcon from 'assets/icons/magnifying-glass.svg';
|
import SearchIcon from 'assets/icons/magnifying-glass.svg';
|
||||||
import { ShadowWrapper } from 'components/Shadow';
|
import { ShadowWrapper } from 'components/Shadow';
|
||||||
|
import { useKeyboardHeight } from 'utility/useKeyboardHeight';
|
||||||
// import MicrophoneIcon from 'assets/icons/microphone.svg';
|
// import MicrophoneIcon from 'assets/icons/microphone.svg';
|
||||||
// import AlbumIcon from 'assets/icons/collection.svg';
|
// import AlbumIcon from 'assets/icons/collection.svg';
|
||||||
// import TrackIcon from 'assets/icons/note.svg';
|
// import TrackIcon from 'assets/icons/note.svg';
|
||||||
@@ -29,11 +30,11 @@ import { ShadowWrapper } from 'components/Shadow';
|
|||||||
// import LocalIcon from 'assets/icons/internal-drive.svg';
|
// import LocalIcon from 'assets/icons/internal-drive.svg';
|
||||||
// import SelectableFilter from './components/SelectableFilter';
|
// import SelectableFilter from './components/SelectableFilter';
|
||||||
|
|
||||||
const Container = styled.View`
|
const Container = styled(Animated.View)`
|
||||||
padding: 4px 32px 0 32px;
|
padding: 4px 32px 0 32px;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
border-top-width: 1px;
|
border-top-width: 0.5px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FullSizeContainer = styled.View`
|
const FullSizeContainer = styled.View`
|
||||||
@@ -114,6 +115,7 @@ export default function Search() {
|
|||||||
|
|
||||||
// Prepare helpers
|
// Prepare helpers
|
||||||
const navigation = useNavigation<MusicNavigationProp>();
|
const navigation = useNavigation<MusicNavigationProp>();
|
||||||
|
const keyboardHeight = useKeyboardHeight();
|
||||||
const getImage = useGetImage();
|
const getImage = useGetImage();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -218,13 +220,18 @@ export default function Search() {
|
|||||||
|
|
||||||
const HeaderComponent = React.useMemo(() => (
|
const HeaderComponent = React.useMemo(() => (
|
||||||
<View>
|
<View>
|
||||||
<Container style={defaultStyles.border}>
|
<Container style={[
|
||||||
|
defaultStyles.border,
|
||||||
|
defaultStyles.view,
|
||||||
|
{ transform: [{ translateY: keyboardHeight }]},
|
||||||
|
]}>
|
||||||
<View>
|
<View>
|
||||||
<Input
|
<Input
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChangeText={setSearchTerm}
|
onChangeText={setSearchTerm}
|
||||||
style={[defaultStyles.input, { marginBottom: 12 }]}
|
style={[defaultStyles.input, { marginBottom: 12 }]}
|
||||||
placeholder={t('search') + '...'}
|
placeholder={t('search') + '...'}
|
||||||
|
icon
|
||||||
/>
|
/>
|
||||||
<SearchIndicator width={14} height={14} fill={defaultStyles.textHalfOpacity.color} />
|
<SearchIndicator width={14} height={14} fill={defaultStyles.textHalfOpacity.color} />
|
||||||
{isLoading && <Loading><ActivityIndicator /></Loading>}
|
{isLoading && <Loading><ActivityIndicator /></Loading>}
|
||||||
|
|||||||
48
src/utility/useKeyboardHeight.ts
Normal file
48
src/utility/useKeyboardHeight.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||||
|
import { useRef, useEffect } from 'react';
|
||||||
|
import { Animated, Keyboard, KeyboardEvent } from 'react-native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This returns an animated height that the keyboard is poking up from the
|
||||||
|
* bottom of the screen. This can be used to position elements to "hug" the
|
||||||
|
* keyboard.
|
||||||
|
* Adapted from https://stackoverflow.com/a/65267045/3586761
|
||||||
|
*/
|
||||||
|
export const useKeyboardHeight = () => {
|
||||||
|
const keyboardHeight = useRef(new Animated.Value(0)).current;
|
||||||
|
const tabBarHeight = useBottomTabBarHeight();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const keyboardWillShow = (e: KeyboardEvent) => {
|
||||||
|
Animated.timing(keyboardHeight, {
|
||||||
|
duration: e.duration,
|
||||||
|
toValue: tabBarHeight - e.endCoordinates.height,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyboardWillHide = (e: KeyboardEvent) => {
|
||||||
|
Animated.timing(keyboardHeight, {
|
||||||
|
duration: e.duration,
|
||||||
|
toValue: 0,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyboardWillShowSub = Keyboard.addListener(
|
||||||
|
'keyboardWillShow',
|
||||||
|
keyboardWillShow
|
||||||
|
);
|
||||||
|
const keyboardWillHideSub = Keyboard.addListener(
|
||||||
|
'keyboardWillHide',
|
||||||
|
keyboardWillHide
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
keyboardWillHideSub.remove();
|
||||||
|
keyboardWillShowSub.remove();
|
||||||
|
};
|
||||||
|
}, [keyboardHeight, tabBarHeight]);
|
||||||
|
|
||||||
|
return keyboardHeight;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user