前提・実現したいこと
readt native の PanGestureHandler を使って Image を動かそうとしています。
Imageは無限に動かせるわけではなく範囲は決まっており、もしその範囲を超えて動かしていた場合、
アニメーションしながら範囲内までイメージを戻したいと思っています。
発生している問題・エラーメッセージ
scale などの Animated.Value ならば interpolate を使うといいんだろうなというのはわかるのですが、
Panの場合、
typescript
1var _translateX = this.currentX; 2var _translateY = this.currentY; 3 4_translateX.setOffset(this._lastX); 5_translateX.setValue(0); 6_translateY.setOffset(this._lastY); 7_translateY.setValue(0); 8 9this.currentX = _translateX; 10this.currentY = _translateY;
といったように Offset を指定する必要があり、この Offset を interpolate する方法がわかりません。
該当のソースコード
reactnative
1 2_handlePanGestureStateChange = (e: PanGestureHandlerGestureEvent) => { 3 this._lastX += e.nativeEvent.translationX; 4 this._lastY += e.nativeEvent.translationY; 5 6 // ここで生の入力値を作成 7 var lastX = this.currentX; 8 var lastY = this.currentY; 9 10 lastX.setOffset(this._lastX); 11 lastX.setValue(0); 12 lastY.setOffset(this._lastY); 13 lastY.setValue(0); 14 15 // 生の値 = lastX, lastY 16 17 // ここでcrop済みの値を作成 18 let minX = (this.state.width / 2 / this._lastScale - this.state.originalWidth / 2) * this._lastScale; 19 let maxX = (this.state.originalWidth - this.state.width / 2 / this._lastScale - this.state.originalWidth / 2) * this._lastScale; 20 let minY = (this.state.height / 2 / this._lastScale - this.state.originalHeight / 2) * this._lastScale; 21 let maxY = (this.state.originalHeight - this.state.height / 2 / this._lastScale - this.state.originalHeight / 2) * this._lastScale; 22 23 this._lastX = Math.max(Math.min(this._lastX, maxX), minX); 24 this._lastY = Math.max(Math.min(this._lastY, maxY), minY); 25 26 var cropedX = this.currentX; 27 var cropedY = this.currentY; 28 29 cropedX.setOffset(this._lastX); 30 cropedX.setValue(0); 31 cropedY.setOffset(this._lastY); 32 cropedY.setValue(0); 33 34 // crop済みの値 = cropedX, cropedY 35 36 this.currentX = // ここで lastX から cropedX にアニメーションさせたい 37 this.currentY = // ここで lastY から cropedY にアニメーションさせたい 38};
reactnative
1render() { 2 return ( 3 <View style={[this.props.style, {borderColor: 'red', borderWidth: 2}]}> 4 {/* imageを表示する部分 */} 5 <View style={{position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', overflow: 'hidden'}}> 6 <Animated.View 7 style={{ 8 width: '100%', 9 height: '100%', 10 transform: [ 11 { translateX: this.currentX }, 12 { translateY: this.currentY } 13 ] 14 }} 15 > 16 <Animated.View 17 style={{ 18 width: '100%', 19 height: '100%', 20 transform: [ 21 { scale: this.state.scale } 22 ] 23 }} 24 > 25 {/* 拡縮の中心が画像の真ん中に来るようにすると計算が楽なのでコンポーネントが画面の真ん中に来るようにする */} 26 <Image 27 source={this.state.open == null ? { uri: '' } : { uri: this.state.open }} 28 style={{ 29 width: this.state.originalWidth, 30 height: this.state.originalHeight, 31 position: 'absolute', 32 top: -this.state.originalHeight / 2 + this.state.viewHeight / 2, 33 left: -this.state.originalWidth / 2 + this.state.width / 2, 34 }} 35 /> 36 </Animated.View> 37 </Animated.View> 38 </View> 39 {/* ジェスチャーのハンドリング */} 40 <View 41 onLayout={(e) => { 42 {/* Viewのサイズを取得しておく */} 43 let width = e.nativeEvent.layout.width; 44 let viewHeight = e.nativeEvent.layout.height; 45 let height = width * this.props.size[1] / this.props.size[0] 46 47 let scaleX = width / this.state.originalWidth; 48 let scaleY = height / this.state.originalHeight; 49 50 this.scaleMin = Math.max(scaleX, scaleY); 51 //this.scaleMin = scaleX; 52 53 this.setState({width: width, height: height, viewHeight: viewHeight}) 54 }} 55 style={{position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', overflow: 'hidden', opacity: 0.5}} 56 > 57 <PanGestureHandler 58 ref={this.panRef} 59 waitFor={[this.pinchRef]} 60 onGestureEvent={Animated.event( 61 [{ nativeEvent: { translationX: this.currentX, translationY: this.currentY } }], 62 { useNativeDriver: true } 63 )} 64 onHandlerStateChange={this._handlePanGestureStateChange} 65 > 66 <Animated.View style={{ width: '100%', height: '100%', backgroundColor: 'blue' }}> 67 <PinchGestureHandler 68 ref={this.pinchRef} 69 onGestureEvent={Animated.event( 70 [{ nativeEvent: { scale: this.currentScale } }], 71 { useNativeDriver: true } 72 )} 73 onHandlerStateChange={this._handlePinchGestureStateChange} 74 > 75 <Animated.View style={{ width: '100%', height: '100%', backgroundColor: 'green', }}/> 76 </PinchGestureHandler> 77 </Animated.View> 78 </PanGestureHandler> 79 </View> 80 </View> 81 ); 82 }
試したこと
this.currentX = croped.interpolate({ inputRange: [0, 1], outputRange: [lastX, cropedX] });
としてみたけどうまくいきません。
どのようにすればoffsetの値をinterpolateすることができるでしょうか?
補足情報(FW/ツールのバージョンなど)
Expo使ってます。
ここにより詳細な情報を記載してください。
あなたの回答
tips
プレビュー