forked from vergnet/application-amicale
Improve animated components to match linter
This commit is contained in:
parent
925bded69b
commit
9d92a88627
3 changed files with 308 additions and 290 deletions
|
@ -1,101 +1,114 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {View} from "react-native";
|
import {View} from 'react-native';
|
||||||
import {List, withTheme} from 'react-native-paper';
|
import {List, withTheme} from 'react-native-paper';
|
||||||
import Collapsible from "react-native-collapsible";
|
import Collapsible from 'react-native-collapsible';
|
||||||
import * as Animatable from "react-native-animatable";
|
import * as Animatable from 'react-native-animatable';
|
||||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
import type {CustomTheme} from '../../managers/ThemeManager';
|
||||||
|
|
||||||
type Props = {
|
type PropsType = {
|
||||||
theme: CustomTheme,
|
theme: CustomTheme,
|
||||||
title: string,
|
title: string,
|
||||||
subtitle?: string,
|
subtitle?: string,
|
||||||
left?: (props: { [keys: string]: any }) => React.Node,
|
left?: () => React.Node,
|
||||||
opened?: boolean,
|
opened?: boolean,
|
||||||
unmountWhenCollapsed: boolean,
|
unmountWhenCollapsed?: boolean,
|
||||||
children?: React.Node,
|
children?: React.Node,
|
||||||
}
|
};
|
||||||
|
|
||||||
type State = {
|
type StateType = {
|
||||||
expanded: boolean,
|
expanded: boolean,
|
||||||
}
|
};
|
||||||
|
|
||||||
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
||||||
|
|
||||||
class AnimatedAccordion extends React.Component<Props, State> {
|
class AnimatedAccordion extends React.Component<PropsType, StateType> {
|
||||||
|
static defaultProps = {
|
||||||
|
subtitle: '',
|
||||||
|
left: null,
|
||||||
|
opened: null,
|
||||||
|
unmountWhenCollapsed: false,
|
||||||
|
children: null,
|
||||||
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
chevronRef: {current: null | AnimatedListIcon};
|
||||||
unmountWhenCollapsed: false,
|
|
||||||
}
|
|
||||||
chevronRef: { current: null | AnimatedListIcon };
|
|
||||||
chevronIcon: string;
|
|
||||||
animStart: string;
|
|
||||||
animEnd: string;
|
|
||||||
|
|
||||||
state = {
|
chevronIcon: string;
|
||||||
expanded: this.props.opened != null ? this.props.opened : false,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
animStart: string;
|
||||||
super(props);
|
|
||||||
this.chevronRef = React.createRef();
|
|
||||||
this.setupChevron();
|
|
||||||
}
|
|
||||||
|
|
||||||
setupChevron() {
|
animEnd: string;
|
||||||
if (this.state.expanded) {
|
|
||||||
this.chevronIcon = "chevron-up";
|
|
||||||
this.animStart = "180deg";
|
|
||||||
this.animEnd = "0deg";
|
|
||||||
} else {
|
|
||||||
this.chevronIcon = "chevron-down";
|
|
||||||
this.animStart = "0deg";
|
|
||||||
this.animEnd = "180deg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleAccordion = () => {
|
constructor(props: PropsType) {
|
||||||
if (this.chevronRef.current != null) {
|
super(props);
|
||||||
this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd});
|
this.state = {
|
||||||
this.setState({expanded: !this.state.expanded})
|
expanded: props.opened != null ? props.opened : false,
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
this.chevronRef = React.createRef();
|
||||||
|
this.setupChevron();
|
||||||
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
|
shouldComponentUpdate(nextProps: PropsType): boolean {
|
||||||
if (nextProps.opened != null && nextProps.opened !== this.props.opened)
|
const {state, props} = this;
|
||||||
this.state.expanded = nextProps.opened;
|
if (nextProps.opened != null && nextProps.opened !== props.opened)
|
||||||
return true;
|
state.expanded = nextProps.opened;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupChevron() {
|
||||||
|
const {state} = this;
|
||||||
|
if (state.expanded) {
|
||||||
|
this.chevronIcon = 'chevron-up';
|
||||||
|
this.animStart = '180deg';
|
||||||
|
this.animEnd = '0deg';
|
||||||
|
} else {
|
||||||
|
this.chevronIcon = 'chevron-down';
|
||||||
|
this.animStart = '0deg';
|
||||||
|
this.animEnd = '180deg';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
toggleAccordion = () => {
|
||||||
const colors = this.props.theme.colors;
|
const {state} = this;
|
||||||
return (
|
if (this.chevronRef.current != null) {
|
||||||
<View>
|
this.chevronRef.current.transitionTo({
|
||||||
<List.Item
|
rotate: state.expanded ? this.animStart : this.animEnd,
|
||||||
{...this.props}
|
});
|
||||||
title={this.props.title}
|
this.setState({expanded: !state.expanded});
|
||||||
subtitle={this.props.subtitle}
|
|
||||||
titleStyle={this.state.expanded ? {color: colors.primary} : undefined}
|
|
||||||
onPress={this.toggleAccordion}
|
|
||||||
right={(props) => <AnimatedListIcon
|
|
||||||
ref={this.chevronRef}
|
|
||||||
{...props}
|
|
||||||
icon={this.chevronIcon}
|
|
||||||
color={this.state.expanded ? colors.primary : undefined}
|
|
||||||
useNativeDriver
|
|
||||||
/>}
|
|
||||||
left={this.props.left}
|
|
||||||
/>
|
|
||||||
<Collapsible collapsed={!this.state.expanded}>
|
|
||||||
{!this.props.unmountWhenCollapsed || (this.props.unmountWhenCollapsed && this.state.expanded)
|
|
||||||
? this.props.children
|
|
||||||
: null}
|
|
||||||
</Collapsible>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): React.Node {
|
||||||
|
const {props, state} = this;
|
||||||
|
const {colors} = props.theme;
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<List.Item
|
||||||
|
title={props.title}
|
||||||
|
subtitle={props.subtitle}
|
||||||
|
titleStyle={state.expanded ? {color: colors.primary} : undefined}
|
||||||
|
onPress={this.toggleAccordion}
|
||||||
|
right={({size}: {size: number}): React.Node => (
|
||||||
|
<AnimatedListIcon
|
||||||
|
ref={this.chevronRef}
|
||||||
|
size={size}
|
||||||
|
icon={this.chevronIcon}
|
||||||
|
color={state.expanded ? colors.primary : undefined}
|
||||||
|
useNativeDriver
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
left={props.left}
|
||||||
|
/>
|
||||||
|
<Collapsible collapsed={!state.expanded}>
|
||||||
|
{!props.unmountWhenCollapsed ||
|
||||||
|
(props.unmountWhenCollapsed && state.expanded)
|
||||||
|
? props.children
|
||||||
|
: null}
|
||||||
|
</Collapsible>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withTheme(AnimatedAccordion);
|
export default withTheme(AnimatedAccordion);
|
||||||
|
|
|
@ -1,170 +1,178 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {StyleSheet, View} from "react-native";
|
import {StyleSheet, View} from 'react-native';
|
||||||
import {FAB, IconButton, Surface, withTheme} from "react-native-paper";
|
import {FAB, IconButton, Surface, withTheme} from 'react-native-paper';
|
||||||
import AutoHideHandler from "../../utils/AutoHideHandler";
|
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import CustomTabBar from "../Tabbar/CustomTabBar";
|
import {StackNavigationProp} from '@react-navigation/stack';
|
||||||
import {StackNavigationProp} from "@react-navigation/stack";
|
import AutoHideHandler from '../../utils/AutoHideHandler';
|
||||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
import CustomTabBar from '../Tabbar/CustomTabBar';
|
||||||
|
import type {CustomTheme} from '../../managers/ThemeManager';
|
||||||
|
|
||||||
const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
|
const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
|
||||||
|
|
||||||
type Props = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
theme: CustomTheme,
|
theme: CustomTheme,
|
||||||
onPress: (action: string, data: any) => void,
|
onPress: (action: string, data?: string) => void,
|
||||||
seekAttention: boolean,
|
seekAttention: boolean,
|
||||||
}
|
};
|
||||||
|
|
||||||
type State = {
|
type StateType = {
|
||||||
currentMode: string,
|
currentMode: string,
|
||||||
}
|
};
|
||||||
|
|
||||||
const DISPLAY_MODES = {
|
const DISPLAY_MODES = {
|
||||||
DAY: "agendaDay",
|
DAY: 'agendaDay',
|
||||||
WEEK: "agendaWeek",
|
WEEK: 'agendaWeek',
|
||||||
MONTH: "month",
|
MONTH: 'month',
|
||||||
}
|
};
|
||||||
|
|
||||||
class AnimatedBottomBar extends React.Component<Props, State> {
|
|
||||||
|
|
||||||
ref: { current: null | Animatable.View };
|
|
||||||
hideHandler: AutoHideHandler;
|
|
||||||
|
|
||||||
displayModeIcons: { [key: string]: string };
|
|
||||||
|
|
||||||
state = {
|
|
||||||
currentMode: DISPLAY_MODES.WEEK,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.ref = React.createRef();
|
|
||||||
this.hideHandler = new AutoHideHandler(false);
|
|
||||||
this.hideHandler.addListener(this.onHideChange);
|
|
||||||
|
|
||||||
this.displayModeIcons = {};
|
|
||||||
this.displayModeIcons[DISPLAY_MODES.DAY] = "calendar-text";
|
|
||||||
this.displayModeIcons[DISPLAY_MODES.WEEK] = "calendar-week";
|
|
||||||
this.displayModeIcons[DISPLAY_MODES.MONTH] = "calendar-range";
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
|
||||||
return (nextProps.seekAttention !== this.props.seekAttention)
|
|
||||||
|| (nextState.currentMode !== this.state.currentMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
onHideChange = (shouldHide: boolean) => {
|
|
||||||
if (this.ref.current != null) {
|
|
||||||
if (shouldHide)
|
|
||||||
this.ref.current.fadeOutDown(500);
|
|
||||||
else
|
|
||||||
this.ref.current.fadeInUp(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onScroll = (event: SyntheticEvent<EventTarget>) => {
|
|
||||||
this.hideHandler.onScroll(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
changeDisplayMode = () => {
|
|
||||||
let newMode;
|
|
||||||
switch (this.state.currentMode) {
|
|
||||||
case DISPLAY_MODES.DAY:
|
|
||||||
newMode = DISPLAY_MODES.WEEK;
|
|
||||||
break;
|
|
||||||
case DISPLAY_MODES.WEEK:
|
|
||||||
newMode = DISPLAY_MODES.MONTH;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case DISPLAY_MODES.MONTH:
|
|
||||||
newMode = DISPLAY_MODES.DAY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.setState({currentMode: newMode});
|
|
||||||
this.props.onPress("changeView", newMode);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const buttonColor = this.props.theme.colors.primary;
|
|
||||||
return (
|
|
||||||
<Animatable.View
|
|
||||||
ref={this.ref}
|
|
||||||
useNativeDriver
|
|
||||||
style={{
|
|
||||||
...styles.container,
|
|
||||||
bottom: 10 + CustomTabBar.TAB_BAR_HEIGHT
|
|
||||||
}}>
|
|
||||||
<Surface style={styles.surface}>
|
|
||||||
<View style={styles.fabContainer}>
|
|
||||||
<AnimatedFAB
|
|
||||||
animation={this.props.seekAttention ? "bounce" : undefined}
|
|
||||||
easing="ease-out"
|
|
||||||
iterationDelay={500}
|
|
||||||
iterationCount="infinite"
|
|
||||||
useNativeDriver
|
|
||||||
style={styles.fab}
|
|
||||||
icon="account-clock"
|
|
||||||
onPress={() => this.props.navigation.navigate('group-select')}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={{flexDirection: 'row'}}>
|
|
||||||
<IconButton
|
|
||||||
icon={this.displayModeIcons[this.state.currentMode]}
|
|
||||||
color={buttonColor}
|
|
||||||
onPress={this.changeDisplayMode}/>
|
|
||||||
<IconButton
|
|
||||||
icon="clock-in"
|
|
||||||
color={buttonColor}
|
|
||||||
style={{marginLeft: 5}}
|
|
||||||
onPress={() => this.props.onPress('today', undefined)}/>
|
|
||||||
</View>
|
|
||||||
<View style={{flexDirection: 'row'}}>
|
|
||||||
<IconButton
|
|
||||||
icon="chevron-left"
|
|
||||||
color={buttonColor}
|
|
||||||
onPress={() => this.props.onPress('prev', undefined)}/>
|
|
||||||
<IconButton
|
|
||||||
icon="chevron-right"
|
|
||||||
color={buttonColor}
|
|
||||||
style={{marginLeft: 5}}
|
|
||||||
onPress={() => this.props.onPress('next', undefined)}/>
|
|
||||||
</View>
|
|
||||||
</Surface>
|
|
||||||
</Animatable.View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '5%',
|
left: '5%',
|
||||||
width: '90%',
|
width: '90%',
|
||||||
},
|
},
|
||||||
surface: {
|
surface: {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderRadius: 50,
|
borderRadius: 50,
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
},
|
},
|
||||||
fabContainer: {
|
fabContainer: {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%'
|
height: '100%',
|
||||||
},
|
},
|
||||||
fab: {
|
fab: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
top: '-25%',
|
top: '-25%',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class AnimatedBottomBar extends React.Component<PropsType, StateType> {
|
||||||
|
ref: {current: null | Animatable.View};
|
||||||
|
|
||||||
|
hideHandler: AutoHideHandler;
|
||||||
|
|
||||||
|
displayModeIcons: {[key: string]: string};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
currentMode: DISPLAY_MODES.WEEK,
|
||||||
|
};
|
||||||
|
this.ref = React.createRef();
|
||||||
|
this.hideHandler = new AutoHideHandler(false);
|
||||||
|
this.hideHandler.addListener(this.onHideChange);
|
||||||
|
|
||||||
|
this.displayModeIcons = {};
|
||||||
|
this.displayModeIcons[DISPLAY_MODES.DAY] = 'calendar-text';
|
||||||
|
this.displayModeIcons[DISPLAY_MODES.WEEK] = 'calendar-week';
|
||||||
|
this.displayModeIcons[DISPLAY_MODES.MONTH] = 'calendar-range';
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps: PropsType, nextState: StateType): boolean {
|
||||||
|
const {props, state} = this;
|
||||||
|
return (
|
||||||
|
nextProps.seekAttention !== props.seekAttention ||
|
||||||
|
nextState.currentMode !== state.currentMode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onHideChange = (shouldHide: boolean) => {
|
||||||
|
if (this.ref.current != null) {
|
||||||
|
if (shouldHide) this.ref.current.fadeOutDown(500);
|
||||||
|
else this.ref.current.fadeInUp(500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onScroll = (event: SyntheticEvent<EventTarget>) => {
|
||||||
|
this.hideHandler.onScroll(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
changeDisplayMode = () => {
|
||||||
|
const {props, state} = this;
|
||||||
|
let newMode;
|
||||||
|
switch (state.currentMode) {
|
||||||
|
case DISPLAY_MODES.DAY:
|
||||||
|
newMode = DISPLAY_MODES.WEEK;
|
||||||
|
break;
|
||||||
|
case DISPLAY_MODES.WEEK:
|
||||||
|
newMode = DISPLAY_MODES.MONTH;
|
||||||
|
break;
|
||||||
|
case DISPLAY_MODES.MONTH:
|
||||||
|
newMode = DISPLAY_MODES.DAY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newMode = DISPLAY_MODES.WEEK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.setState({currentMode: newMode});
|
||||||
|
props.onPress('changeView', newMode);
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): React.Node {
|
||||||
|
const {props, state} = this;
|
||||||
|
const buttonColor = props.theme.colors.primary;
|
||||||
|
return (
|
||||||
|
<Animatable.View
|
||||||
|
ref={this.ref}
|
||||||
|
useNativeDriver
|
||||||
|
style={{
|
||||||
|
...styles.container,
|
||||||
|
bottom: 10 + CustomTabBar.TAB_BAR_HEIGHT,
|
||||||
|
}}>
|
||||||
|
<Surface style={styles.surface}>
|
||||||
|
<View style={styles.fabContainer}>
|
||||||
|
<AnimatedFAB
|
||||||
|
animation={props.seekAttention ? 'bounce' : undefined}
|
||||||
|
easing="ease-out"
|
||||||
|
iterationDelay={500}
|
||||||
|
iterationCount="infinite"
|
||||||
|
useNativeDriver
|
||||||
|
style={styles.fab}
|
||||||
|
icon="account-clock"
|
||||||
|
onPress={(): void => props.navigation.navigate('group-select')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={{flexDirection: 'row'}}>
|
||||||
|
<IconButton
|
||||||
|
icon={this.displayModeIcons[state.currentMode]}
|
||||||
|
color={buttonColor}
|
||||||
|
onPress={this.changeDisplayMode}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
icon="clock-in"
|
||||||
|
color={buttonColor}
|
||||||
|
style={{marginLeft: 5}}
|
||||||
|
onPress={(): void => props.onPress('today')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={{flexDirection: 'row'}}>
|
||||||
|
<IconButton
|
||||||
|
icon="chevron-left"
|
||||||
|
color={buttonColor}
|
||||||
|
onPress={(): void => props.onPress('prev')}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
icon="chevron-right"
|
||||||
|
color={buttonColor}
|
||||||
|
style={{marginLeft: 5}}
|
||||||
|
onPress={(): void => props.onPress('next')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</Surface>
|
||||||
|
</Animatable.View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default withTheme(AnimatedBottomBar);
|
export default withTheme(AnimatedBottomBar);
|
||||||
|
|
|
@ -1,66 +1,63 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {StyleSheet} from "react-native";
|
import {StyleSheet} from 'react-native';
|
||||||
import {FAB} from "react-native-paper";
|
import {FAB} from 'react-native-paper';
|
||||||
import AutoHideHandler from "../../utils/AutoHideHandler";
|
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import CustomTabBar from "../Tabbar/CustomTabBar";
|
import AutoHideHandler from '../../utils/AutoHideHandler';
|
||||||
import {StackNavigationProp} from "@react-navigation/stack";
|
import CustomTabBar from '../Tabbar/CustomTabBar';
|
||||||
|
|
||||||
type Props = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
icon: string,
|
||||||
icon: string,
|
onPress: () => void,
|
||||||
onPress: () => void,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const AnimatedFab = Animatable.createAnimatableComponent(FAB);
|
const AnimatedFab = Animatable.createAnimatableComponent(FAB);
|
||||||
|
|
||||||
export default class AnimatedFAB extends React.Component<Props> {
|
|
||||||
|
|
||||||
ref: { current: null | Animatable.View };
|
|
||||||
hideHandler: AutoHideHandler;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.ref = React.createRef();
|
|
||||||
this.hideHandler = new AutoHideHandler(false);
|
|
||||||
this.hideHandler.addListener(this.onHideChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
onScroll = (event: SyntheticEvent<EventTarget>) => {
|
|
||||||
this.hideHandler.onScroll(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
onHideChange = (shouldHide: boolean) => {
|
|
||||||
if (this.ref.current != null) {
|
|
||||||
if (shouldHide)
|
|
||||||
this.ref.current.bounceOutDown(1000);
|
|
||||||
else
|
|
||||||
this.ref.current.bounceInUp(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<AnimatedFab
|
|
||||||
ref={this.ref}
|
|
||||||
useNativeDriver
|
|
||||||
icon={this.props.icon}
|
|
||||||
onPress={this.props.onPress}
|
|
||||||
style={{
|
|
||||||
...styles.fab,
|
|
||||||
bottom: CustomTabBar.TAB_BAR_HEIGHT
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
fab: {
|
fab: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
margin: 16,
|
margin: 16,
|
||||||
right: 0,
|
right: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default class AnimatedFAB extends React.Component<PropsType> {
|
||||||
|
ref: {current: null | Animatable.View};
|
||||||
|
|
||||||
|
hideHandler: AutoHideHandler;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.ref = React.createRef();
|
||||||
|
this.hideHandler = new AutoHideHandler(false);
|
||||||
|
this.hideHandler.addListener(this.onHideChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
onScroll = (event: SyntheticEvent<EventTarget>) => {
|
||||||
|
this.hideHandler.onScroll(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
onHideChange = (shouldHide: boolean) => {
|
||||||
|
if (this.ref.current != null) {
|
||||||
|
if (shouldHide) this.ref.current.bounceOutDown(1000);
|
||||||
|
else this.ref.current.bounceInUp(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): React.Node {
|
||||||
|
const {props} = this;
|
||||||
|
return (
|
||||||
|
<AnimatedFab
|
||||||
|
ref={this.ref}
|
||||||
|
useNativeDriver
|
||||||
|
icon={props.icon}
|
||||||
|
onPress={props.onPress}
|
||||||
|
style={{
|
||||||
|
...styles.fab,
|
||||||
|
bottom: CustomTabBar.TAB_BAR_HEIGHT,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue