Rotate View from a specific point - React Native - javascript

I'm trying to rotate a View from a starting point,
I'm tried to add prev translateX and add it again after rotating as describing here
but not works well :\ it's the same
Code snippet
const rotateAnimationStyle = useAnimatedStyle(() => {
return {
transform: [
{translateX: -1 * (120 / 2)},
// {translateY: 0},
{rotateZ: `${rotateAnimationValuew.value}deg`},
{translateX: 120 / 2},
// {translateY: 0},
],
};
});
const addAttachment = () => {
isAnimated.value = withTiming(!isAnimated.value, {duration: 4000});
rotateAnimationValuew.value = isAnimated.value
? withTiming(0, {
duration: 1500,
easing: Easing.linear,
})
: withTiming(90, {
duration: 1500,
easing: Easing.linear,
});
console.log(isAnimated.value);
};
<Animated.View
style={[styles.attachmentsElements, rotateAnimationStyle]}>
<View style={[styles.circle, {zIndex: 1}]}>
<Text>close</Text>
</View>
<View style={styles.circle}>
<Text>Camera</Text>
</View>
<View style={styles.circle}>
<Text>video</Text>
</View>
<View style={styles.circle}>
<Text>Contacts</Text>
</View>
</Animated.View>

Related

ComponentDidMount vs useEffect

There is a class components work piece. I want to convert it into a function component and implement it in the same way, but there's a problem.
Unlike the class type, the function type returns to the place where it was created without staying after the picture has moved.
This is the function components.
const [dogs, setDogs] = useState([])
function addDog(){
// setDogs([...dogs, {id: dogCount++}])
dogCount++;
console.log(dogCount)
// console.log(dogs)
const newDog = {id: dogCount, bottom: 125}
setDogs([...dogs, newDog])
}
return (
<View style={styles.entirebottomsheet}>
<View style={styles.container}>
<TouchableOpacity onPress={()=>{addDog();}} style={styles.dogButton}>
<Text>Dog</Text>
</TouchableOpacity>
{dogs.map(dog => {
return (
<DogContainer
key={dog.id}
style={{bottom: dog.bottom, position: 'absolute'}}
/>
);
})}
</View>
</View>
);
function DogContainer () {
const positionX = new Animated.Value(0);
const positionY = new Animated.Value(0);
// DogContainer.defaultProps = {
// onComplete() {}
// }
const getDogStyle = () => ({
transform: [{translateX: positionX}],
});
useEffect(() => {
Animated.spring(positionX, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start();
Animated.spring(positionY, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start();
return (
console.log('finish')
)
}, []);
return (
<Animated.View style={[{ bottom: 125},{
transform: [{translateX: positionX}, {translateY: positionY}],
}]}>
<Image source={dogImg} style={{width: 60, height: 60}}/>
</Animated.View>
);
}
This is the class components.
export default class App extends React.Component {
// let {up} = this.props.up;
state = {
dogs: [],
cats: [],
chicks: [],
};
addDog = () => {
console.log(...this.state.dogs);
this.setState(
{
dogs: [
...this.state.dogs,
{
id: dogCount,
bottom: 125,
},
],
},
() => {
dogCount++;
},
);
};
removeDog = id => {
this.setState({
dogs: this.state.dogs.filter(dog => {
return dog.id !== id;
}),
});
};
addCat = () => {
console.log(...this.state.cats);
this.setState(
{
cats: [
...this.state.cats,
{
id: catCount,
bottom: 125,
},
],
},
() => {
catCount++;
},
);
};
removeCat = id => {
this.setState({
cats: this.state.cats.filter(cat => {
return cat.id !== id;
}),
});
};
addChick = () => {
console.log(...this.state.chicks);
this.setState(
{
chicks: [
...this.state.chicks,
{
id: chickCount,
bottom: 125,
},
],
},
() => {
chickCount++;
},
);
};
removeChick = id => {
this.setState({
chicks: this.state.chicks.filter(chick => {
return chick.id !== id;
}),
});
};
render() {
return (
<GestureHandlerRootView>
<View style={styles.entirebottomsheet}>
<View style={styles.container}>
<TouchableOpacity onPress={this.addDog} style={styles.dogButton}>
<Text>Dog</Text>
</TouchableOpacity>
{this.state.dogs.map(dog => {
return (
<DogContainer
key={dog.id}
style={{bottom: dog.bottom, position: 'absolute'}}
onComplete={() => this.removeDog(dog.id)}
/>
);
})}
</View>
<View style={styles.container}>
<TouchableOpacity onPress={this.addCat} style={styles.catButton}>
<Text>Cat</Text>
</TouchableOpacity>
{this.state.cats.map(cat => {
return (
<CatContainer
key={cat.id}
style={{bottom: cat.bottom, position: 'absolute'}}
onComplete={() => this.removeCat(cat.id)}
/>
);
})}
</View>
<View style={styles.container}>
<TouchableOpacity onPress={this.addChick} style={styles.chickButton}>
<Text style={{position: 'absolute'}}>Chick</Text>
</TouchableOpacity>
{this.state.chicks.map(chick => {
return (
<ChickContainer
key={chick.id}
style={{bottom: chick.bottom, position: 'absolute'}}
onComplete={() => this.removeChick(chick.id)}
/>
);
})}
</View>
</View>
</GestureHandlerRootView>
);
}
}
class DogContainer extends React.Component {
state = {
position: new Animated.ValueXY({
x: 0,
y: 0,
}),
};
static defaultProps = {
onComplete() {},
};
componentDidMount() {
Animated.spring(this.state.position.x, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start(this.props.onComplete);
Animated.spring(this.state.position.y, {
duration: 1000,
toValue: -340,
easing: Easing.ease,
useNativeDriver: true,
}).start(this.props.onComplete);
}
getDogStyle() {
return {
transform: [
{translateY: this.state.position.y},
{translateX: this.state.position.x},
],
};
}
render() {
return (
<Animated.View style={[this.getDogStyle(), this.props.style]}>
<Image source={dogImg} style={{width: 60, height: 60, borderRadius: 30}} />
</Animated.View>
);
}
}
Try to use useRef() hook
function DogContainer () {
const positionX = useRef(new Animated.Value(0)).current;
const positionY = useRef(new Animated.Value(0)).current;
...
In the Class-based version of DogContainer the position coordinate was a part of state.
class DogContainer extends React.Component {
state = {
position: new Animated.ValueXY({
x: 0,
y: 0,
}),
};
static defaultProps = {
onComplete() {},
};
componentDidMount() {
Animated.spring(this.state.position.x, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start(this.props.onComplete);
Animated.spring(this.state.position.y, {
duration: 1000,
toValue: -340,
easing: Easing.ease,
useNativeDriver: true,
}).start(this.props.onComplete);
}
getDogStyle() {
return {
transform: [
{translateY: this.state.position.y},
{translateX: this.state.position.x},
],
};
}
render() {
return (
<Animated.View style={[this.getDogStyle(), this.props.style]}>
<Image source={dogImg} style={{width: 60, height: 60, borderRadius: 30}} />
</Animated.View>
);
}
}
Function component using the useState hook
function DogContainer ({ onComplete = () => {} }) {
const [position, setPosition] = React.useState(
new Animated.ValueXY({
x: 0,
y: 0,
})
);
const getDogStyle = () => ({
transform: [{
translateX: position.x,
translateY: position.y,
}],
});
useEffect(() => {
Animated.spring(position.x, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start(onComplete);
Animated.spring(position.y, {
duration: 1000,
toValue: width / 3,
easing: Easing.ease,
useNativeDriver: true,
}).start(onComplete);
console.log('finish');
}, []);
return (
<Animated.View
style={[
{ bottom: 125},
{ transform: [
{ translateX: position.x },
{ translateY: position.y }
],
}
]}
>
<Image source={dogImg} style={{ width: 60, height: 60 }} />
</Animated.View>
);
}

React Native Wheel of Fortune

I am developing the react native application which contains the wheel of fortune. There are two wheels in my application. Wheel#1 is running smoothly but in Wheel#2 is being required to add Inner & Outer wheels. I am using D3 shape and React Native SVG packages to achieve my goal.
import React, {Component} from 'react';
import {
View,
StyleSheet,
Dimensions,
Animated,
TouchableOpacity,
Image,
} from 'react-native';
import * as d3Shape from 'd3-shape';
import Svg, {G, Text, TSpan, Path, Pattern} from 'react-native-svg';
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const {width, height} = Dimensions.get('screen');
class WheelOfFortune extends Component {
constructor(props) {
super(props);
this.state = {
enabled: false,
started: false,
finished: false,
winner: null,
gameScreen: new Animated.Value(width - 40),
wheelOpacity: new Animated.Value(1),
imageLeft: new Animated.Value(width / 2 - 30),
imageTop: new Animated.Value(height / 2 - 70),
};
this.angle = 0;
this.prepareWheel();
}
prepareWheel = () => {
this.Rewards = this.props.options.rewards;
this.RewardCount = this.Rewards.length;
this.numberOfSegments = this.RewardCount;
this.fontSize = 20;
this.oneTurn = 360;
this.angleBySegment = this.oneTurn / this.numberOfSegments;
this.angleOffset = this.angleBySegment / 2;
this.winner = this.props.options.winner
? this.props.options.winner
: Math.floor(Math.random() * this.numberOfSegments);
this._wheelPaths = this.makeWheel();
this._angle = new Animated.Value(0);
this.props.options.onRef(this);
};
resetWheelState = () => {
this.setState({
enabled: false,
started: false,
finished: false,
winner: null,
gameScreen: new Animated.Value(width - 40),
wheelOpacity: new Animated.Value(1),
imageLeft: new Animated.Value(width / 2 - 30),
imageTop: new Animated.Value(height / 2 - 70),
});
};
_tryAgain = () => {
this.prepareWheel();
this.resetWheelState();
this.angleListener();
this._onPress();
};
angleListener = () => {
this._angle.addListener(event => {
if (this.state.enabled) {
this.setState({
enabled: false,
finished: false,
});
}
this.angle = event.value;
});
};
componentWillUnmount() {
this.props.options.onRef(undefined);
}
componentDidMount() {
this.angleListener();
}
makeWheel = () => {
const data = Array.from({length: this.numberOfSegments}).fill(1);
const arcs = d3Shape.pie()(data);
var colors = this.props.options.colors
? this.props.options.colors
: [
'#E07026',
'#E8C22E',
'#ABC937',
'#4F991D',
'#22AFD3',
'#5858D0',
'#7B48C8',
'#D843B9',
'#E23B80',
'#D82B2B',
];
return arcs.map((arc, index) => {
const instance = d3Shape
.arc()
.padAngle(0.01)
.outerRadius(width / 2)
.innerRadius(this.props.options.innerRadius || 100);
return {
path: instance(arc),
color: colors[index % colors.length],
value: this.Rewards[index],
centroid: instance.centroid(arc),
};
});
};
_getWinnerIndex = () => {
const deg = Math.abs(Math.round(this.angle % this.oneTurn));
// wheel turning counterclockwise
if (this.angle < 0) {
return Math.floor(deg / this.angleBySegment);
}
// wheel turning clockwise
return (
(this.numberOfSegments - Math.floor(deg / this.angleBySegment)) %
this.numberOfSegments
);
};
_onPress = () => {
const duration = this.props.options.duration || 10000;
this.setState({
started: true,
});
Animated.timing(this._angle, {
toValue:
365 -
this.winner * (this.oneTurn / this.numberOfSegments) +
360 * (duration / 1000),
duration: duration,
useNativeDriver: true,
}).start(() => {
const winnerIndex = this._getWinnerIndex();
this.setState({
finished: true,
winner: this._wheelPaths[winnerIndex].value,
});
this.props.getWinner(this._wheelPaths[winnerIndex].value, winnerIndex);
});
};
_textRender = (x, y, number, i) => (
<Text
x={x - number.length * 5}
y={y - 80}
fill={
this.props.options.textColor ? this.props.options.textColor : '#fff'
}
textAnchor="middle"
fontSize={this.fontSize}>
{Array.from({length: number.length}).map((_, j) => {
// Render reward text vertically
if (this.props.options.textAngle === 'vertical') {
return (
<TSpan x={x} dy={this.fontSize} key={`arc-${i}-slice-${j}`}>
{number.charAt(j)}
</TSpan>
);
}
// Render reward text horizontally
else {
return (
<TSpan
y={y - 40}
dx={this.fontSize * 0.07}
key={`arc-${i}-slice-${j}`}>
{number.charAt(j)}
</TSpan>
);
}
})}
</Text>
);
_renderSvgWheel = () => {
return (
<View style={styles.container}>
{this._renderKnob()}
<Animated.View
style={{
alignItems: 'center',
justifyContent: 'center',
transform: [
{
rotate: this._angle.interpolate({
inputRange: [-this.oneTurn, 0, this.oneTurn],
outputRange: [
`-${this.oneTurn}deg`,
`0deg`,
`${this.oneTurn}deg`,
],
}),
},
],
backgroundColor: this.props.options.backgroundColor
? this.props.options.backgroundColor
: '#fff',
width: width - 20,
height: width - 20,
borderRadius: (width - 20) / 2,
borderWidth: this.props.options.borderWidth
? this.props.options.borderWidth
: 2,
borderColor: this.props.options.borderColor
? this.props.options.borderColor
: '#fff',
opacity: this.state.wheelOpacity,
}}>
<AnimatedSvg
width={this.state.gameScreen}
height={this.state.gameScreen}
viewBox={`0 0 ${width} ${width}`}
style={{
transform: [{rotate: `-${this.angleOffset}deg`}],
margin: 10,
}}>
<G y={width / 2} x={width / 2}>
{this._wheelPaths.map((arc, i) => {
const [x, y] = arc.centroid;
const number = arc.value.toString();
return (
<G key={`arc-${i}`}>
<Path d={arc.path} strokeWidth={2} fill={arc.color} />
<G
rotation={
(i * this.oneTurn) / this.numberOfSegments +
this.angleOffset
}
origin={`${x}, ${y}`}>
{this._textRender(x, y, number, i)}
</G>
</G>
);
})}
</G>
</AnimatedSvg>
</Animated.View>
</View>
);
};
_renderKnob = () => {
const knobSize = this.props.options.knobSize
? this.props.options.knobSize
: 20;
// [0, this.numberOfSegments]
const YOLO = Animated.modulo(
Animated.divide(
Animated.modulo(
Animated.subtract(this._angle, this.angleOffset),
this.oneTurn,
),
new Animated.Value(this.angleBySegment),
),
1,
);
return (
<Animated.View
style={{
width: knobSize,
height: knobSize * 2,
justifyContent: 'flex-end',
zIndex: 1,
opacity: this.state.wheelOpacity,
transform: [
{
rotate: YOLO.interpolate({
inputRange: [-1, -0.5, -0.0001, 0.0001, 0.5, 1],
outputRange: [
'0deg',
'0deg',
'35deg',
'-35deg',
'0deg',
'0deg',
],
}),
},
],
}}>
<Svg
width={knobSize}
height={(knobSize * 100) / 57}
viewBox={`0 0 57 100`}
style={{
transform: [{translateY: 8}],
}}>
<Image
source={
this.props.options.knobSource
? this.props.options.knobSource
: require('../assets/images/knob.png')
}
style={{ width: knobSize, height: (knobSize * 100) / 57 }}
/>
</Svg>
</Animated.View>
);
};
_renderTopToPlay() {
if (this.state.started == false) {
return (
<TouchableOpacity onPress={() => this._onPress()}>
{this.props.options.playButton()}
</TouchableOpacity>
);
}
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={{
position: 'absolute',
width: width,
height: height / 2,
justifyContent: 'center',
alignItems: 'center',
}}>
<Animated.View style={[styles.content, {padding: 10}]}>
{this._renderSvgWheel()}
</Animated.View>
</TouchableOpacity>
{this.props.options.playButton ? this._renderTopToPlay() : null}
</View>
);
}
}
export default WheelOfFortune;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
content: {},
startText: {
fontSize: 50,
color: '#fff',
fontWeight: 'bold',
textShadowColor: 'rgba(0, 0, 0, 0.4)',
textShadowOffset: {width: -1, height: 1},
textShadowRadius: 10,
},
});
End Result Look like this
Now I want to add an Inner wheel to it Like this

borderRadius doesn't work on image when resizeMode is set to 'contain'

I've been trying to build an Image carousel with a bunch of randomly selected images. I wanted to maintain their aspect ratios so I set the resizeMode to 'contain'. Somehow that step leads to the loss of any set borderRadius! What could be the reason? And if that step doesn't work at all, any other ideas on how to maintain the correct aspect ratio + get the corners rounded?
Thanks a lot for your help!
here's the code:
import React, { useCallback, memo, useRef, useState } from "react";
import {
FlatList,
View,
Dimensions,
Text,
StyleSheet,
Image,
} from "react-native";
const images = [
Image1,
Image2,
Image3,
Image4,
Image5,
Image6,
Image7,
Image8,
Image9,
Image10,
Image11,
Image12,
Image13,
Image14,
Image15,
Image16,
Image17,
Image18,
Image19,
Image20,
Image21,
Image22,
Image23,
Image24,
Image25,
Image26,
Image27,
Image28,
Image29,
Image30,
Image31,
Image32,
Image33,
Image34,
Image35,
Image36,
Image37,
Image38,
Image39,
Image40,
Image41,
]
const { width: windowWidth, height: windowHeight } = Dimensions.get("window");
const randomImage = () =>
images[Math.floor(Math.random() * images.length)];
const styles = StyleSheet.create({
slide: {
height: windowHeight,
width: windowWidth,
//justifyContent: "center",
alignItems: "center",
},
slideImage: {
height: '70%',
width: '90%',
borderRadius: 20,
marginTop: 20,
},
slideTitle: {
fontSize: 24,
marginTop: 0,
},
slideSubtitle: {
fontSize: 18,
marginTop: 10,
},
pagination: {
position: "absolute",
bottom: 8,
justifyContent: "center",
flexDirection: "row",
marginBottom: 12
},
paginationDot: {
width: 8,
height: 8,
borderRadius: 4,
marginHorizontal: 2,
},
paginationDotActive: { backgroundColor: "lightblue" },
paginationDotInactive: { backgroundColor: "gray" },
carousel: {},
});
const slideList = Array.from({ length: 999 }).map((_, i) => {
return {
id: i,
image: randomImage,
title: `This is the title ${i + 1}!`,
subtitle: `This is the subtitle ${i + 1}!`,
};
});
const Slide = memo(function Slide({ data }) {
return (
<View style={styles.slide}>
<Image resizeMode = 'contain' source = {randomImage()} style={styles.slideImage}></Image>
<Text style={styles.slideTitle}>{data.title}</Text>
<Text style={styles.slideSubtitle}>{data.subtitle}</Text>
</View>
);
});
function Pagination({ index }) {
return (
<View style={styles.pagination} pointerEvents="none">
{slideList.map((_, i) => {
return (
<View
key={i}
style={[
styles.paginationDot,
index === i
? styles.paginationDotActive
: styles.paginationDotInactive,
]}
/>
);
})}
</View>
);
}
export default function Carousel() {
const [index, setIndex] = useState(0);
const indexRef = useRef(index);
indexRef.current = index;
const onScroll = useCallback((event) => {
const slideSize = event.nativeEvent.layoutMeasurement.width;
const index = event.nativeEvent.contentOffset.x / slideSize;
const roundIndex = Math.round(index);
const distance = Math.abs(roundIndex - index);
// Prevent one pixel triggering setIndex in the middle
// of the transition. With this we have to scroll a bit
// more to trigger the index change.
const isNoMansLand = 0.4 < distance;
if (roundIndex !== indexRef.current && !isNoMansLand) {
setIndex(roundIndex);
}
}, []);
const flatListOptimizationProps = {
initialNumToRender: 0,
maxToRenderPerBatch: 1,
removeClippedSubviews: true,
scrollEventThrottle: 16,
windowSize: 2,
keyExtractor: useCallback(s => String(s.id), []),
getItemLayout: useCallback(
(_, index) => ({
index,
length: windowWidth,
offset: index * windowWidth,
}),
[]
),
};
const renderItem = useCallback(function renderItem({ item }) {
return <Slide data={item} />;
}, []);
return (
<>
<FlatList
data={slideList}
style={styles.carousel}
renderItem={renderItem}
pagingEnabled
horizontal
showsHorizontalScrollIndicator={false}
bounces={false}
onScroll={onScroll}
{...flatListOptimizationProps}
/>
<Pagination index={index}></Pagination>
</>
);
}
``
Actually borderRadius works but you can't see it because of an incorrect ratio.
If your image has a 16:9 ratio, for example, 1600x900 dimensions, then you need to set width and height with the same ratio.
<Image
source={ 1600x900 }
resizeMode="contain"
style={{
width: 300,
height: 300,
borderRadius: 15,
backgroundColor: 'red'
}} />
The result will be:
Because the image has width and height 300, ie 1:1 ratio. If you modify width and height like 320 and 180, ie 16:9, then the image fills all the space and borders will be visible.
Another workaround is to wrap your image with view that hides the overflow
<View
style={{
width: 300,
height: 300,
borderRadius: 150,
overflow: 'hidden',
}}
>
<Image
source={item.image}
style={{
width: 300,
height: 300,
}}
resizeMode='contain'
/>
</View>

On scroll React Native Animated do the animation but flickering

In my react native app I'm trying to animate opacity of a View.
When I scroll, I saw the animation do the job, but it’s flickering at the same time. I don’t know why.
Video example : https://cdn.discordapp.com/attachments/102861040538120192/560165613092339734/video.mov
Here is the code I made
const Scrollable = () => {
const largeHeaderSize = useState({
height: 0,
y: 0
});
const animatedValueScrollY = new Animated.Value(largeHeaderSize.height);
const [scrollY, setScrollY] = useState(0);
const headerOpacity = animatedValueScrollY.interpolate({
inputRange: [0, largeHeaderSize.height],
outputRange: [1, 0],
extrapolate: "clamp"
});
return (
<SafeAreaView>
<Animated.View
style={{
borderBottomWidth:
scrollY >= largeHeaderSize.height ? StyleSheet.hairlineWidth : 0
}}>
<View>
<Animated.View style={{ zIndex: 1, opacity: headerOpacity }}>
<Text>Title</Text>
</Animated.View>
</View>
</Animated.View>
<Animated.ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: animatedValueScrollY } } }],
{
useNativeDriver: true,
listener: event => setScrollY(event.nativeEvent.contentOffset.y)
}
)}
scrollEventThrottle={16}
contentInset={{
top: 0,
bottom: 50
}}
contentOffset={{
y: 0
}}
/>
</SafeAreaView>
);
};
How I can I solve that?
The solution is to use the useRef hook like so:
const animatedValueScrollY = useRef(new Animated.Value(0))
const headerOpacity = animatedValueScrollY.current.interpolate({
inputRange: [0, largeHeaderSize.height],
outputRange: [1, 0],
extrapolate: 'clamp'
});

How to get and pass the details of the active slide in react native using react-native-snap-carousel

I need to pass the details of the currently active slide to another js file. how can I do this (there are 8 slides)?
The details that I need to pass is the slide's name and Index,
Here is my carousel js file :
import React, { Component } from 'react';
import { Dimensions, View, Image } from 'react-native';
import Carousel from 'react-native-snap-carousel';
const { height, width } = Dimensions.get('window');
class TeamScroll extends Component {
render() {
return (
<View >
<View style={{ transform: [{ rotate: '-14deg' }] }}>
<Carousel
ref={(c) => { this.props.carouselRef = c; }}
inactiveSlideOpacity={0.6}
inactiveSlideScale={0.65}
firstItem={1}
sliderWidth={width}
itemWidth={width / 3} >
<Image
source={require('./Images/logo-chepauk.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logo-dindigul.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logo-kanchi.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logo-karaikudi.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logo-kovai.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logomadurai.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logothiruvallur.png')}
style={styles.logoStyle} />
<Image
source={require('./Images/logotuti.png')}
style={styles.logoStyle} />
</Carousel>
</View>
</View>
);
}
}
const styles = {
logoStyle: {
transform: [{ rotate: '14deg' }],
width: width / 3,
height: width / 3
}
};
export default TeamScroll;
Here is one of the files where I need to use these details
import React, { Component } from 'react';
import { Image, Text, View, TouchableWithoutFeedback, Animated, Dimensions } from 'react-native';
import { Actions } from 'react-native-router-flux';
import TeamScroll from './TeamScroll';
const a = require('./Images/over3_selected.png');
const b = require('./Images/over3.png');
const c = require('./Images/over5_selected.png');
const d = require('./Images/over5.png');
const e = require('./Images/over10_selected.png');
const f = require('./Images/over10.png');
const Sound = require('react-native-sound');
const btnSound = new Sound('btn_sound.mp3', Sound.MAIN_BUNDLE);
const w = Dimensions.get('window').width;
const h = Dimensions.get('window').height;
class ChallengeScreen extends Component {
state = {
threePressed: false,
fivePressed: false,
tenPressed: false,
}
componentWillMount() {
this.slide1 = new Animated.Value(0);
this.slide2 = new Animated.Value(0);
this.slide3 = new Animated.Value(0);
this.ball1();
this.ball2();
this.ball3();
}
ball1() {
Animated.timing(
this.slide1, {
delay: 100,
toValue: -(w / 2.57),
duration: 700,
}
).start();
}
ball2() {
Animated.timing(
this.slide2, {
delay: 200,
toValue: -(w / 2.25),
duration: 900,
}
).start();
}
ball3() {
Animated.timing(
this.slide3, {
delay: 300,
toValue: -(w / 2),
duration: 1100,
}
).start();
}
render() {
return (
<Image
source={require('./Images/bg_inner.png')} style={styles.backgroundStyle}>
<Text style={styles.chooseteamtextStyle}>
CHOOSE YOUR TEAM
</Text>
<Image source={require('./Images/team-logo-band.png')} style={styles.band1Style}>
<TeamScroll carouselRef />
</Image>
<Text style={styles.opponentStyle}>
YOUR OPPONENT
</Text>
<Image source={require('./Images/team-logo-band.png')} style={styles.band2Style}>
<TeamScroll carouselRef />
</Image>
<Text style={styles.overstextStyle}>
OVERS
</Text>
<View style={styles.viewStyle}>
<TouchableWithoutFeedback
onPress={() => {
btnSound.play();
playFunc(3, this.props.challenge); }
}
onPressIn={() => {
this.setState({ threePressed: true });
}}
onPressOut={() => {
this.setState({ threePressed: false });
}}
>
<Animated.Image source={this.state.threePressed ? a : b}
style={[styles.over3Style, { transform: [{ translateY: this.slide1 }] }]} />
</ TouchableWithoutFeedback>
<TouchableWithoutFeedback
onPress={() => {
btnSound.play();
playFunc(5, this.props.challenge); }
}
onPressIn={() => {
this.setState({ fivePressed: true });
}}
onPressOut={() => {
this.setState({ fivePressed: false });
}}>
<Animated.Image source={this.state.fivePressed ? c : d}
style={[styles.over5Style, { transform: [{ translateY: this.slide2 }] }]} />
</ TouchableWithoutFeedback>
<TouchableWithoutFeedback
onPress={() => {
btnSound.play();
playFunc(10, this.props.challenge); }
}
onPressIn={() => {
this.setState({ tenPressed: true });
}}
onPressOut={() => {
this.setState({ tenPressed: false });
}}>
<Animated.Image source={this.state.tenPressed ? e : f}
style={[styles.over10Style, { transform: [{ translateY: this.slide3 }] }]} />
</ TouchableWithoutFeedback>
</View>
</ Image>
);
}
}
function playFunc(num, param) {
if (num === 3 && param === 'Computer') {
Actions.screen4({ balls: 18 });
}
else if (num === 5 && param === 'Computer') {
Actions.screen4({ balls: 30 });
}
else if (num === 10 && param === 'Computer') {
Actions.screen4({ balls: 60 });
}
else if (num === 3 && param === 'Team') {
Actions.screen3({ balls: 18 });
}
else if (num === 5 && param === 'Team') {
Actions.screen3({ balls: 30 });
}
else if (num === 10 && param === 'Team') {
Actions.screen3({ balls: 60 });
}
}
const styles = {
viewStyle: {
flexDirection: 'row',
justifyContent: 'flex-start'
},
backgroundStyle: {
flex: 1,
width: w,
height: h,
flexWrap: 'wrap',
},
chooseteamtextStyle: {
textAlign: 'center',
marginTop: h / 6.57,
fontSize: 22,
color: 'white',
fontFamily: 'Switzerland-Cond-Black-Italic',
transform: [{ rotate: '-14deg' }]
},
band1Style: {
resizeMode: 'stretch',
width: (w / 0.947),
height: (h / 3.93),
},
opponentStyle: {
textAlign: 'center',
marginTop: -(h / 59.2),
fontSize: 22,
color: 'white',
fontFamily: 'Switzerland-Cond-Black-Italic',
transform: [{ rotate: '-15deg' }]
},
band2Style: {
resizeMode: 'stretch',
width: (w / 0.947),
height: (h / 4),
},
overstextStyle: {
textAlign: 'center',
bottom: (h / 59.2),
fontSize: 22,
color: 'white',
fontFamily: 'Switzerland-Cond-Black-Italic',
transform: [{ rotate: '-15deg' }]
},
over3Style: {
flexDirection: 'row',
alignItems: 'flex-start',
width: (w / 4.5),
height: (h / 7.4),
top: (h / 3.482),
left: (w / 5.142),
},
over5Style: {
flexDirection: 'row',
alignItems: 'center',
width: (w / 4.5),
height: (h / 7.4),
bottom: -(h / 3.48),
left: (h / 8.45)
},
over10Style: {
flexDirection: 'row',
alignItems: 'flex-end',
width: (w / 4.5),
height: (h / 7.4),
top: (h / 3.48),
right: -(w / 5.42)
}
};
export default ChallengeScreen;
I have tried using state and props for doing it, and also using getters like currentIndex using carousel's reference but couldn't get the details
What about adding a dedicated prop to <TeamScroll />?
TeamScroll.js
class TeamScroll extends Component {
static propTypes = {
snapCallback: PropTypes.func
}
static defaultProps = {
snapCallback: () => {}
}
constructor (props) {
super(props);
this._onSnapToItem = this._onSnapToItem.bind(this);
}
_onSnapToItem (index) {
this.props.snapCallback(index, this.state.customData);
}
render() {
return (
<View >
<View style={{ transform: [{ rotate: '-14deg' }] }}>
<Carousel onSnapToItem={this._onSnapToItem}>
// images
</Carousel>
</View>
</View>
);
}
}
ChallengeScreen.js
class ChallengeScreen extends Component {
onSnap (index, data) {
console.log('CAROUSEL INDEX', { index, data });
}
render() {
return (
<Image source={require('./Images/team-logo-band.png')} style={styles.band2Style}>
<TeamScroll carouselRef snapCallback={onSnap} />
</Image>
);
}
}
I'm using this
class TeamScroll extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
};
}
changePage(nextIndex, isLast) {
this.setState({ currentIndex: nextIndex });
this.props.onChangePage(nextIndex + 1, isLast);
}
render() {
return (
<Page>
<Carousel
ref={(carousel) => { this.carousel = carousel; }}
firstItem={this.state.currentIndex}
onSnapToItem={(index) => this.changePage(index, index === screens.length - 1)}
data={screens}
renderItem={this.renderCarouselItem}
/>
);
}
}
Note that I'm using the new syntax introduced in version 3, but it works as well in version 2.
The class has onChangePage prop that gets called when you snap to another item.
You can use the onChangePage with
<TeamScroll onChangePage={(pageIndex, isLastPage) => {
// do something here, maybe
this.setState({ currentPage: pageIndex });
}} />

Categories

Resources