Android scrollview doesnt scroll and cuts off text - react-native

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'
},

Related

react native why my absolute view is not showing all only the half?

why my purple absolute view is not showing all, only the half ?
look at the image
Code:
CardView:
const { width } = Dimensions.get('window');
const MAX_NAME_WIDTH = width / 2 - 48;
const CARD_WIDTH = width * 0.45;
const UserCardAdvanced = ({ user_id, username, profile_image, followingShops, is_verification, isD, stars, onPress, onPressReviews, onPressFollow }: IUserCardAdvanced) => {
return (
<Pressable onPress={onPress} style={s.card}>
{ isD &&
<PurpleNotice />
}
<Image source={{uri: profile_image}} resizeMode='contain' style={s.profile_image} />
<View style={s.starContainer}>
<Stars
star_filled={stars?.fill}
disabled
is_all
size={15}
onPressAll={onPressReviews}
/>
<Text style={s.reviewTotal}>{stars?.total_reviews}</Text>
</View>
<View style={s.nameContainer}>
<NameWithVerification
name={username}
is_verification={is_verification}
nameStyle={s.nameStyle}
/>
</View>
<FollowBtn
onPress={onPressFollow}
is_followed={false}
size={24}
/>
</Pressable>
)
}
const s = StyleSheet.create({
card: {
padding: 12,
backgroundColor: '#fff',
borderRadius: 8,
elevation: 3,
margin: 6,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 20,
zIndex: 99921,
width: CARD_WIDTH
},
starContainer: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 8
},
reviewTotal: {
fontFamily: globalStyles.font_regular,
color: '#333',
marginLeft: 4
},
nameContainer: {
marginVertical: 8
},
nameStyle: {
color: '#333',
fontSize: 13,
maxWidth: MAX_NAME_WIDTH
},
profile_image: {
height: 84,
width: 84,
borderRadius: 50,
},
username: {
fontFamily: globalStyles.font_regular,
color: '#555',
marginTop: 12,
textAlign: 'center'
}
})
Purple Notice
const PurpleNotice = (isD: isD) => {
return (
<View style={s.view}>
<Text style={s.text}>TESTTESTETS</Text>
</View>
)
}
const s = StyleSheet.create({
view: {
padding: 2,
paddingHorizontal: 10,
backgroundColor: globalStyles.globalColor,
borderRadius: 6,
position: 'absolute',
top: -10,
left: 0,
zIndex: 99999
},
text: {
fontFamily: globalStyles.font_light,
color: '#fff',
fontSize: 11,
textTransform: 'uppercase',
textShadowColor: '#fff',
textShadowOffset: {
height: 2,
width: 2
}
}
});
I dont know what I am doing wrong i am very thankful for your help!!
.........................................
.........................................
.........................................
.........................................
.........................................
You can add zIndex={1} to that purple view.
use right:0 in style
const s = StyleSheet.create({
view: {
padding: 2,
paddingHorizontal: 10,
backgroundColor: globalStyles.globalColor,
borderRadius: 6,
position: 'absolute',
top: -10,
left: 0,
right:0, //use this also
zIndex: 99999
},
text: {
fontFamily: globalStyles.font_light,
color: '#fff',
fontSize: 11,
textTransform: 'uppercase',
textShadowColor: '#fff',
textShadowOffset: {
height: 2,
width: 2
}
}
});

I want to get individual access from flatlist when I press Accept or decline

need help if I press on accept button then simultaneously all requests getting accepted but I should be accepted as individually
I have given two screenshots of my output.
import 'react-native-gesture-handler';
import React, { useState } from 'react';
// import { StyleSheet, Linking, Text, View, Image, TextInput, Alert, TouchableOpacity, ScrollView, ImageBackground, FlatList, SafeAreaView, StatusBar} from 'react-native';
import { StatusBar, FlatList, Image, Animated, Text, View, Dimensions, StyleSheet, TouchableOpacity, Easing, SafeAreaViewBase, SafeAreaView ,Button} from 'react-native';
import {
Avatar
} from 'react-native-paper';
import faker from 'faker';
import { Card, CardTitle, CardContent, CardAction, CardButton, CardImage } from 'react-native-material-cards'
import './global';
export function notificationscreen({ navigation }) {
faker.seed(10);
const DATA = [...Array(30).keys()].map((_, i) => {
return {
key: faker.random.uuid(),
image: `https://randomuser.me/api/portraits/${faker.helpers.randomize(['women', 'men'])}/${faker.random.number(60)}.jpg`,
name:faker.name.findName(),
fname: faker.name.firstName(),
sname: faker.name.lastName(),
// jobTitle: faker.name.jobTitle(),
// email: faker.internet.email(),
};
});
const SPACING = 20;
const AVATAR_SIZE = 55;
const [acpt, accept] = useState(false)
const [rjct, reject] = useState(false)
const stat = ({ acpt, rjct,item }) => {
let content
if (acpt) {
content = <Text style={{ fontSize: 24, color: 'red' }}>Error</Text>
} else if (rjct) {
content = <Text style={{ fontSize: 24, color: 'gray' }}>Loading...</Text>
} else {
content = (
<View>
<Text style={{ fontSize: 60 }}>{title}</Text>
</View>
)
}
return <View style={{ padding: 24 }}>{content}</View>
}
return (
<View style={{flex: 1, backgroundColor: '#fff'}}>
<FlatList
data={DATA}
keyExtractor= {item=> item.key}
contentContainerStyle={{
padding: 8,
}}
renderItem = {({item, index}) =>{
return <View style={[styles.FlatList,acpt||rjct ? styles.whiteFlatlist:''
]}>
<View style={{flexDirection: 'row'}}>
<Image
source={{uri: item.image}}
style={{width: AVATAR_SIZE, height: AVATAR_SIZE, borderRadius: AVATAR_SIZE, marginRight:SPACING/2}}
/>
<View>
{[rjct ? <Text style={styles.declinemessage}> You have declined {item.fname}'s {"\n"} connection request. If you changed {"\n"} your mind, send them a connection {"\n"}request through their profile.
</Text>:[acpt? <Text style={styles.message}>{item.fname} is now your connection.{"\n"}Click to chat with them right now!</Text>: <Text style={styles.message}>{item.name} has sent you a {"\n"}connection request.</Text>]
]}</View>
</View>
<View style={{flexDirection:'row'}}>
<TouchableOpacity
style={[rjct ? styles.none :[acpt ? styles.bigButton : styles.buttonColorAccept]]}
onPress={accept}>
<View>
{[acpt ? <Text style={styles.buttonText}> Find more connections like {item.fname}</Text>: [rjct? null:<Text style={styles.buttonText}>Accept</Text>]]}
</View>
</TouchableOpacity>
<TouchableOpacity
style={[rjct||acpt ? styles.none :styles.buttonColorDecline ]}
onPress={reject}
>
<Text style={styles.buttonText}>{[rjct||acpt ? "" :"Decline" ] }</Text>
</TouchableOpacity>
</View>
</View>
}}
/>
</View>
)
}
const styles = StyleSheet.create({
FlatList:{
padding: 25,
marginBottom: 7,
backgroundColor:"rgba(0, 0, 0, 0.1)",
borderRadius: 10,
shadowColor:"0px 4px 10px 0px rgba(0, 0, 0, 0.25)",
shadowOffset:{
width: 0,
height: 10
},
shadowOpacity: .3,
shadowRadius: 20,
},
button:{
borderRadius: 20,
// backgroundColor: "#ffad2f",
width: 105,
height: 32,
shadowColor: "0px 4px 10px 0px rgba(0, 0, 0, 0.2)",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.32,
shadowRadius: 5.46,
elevation: 9,
// marginLeft:55
marginTop:15
},
none:{
},
buttonText:{
fontWeight: "900",
fontSize: 18,
color: "#FFFFFF",
width: "auto", /* 50px */
height: "auto", /* 19px */
overflow: "visible",
fontFamily: "JosefinSans-Regular",
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
marginTop:1
},
buttonColorAccept:{
backgroundColor:"#ffad2f",
marginLeft: 70,
borderRadius: 20,
// backgroundColor: "#ffad2f",
width: 105,
height: 32,
shadowColor: "0px 4px 10px 0px rgba(0, 0, 0, 0.2)",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.32,
shadowRadius: 5.46,
elevation: 9,
// marginLeft:55
marginTop:15
},
buttonColorDecline:
{
backgroundColor: "#e71d36",
marginLeft: 15,
borderRadius: 20,
// backgroundColor: "#ffad2f",
width: 105,
height: 32,
shadowColor: "0px 4px 10px 0px rgba(0, 0, 0, 0.2)",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.32,
shadowRadius: 5.46,
elevation: 9,
// marginLeft:55
marginTop:15
},
bigButton:{
width:300,
height:30,
backgroundColor:"#ffad2f",
borderRadius:25,
marginLeft:50,
shadowColor: "0px 4px 10px 0px rgba(0, 0, 0, 0.2)",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.32,
shadowRadius: 5.46,
marginLeft:19,
elevation: 9,
marginTop: 15,
textAlign: 'center',
// justifyContent: 'center'
},
message:
{
fontWeight: '900',
fontFamily:'JosefinSans-Regular',
fontSize: 16,
marginLeft: -5,
width: 300,
marginLeft:10,
marginTop: 7,
lineHeight:21.5,
// lineHeight:25,
textAlign:"left",
fontStyle:"normal",
},
declinemessage:{
fontWeight: '900',
fontFamily:'JosefinSans-Regular',
fontSize: 15,
fontWeight:"900",
marginLeft: 5,
marginTop: 7,
lineHeight:20,
textAlign:"left",
fontStyle:"normal",
letterSpacing: .05
},
whiteFlatlist:{
backgroundColor:"#ffffff",
padding: 25,
marginBottom: 7,
borderRadius: 10,
shadowColor:"0px 4px 10px 0px rgba(0, 0, 0, 0.25)",
shadowOffset:{
width: 0,
height: 10
},
shadowOpacity: .3,
shadowRadius: 20,
elevation:9
}
});
From what I understand, you want each list item to have its on accept and reject variable. You have declared the accept and reject in the parent component of the FlatList.
I think you'd want to move these variables into the renderItem so that each item of the list has its own accept/reject state.
I'd also suggest you give your state setters a name that clearly states its a setter.
const [accept, setAccept] = useState(false)
// just from reading the variable names you know which is the setter
const [acpt, accept] = useState(false)
// here the naming is vague and finding the setter requires
// referencing the declaration

Unable to create curved view in react-native

<View style={{
width: window.width,
height: window.width / 7,
backgroundColor: colors.white}}>
<View style={{
backgroundColor: colors.primary,
borderBottomLeftRadius: 80,
borderBottomRightRadius: 80,
height: window.width / 7,
width: window.width,
flex: 1,
}}>
<View style={{
backgroundColor: '#000',
height: window.width / 7,
width: window.width / 3,
borderRadius: 100,
alignSelf: 'center',
position: 'absolute',
bottom: 0,
overflow: 'hidden',
}}>
</View>
</View>
Check the below solution
import * as React from "react";
import { View, StyleSheet } from "react-native";
export default function Curve() {
return (
<View style={{ margin: 50 }}>
<View style={styles.squreStyle} />
<View style={styles.arcStyle} />
</View>
);
}
const styles = StyleSheet.create({
squreStyle: {
width: "100%",
height: 75,
borderRadius: 12,
backgroundColor: "black",
},
arcStyle: {
width: "20%",
height: 70,
position: "absolute",
bottom: -25,
left: "40%",
borderRadius: 35,
backgroundColor: "black",
transform: [{ scaleX: 5 }, { scaleY: 1 }],
},
});
Sample image of the working code
Edit - Modified according to the requirements of Scroll & Write content inside header.
import * as React from "react";
import { View, StyleSheet, Text, ScrollView } from "react-native";
export default function Curve() {
return (
<ScrollView>
<View style={{marginVertical: 50}}>
<View style={styles.squreStyle}>
<Text style={{ color: "white", textAlign: "center" }}>Sample Header</Text>
</View>
<View style={styles.arcStyle} />
</View>
<View style={{ height: 500, backgroundColor: "green" }} />
<View style={{ height: 500, backgroundColor: "yellow" }} />
</ScrollView>
);
}
const styles = StyleSheet.create({
squreStyle: {
width: "100%",
height: 75,
borderRadius: 12,
backgroundColor: "black",
zIndex: 1,
},
arcStyle: {
width: "20%",
height: 70,
position: "absolute",
bottom: -25,
left: "40%",
borderRadius: 35,
backgroundColor: "black",
transform: [{ scaleX: 5 }, { scaleY: 1 }],
},
});
Hope this helps you. Feel free for doubts.
The thing is react native doesnt let us add border radius to sides unless of same height and width so that it can be a circle. What i did is exactly created a circle and pushed it upwards with top so that it seems like this. You can control the curvature by fixing the height and width and make it dynamic so that in every screen it looks the same.
Please check code below and also the expo snack:
expo-snack
Code:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.newD}></View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
newD:{
height:500,
width:500,
backgroundColor:'red',
marginLeft:-70,
borderRadius:500,
top:-280
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
Hope it helps. feel free for doubts
You can use react-native-canvas for draw it
import {Dimensions} from 'react-native';
import Canvas from 'react-native-canvas';
const {width} = Dimensions.get('window');
...
drawArc = (canvas) => {
const height = 150;
const ctx = canvas.getContext('2d');
context.moveTo(0,height/2);
context.quadraticCurveTo(width/2, height, width, height/2);
};
...
<Canvas
ref={canvas => drawArc(canvas) />
...
Hope this helps to you.

React Native Shadow Styles not working on View Component

I was wondering if anyone knew anyway to make the shadow styles on a react native view component work. I scavenged all of the web and could not find any solutions. My code is shown below:
//Stylesheet code:
...
profileImage: {
width: 170,
height: 170,
overflow: "hidden",
marginLeft: (Dimensions.get('window').width/2) - 85,
marginTop: 30,
borderRadius: 170,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 5
},
...
//View component:
<View style={styles.profileImage}>
<Image source={require("../assets/images/temporaryProfilePicture.jpg")} style={styles.image} resizeMode="cover"></Image>
</View>
...
Any and all help would be largely appreciated. Thank you in advance!
This is what ive achieved with your code and link to it :expo-snack :
import * as React from 'react';
import { Text, View, StyleSheet,Dimensions ,Image} from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Image source={{uri:'https://source.unsplash.com/random'}} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
width: 170,
height: 170,
overflow: "hidden",
marginLeft: (Dimensions.get('window').width/2) - 85,
marginTop: 30,
borderRadius: 170,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 5
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});

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.