2016-12-24 362 views
0

我有一個視圖,我想縮小到右下角,並在底部和右側留有一些邊距/填充。React Native:動畫縮放,但縮小到角落而不是中心

我能夠縮小它,但縮小到中心位置。所述video元件是所述一個收縮:

enter image description here

import React, { Component } from 'react'; 
import { 
    AppRegistry, 
    StyleSheet, 
    View, 
    PanResponder, 
    Animated, 
    Dimensions, 
} from 'react-native'; 

const styles = StyleSheet.create({ 
    container: { 
    flex: 1, 
    alignSelf: 'stretch', 
    backgroundColor: '#000000', 
    }, 
    overlay: { 
    flex: 1, 
    alignSelf: 'stretch', 
    backgroundColor: '#0000ff', 
    opacity: 0.5, 
    }, 
    video: { 
    position: 'absolute', 
    backgroundColor: '#00ff00', 
    bottom: 0, 
    right: 0, 
    width: Dimensions.get("window").width, 
    height: Dimensions.get("window").height, 
    padding: 10, 
    } 
}); 

function clamp(value, min, max) { 
    return min < max 
    ? (value < min ? min : value > max ? max : value) 
    : (value < max ? max : value > min ? min : value) 
} 

export default class EdmundMobile extends Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     pan: new Animated.ValueXY(), 
     scale: new Animated.Value(1), 
    }; 
    } 

    componentWillMount() { 
    this._panResponder = PanResponder.create({ 
     onMoveShouldSetResponderCapture:() => true, 
     onMoveShouldSetPanResponderCapture:() => true, 

     onPanResponderGrant: (e, gestureState) => { 
     this.state.pan.setOffset({x: this.state.pan.x._value, y: 0}); 
     this.state.pan.setValue({x: 0, y: 0}); 
     }, 

     onPanResponderMove: (e, gestureState) => { 
     let width = Dimensions.get("window").width; 
     let difference = Math.abs((this.state.pan.x._value + width)/width); 
     if (gestureState.dx < 0) { 
      this.setState({ scale: new Animated.Value(difference) }); 
      return Animated.event([ 
      null, {dx: this.state.pan.x, dy: 0} 
      ])(e, gestureState); 
     } 
     }, 

     onPanResponderRelease: (e, {vx, vy}) => { 
     this.state.pan.flattenOffset(); 
     if (vx >= 0) { 
      velocity = clamp(vx, 3, 5); 
     } else if (vx < 0) { 
      velocity = clamp(vx * -1, 3, 5) * -1; 
     } 

     if (Math.abs(this.state.pan.x._value) > 200) { 
      Animated.spring(this.state.pan, { 
      toValue: {x: -Dimensions.get("window").width, y: 0}, 
      friction: 4 
      }).start() 
      Animated.spring(this.state.scale, { 
      toValue: 0.2, 
      friction: 4 
      }).start() 
     } else { 
      Animated.timing(this.state.pan, { 
      toValue: {x: 0, y: 0}, 
      friction: 4 
      }).start() 
      Animated.spring(this.state.scale, { 
      toValue: 1, 
      friction: 10 
      }).start() 
     } 
     } 
    }); 
    } 

    render() { 
    let { pan, scale } = this.state; 
    let translateX = pan.x; 
    let swipeStyles = {transform: [{translateX}]}; 
    let videoScale = scale 
    let localVideoStyles = {transform: [{scale: videoScale}]}; 
    return (
     <View style={styles.container}> 
     <Animated.View style={[styles.video, localVideoStyles]}></Animated.View> 
     <Animated.View style={[styles.overlay, swipeStyles]} {...this._panResponder.panHandlers}> 
     </Animated.View> 
     </View> 
    ); 
    } 
} 

AppRegistry.registerComponent('EdmundMobile',() => EdmundMobile); 
+0

嗨再次讓你找到答案了嗎? – Codesingh

+0

對於其他問題是的,我通過添加'Animated.spring'來自己想出它。不是這一個雖然 – Edmund

+0

添加flex:1爲視頻視圖 – Codesingh

回答

1

確定我想出一個解決方案。有點動手,但我認爲它提供了我需要的所有定製。

因此,我不是通過轉換比例來將width, height, bottom, top樣式附加到狀態,而是通過響應pan響應者的內容來更改它們。

import React, { Component } from 'react'; 
import { 
    AppRegistry, 
    StyleSheet, 
    View, 
    PanResponder, 
    Animated, 
    Dimensions, 
} from 'react-native'; 

const styles = StyleSheet.create({ 
    container: { 
    flex: 1, 
    alignSelf: 'stretch', 
    backgroundColor: '#000000', 
    }, 
    overlay: { 
    flex: 1, 
    alignSelf: 'stretch', 
    backgroundColor: '#0000ff', 
    opacity: 0.5, 
    }, 
    video: { 
    position: 'absolute', 
    backgroundColor: '#00ff00', 
    } 
}); 

function clamp(value, min, max) { 
    return min < max 
    ? (value < min ? min : value > max ? max : value) 
    : (value < max ? max : value > min ? min : value) 
} 

const MIN_VIDEO_WIDTH = 120; 
const MIN_VIDEO_HEIGHT = 180; 

export default class EdmundMobile extends Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     pan: new Animated.ValueXY(), 
     width: new Animated.Value(Dimensions.get("window").width), 
     height: new Animated.Value(Dimensions.get("window").height), 
     bottom: new Animated.Value(0), 
     right: new Animated.Value(0), 
    }; 
    } 

    componentWillMount() { 
    this._panResponder = PanResponder.create({ 
     onMoveShouldSetResponderCapture:() => true, 
     onMoveShouldSetPanResponderCapture:() => true, 

     onPanResponderGrant: (e, gestureState) => { 
     this.state.pan.setOffset({x: this.state.pan.x._value, y: 0}); 
     this.state.pan.setValue({x: 0, y: 0}); 
     }, 

     onPanResponderMove: (e, gestureState) => { 
     let width = Dimensions.get("window").width; 
     let difference = Math.abs((this.state.pan.x._value + width)/width); 
     console.log(difference); 
     if (gestureState.dx < 0) { 
      const newVideoHeight = difference * Dimensions.get("window").height; 
      const newVideoWidth = difference * Dimensions.get("window").width; 
      if (newVideoWidth > MIN_VIDEO_WIDTH) { 
      this.setState({ 
       width: new Animated.Value(newVideoWidth), 
      }); 
      } 
      if (newVideoHeight > MIN_VIDEO_HEIGHT) { 
      this.setState({ 
       height: new Animated.Value(newVideoHeight), 
      }); 
      } 

      this.setState({ 
      bottom: new Animated.Value((1- difference) * 20), 
      right: new Animated.Value((1 - difference) * 20), 
      }); 

      return Animated.event([ 
      null, {dx: this.state.pan.x, dy: 0} 
      ])(e, gestureState); 
     } 
     }, 

     onPanResponderRelease: (e, {vx, vy}) => { 
     this.state.pan.flattenOffset(); 
     if (vx >= 0) { 
      velocity = clamp(vx, 3, 5); 
     } else if (vx < 0) { 
      velocity = clamp(vx * -1, 3, 5) * -1; 
     } 

     if (Math.abs(this.state.pan.x._value) > 200) { 
      Animated.spring(this.state.pan, { 
      toValue: {x: -Dimensions.get("window").width, y: 0}, 
      friction: 4 
      }).start() 
      Animated.spring(this.state.width, { 
      toValue: MIN_VIDEO_WIDTH, 
      friction: 4 
      }).start() 
      Animated.spring(this.state.height, { 
      toValue: MIN_VIDEO_HEIGHT, 
      friction: 4 
      }).start() 
      Animated.timing(this.state.bottom, { 
      toValue: 20, 
      }).start() 
      Animated.timing(this.state.right, { 
      toValue: 20, 
      }).start() 
     } else { 
      Animated.timing(this.state.pan, { 
      toValue: {x: 0, y: 0}, 
      }).start() 
      Animated.timing(this.state.width, { 
      toValue: Dimensions.get("window").width, 
      friction: 4 
      }).start() 
      Animated.timing(this.state.height, { 
      toValue: Dimensions.get("window").height, 
      friction: 4 
      }).start() 
      Animated.timing(this.state.bottom, { 
      toValue: 0, 
      }).start() 
      Animated.timing(this.state.right, { 
      toValue: 0, 
      }).start() 
     } 
     } 
    }); 
    } 

    render() { 
    let { pan, width, height, bottom, right } = this.state; 
    let translateX = pan.x; 
    let swipeStyles = {transform: [{translateX}]}; 
    let videoStyles = { 
     width: width, 
     height: height, 
     bottom: bottom, 
     right: right, 
    }; 
    return (
     <View style={styles.container}> 
     <Animated.View style={[styles.video, videoStyles]}></Animated.View> 
     <Animated.View style={[styles.overlay, swipeStyles]} {...this._panResponder.panHandlers}> 
     </Animated.View> 
     </View> 
    ); 
    } 
} 

AppRegistry.registerComponent('EdmundMobile',() => EdmundMobile); 

enter image description here

+0

酷男的任何邏輯? – Codesingh

+0

正是我上面寫的關於改變高度/寬度/底部/右邊 – Edmund

+0

接下來是什麼? – Codesingh