wcandillon / can-it-be-done-in-react-native Goto Github PK
View Code? Open in Web Editor NEWโ๏ธ ๐บ Projects from the โCan it be done in React Native?โ YouTube series
Home Page: https://www.youtube.com/wcandillon
License: MIT License
โ๏ธ ๐บ Projects from the โCan it be done in React Native?โ YouTube series
Home Page: https://www.youtube.com/wcandillon
License: MIT License
I am curious if such an example is possible.
Here's the pure d3 implementation:
https://observablehq.com/@d3/force-directed-tree?collection=@d3/d3-force
Seems plausible given d3-force
and d3-hierachy
have no DOM dependencies - but I am just not quite sure how it would all come together.
I tried dropping the draggable chrome tabs into my project, but found that any re-renders caused the dragging to lock up. I determined this by placing a shouldComponentUpdate
that always returns false, which then allows me to drag the tabs around. Any idea what causes this? I noticed that sometimes they re-spring to their starting positions on re-renders, so I suspect that maybe something is going wrong with the gestureState...
On Vertical FlatList pinch to zoom work perfectly like Instagram. But horizontal flatlist pinch to zoom, it zooms inside the child view doesn't zoom like Instagram.
Hello @wcandillon, your Liquid Swipe example is great, but on Android I can't drag the arrow, there is no interaction at all. I've tried cloning your project and the interaction works, but in my project (I don't use expo neither typescript) I can't interact with the arrow/liquid swipe.
I guess its some incompatibility to the dependencies (gesture-handler/reanimated).
I am using react-native: 0.59.9.
I am new to react native, also apologize about my poor English
Hey William! I'm a big fan of your show and I've learned a lot related to reanimated and react-native-gesture-handler.
Recently, I've unsuccessfully tried to add double tap to zoom in / out support to the reanimated example image viewer.
It might make an interesting bonus episode since it would involve extending a complex component that already supports sophisticated gesture interactions. Maybe you could give some tips for managing complexity for components that support many interactions.
Thanks for the consideration!
Hi,
I found that the animation just keeps on lopping once I tap on the image, even when I am back from the BlankScreen.
I'm implementing the example with the latest react-naitive-redash, I change some imports like, callTiming to timing , callDelay to delay().
Thank you.
Hey guys, I am incredibly sorry to open a ticket for this but ...
I am currently doing my apprenticeship as a Softwareengineer (in Germay - Fachinformatiker Anwendungsentwicklung) and I am finishing up my project which I have to do.
Although it is not essential, I'd really like to get that D3 & SVG Animation to work
https://www.youtube.com/watch?v=uSucm5jjkRI&t=97s
It doesn't work anymore, first I thought it was something related to redash (the decay function) but it seems to be deeper (connected to reanimated or gesture-handler ?). It would be awesome if someone would be able to show me a fix.
Best wishes
Shumuu
Hi @wcandillon , I was testing your project, but I'm having some problems.
I'm trying it on snack.expo.io, here is the link: https://snack.expo.io/SJls1_mk94
A first error I get is: import Story, {type StoryModel} from './Story';
It seems like it's not going well.
On android it doesn't seem to work well the cube transaction, which seems to work on ios.
The problems are that between one story and another there seems to be some space, so the two stories are not adjacent.
During the cube transaction, instead of expanding the image especially in the right part, it would be better if it retracts as I believe the original version does.
Let me know what you think.
Hi @wcandillon ,
it would be very interesting as a project for 2020 to create your own boilerplate template, putting your experience in developing the components of the apps and the apps themselves.
So a new series could be made, where we spectators could contribute to the project through pull requests and discussions on which ways, technologies (module and lib) would be advisable to use.
I know a complex project is definitely not part of your project series, but it would be very interesting and helpful.
In this example, if something changes in parent's state(any variable's value), the component re-renders and the pinchzoom stops working.
https://github.com/wcandillon/can-it-be-done-in-react-native/tree/master/season3/src/Instagram
Hi, on swiper how to make pagination like a ScrollView.pagingEnabled?
When I try the same Horizontally,
The last Card gets stuck on the left. Just do the same example with translateX and on the AnimatedFlatList use the prop horizontal={true}
Add support for rtl animated bottom tab view
this.value = new Animated.Value(0);
const translateX = value.interpolate({
inputRange: [0, width],
outputRange: [-width, 0],
});
<Animated.View
style={[
styles.curveContainer,
{
transform: [{ translateX: translateX }],
right: I18nManager.isRTL ? 0 : -120,
left: I18nManager.isRTL ? -110 : 0,
},
]}
>
<Path
fill={"blue"}
d="M33.9814453,21.1347656 C47.3945312,11.8701172 58.0839844,0 75.5791016,0 C93.0742187,0 99.9394531,12.5800781 118.030273,22.9746094 C130.09082,29.9042969 141.414063,34.0024414 152,35.269043 L0.552734375,35.269043 C13.8964844,32.0226237 25.039388,27.3111979 33.9814453,21.1347656 Z"
/>
</Animated.View>
Hi,
Chart crashes after some scrolling.
Crash happens only on iOS app/simulator.
Code looks almost exactly the same, but cannot pinpoint the issue.
Here is the code:
import React from "react";
import { StyleSheet, View, Dimensions, Animated } from "react-native";
import { Svg } from "expo";
import * as path from "svg-path-properties";
import * as shape from "d3-shape";
import { scaleTime, scaleLinear } from "d3-scale";
import { PriceFormat } from "../../utils/Format";
import styling from "../../utils/Styles";
const { Path } = Svg;
const d3 = { shape };
const height = 200;
const { width } = Dimensions.get("window");
const horizontalPadding = 0;
const horizontalPaddingLeft = 0;
const horizontalPaddingRight = 20;
const verticalPadding = 10;
const labelWidth = 100;
const cursorRadius = 6;
export default class Chart extends React.Component {
cursorLine = React.createRef();
cursor = React.createRef();
label = React.createRef();
labelBottom = React.createRef();
labelViewTop = React.createRef();
labelViewBot = React.createRef();
state = {
x: new Animated.Value(0),
ready: false
};
toChartData(dataProvided, currentPrice = null) {
let data = [];
let low = currentPrice;
let high = currentPrice;
for (let i = 0; i < dataProvided.length; i++) {
data.push({ x: dataProvided[i][0], y: dataProvided[i][1] });
if (low > dataProvided[i][1]) low = dataProvided[i][1];
else if (high < dataProvided[i][1]) high = dataProvided[i][1];
}
if (currentPrice) {
const time = new Date();
data.push({ x: time.getTime(), y: currentPrice });
if (low > currentPrice) low = currentPrice;
else if (high < currentPrice) high = currentPrice;
}
return { data: data };
}
moveCursor(value) {
const { x, y } = this.properties.getPointAtLength(this.lineLength - value);
if (this.cursorLine.current) {
this.cursorLine.current.setNativeProps({
top: -20,
left: x
});
}
if (this.cursor.current) {
this.cursor.current.setNativeProps({
top: y - cursorRadius,
left: x - cursorRadius
});
}
}
componentDidMount() {
const { data, currentPrice } = this.props;
const res = this.toChartData(data, currentPrice);
this.scaleX = scaleTime()
.domain([res.min.x, res.max.x])
.range([
horizontalPadding + horizontalPaddingLeft,
width - horizontalPadding - horizontalPaddingRight - 1
]);
this.scaleY = scaleLinear()
.domain([res.min.y, res.max.y])
.range([height - verticalPadding, verticalPadding]);
this.line = d3.shape
.line()
.x(d => this.scaleX(d.x))
.y(d => this.scaleY(d.y))
.curve(d3.shape.curveMonotoneX)(res.data);
this.properties = path.svgPathProperties(this.line);
this.lineLength = this.properties.getTotalLength();
this.setState({ ready: true }, () => {
this.state.x.addListener(({ value }) => this.moveCursor(value));
this.moveCursor(0);
});
}
render() {
const { line, lineLength, cursorLine, cursor } = this;
const { ready, x } = this.state;
if (!ready) return null;
return (
<View style={styles.container}>
<Svg {...{ width, height }}>
<Path
d={line}
fill="transparent"
stroke={styling.c.Blue}
strokeWidth={3}
/>
<View ref={cursorLine} style={styles.line} />
<View ref={cursor} style={styles.cursor} />
</Svg>
<Animated.ScrollView
style={StyleSheet.absoluteFill}
contentContainerStyle={{ width: lineLength * 2 }}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
bounces={false}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: { x }
}
}
],
{ useNativeDriver: true }
)}
horizontal
/>
</View>
);
}
}
Hey thanks for your tutorials on youtube! , btw I was looking to your flipcard code here, any idea why is not working on Android ?
Hey @wcandillon, your Accordion looks great.
If ever you plan to opensource a reanimated alternative to https://github.com/oblador/react-native-collapsible that would be so great.
I think there's a real need for that. I can't stand anymore the non-native height animation, it's "ok" but for DEV on Android it's really painfully slow. Unfortunately, don't have much time to work on this atm.
If anyone here is willing to implement this, I'd be happy to be a beta tester
Hi @wcandillon , I tried the project on the expo link, but it doesn't seem to work, blue screen.
Tested on android.
This is great work - I just looked at the WhatsApp sample, and with a few lines of code, you basically blew out all the gallery packages out there out of the water. Needed just a little tweaking for orientation changes and already looks like a rather capable gallery I can build up upon. (That being said: I'd love to see a kick-ass gallery from you with all the bells and whistles!)
Now please excuse me, I'll have to go buy you some coffee ;)
Hello. I am trying to load Wallet.tsx in src folder, but am getting error ts(2769) on line 113. Any help would be appreciated.
Hello @wcandillon,
I love watching your content especially Can it be done in RN series.
I wonder that soft ripple animation can it be done in react native?
Here is the soft ripple animation:
https://www.instagram.com/p/CBxl4KEgHm6
What do you think? If it is possible can you make a video about that :)
@wcandillon
I noticed that the useCode
execution block in AnimationUtil
endlessly loops while the gallery is open:
Repro:
1: Add a call
statement to AnimationUtil
:
useCode(
() => [
call([], ([]) => console.log("animationutil")),
...
2: Open the sample and just drag a picture a little - the console will start logging over and over again until you close the view.
In the Chrome Tab Sort demo, how would you restrict so that the PanGesture only started if two fingers?
Thanks!
can you please help to fix the jumping animated view
?
import React, {useRef} from 'react';
import {
View,
Text,
StyleSheet,
Platform,
TextInput,
Dimensions,
Alert,
FlatList,
} from 'react-native';
import Animated, {Easing} from 'react-native-reanimated';
import {
withTimingTransition,
onGestureEvent,
withSpringTransition,
delay,
} from 'react-native-redash';
import {TapGestureHandler, State} from 'react-native-gesture-handler';
const {width, height} = Dimensions.get('window');
import FontAwesome from 'react-native-vector-icons/FontAwesome5';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {Divider, List} from 'react-native-paper';
import RNGooglePlaces from 'react-native-google-places';
import {
SCREEN_HEIGHT,
SCREEN_WIDTH,
LOCATION_SELECT_VIEW_HEIGHT,
} from '../../utils/constants';
const {
Value,
event,
block,
cond,
eq,
set,
useCode,
Clock,
startClock,
stopClock,
debug,
timing,
clockRunning,
interpolate,
Extrapolate,
SpringUtils,
} = Animated;
const runTiming = (clock, value, dest) => {
const state = {
finished: new Value(0),
position: new Value(0),
time: new Value(0),
frameTime: new Value(0),
};
const config = {
duration: 1000,
toValue: new Value(0),
easing: Easing.inOut(Easing.ease),
};
return block([
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.time, 0),
set(state.position, value),
set(state.frameTime, 0),
set(config.toValue, dest),
startClock(clock),
]),
timing(clock, state, config),
cond(state.finished, debug('stop clock', stopClock(clock))),
state.position,
]);
};
const Ravi = props => {
const {
navigation,
mapData,
onSetPickUpLocation,
onSetPickOffLocation,
onSetPredictions,
onLocationSelected,
} = props;
const isOpen = useRef(new Animated.Value(0));
const isOpenAnimation = withSpringTransition(isOpen.current, {
...SpringUtils.makeDefaultConfig(),
overshootClamping: true,
damping: new Animated.Value(20),
});
const buttonOpacity = interpolate(isOpenAnimation, {
inputRange: [0, 1],
outputRange: [1, 0],
});
const gestureState = useRef(new Animated.Value(State.UNDETERMINED));
const gestureHandler = onGestureEvent({state: gestureState.current});
const backArrowGestureState = useRef(new Animated.Value(State.UNDETERMINED));
const backArrowGestureHandler = onGestureEvent({
state: backArrowGestureState.current,
});
// useCode(
// () =>
// cond(eq(gestureState.current, State.END), [
// // set(gestureState.current, State.UNDETERMINED),
// set(buttonOpacity, runTiming(new Clock(), 1, 0)),
// ]),
// [gestureState.current],
// );
useCode(
() =>
cond(eq(gestureState.current, State.END), [
cond(eq(isOpen.current, 0), set(isOpen.current, 1)),
set(buttonOpacity, runTiming(new Clock(), 1, 0)),
]),
[gestureState.current],
);
useCode(
() =>
cond(eq(backArrowGestureState.current, State.END), [
set(gestureState.current, State.UNDETERMINED),
set(buttonOpacity, runTiming(new Clock(), 0, 1)),
delay(set(isOpen.current, 0), 250),
]),
[backArrowGestureState.current],
);
const onPickUpQueryChange = text => {
onSetPickUpLocation(text);
RNGooglePlaces.getAutocompletePredictions(text)
.then(places => {
console.log(places, 'pickup');
onSetPredictions(places, 'pickup');
})
.catch(error => console.log(error.message, 'sss'));
};
const onPickOffQueryChange = text => {
onSetPickOffLocation(text);
RNGooglePlaces.getAutocompletePredictions(text)
.then(places => {
console.log(places, 'pickoff');
onSetPredictions(places, 'pickoff');
})
.catch(error => console.log(error.message, 'sss'));
};
const onSelectSuggestion = placeID => {
RNGooglePlaces.lookUpPlaceByID(placeID)
.then(results => {
console.log(results, mapData.predictions.type, 'type');
onLocationSelected(results, mapData.predictions.type);
})
.catch(error => console.log(error.message));
};
const keyExtractor = item => item.placeID;
const renderItem = ({item}) => {
return (
<List.Item
onPress={() => onSelectSuggestion(item.placeID)}
title={item.primaryText}
description={item.secondaryText}
left={() => <Icon style={{...styles.leftIcon}} name="location-on" />}
right={() => <Icon style={{...styles.leftIcon}} name="location-on" />}
/>
);
};
const buttonY = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [100, 0],
extrapolate: Extrapolate.CLAMP,
});
const bgY = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [-height / 3, 0],
extrapolate: Extrapolate.CLAMP,
});
const textInputZindex = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [1, -1],
extrapolate: Extrapolate.CLAMP,
});
const textInputOpacity = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [1, 0],
extrapolate: Extrapolate.CLAMP,
});
const textInputTransY = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [0, 50],
extrapolate: Extrapolate.CLAMP,
});
const sideMenuOpacity = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
});
const sideMenutransY = interpolate(buttonOpacity, {
inputRange: [0, 1],
outputRange: [-60, 0],
extrapolate: Extrapolate.CLAMP,
});
return (
<>
<Animated.View
style={{
top: Platform.select({ios: 40, android: 20}),
width: 40,
backgroundColor: '#fff',
padding: 10,
marginLeft: 10,
// borderRadius: 10,
shadowOffset: {width: 10, height: 10},
shadowColor: '#CBCBCB',
shadowOpacity: 1,
elevation: 3,
...Platform.select({
ios: {
zIndex: 99,
},
}),
transform: [{translateY: sideMenutransY}],
opacity: sideMenuOpacity,
}}>
<FontAwesome
name="bars"
size={24}
backgroundColor="#fff"
color="#707070"
onPress={() => navigation.openDrawer()}
/>
</Animated.View>
<Animated.View
style={{
height: height / 4,
backgroundColor: 'white',
justifyContent: 'flex-end',
...StyleSheet.absoluteFillObject,
top: null,
opacity: buttonOpacity,
transform: [{translateY: buttonY}],
}}>
<TapGestureHandler {...gestureHandler}>
<Animated.View
style={{
...styles.button,
backgroundColor: '#2E71DC',
opacity: buttonOpacity,
transform: [{translateY: buttonY}],
}}>
<Text style={{fontSize: 20, fontWeight: 'bold', color: 'white'}}>
SIGN IN WITH FACEBOOK
</Text>
</Animated.View>
</TapGestureHandler>
</Animated.View>
<Animated.View
style={{
backgroundColor: 'white',
zIndex: textInputZindex,
opacity: textInputOpacity,
transform: [{translateY: textInputTransY}],
// height: height / 3,
...StyleSheet.absoluteFill,
bottom: null,
justifyContent: 'center',
}}>
<View style={{flexDirection: 'row'}}>
<Animated.View style={{...styles.backArrow, flex: 0.13}}>
<TapGestureHandler {...backArrowGestureHandler}>
<Animated.View>
<FontAwesome name="arrow-left" size={24} />
</Animated.View>
</TapGestureHandler>
</Animated.View>
<View style={{flex: 1, marginTop: 20}}>
<View style={{...styles.mainView}}>
<View style={{...styles.cricleView}} />
<View style={[{...styles.viewText}]}>
<Text style={[{...styles.titleText}]}>Pickup location</Text>
<View
style={{
flexDirection: 'row',
}}>
<View style={[{flex: 1}]}>
<TextInput
style={{
color: '#000',
paddingVertical: 1,
}}
placeholder="pickup location"
// value={mapData?.pickUpLocation}
// onChangeText={onPickUpQueryChange}
underlineColorAndroid={'transparent'}
/>
</View>
</View>
</View>
</View>
<Divider
style={{
borderColor: '#9B9B9B',
borderWidth: 0.5,
marginTop: 10,
marginBottom: 10,
marginLeft: 40,
}}
/>
<View style={{...styles.mainView}}>
<View style={[{...styles.iconView}]}>
<FontAwesome
name="map-marker-alt"
size={16}
color={'#F5A623'}
/>
</View>
<View style={[{...styles.viewText}]}>
<Text style={[{...styles.titleText}]}>Drop Off</Text>
<View
style={{
flexDirection: 'row',
}}>
<View style={[{flex: 1}]}>
<TextInput
style={{
color: '#000',
paddingVertical: 1,
}}
placeholder="Location"
// value={mapData?.pickOffLocation}
// onChangeText={onPickOffQueryChange}
underlineColorAndroid={'transparent'}
autoFocus
/>
</View>
<View style={[{...styles.imageView2}]}>
<FontAwesome
name="map-marked-alt"
size={16}
color={'#3AE1FE'}
/>
</View>
</View>
</View>
</View>
</View>
</View>
</Animated.View>
<Animated.View
style={{
backgroundColor: 'white',
zIndex: textInputZindex,
opacity: textInputOpacity,
transform: [{translateY: textInputTransY}],
// height: height / 2,
...StyleSheet.absoluteFill,
top: LOCATION_SELECT_VIEW_HEIGHT + 20,
justifyContent: 'center',
}}>
<FlatList
data={mapData.predictions.data}
renderItem={renderItem}
keyExtractor={keyExtractor}
showsVerticalScrollIndicator={false}
contentContainerStyle={{flexGrow: 1}}
/>
</Animated.View>
</>
);
};
export default Ravi;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
searchResultsWrapper: {
top: LOCATION_SELECT_VIEW_HEIGHT + 60,
position: 'absolute',
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
backgroundColor: '#fff',
},
button: {
backgroundColor: 'white',
height: 70,
marginHorizontal: 20,
borderRadius: 35,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 5,
},
backArrow: {
justifyContent: 'flex-start',
top: Platform.select({ios: 40, android: 20}),
left: 10,
right: 0,
},
mainView: {flexDirection: 'row', marginHorizontal: 10},
cricleView: {
backgroundColor: '#3AE1FE',
borderRadius: 12,
width: 12,
height: 12,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 5,
marginVertical: 8,
},
iconView: {
marginHorizontal: 5,
marginVertical: 8,
},
viewText: {
flexDirection: 'column',
flex: 0.85,
justifyContent: 'center',
marginLeft: 10,
},
titleText: {
color: '#222',
fontSize: 14,
fontFamily: 'OpenSans-Regular',
marginVertical: 5,
},
imageView2: {alignSelf: 'flex-end', flex: 0.1},
});
Hi, on swiper how to start the scroll in a position other than 0?
Hello,
First of all thanks for providing video and code for Instagram stories.
But I need a slight help to know how I can access the current story value in the footer component.
I want to add a share button in the footer part which accesses the current story value.
Thanks
Hi
First, thank you for this great course
I'm having trouble in animated path in react-native-svg
I just executed this code without expo and it's crashed :(
"react-native": "0.61.4",
"react-native-redash": "^8.6.0",
"react-native-svg": "^9.13.3",
Hi,
My App got multiple profiles so I want to show a switcher or a dropdown ( similar to this - https://dribbble.com/shots/6913358-Dropdown-transitions). I have a Screen where I'm showing Profile name. If user click on this View (Profile name) whole screen should turns dark and at the same time dropdown should open. Hence I created another component with Modal and placed Profile list inside.
I took reference from your List example - the-10-min/src/Accordion/List.tsx
But here I don't know wants the Height of the list as each Profile item height varies. Some Profile have extra set of info. Can I use percentage values? Or do I need to use onLayout to know the Height of the complete List?
height = bInterpolate( transition, initial.height, 100% );
I want to attach an event listener to the cursor component so as to display the value at a particular point in a different part of the screen.
I have tried the method here
software-mansion/react-native-gesture-handler#91
But this doesn't work. Any idea ?
Hi William,
After trying out the image viewer I am running into some issues on Android. It look like this panState
coming from the parent <PanGestureHandler>
is coming in as State.FAILED
. This is not triggering the // Gesture ended, keep offset, reset values,
part of the useCode
block.
I tried adding an or conditionals for FAILED
here but now the pan decay is not correctly clamping the offsets and the user can pan past the clamp boundaries once zoomed in.
I'll continue investigating, but I wanted to open a ticket to track this (and see if you have encountered it as well).
Hello,
I tried your custom Slider tutorial.
I tried to concat a rounded number into a textInput. On iOS i get an integer and on android it always returns a double. is there a way to concat a integer on android aswell?
I'm struggling quite a bit to make the WhatsApp sample work nicely with orientation changes. While I can trigger a re-rendering with the change (if the screen width changes), it appears the hooks and listeners operate partially on the wrong with, which completely messes up the margins or even changes the index.
If anybody has solved this already, thanks for your advice.
Sorry, I have a problem with this example, I try to replicate but I have the same error, the error is when you touch an element then close it, being by the X or by means of a gesture, after touching the image, at some point the touch event has not been fire and never displays the detail page again, you need to tap again in this case is success,
In the case if I comment on the effect of shared element the tap works correctly, can you help me with that? Thank you
`
export default createSharedElementStackNavigator(
{
Explore,
Listing,
},
{
mode: 'modal',
headerMode: 'none',
defaultNavigationOptions: {
// cardStyleInterpolator: ({ current: { progress } }) => {
// const opacity = progress.interpolate({
// inputRange: [0, 1],
// outputRange: [0, 1],
// extrapolate: 'clamp',
// });
// return { cardStyle: { opacity } };
// },
gestureEnabled: false,
cardStyle: {
backgroundColor: 'transparent',
},
},
}
);
`
onScroll
function seems cannot be found in v14.0.4 andonScroll
is not a function error is prompted. I have installed v8.0.0 and it works fine. Please LMK if this is a version issue. Thank you.
Tapping on the TextInput in the Story doesn't do anything. It seems like the ScrollView is not propagating touches to the TextInput in the Story component.
Is there a way to allow the scrollview to allow the TextInput to receive the touch and respond to the scroll?
hello,
thank's for what you are doing, but i see that scrollView in the modalVideo component doesn't work any more.
;)
Hey there.
Been trying to work on a replacement for the Slider example you did on Youtube, but without the deprecated Interactable component.
However my current issue is that i want to update the snap-points when the layout changes.
however it doesnt seem to be do that? I assume withSpring only does one hook?
import * as React from "react"
import { Dimensions, View, StyleSheet, SliderProperties } from "react-native"
import { PanGestureHandler } from "react-native-gesture-handler"
import { useLayout } from "react-native-hooks"
import { withSpring, snapPoint, clamp, panGestureHandler } from "react-native-redash"
import { useMemoOne } from "use-memo-one"
import Ani from "react-native-reanimated"
export interface SliderProps {
steps: number,
size: number
}
export function Slider(props: SliderProps) {
const { steps = 1, size = 10 } = props;
// Uses layout and check the width
const { onLayout, ...layout } = useLayout();
const { width } = layout;
const [offset] = React.useMemo(() => [
new Ani.Value(0)
], [steps, size]);
// Tries to update snappoints when width changes.
const snapPoints = React.useMemo(() => {
let points = []
for (let i = 0; i < steps; i++) {
points.push(Ani.add(0, i * ((width + (size / 2)) / steps)));
}
// console.log("Updated snap points.");
return points;
}, [steps, size, width]);
const { state, translationX, velocityX, gestureHandler } = panGestureHandler();
const translateX = withSpring({
state,
velocity: velocityX,
value: translationX,
offset: offset,
snapPoints,
config: {
overshootClamping: true,
damping: 10,
mass: 2,
restDisplacementThreshold: 0.001,
restSpeedThreshold: 0.001,
stiffness: 100,
},
onSnap: value => console.log("snapping", value)
});
return <View onLayout={onLayout} style={{
height: size,
borderRadius: size / 2,
backgroundColor: "#F1F2F6"
}}>
<Ani.View style={{
...StyleSheet.absoluteFillObject,
backgroundColor: "#dc5312",
borderRadius: size / 2,
height: size,
}} />
<PanGestureHandler {...gestureHandler}>
<Ani.View style={{
width: size,
height: size,
transform: [
{ translateX }
],
borderRadius: size / 2,
borderWidth: 0.5,
borderColor: "#88888888",
backgroundColor: "#ffffff",
shadowOpacity: 0.86,
shadowColor: "#FFF",
shadowRadius: 30,
shadowOffset: { width: 10, height: 10 },
overflow: "visible"
}} />
</PanGestureHandler>
</View>
}
Is there any way to update the snap points somehow?
Love your course and videos. I'm trying to figure out how to reset the TapGesture example animation. So after the long press and state transition to active
with the check icon displayed, if I want to tap on that a second time and reset the animation, I just can't wrap my head around the model well enough to figure it out.
I really like the pattern used in the Instagram Stories example where you place an empty ScrollView over top of the content and simply animate the content based on the scroll position. It's a really elegant solution to get native scroll based animations.
However, there is an issue that I can't seem to solve: The ScrollView component overlays the visual content, instead of wrapping it, which blocks touch events to the content and prevents you from putting any buttons in the actual story. To recreate simply place a button inside the image representing the Instagram story in solution 3 to the Instagram stories problem. It will not receive any touch events.
I've tried just about everything to continue with this approach, but it seems that either the ScrollView receives the touches OR the underlying content but not both. Is there any solution to this? Or does anyone know any strategies that I can attempt?
In bonuses/simple-animation example, there is an error: runTiming is not a function. I use timing instead of runTiming, erros gone, but the logo rotate only once. How can I make it loop? My redash verson is 9.5.0, should I fallback to 7.1.1?
Hey there!
Awesome job @wcandillon! Could you or anybody help me on finishing this example as it states in this TODO line.
The thing is, in order for this example to work, you need to wait ~1s for swiping the next card, you cannot really swipe them fast.
How could we not ignore the user trying to drag again while the animation (spring) is still running?
P.S. I am currently experimenting that each Card
has its own PanGestureHandler
instead of only the top Card
.
Wallet example works great. It produces a warning on the uniqueness on the "key" though.
Warning: Each child in a list should have a unique "key" prop.%s%s See https://fb.me/react-warning-keys for more information.%s,
Check the render method of VirtualizedList
., ,
in CellRenderer (at VirtualizedList.js:767)
in VirtualizedList (at FlatList.js:676)
in FlatList (at createAnimatedComponent.js:151)
in AnimatedComponent (at Wallet.tsx:61)
in Wallet (at SceneView.js:9)
in SceneView (at StackViewLayout.tsx:909)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewCard.tsx:106)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at screens.native.js:71)
in Screen (at StackViewCard.tsx:93)
in Card (at createPointerEventsContainer.tsx:95)
in Container (at StackViewLayout.tsx:984)
in RCTView (at screens.native.js:101)
in ScreenContainer (at StackViewLayout.tsx:393)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewLayout.tsx:383)
in PanGestureHandler (at StackViewLayout.tsx:376)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.tsx:104)
in RCTView (at Transitioner.tsx:267)
in Transitioner (at StackView.tsx:41)
in StackView (at createNavigator.js:80)
in Navigator (at createKeyboardAwareNavigator.js:12)
in KeyboardAwareNavigator (at createAppContainer.js:430)
in NavigationContainer (at App.tsx:171)
in Unknown (at App.tsx:169)
in _default (at withExpoRoot.js:26)
in RootErrorBoundary (at withExpoRoot.js:25)
in ExpoRoot (at renderApplication.js:40)
in RCTView (at AppContainer.js:101)
in DevAppContainer (at AppContainer.js:115)
in RCTView (at AppContainer.js:119)
in AppContainer (at renderApplication.js:39)
Stack trace:
node_modules\react-native\Libraries\YellowBox\YellowBox.js:63:8 in console.error
node_modules\expo\build\environment\muteWarnings.fx.js:27:24 in error
node_modules\react\cjs\react.development.js:172:36 in warningWithoutStack
node_modules\react\cjs\react.development.js:612:32 in warning
node_modules\react\cjs\react.development.js:1723:14 in validateExplicitKey
node_modules\react\cjs\react.development.js:1745:28 in validateChildKeys
node_modules\react\cjs\react.development.js:1998:22 in cloneElementWithValidation
node_modules\react-native\Libraries\Lists\VirtualizedList.js:1033:6 in render
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:13042:21 in finishClassComponent
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:12970:4 in updateClassComponent
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20459:25 in beginWork$$1
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:19370:24 in performUnitOfWork
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:19347:39 in workLoopSync
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18997:22 in renderRoot
[native code]:null in renderRoot
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18709:28 in runRootCallback
[native code]:null in runRootCallback
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5642:32 in runWithPriority$argument_1
node_modules\scheduler\cjs\scheduler.development.js:643:23 in unstable_runWithPriority
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5638:22 in flushSyncCallbackQueueImpl
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5627:28 in flushSyncCallbackQueue
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18556:30 in scheduleUpdateOnFiber
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:7799:17 in classComponentUpdater.enqueueSetState
node_modules\react\cjs\react.development.js:325:31 in Component.prototype.setState
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:127662:27 in
node_modules@react-navigation\core\lib\module\getChildNavigation.js:1:1478 in actionHelpers.actionName
src\Examples\Examples.tsx:105:19 in Thumbnail.props.onPress
node_modules\react-native-reanimated\src\core\AnimatedCall.js:9:27 in listener
node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:190:12 in emit
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:436:47 in __callFunction
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:26 in __guard$argument_0
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:110:17 in __guard$argument_0
[native code]:null in callFunctionReturnFlushedQueue
...
Hi @wcandillon , I follow your series, take a look at this: https://dribbble.com/shots/3238568
Do you think we can do it in react-native?
Would you succeed? ;)
Make tutorial use box-shadow for React Native on Android and iOS.
Example for design: Neumorphism in user interfaces
Tools: Neumorphism.io
thanks so much for these greate tutorials
in apple-appoftheday / components / AppModal.tsx
I guess you Imported clockRunning from react-native-redash instead of the reanimated module itself
All other examples in the 10 min folder works great, except 3DTransformations which throws this error.
[3292,{"type":"value","value":"<>"}] is not usable as a native method argument
Stack trace:
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:319:8 in enqueueNativeCall
node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:137:10 in fn
node_modules\react-native-reanimated\src\core\AnimatedNode.js:143:29 in __nativeInitialize
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:141646:32 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
node_modules\react-native-reanimated\src\core\AnimatedNode.js:173:13 in __addChild
node_modules\react-native-reanimated\src\core\AnimatedNode.js:97:26 in __attach
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:144661:21 in AnimatedProps
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:144641:29 in createOrReusePropsNode
node_modules\react-native-reanimated\src\createAnimatedComponent.js:142:6 in AnimatedComponent#_attachProps
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:144361:27 in AnimatedComponent
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:8251:26 in constructClassInstance
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:12940:6 in updateClassComponent
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:307:15 in invokeGuardedCallbackImpl
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:531:36 in invokeGuardedCallback
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20488:8 in beginWork$$1
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:19370:24 in performUnitOfWork
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:19347:39 in workLoopSync
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18997:22 in renderRoot
[native code]:null in renderRoot
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18709:28 in runRootCallback
[native code]:null in runRootCallback
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5642:32 in runWithPriority$argument_1
node_modules\scheduler\cjs\scheduler.development.js:643:23 in unstable_runWithPriority
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5638:22 in flushSyncCallbackQueueImpl
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5627:28 in flushSyncCallbackQueue
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18556:30 in scheduleUpdateOnFiber
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:7799:17 in classComponentUpdater.enqueueSetState
node_modules\react\cjs\react.development.js:325:31 in Component.prototype.setState
http://192.168.2.51:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:127662:27 in
node_modules@react-navigation\core\lib\module\getChildNavigation.js:1:1478 in actionHelpers.actionName
src\Examples\Examples.tsx:95:19 in Thumbnail.props.onPress
node_modules\react-native-reanimated\src\core\AnimatedCall.js:9:27 in listener
node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:190:12 in emit
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:436:47 in __callFunction
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:26 in __guard$argument_0
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:110:17 in __guard$argument_0
[native code]:null in callFunctionReturnFlushedQueue
...
Hey, I saw you were doing epic work. So, I started your animation series.
I am getting this error in youtube transitions. I have spent many time searching but I cant fix it. It would be great if you can tell what I am doing wrong:
My system:
-Macbook Pro
-MAC OS
-Expo 37
-Iphone 11
Season 1: Youtube-transitions:
import {
clockRunning,
Clock,
startClock,
spring,
stopClock,
Extrapolate,
cond,
eq,
set,
add,
sub,
multiply,
lessThan,
interpolate,
timing,
neq,
greaterThan,
Value,
} from "react-native-reanimated";
const { width, height } = Dimensions.get("window");
const shadow = {
alignItems: "center",
elevation: 1,
shadowColor: "black",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.18,
shadowRadius: 2,
};
type VideoModalProps = {
video: VideoModel,
};
const { event } = Animated;
function runSpring(clock: Clock, value: Value, dest: Value): Value {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0),
};
const config = {
damping: 20,
mass: 1,
stiffness: 100,
overshootClamping: false,
restSpeedThreshold: 1,
restDisplacementThreshold: 0.5,
toValue: new Value(0),
};
return [
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.velocity, 0),
set(state.position, value),
set(config.toValue, dest),
startClock(clock),
]),
spring(clock, state, config),
cond(state.finished, stopClock(clock)),
state.position,
];
}
export default class VideoModal extends React.PureComponent<VideoModalProps> {
onGestureEvent: $Call<event>;
translationY = new Value(0);
velocityY = new Value(0);
gestureState = new Value(State.UNDETERMINED);
constructor(props) {
super(props);
const { translationY, velocityY, gestureState: state } = this;
this.onGestureEvent = event(
[
{
nativeEvent: {
translationY,
velocityY,
state,
},
},
],
{ useNativeDriver: true }
);
const clockY = new Clock();
const finalTranslateY = add(translationY, multiply(0.2, velocityY));
const translationThreshold = height / 2;
const snapPoint = cond(
lessThan(finalTranslateY, translationThreshold),
0,
height
);
this.translateY = cond(
eq(state, State.END),
[
set(translationY, runSpring(clockY, translationY, snapPoint)),
translationY,
],
translationY
);
}
render() {
const { video } = this.props;
const { onGestureEvent, translateY } = this;
return (
<>
<View
style={{
height: 20,
backgroundColor: "black",
}}
/>
<PanGestureHandler
onHandlerStateChange={onGestureEvent}
{...{ onGestureEvent }}
>
<Animated.View
style={{
transform: [{ translateY }],
...shadow,
}}
>
<View style={{ backgroundColor: "white", width }}>
<View style={{ ...StyleSheet.absoluteFillObject }}>
<PlayerControls title={video.title} onPress={() => true} />
</View>
<Video
source={video.video}
style={{ width, height: width / 1.78 }}
resizeMode={"cover"}
// shouldPlay
/>
</View>
<View style={{ backgroundColor: "white", width, height }}>
<View>
<VideoContent {...{ video }} />
</View>
</View>
</Animated.View>
</PanGestureHandler>
</>
);
}
}
Steps to reproduce:
-clone repository
-go into season3 folder
-npm install
-npm start
Application fails to build: "Unable to resolve "./Matrix" from "node_modules/react-native-redash/lib/module/index.js"
Failed building JavaScript bundle."
Everything is working perfectly besides the fact that I need to wait the spring animation to finish before swiping the next item.
Does anyone have any idea why?
// TODO: handle case where the user drags the card again before the spring animation finished
this.translateY = cond(
eq(gestureState, State.END),
[
set(translationY, runSpring(clockY, translationY, 0)),
set(offsetY, translationY),
translationY,
],
cond(
eq(gestureState, State.BEGAN),
[stopClock(clockY), translationY],
translationY,
),
);
this.translateX = cond(
eq(gestureState, State.END),
[
set(translationX, runSpring(clockX, translationX, snapPoint)),
set(offsetX, translationX),
cond(and(eq(clockRunning(clockX), 0), neq(translationX, 0)), [
call([translationX], this.swipped),
]),
translationX,
],
cond(
eq(gestureState, State.BEGAN),
[stopClock(clockX), translationX],
translationX,
),
);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.