2016-08-28 10 views
0

ViewでPanResponderを使用しようとしています。 onStartShouldSetPanResponderonMoveShouldSetPanResponderではなく、onPanResponderMove,とonPanResponderReleaseはまったくトリガーされません。私は、ネイティブのバージョンを反応させ、反応します:onPanResponderReleaseがトリガーされていません

以下
"react": "^15.2.1", 
"react-native": "^0.30.0", 

は、あなたが以下のハンドラが真

 onStartShouldSetPanResponder: (evt, gestureState) => true, 
     onStartShouldSetPanResponderCapture: (evt, gestureState) => true, 
     onMoveShouldSetPanResponder: (evt, gestureState) => true, 
     onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, 

返すことを確認する必要があり、コード

'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

+0

私はこの問題を解決しました。 PanResponderのすべてのハンドラにtrueを返す必要があります。 –

答えて

0

ですonStart...とd onMove...は、onStart...のコンポーネントのレンダリングを開始すると、PanResponderが作成されることになります。ユーザー開始タブまたはonMoveの移動時に作成されます(遅延)。アンドロイド側で

、あなたはまだだけでなく、onPanResponderReleaseがトリガされないことをここに報告された問題を見つけることができhttps://github.com/facebook/react-native/issues/9447

私はこのケースを処理するためにonPanResponderTerminateを使用して終了。うまくいけば、あなたはそれについてより多くの洞察を得ることができます。

関連する問題