Remove Image from image array React Native - react-native

I need to remove or hide image from array after click on this image.
I'm trying to do this, but it's not work for me
I just study React Native, please help me
const [hiddenObject, setHiddenObject] = useState(false);
const findObjects = {
postList: [
{ img: require("../obj1.png"), opacity: 1, w: 35, h: 50, left: 0, top: 0 },
{
img: require("../obj2.png"),
opacity: 1,
w: 35,
h: 50,
left: 170,
top: 20,
},
{
img: require("../obj3.png"),
opacity: 1,
w: 35,
h: 50,
left: 277,
top: 50,
},
{
img: require("../obj1.png"),
opacity: 1,
w: 35,
h: 50,
left: 510,
top: 7,
},
],
};
const hiddenObject2 = (item) => {
item.opacity = 0;
setHiddenObject(hiddenObject);
findObjects.postList.splice(item, 1);
};
return (
<View>
{findObjects.postList.map((item) => {
return (
<TouchableOpacity
onPress={hiddenObject2}
key={Math.random()}
style={{ width: "auto", opacity: hiddenObject ? 0 : item.opacity }}
>
<Image
source={item.img}
style={[
gStyle.imgObject,
{
width: item.w,
height: item.h,
left: item.left,
top: item.top,
opacity: hiddenObject ? 0 : item.opacity,
},
]}
/>
</TouchableOpacity>
);
})}
</View>
);

Related

React native swipe animation not working and no error

I'm using a swipe animation, the same one that is being used in apps like tinder.
The animation used to work in a Class component and in JSX but I had to change it to a function with hooks in TSX for a project. Now the animation Doensn't work anymore but it also doesn't give a error. I guess I'm missing some code that is necessary to let it work or it also can be something with the Panresponder. But I absolutely got no clue.
Thanks in advance.
const SCREEN_HEIGHT = Dimensions.get('window').height
const SCREEN_WIDTH = Dimensions.get('window').width
const { width, height } = Dimensions.get('screen')
const thumbMeasure = (width - 48 - 32) / 3
const MyComponent = (props: { index: any }) => {
const [imagesData, setImagesData] = useState<Images[]>([])
console.clear()
console.log('Images data:', imagesData)
useEffect(() => {
LogBox.ignoreLogs(['Animated: `useNativeDriver`']);
}, [])
useEffect(() => {
axios
.get<Images[]>('https://api.thecatapi.com/v1/images/search?breed_ids=beng&include_breeds=true')
.then((response: AxiosResponse) => {
setImagesData(response.data)
})
}, [])
const position = new Animated.ValueXY()
const [index, setIndex] = useState(props.index || 0)
const [panResponder, setPanResponder] = useState<any>()
const rotate = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: ['-30deg', '0deg', '10deg'],
extrapolate: 'clamp',
})
const rotateAndTranslate = {
transform: [{
rotate: rotate
},
...position.getTranslateTransform()
]
}
const likeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
})
const dislikeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 0],
extrapolate: 'clamp',
})
const nextCardOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 1],
extrapolate: 'clamp',
})
const nextCardScale = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0.8, 1],
extrapolate: 'clamp',
})
useEffect(() => {
setPanResponder( PanResponder.create({
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
onPanResponderMove: (_evt, gestureState) => {
position.setValue({ x: gestureState.dx, y: gestureState.dy })
},
onPanResponderRelease: (_evt, gestureState) => {
if (gestureState.dx > 120) {
Animated.spring(position, {
toValue: { x: SCREEN_WIDTH + 100, y: gestureState.dy },
useNativeDriver: true,
}).start(() => {
setIndex( () => {
position.setValue({ x: 0, y: 0 })
return index + 1
})
})
} else if (gestureState.dx < -120) {
Animated.spring(position, {
toValue: { x: -SCREEN_WIDTH - 100, y: gestureState.dy },
useNativeDriver: true,
}).start(() => {
setIndex( () => {
position.setValue({ x: 0, y: 0 })
return index + 1
})
})
} else {
Animated.spring(position, {
toValue: { x: 0, y: 0 },
friction: 4, useNativeDriver: true,
}).start()
}
},
}))
}, [])
const Users = () => {
return imagesData.map((item, i) => {
if (i < index) {
return null
} else if (i == index) {
return (
<Animated.View
{...panResponder.panhandlers}
key={item.id}
style={[
rotateAndTranslate,
{
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: likeOpacity,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: dislikeOpacity,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
<View style={{backgroundColor: '', color: 'black', fontSize: 20, fontWeight: '800', position: 'absolute', bottom: 95, right: 40, zIndex: 1000, width: '85%', height: '20%', borderRadiusTop: 20, }}>
<Text style={{ color: 'white', fontSize: 32, fontWeight: '800' }}>
{item.breeds[0].name}
</Text>
<Text style={{ color: 'white', fontSize: 18, fontWeight: '600' }}>
{item.breeds[0].origin}
</Text>
<View style={styles.iconen}>
<Ionicons style={styles.icon} name="timer" />
<Text style={styles.subtitle}>{item.breeds[0].life_span}</Text>
<Ionicons style={styles.icon} name="barbell-outline" />
<Text style={styles.subtitle}>{item.breeds[0].weight.metric}</Text>
<Ionicons style={styles.icon} name="earth" />
<Text style={styles.subtitle}>{item.breeds[0].country_code}</Text>
</View>
</View>
</Animated.View>
)
} else {
return (
<Animated.View
key={item.id}
style={[
{
opacity: nextCardOpacity,
transform: [{ scale: nextCardScale }],
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
</Animated.View>
)
}
})
.reverse()
}
return (
<View>
<View>
{Users()}
</View>
<View style={{ height: SCREEN_HEIGHT - 80 }}>
<ButtonVote />
</View>
</View>
)
}

Converting Class to function with hooks

I'm stuck with converting a Class component to a function / const while using hooks.
I'm getting this Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
I googled this warning but only saw this warning with Classes, did I convert this Class wrong?
const MyComponent = (props) => {
const position = new Animated.ValueXY()
const [index, setIndex] = useState(props.index || 0)
const rotate = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: ['-30deg', '0deg', '10deg'],
extrapolate: 'clamp',
})
const rotateAndTranslate = {
transform: [
{
rotate: rotate,
},
position.getTranslateTransform(),
],
}
const likeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
})
const dislikeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 0],
extrapolate: 'clamp',
})
const nextCardOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 1],
extrapolate: 'clamp',
})
const nextCardScale = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0.8, 1],
extrapolate: 'clamp',
})
useEffect(() => {
PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderMove: (evt, gestureState) => {
position.setValue({ x: gestureState.dx, y: gestureState.dy })
},
onPanResponderRelease: (evt, gestureState) => {
if (gestureState.dx > 120) {
Animated.spring(position, {
toValue: { x: SCREEN_WIDTH + 100, y: gestureState.dy },
useNativedriver: true,
}).start(() => {
setIndex(index + 1, () => {
position.setValue({ x: 0, y: 0 })
})
})
} else if (gestureState.dx < -120) {
Animated.spring(position, {
toValue: { x: -SCREEN_WIDTH - 100, y: gestureState.dy },
useNativedriver: true,
}).start(() => {
setIndex(index + 1, () => {
position.setValue({ x: 0, y: 0 })
})
})
} else {
Animated.spring(position, {
toValue: { x: 0, y: 0 },
friction: 4,
useNativedriver: true,
}).start()
}
},
})
}, [])
const Users = () => {
return imagesData
.map((item, i) => {
if (i < index) {
return null
} else if (i == index) {
return (
<Animated.View
{...PanResponder.panHandlers}
key={item.id}
style={[
rotateAndTranslate,
{
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: likeOpacity,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: dislikeOpacity,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
<View
style={{
backgroundColor: '',
color: 'black',
fontSize: 20,
fontWeight: '800',
position: 'absolute',
bottom: 95,
right: 40,
zIndex: 1000,
width: '85%',
height: '20%',
borderRadiusTop: 20,
}}
>
<Text
style={{ color: 'white', fontSize: 32, fontWeight: '800' }}
>
Black cat
</Text>
<Text
style={{ color: 'white', fontSize: 18, fontWeight: '600' }}
>
Black cat family
</Text>
<View style={styles.iconen}>
<Ionicons style={styles.icon} name="timer" />
<Text style={styles.subtitle}>12 -14</Text>
<Ionicons style={styles.icon} name="barbell-outline" />
<Text style={styles.subtitle}>12 - 14</Text>
<Ionicons style={styles.icon} name="earth" />
<Text style={styles.subtitle}>Belgium</Text>
</View>
</View>
</Animated.View>
)
} else {
return (
<Animated.View
key={item.id}
style={[
{
opacity: nextCardOpacity,
transform: [{ scale: nextCardScale }],
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
</Animated.View>
)
}
})
.reverse()
}
return (
<View>
<View>{Users}</View>
<View style={{ height: SCREEN_HEIGHT - 80 }}>
<ButtonVote />
</View>
</View>
)
}
Users is a component, you should call it like
<Users />
instead of
{Users}

Unable to view data in react native using Axios from an API

I'm using Axios to retrieve my data from my API in this Class component in TSX.
It doesn't give any error, it just doesn't show my Images or not even the data in a console.log. I'm now using a class component with tsx because in my previous attempts to let a animated slider work I used: Class component in jsx, Class component in tsx, Function in JSX with hooks aswell in TSX. At every attempt there were different errors that I couldn't solve that's why I'm using this strategy now and I guess I'm close now to the sollution, it's just the Data that's not viewing.
Thanks in advance
class MyComponent extends Component {
componentDidMount() {
LogBox.ignoreLogs(['Animated: `useNativeDriver`'])
}
position
rotate: number
rotateAndTranslate
likeOpacity
dislikeOpacity
nextCardOpacity
nextCardScale
PanResponder
imagesData: Images[]
mySpecialFunction() {
console.log('Images data:', this.imagesData)
}
constructor(props) {
super(props)
LogBox.ignoreLogs(['Animated: `useNativeDriver`'])
axios
.get<Images[]>(
'https://api.thecatapi.com/v1/images/search?breed_ids=beng&include_breeds=true',
)
.then((response: AxiosResponse) => {
this.imagesData = response.data
})
this.position = new Animated.ValueXY()
this.state = {
currentIndex: 0,
}
this.rotate = this.position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: ['-30deg', '0deg', '10deg'],
extrapolate: 'clamp',
})
this.rotateAndTranslate = {
transform: [
{
rotate: this.rotate,
},
...this.position.getTranslateTransform(),
],
}
this.likeOpacity = this.position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
})
this.dislikeOpacity = this.position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 0],
extrapolate: 'clamp',
})
this.nextCardOpacity = this.position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 1],
extrapolate: 'clamp',
})
this.nextCardScale = this.position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0.8, 1],
extrapolate: 'clamp',
})
}
UNSAFE_componentWillMount() {
this.PanResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderMove: (evt, gestureState) => {
this.position.setValue({ x: gestureState.dx, y: gestureState.dy })
},
onPanResponderRelease: (evt, gestureState) => {
if (gestureState.dx > 120) {
Animated.spring(this.position, {
toValue: { x: SCREEN_WIDTH + 100, y: gestureState.dy },
useNativedriver: true,
}).start(() => {
this.setState({ currentIndex: this.state.currentIndex + 1 }, () => {
this.position.setValue({ x: 0, y: 0 })
})
})
} else if (gestureState.dx < -120) {
Animated.spring(this.position, {
toValue: { x: -SCREEN_WIDTH - 100, y: gestureState.dy },
useNativedriver: true,
}).start(() => {
this.setState({ currentIndex: this.state.currentIndex + 1 }, () => {
this.position.setValue({ x: 0, y: 0 })
})
})
} else {
Animated.spring(this.position, {
toValue: { x: 0, y: 0 },
friction: 4,
useNativedriver: true,
}).start()
}
},
})
}
renderUsers = () => {
if (this.imagesData) {
return this.imagesData
.map((item, i) => {
if (i < this.state.currentIndex) {
return null
} else if (i == this.state.currentIndex) {
return (
<Animated.View
{...this.PanResponder.panHandlers}
key={item.id}
style={[
this.rotateAndTranslate,
{
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: this.likeOpacity,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: this.dislikeOpacity,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
<View
style={{
backgroundColor: '',
color: 'black',
fontSize: 20,
fontWeight: '800',
position: 'absolute',
bottom: 95,
right: 40,
zIndex: 1000,
width: '85%',
height: '20%',
borderRadiusTop: 20,
}}
>
<Text
style={{ color: 'white', fontSize: 32, fontWeight: '800' }}
>
Black cat
</Text>
<Text
style={{ color: 'white', fontSize: 18, fontWeight: '600' }}
>
Black cat family
</Text>
<View style={styles.iconen}>
<Ionicons style={styles.icon} name="timer" />
<Text style={styles.subtitle}>
{item.breeds[0].life_span}
</Text>
<Ionicons style={styles.icon} name="barbell-outline" />
<Text style={styles.subtitle}>
{item.breeds[0].weight.metric}
</Text>
<Ionicons style={styles.icon} name="earth" />
<Text style={styles.subtitle}>
{item.breeds[0].country_code}
</Text>
</View>
</View>
</Animated.View>
)
} else {
return (
<Animated.View
key={item.id}
style={[
{
opacity: this.nextCardOpacity,
transform: [{ scale: this.nextCardScale }],
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
</Animated.View>
)
}
})
.reverse()
}
}
render() {
return (
<View>
<View>{this.renderUsers()}</View>
<View style={{ height: SCREEN_HEIGHT - 80 }}>
<ButtonVote />
</View>
</View>
)
}
}
Try this way by using state for reflecting changes after API respond
class MyComponent extends Component {
state = {
imagesData: [],
};
// rest of the code remains the same
componentDidMount() {
axios.get(`xxxxxx`).then((res) => {
const imagesData = res.data;
this.setState({ imagesData });
});
}
renderUsers = () => {
if (this.state.imagesData) {
return this.state.imagesData.map((item, i) => {}).reverse();
}
};
render() {
return <View></View>;
}
}

Android scrollview doesnt scroll and cuts off text

I have a scrollview and I want it to be able to scroll text in a certain part of the screen (the rest of the screen should not be able to scroll)
However, the scrollview doesn't scroll and the text inside of it gets cut off, and most of it doesn't show. When I remove the scrollview, the full-text shows.
Here is a link to how the screen looks like https://imgur.com/a/CVnLRyi
Fyi, the points variable contains a huge chunk of text
Below is my code:
import { StyleSheet, View, Text,FlatList, TouchableOpacity, ScrollView } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Lesson } from "../../App";
const data = require('../Data/MainData.json').mainData
function Flashcards({route, navigation}) {
let index = []
let counter = 0
let points = ""
const { PrimaryType } = route.params.params;
const {TopicName} = route.params.params;
const {Elements} = route.params.params;
const {Chapter} = route.params.params;
// setting up variables...
for (var i = 0; i <= Elements.length-1; i++){
if (data[Elements[i]].topic.toLowerCase() == Chapter.toLowerCase()){
index.push(Elements[i])
}
}
for (var i = 1; i <= 20; i++){
if (data[index[counter]][`point${i}`] != "Empty Cell"){
points += `${data[index[counter]][`point${i}`]}\n\n`
}
}
return (
// un-scrollable section
<View style = {styles.container}> // UI starts here
<View style={styles.rect1Stack}>
<View style={styles.rect1}>
<Text style={styles.lowerPrimary}>{PrimaryType}</Text>
<Text style={styles.syllabus}>Primary School {TopicName}</Text>
</View>
<View style={styles.rect2}></View>
</View>
// scrollable text section
<ScrollView style = {styles.ScrollView}>
<Text style={styles.conceptName}>{data[index[counter]].concepts}</Text>
<Text style={styles.info}>{points}</Text>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
},
rect1: {
top: 0,
height: 207,
position: "absolute",
backgroundColor: "rgba(247,142,105,1)",
left: 3,
right: 4
},
lowerPrimary: {
fontFamily: "roboto-700",
color: "rgba(255,255,255,1)",
fontSize: 26,
height: 88,
width: 286,
marginTop: 30,
marginLeft: 20
},
rect2: {
top: 148,
left: 0,
height: 83,
position: "absolute",
backgroundColor: "rgba(255,255,255,1)",
borderRadius: 43,
right: 0
},
rect1Stack: {
height: 231,
marginLeft: -3,
marginRight: -4
},
syllabus: {
fontFamily: "roboto-700",
color: "rgba(255,255,255,1)",
fontSize: 20,
height: 35,
width: 286,
marginTop: -30,
marginLeft: 20
},
yellowrec: { //unused property
height: 400,
backgroundColor: "rgba(255,231,185,1)",
marginTop: 0,
marginLeft: 20,
marginRight: 10
},
conceptName: {
fontFamily: "roboto-regular",
color: "#121212",
fontSize: 18,
height: 80,
marginTop: 10,
textAlign: "center",
marginLeft: 0,
marginRight: 0,
alignSelf: "center"
},
info: {
position: "absolute",
fontFamily: "roboto-regular",
color: "#121212",
top: 50,
left: 5,
width: 360,
fontSize: 18,
marginLeft: 10,
},
ScrollView: {
top: 0,
left: 0,
marginRight: 10,
height: 7000,
marginLeft: 10,
backgroundColor: "rgba(255,231,185,1)"
}
});
export default Flashcards;```
You can Just the split screen into two by using the flex
eg:
container: {
flex: 1,
},
rect1Stack:{
flex:.4,
backgroundColor:'green',
},
scrollView:{
flex:.6,
backgroundColor:'blue'
},

onPanResponderRelease not being triggered

I am trying to use the PanResponder on a View. The onStartShouldSetPanResponder and onMoveShouldSetPanResponder but onPanResponderMove, onPanResponderGrant and onPanResponderRelease does not get triggered at all. My react and react native versions are:
"react": "^15.2.1",
"react-native": "^0.30.0",
Below is the code
'use strict'
import React from 'react'
const Icon = require('react-native-vector-icons/Ionicons')
let THUMB_URLS = require('../Statics/ListingsData.js')
let SidePanelComponent = require('./common/SidePanel.js')
let RecentSearches = require('./Views/RecentSearches/RecentSearches.js')
let TimerMixin = require('react-timer-mixin')
const Loader = require('./common/LoadingState.js')
import { getImageURL, getUserImageURL } from './_helpers/images'
const config = require('../config')
import GoogleAnalytics from 'react-native-google-analytics-bridge'
GoogleAnalytics.setTrackerId(config.google_analytics_id)
const windowSize = require('Dimensions').get('window')
const deviceWidth = windowSize.width
const deviceHeight = windowSize.height
import {
Image,
Text,
View,
TouchableOpacity,
TouchableWithoutFeedback,
ScrollView,
StyleSheet,
Platform,
Animated,
PanResponder
} from 'react-native'
let LISTINGS = []
const ListingsViewComponent = React.createClass({
mixins: [TimerMixin],
getInitialState: function () {
return {
listings: [],
dataSource: [],
showSearchIcon: false,
showSidePanel: false,
photo: {},
componentloading: true,
showHeartIcon: [],
startX: 0,
startY: 0,
showWishlistMenu: false,
wishlistCurrentY: 0,
showNewWishlistTextInput: false,
currentRowdata: {},
wishlistOptions: [],
showrecentsearches: false,
isDataLoading: true,
scrolling: false,
_listViewDirtyPressEnabled: true,
scrollAnimationEnd: false,
scrollStates: [],
goingtonextview: false,
heroImageContainerHeight: deviceWidth,
searchbar: new Animated.ValueXY()
}
},
_panListingsResponder: {},
componentWillMount: function () {
this._panListingsResponder = PanResponder.create({
onStartShouldSetPanResponder: (e, g) => {
this.setState({
startX: e.nativeEvent.pageX,
startY: e.nativeEvent.pageY
})
},
onStartShouldSetPanResponderCapture: (e, g) => {
},
onMoveShouldSetPanResponder: (e, g) => {
this.setState({
heroImageContainerHeight: deviceWidth - (e.nativeEvent.pageY - this.state.startY)
})
},
onMoveShouldSetPanResponderCapture: (e, g) => {},
onPanResponderGrant: (e, g) => {},
onPanResponderMove: (e, g) => {
this.setState({
heroImageContainerHeight: deviceWidth - (e.nativeEvent.pageY - this.state.startY)
})
},
onPanResponderTerminationRequest: (e, g) => {
console.log('onPanResponderTerminationRequest', e.nativeEvent)
return false
},
onPanResponderRelease: (e, g) => {
console.log('_onResponderRelease', e.nativeEvent)
},
onPanResponderTerminate: (e, g) => {
console.log('onPanResponderTerminate', e.nativeEvent)
},
onShouldBlockNativeResponder: (e, g) => true
})
let listingsendpoint = 'http://faithstay-staging.herokuapp.com/api/listings'
this.setState({
isDataLoading: true
})
fetch(listingsendpoint)
.then((response) => response.json())
.then((listingsData) => {
const listings = listingsData
LISTINGS = []
LISTINGS.push(THUMB_URLS[0])
LISTINGS.push(THUMB_URLS[1])
LISTINGS.push(THUMB_URLS[2])
listings.map((listing) => {
LISTINGS.push(listing)
})
this.setState({
isDataLoading: false,
listings: LISTINGS
})
})
.catch((error) => {
console.warn(error)
})
},
componentDidMount: function () {
GoogleAnalytics.trackScreenView('Faithstay-Listings-Page')
},
_showSidePanel: function () {
this.setState({
showSidePanel: true
})
},
_closeSidePanel: function () {
this.setState({
showSidePanel: false
})
},
_showRecentSearches: function () {
this.setState({
showrecentsearches: true
})
},
_closeRecentSearches: function () {
this.setState({
showrecentsearches: false
})
},
componentWillReceiveProps: function () {
this.setState({
goingtonextview: false
})
},
getSearchBarStyle: function () {
return [
styles.searchbar, {
top: this.state.heroImageContainerHeight
}
]
},
render: function () {
let sidePanelViewContainer
if (this.state.showSidePanel) {
sidePanelViewContainer = (<SidePanelComponent {...this.props} imageuri={this.state.photo} onClose={this._closeSidePanel} />)
}
let searchIconContainer = <Animated.View style={this.getSearchBarStyle()}>
<TouchableOpacity style={styles.searchBarInner} onPress={this._showRecentSearches}>
<Text style={styles.searchtext}>
{'Where do you want to go?'}
</Text>
<Icon
name={'ios-search'}
size={30}
color={'#cfcfcf'}
style={styles.searchicon}
/>
</TouchableOpacity>
</Animated.View>
if (!this.state.showrecentsearches) {
if (this.state.isDataLoading) {
return (<Loader />)
} else {
return (
<View style={styles.container} {...this._panListingsResponder.panHandlers}>
<View style={[styles.heroImageContainer, { height: this.state.heroImageContainerHeight }]}>
<Image source={{uri: 'https://faithstay-statics.imgix.net/images/homepage_carousel_4.jpg'}} style={[styles.heroImage, { height: this.state.heroImageContainerHeight }]} />
<View style={[styles.scrimLayer, { height: this.state.heroImageContainerHeight }]} />
<View style={styles.logoContainer}>
<Image source={require('../Statics/images/anchor_3x.png')} style={styles.logoImage} />
<Text style={styles.logoText}>{'FaithStay'}</Text>
</View>
<View style={styles.horizontalDivider} />
<View style={styles.betaVersionContainer}>
<Text style={styles.betaVersionText}>{'Beta Version'}</Text>
</View>
<View style={[styles.pageTitleContainer, {top: this.state.heroImageContainerHeight - 85}]}>
<Text style={styles.pageTitle}>{'Home'}</Text>
</View>
<View style={[styles.movableScrim, {backgroundColor: `rgba(0, 0, 0, ${(deviceWidth - this.state.heroImageContainerHeight) / deviceWidth})`}]} />
</View>
{searchIconContainer}
<ScrollView style={styles.listView}>
{this.getListingsView()}
</ScrollView>
{sidePanelViewContainer}
</View>
)
}
}
return (<RecentSearches {...this.props} closeRecentSearches={this._closeRecentSearches} />)
},
_gotoUserProfilePage: function (user) {
this.props.navigator.push({
id: 15,
passProps: {
user
}
})
},
getListingsView: function () {
let listings = this.state.listings
const listingsArray = []
listings.map((listing, i) => {
let currentlisting = listing
let type = currentlisting.type
if (type !== 'NOT_A_LISTING') {
let imgSource = {
uri: getImageURL(currentlisting.images[0])
}
let profileimg = {
uri: getUserImageURL(currentlisting.host)
}
let title = currentlisting.title
let reviews = '18'
let address_values = currentlisting.google_place.formatted_address ? currentlisting.google_place.formatted_address.split(',') : []
let listing_address = {}
if (address_values.length > 0) {
listing_address = {
country: address_values[address_values.length - 1].trim(),
state: address_values[address_values.length - 2].trim(),
city: address_values[address_values.length - 3].trim()
}
}
let city = listing_address.city + ', ' + listing_address.state
let baseprice = currentlisting.base_price ? '$' + currentlisting.base_price : '0'
listingsArray.push(<View>
<TouchableWithoutFeedback onPress={() => this._pressRow(currentlisting)}>
<View>
<View style={styles.row}>
<Image style={styles.thumb} source={imgSource} >
<View style={styles.priceconatiner}>
<Text style={styles.pricetext}>{baseprice}</Text>
</View>
</Image>
</View>
<TouchableOpacity style={styles.profileImgContainer} onPress={() => this._gotoUserProfilePage(currentlisting.host)}>
<Image style={styles.profileimg} source={profileimg} />
</TouchableOpacity>
<View style={styles.listingtextcontainer}>
<Text style={styles.listingtexttitle}>{title}</Text>
<Text style={styles.listingtexttdescription}>{'Entire Home' + ' - ' + reviews + ' Reviews' + ' - ' + city}</Text>
</View>
</View>
</TouchableWithoutFeedback>
</View>)
} else {
let listing_title = listing.title
let listing_description = listing.description
let imageuri = listing.image;
listingsArray.push(<View><TouchableWithoutFeedback onPress={() => this._pressNonListingRow(currentlisting)}>
<View>
<View style={styles.rowNotListing}>
<Image style={styles.thumbNotListing} source={{uri: imageuri}}>
<View style={styles.thumbNotListing, {position: 'absolute', left:0, top: 0, right:0, bottom:0, backgroundColor: 'rgba(0,0,0,0.2)'}} >
</View>
<View style={styles.thumbNotListingSubContainer}>
<Text style={styles.listingtitle_notlisting}>{listing_title}</Text>
<Text style={styles.listingdescription_notlisting}>{listing_description}</Text>
</View>
</Image>
</View>
</View>
</TouchableWithoutFeedback>
</View>)
}
})
return listingsArray
},
_pressRow: function (listing) {
this.props.navigator.push({
id: 4,
passProps: {
listingdata: listing
}
})
},
_pressNonListingRow: function (listing) {
this.props.navigator.push({
id: 9,
passProps: {
filterData: listing
}
})
}
})
const paddingHorizontal = 15
const paddingVertical = 10
const distanceBetweenIcons = (deviceWidth - 115) / 3
const statusBarHeight = (Platform.OS === 'ios') ? 20 : 0
const isAndroid = Platform.OS === 'android'
const styles = StyleSheet.create({
listView: {
height: deviceHeight - 70,
top: (Platform.OS === 'ios') ? 40 : 0,
left: 0
},
scrimLayer: {
position: 'absolute',
top: 0,
left: 0,
width: deviceWidth,
height: deviceWidth,
backgroundColor: 'rgba(0, 0, 0, 0.2)'
},
movableScrim: {
position: 'absolute',
top: 0,
left: 0,
width: deviceWidth,
height: deviceWidth
},
container: {
flex: 1,
paddingTop: statusBarHeight,
width: deviceWidth,
height: deviceHeight
},
row: {
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
width: deviceWidth,
height: deviceHeight / 2
},
separator: {
height: 1,
backgroundColor: '#CCCCCC'
},
thumb: {
width: deviceWidth,
height: deviceHeight / 2 - 80
},
thumbNotListing: {
width: deviceWidth,
height: deviceHeight / 2,
justifyContent: 'center'
},
thumbNotListingSubContainer: {
alignSelf: 'center',
justifyContent: 'center'
},
listingtitle_notlisting: {
textAlign: 'center',
alignSelf: 'center',
fontSize: 24,
fontWeight: 'bold',
color: '#ffffff'
},
listingdescription_notlisting: {
textAlign: 'center',
alignSelf: 'center',
fontSize: 16,
marginTop: 10,
color: '#ffffff'
},
text: {
flex: 1,
},
tabbar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
width: deviceWidth,
height: 49,
backgroundColor: '#f5f5f5',
justifyContent: 'space-between',
borderTopWidth: 1,
borderTopColor: '#dce0e0'
},
searchbar: {
width: deviceWidth - 30,
height: 50,
left: 15,
top: deviceWidth - 5,
position: 'absolute',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
shadowOpacity: 0.5
},
searchBarInner: {
width: deviceWidth - 30,
height: 50,
justifyContent: 'center',
backgroundColor: '#f5f5f5',
shadowOpacity: 0.5
},
searchonlyicon: {
width: 50,
height: 50,
borderRadius: 25,
left: 20,
top: 40,
position: 'absolute',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
shadowOpacity: 0.5
},
searchtext: {
width: 160,
position: 'absolute',
fontSize: 15,
color: '#565a5c',
left: (deviceWidth - 30) / 2 - 80,
top: 15,
fontFamily: 'RobotoCondensed-Regular'
},
searchicon: {
width: 30,
height: 30,
position: 'absolute',
top: 8,
left: 12
},
homeicon: {
width: 30,
height: 30,
position: 'absolute',
top: paddingVertical - 2,
left: paddingHorizontal,
justifyContent: 'center',
},
hearticon: {
width: 40,
height: 30,
position: 'absolute',
top: paddingVertical,
justifyContent: 'center',
left: distanceBetweenIcons
},
emailicon: {
width: 45,
height: 30,
position: 'absolute',
top: paddingVertical,
justifyContent: 'center',
left: 2 * distanceBetweenIcons
},
bagicon: {
width: 35,
height: 20,
position: 'absolute',
top: paddingVertical + 6,
justifyContent: 'center',
left: 3 * distanceBetweenIcons
},
personicon: {
width: 30,
height: 30,
position: 'absolute',
top: paddingVertical,
justifyContent: 'center',
right: paddingHorizontal
},
priceconatiner: {
position: 'absolute',
top: deviceHeight / 2 - 150,
left: 0,
width: 60,
height: 40,
backgroundColor: 'rgba(60,63,64,0.9)',
justifyContent: 'center'
},
pricetext: {
fontSize: 20,
color: '#fff',
fontWeight: 'bold',
textAlign: 'center',
width: 60,
fontFamily: 'HelveticaNeue'
},
profileImgContainer: {
position: 'absolute',
top: deviceHeight / 2 - 108,
right: isAndroid ? 0 : 20, // NOTE: add to width, vs pushing it with position values
width: isAndroid ? 70 : 50, // NOTE: on android, the view must be as big as the image, otherwise the image will be cut off
height: 50,
paddingLeft: paddingHorizontal,
justifyContent: 'center'
},
profileimg: {
width: 50,
height: 50,
borderRadius: 25
},
listingtextcontainer: {
position: 'absolute',
top: deviceHeight / 2 - 70,
left: paddingHorizontal,
justifyContent: 'space-between',
height: 50
},
listingtexttitle: {
paddingTop: 5,
fontSize: 16,
fontFamily: 'HelveticaNeue',
color: '#565a5c',
fontWeight: 'bold'
},
listingtexttdescription: {
fontSize: 14,
fontFamily: 'HelveticaNeue',
color: '#82888a',
paddingBottom: 5
},
wishlistIcon: {
position: 'absolute',
right: 20,
top: 20
},
hearticonwishlist: {
width: 30,
height: 30
},
wishlistScrollView: {
position: 'absolute',
right: 20,
width: deviceWidth - 60,
height: 80,
backgroundColor: '#fff'
},
scrollRow: {
width: 180,
height: 40,
justifyContent: 'center',
padding: 5,
borderBottomWidth: 1,
borderBottomColor: '#f5f5f5'
},
wishlistScrollViewContainer: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
width: deviceWidth,
height: deviceHeight,
backgroundColor: 'rgba(255,255,255,0.1)'
},
touchableScrollViewContainer: {
width: deviceWidth,
height: deviceHeight,
position: 'absolute',
top: 0,
bottom: 0,
left: 0
},
fontWishlistScroller: {
color: '#565a5c',
fontSize: 14
},
rowNotListing: {
flexDirection: 'row',
justifyContent: 'center',
width: deviceWidth,
height: deviceHeight / 2
},
heroImageContainer: {
width: deviceWidth,
height: deviceWidth
},
heroImage: {
width: deviceWidth,
height: deviceWidth
},
logoContainer: {
width: 120,
position: 'absolute',
left: (deviceWidth / 2) - 60,
top: 19,
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: 'transparent'
},
logoImage: {
width: 18,
height: 30,
top: 3
},
logoText: {
fontFamily: 'RobotoCondensed-Regular',
fontSize: 25,
fontWeight: '400',
textAlign: 'center',
color: '#fffff0',
marginLeft: 7.7
},
horizontalDivider: {
width: 32,
position: 'absolute',
left: deviceWidth / 2 - 16,
top: 59,
borderBottomWidth: 1,
borderColor: '#ffffff'
},
betaVersionContainer: {
width: 120,
position: 'absolute',
left: deviceWidth / 2 - 60,
top: 79,
justifyContent: 'center',
backgroundColor: 'transparent'
},
betaVersionText: {
fontFamily: 'RobotoCondensed-Regular',
fontSize: 14,
fontStyle: 'italic',
fontWeight: '300',
textAlign: 'center',
color: '#ffffff',
alignSelf: 'center'
},
pageTitleContainer: {
position: 'absolute',
top: deviceWidth - 85,
left: 20,
backgroundColor: 'transparent'
},
pageTitle: {
fontSize: 34,
fontFamily: 'RobotoCondensed-Bold',
color: '#ffffff'
}
})
module.exports = ListingsViewComponent
I got it working properly by using onPanResponderEnd instead of onPanResponderRelease.
Also if we still want to use onPanResponderRelease then we should allow termination request by:
onPanResponderTerminationRequest: () => true
You need to make sure the following handlers return true
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
The only different between onStart... and onMove... is that the PanResponder will be created when you start rendering the component for onStart..., it will be created (lazy) when user start tab or move for onMove.
On android side, you may still find that onPanResponderRelease will not be triggered, an issue reported here as well https://github.com/facebook/react-native/issues/9447
I ended up using onPanResponderTerminate to handle this case. Hopefully you can get more insights about it.