Skip to content

Commit

Permalink
fix: correct Card animation drivers related to elevation (#3041)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewalczak authored Jan 26, 2022
1 parent 1fd0e2a commit 7a0e3ab
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
20 changes: 20 additions & 0 deletions example/src/Examples/CardExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Text,
Switch,
} from 'react-native-paper';
import { PreferencesContext } from '..';
import ScreenWrapper from '../ScreenWrapper';

const CardExample = () => {
Expand All @@ -19,6 +20,8 @@ const CardExample = () => {
const [isOutlined, setIsOutlined] = React.useState(false);
const mode = isOutlined ? 'outlined' : 'elevated';

const preferences = React.useContext(PreferencesContext);

return (
<ScreenWrapper contentContainerStyle={styles.content}>
<View style={styles.preference}>
Expand Down Expand Up @@ -120,6 +123,23 @@ const CardExample = () => {
</Paragraph>
</Card.Content>
</Card>
<Card
style={styles.card}
onPress={() => {
preferences.toggleTheme();
}}
mode={mode}
>
<Card.Title
title="Pressable Theme Change"
left={(props) => <Avatar.Icon {...props} icon="format-paint" />}
/>
<Card.Content>
<Paragraph>
This is pressable card. If you press me, I will switch the theme.
</Paragraph>
</Card.Content>
</Card>
</ScrollView>
</ScreenWrapper>
);
Expand Down
2 changes: 1 addition & 1 deletion example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const CustomDefaultTheme = {
},
};

const PreferencesContext = React.createContext<any>(null);
export const PreferencesContext = React.createContext<any>(null);

const DrawerContent = () => {
return (
Expand Down
77 changes: 60 additions & 17 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type ElevatedCardProps = {
elevation?: number;
};

type HandlePressType = 'in' | 'out';

type Props = React.ComponentProps<typeof Surface> & {
/**
* Resting elevation of the card which controls the drop shadow.
Expand Down Expand Up @@ -111,30 +113,69 @@ const Card = ({
accessible,
...rest
}: (OutlinedCardProps | ElevatedCardProps) & Props) => {
// Default animated value
const { current: elevation } = React.useRef<Animated.Value>(
new Animated.Value(cardElevation)
);
// Dark adaptive animated value, used in case of toggling the theme,
// it prevents animating the background with native drivers inside Surface
const { current: elevationDarkAdaptive } = React.useRef<Animated.Value>(
new Animated.Value(cardElevation)
);
const { animation, dark, mode, roundness } = theme;

const prevDarkRef = React.useRef<boolean>(dark);
React.useEffect(() => {
prevDarkRef.current = dark;
});

const prevDark = prevDarkRef.current;
const isAdaptiveMode = mode === 'adaptive';
const animationDuration = 150 * animation.scale;

React.useEffect(() => {
/**
* Resets animations values if updating to dark adaptive mode,
* otherwise, any card that is in the middle of animation while
* toggling the theme will stay at that animated value until
* the next press-in
*/
if (dark && isAdaptiveMode && !prevDark) {
elevation.setValue(cardElevation);
elevationDarkAdaptive.setValue(cardElevation);
}
}, [
prevDark,
dark,
isAdaptiveMode,
cardElevation,
elevation,
elevationDarkAdaptive,
]);

const runElevationAnimation = (pressType: HandlePressType) => {
const isPressTypeIn = pressType === 'in';
if (dark && isAdaptiveMode) {
Animated.timing(elevationDarkAdaptive, {
toValue: isPressTypeIn ? 8 : cardElevation,
duration: animationDuration,
useNativeDriver: false,
}).start();
} else {
Animated.timing(elevation, {
toValue: isPressTypeIn ? 8 : cardElevation,
duration: animationDuration,
useNativeDriver: true,
}).start();
}
};

const handlePressIn = () => {
const {
dark,
mode,
animation: { scale },
} = theme;
Animated.timing(elevation, {
toValue: 8,
duration: 150 * scale,
useNativeDriver: !dark || mode === 'exact',
}).start();
runElevationAnimation('in');
};

const handlePressOut = () => {
Animated.timing(elevation, {
toValue: cardElevation,
duration: 150 * animation.scale,
useNativeDriver: !dark || mode === 'exact',
}).start();
runElevationAnimation('out');
};

const total = React.Children.count(children);
Expand All @@ -143,15 +184,17 @@ const Card = ({
? (child.type as any).displayName
: null
);
const borderColor = color(theme.dark ? white : black)
const borderColor = color(dark ? white : black)
.alpha(0.12)
.rgb()
.string();
const computedElevation =
dark && isAdaptiveMode ? elevationDarkAdaptive : elevation;

return (
<Surface
style={[
{ borderRadius: roundness, elevation, borderColor },
{ borderRadius: roundness, elevation: computedElevation, borderColor },
cardMode === 'outlined' ? styles.outlined : {},
style,
]}
Expand Down

0 comments on commit 7a0e3ab

Please sign in to comment.