I want to show a cancel button, on the focus TextInput animation.
I did the following code, but a cancel button does not display and follow the box when focused. It's only shown after the animation end.
And when cancel button displayed, it is not on the same line with textinput.
How do I fix this?
const { width } = Dimensions.get('window');
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused
class Search extends React.Component {
constructor(props: IProps) {
super(props);
this.state = {
inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
searchBarFocused: false,
}
}
private onFocus = () => {
Animated.timing(this.state.inputLength, {
toValue: SEARCH_SHRINK_WIDTH,
duration: 250,
}).start(() => this.setState({ searchBarFocused: true }));
}
private onBlur = () => {
Animated.timing(this.state.inputLength, {
toValue: SEARCH_FULL_WIDTH,
duration: 250,
}).start(() => this.setState({ searchBarFocused: false }));
}
<View style={styles.searchContainer}>
<Animated.View style={[
styles.search,
{
width: this.state.inputLength,
position: 'absolute',
left: 16,
alignSelf: 'center'
},
searchBarFocused === true ? undefined : { justifyContent: 'center' }
]}>
<Image source={searchIcon} style={styles.image} />
<TextInput
style={styles.searchInput}
....
onBlur={this.onBlur}
onFocus={this.onFocus}
/>
</Animated.View>
{searchBarFocused &&
<Touchable style={styles.cancelSearch} onPress={this.cancelSearch}>
<Text style={styles.cancelSearchText}>Cancel</Text>
</Touchable>
}
</View>
const styles = StyleSheet.create({
searchContainer: {
flexDirection: 'row',
height: 72,
borderBottomColor: SOLITUDE_COLOR,
},
search: {
flex: 1,
flexDirection: 'row',
height: 40,
borderRadius: 6,
},
cancelSearch: {
marginHorizontal: 16,
textAlign: 'center',
justifyContent: 'center'
}
});
gif: when unfocus and focused
Here is a slightly modified version of your code.
import React from "react";
import {
Dimensions,
View,
Animated,
TextInput,
TouchableOpacity,
StyleSheet,
} from "react-native";
const { width } = Dimensions.get("window");
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
cancelPosition: new Animated.Value(0),
opacity: new Animated.Value(0),
searchBarFocused: false
};
}
onFocus = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_SHRINK_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 16,
duration: 400
}),
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 250
})
]).start();
};
onBlur = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_FULL_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 0,
duration: 250
}),
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 250
})
]).start();
};
render() {
const { searchBarFocused } = this.state;
return (
<View style={styles.searchContainer}>
<Animated.View
style={[
styles.search,
{
width: this.state.inputLength,
position: "absolute",
left: 16,
alignSelf: "center"
},
searchBarFocused === true ? undefined : { justifyContent: "center" }
]}
>
<TextInput
style={styles.searchInput}
onBlur={this.onBlur}
onFocus={this.onFocus}
placeholder="Type something"
/>
</Animated.View>
<AnimatedTouchable
style={[styles.cancelSearch, { right: this.state.cancelPosition }]}
onPress={() => null}
>
<Animated.Text
style={[styles.cancelSearchText, { opacity: this.state.opacity }]}
>
Cancel
</Animated.Text>
</AnimatedTouchable>
</View>
);
}
}
const styles = StyleSheet.create({
searchContainer: {
flexDirection: "row",
height: 72,
borderBottomColor: "#00000033",
paddingTop: 100
},
search: {
flex: 1,
flexDirection: "row",
height: 40,
borderRadius: 6,
backgroundColor: "red"
},
cancelSearch: {
position: "absolute",
marginHorizontal: 16,
textAlign: "center",
justifyContent: "center",
alignSelf: "center"
}
});
You're setting searchBarFocused only after your animation completes. Since the cancel button is conditionally rendered based on searchBarFocused, it only appears at the end of the animation.
Related
When i run my react native code it gives error and says:
Attempt to invoke virtual method 'com.facebook.react.bridge.CatalystInstance com.facebook.react.bridge.ReactContext.getCatalystInstance()' on a null object reference
but in case when I run my code the second time it does not show this type of error and code runs successfully. what is the reason behind this error? Please suggest any answer.
and my App.js files here..
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image, Platform, Animated } from 'react-native';
const Sliding_Drawer_Width = 300;
export default class App extends Component {
constructor()
{
super();
this.Animation = new Animated.Value(0);
this.Sliding_Drawer_Toggle = true;
}
ShowSlidingDrawer = () =>
{
if( this.Sliding_Drawer_Toggle === true )
{
Animated.timing(
this.Animation,
{
toValue: 1,
duration: 500
}
).start(() =>
{
this.Sliding_Drawer_Toggle = false;
});
}
else
{
Animated.timing(
this.Animation,
{
toValue: 0,
duration: 500
}
).start(() =>
{
this.Sliding_Drawer_Toggle = true;
});
}
}
render() {
const Animation_Interpolate = this.Animation.interpolate(
{
inputRange: [ 0, 1 ],
outputRange: [ -(Sliding_Drawer_Width - 32), 0 ]
});
return (
<View style = { styles.MainContainer }>
<Text style = {styles.TextStyle}> Components Which You Want To Show in App, Place Them Here. </Text>
<Animated.View style = {[ styles.Root_Sliding_Drawer_Container, { transform: [{ translateX: Animation_Interpolate }]}]}>
<View style = { styles.Main_Sliding_Drawer_Container }>
<Text style = { styles.TextStyle } > Put All Your Components Here Which You Want To Show Inside Sliding Drawer. </Text>
</View>
<TouchableOpacity onPress = { this.ShowSlidingDrawer } style = {{ padding: 1 }}>
<Image source = {{ uri : 'https://reactnativecode.com/wp-content/uploads/2017/11/Arrow_Icon.png' }} style = {{resizeMode: 'contain', width: 30, height: 30 }} />
</TouchableOpacity>
</Animated.View>
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer:
{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
Root_Sliding_Drawer_Container:
{
position: 'absolute',
flexDirection: 'row',
left: 0,
bottom: 0,
top: (Platform.OS == 'ios') ? 20 : 0,
width: Sliding_Drawer_Width,
},
Main_Sliding_Drawer_Container:
{
flex: 1,
backgroundColor: '#FFC107',
paddingHorizontal: 10,
justifyContent: 'center',
alignItems: 'center'
},
TextStyle: {
fontSize: 25,
padding: 10,
textAlign: 'center',
color: '#FF5722'
}
});
Hi I have TextInput like this
Now when i enter text inside TextInput and when i click on cancel then the it is clearing the text inside TextInput , Now along with this I want to hide Cancel when is is clicked.
Here is my code
import React, { Component } from 'react';
import {
Dimensions,
View,
Animated,
TextInput,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import colors from '../styles/colors';
const { width } = Dimensions.get('window');
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
cancelPosition: new Animated.Value(0),
opacity: new Animated.Value(0),
searchBarFocused: false,
text: '',
showCancel: true
};
}
onFocus = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_SHRINK_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 16,
duration: 400
}),
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 250
}),
]).start();
};
onBlur = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_FULL_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 0,
duration: 250
}),
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 250
})
]).start();
};
clearInput = () => {
this.textInputRef.clear();
//this.onFocus.bind(this);
this.setState({
showCancel: !this.state.showCancel
});
}
_renderCancel() {
if (this.state.showCancel) {
return (
<AnimatedTouchable
style={[styles.cancelSearch, { right: this.state.cancelPosition }]}
onPress={(this.clearInput.bind(this))}
>
<Animated.Text
style={[styles.cancelSearchText, { opacity: this.state.opacity, color: colors.darkBlue }]}
onChangeText={text => this.setState({ text })}
value={this.state.text}
>
Cancel
</Animated.Text>
</AnimatedTouchable>
);
} else {
return null;
}
}
render() {
const { searchBarFocused } = this.state;
return (
<View style={styles.searchContainer}>
<Animated.View
style={[
styles.search,
{
width: this.state.inputLength,
position: 'absolute',
left: 16,
alignSelf: 'center'
},
searchBarFocused === true ? undefined : { justifyContent: 'center' }
]}
>
<TextInput
style={styles.searchInput}
onBlur={this.onBlur}
onFocus={this.onFocus}
placeholder="Enter condition, primary care, speciality"
ref={(ref) => { this.textInputRef = ref; }}
/>
</Animated.View>
<AnimatedTouchable
style={[styles.cancelSearch, { right: this.state.cancelPosition }]}
onPress={this.clearInput.bind(this)}
>
<Animated.Text
style={[styles.cancelSearchText, { opacity: this.state.opacity, color: colors.darkBlue }]}
onChangeText={text => this.setState({ text })}
value={this.state.text}
>
Cancel
</Animated.Text>
</AnimatedTouchable>
{this._renderCancel() }
</View>
);
}
}
const styles = StyleSheet.create({
searchContainer: {
flexDirection: 'row',
height: 72,
borderColor: colors.light_green,
paddingTop: 100
},
search: {
height: 40,
width: '100%',
marginTop: 5,
borderRadius: 6,
alignItems: 'flex-start',
justifyContent: 'flex-start',
borderColor: colors.light_green,
fontSize: 20,
borderWidth: 1,
},
cancelSearch: {
position: 'absolute',
marginHorizontal: 16,
textAlign: 'center',
justifyContent: 'center',
alignSelf: 'center',
color: colors.darkBlue
}
});
can anyone help me how to hide Cancel when it is clicked.
when cancel is clicked i want my original TextInput to be like this
set the style to following :
style={{ opacity: this.state.isVisible ? 1 : 0 }}
and set state isVisibile accordingly to make it visible/hidden.
If you are trying to implement the clear text then you can use
clearButtonMode.
clearButtonMode
Else if you are using state i.e showCancel you can use as
{showCancel? <CancelButton/> : <View/>}
Im trying to play full screen video using react native video, how can I play video full screen for both android and ios?in my case ios playing full screen correctly and in android video is stretched.
for landscape mode I used transform: [{ rotate: '90deg' }], its works but in android the video screen in stretched
Your help is highly appreciated.
here is my code
return (
<View onLayout={this.onLayout.bind(this)} style={styles.fullScreen} key={this.state.key}>
<View style={styles.backButtonWrapper}>
<TouchableOpacity onPress={() => this.props.navigation.goBack()}>
<Image source={Share} />
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.videoView}
onPress={this.playOrPauseVideo.bind(this, paused)}>
<Video
ref={videoPlayer => this.videoPlayer = videoPlayer}
onEnd={this.onVideoEnd.bind(this)}
onLoad={this.onVideoLoad.bind(this)}
onProgress={this.onProgress.bind(this)}
source={{ uri: this.props.detailedWorkout.videoLink }}
paused={paused}
volume={Math.max(Math.min(1, volume), 0)}
resizeMode="none"
style={styles.videoContainer} />
{paused &&
<View style={styles.pauseImageWrapper}>
<Image style={styles.videoIcon} source={PlayButton} />
</View>
}
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
},
backgroundVideo: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
fullScreen: {
flex: 1,
backgroundColor: "white"
},
videoView: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
videoContainer: {
width: Dimensions.get('window').height,
height: Dimensions.get('window').width,
minWidth: Dimensions.get('window').height,
minHeight: Dimensions.get('window').width,
width: Dimensions.get('screen').height,
height: Dimensions.get('screen').width,
transform: [{ rotate: '90deg' }],
},
videoIcon: {
width: 50,
height: 50
},
pauseImageWrapper: {
alignItems: 'center',
alignSelf: 'center',
position: "absolute",
},
backButtonWrapper: {
backgroundColor: 'red',
position: 'absolute',
zIndex: 1,
alignSelf: "flex-end"
}
});
I solve the issue using react-native-orientation.I'll post my code for anyone who having this issue.Cheers thanks for your help
import React, { Component, PropTypes } from "react";
import {
View,
Dimensions,
StyleSheet,
TouchableOpacity,
Image,
StatusBar,
Platform,
} from "react-native";
import {
Share,
PlayButton
} from "../../config/images";
import {
TextLogo,
IconWithCount,
DefaultIcon,
ClickableIcon,
} from "../../mixing/UI";
import {
WorkoutDetail,
KeyValueText,
DetailText,
ProgressController
} from "../../components";
import Orientation from "react-native-orientation";
import Video from "react-native-video"
const width = Dimensions.get("window").width;
const height = Dimensions.get("window").height;
let FORWARD_DURATION = 7;
export default class VideoPlayer extends Component {
constructor(props, context, ...args) {
super(props, context, ...args);
this.state = { paused: false };
}
componentDidMount() {
Orientation.lockToLandscapeLeft();
}
componentWillUnmount() {
Orientation.lockToPortrait();
}
componentWillMount() {
StatusBar.setHidden(true);
Orientation.lockToLandscapeLeft();
}
onVideoEnd() {
this.videoPlayer.seek(0);
this.setState({ key: new Date(), currentTime: 0, paused: true });
}
onVideoLoad(e) {
this.setState({ currentTime: e.currentTime, duration: e.duration });
}
onProgress(e) {
this.setState({ currentTime: e.currentTime });
}
playOrPauseVideo(paused) {
this.setState({ paused: !paused });
}
onBackward(currentTime) {
let newTime = Math.max(currentTime - FORWARD_DURATION, 0);
this.videoPlayer.seek(newTime);
this.setState({ currentTime: newTime })
}
onForward(currentTime, duration) {
if (currentTime + FORWARD_DURATION > duration) {
this.onVideoEnd();
} else {
let newTime = currentTime + FORWARD_DURATION;
this.videoPlayer.seek(newTime);
this.setState({ currentTime: newTime });
}
}
getCurrentTimePercentage(currentTime, duration) {
if (currentTime > 0) {
return parseFloat(currentTime) / parseFloat(duration);
} else {
return 0;
}
}
onProgressChanged(newPercent, paused) {
let { duration } = this.state;
let newTime = newPercent * duration / 100;
this.setState({ currentTime: newTime, paused: paused });
this.videoPlayer.seek(newTime);
}
onLayout(e) {
const { width, height } = Dimensions.get('window')
}
goBack = () => {
this.props.navigation.goBack();
Orientation.lockToPortrait();
}
// navigation options
static navigationOptions = { header: null }
// render
render() {
let { onClosePressed, video, volume } = this.props;
let { currentTime, duration, paused } = this.state;
const completedPercentage = this.getCurrentTimePercentage(currentTime, duration) * 100;
return (
<View onLayout={this.onLayout.bind(this)} style={styles.fullScreen} key={this.state.key}>
<View style={styles.backButtonWrapper}>
<TouchableOpacity onPress={() => this.goBack()}>
<Image source={Share} />
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.videoView}
onPress={this.playOrPauseVideo.bind(this, paused)}>
<Video
ref={videoPlayer => this.videoPlayer = videoPlayer}
onEnd={this.onVideoEnd.bind(this)}
onLoad={this.onVideoLoad.bind(this)}
onProgress={this.onProgress.bind(this)}
source={{ uri: this.props.detailedWorkout.videoLink }}
paused={paused}
volume={Math.max(Math.min(1, volume), 0)}
resizeMode="none"
style={Platform.OS === "android" ? styles.videoContainerAndroid : styles.videoContainerIOS} />
{paused &&
<View style={styles.pauseImageWrapper}>
<Image style={styles.videoIcon} source={PlayButton} />
</View>
}
</TouchableOpacity>
</View>
);
}
}
// styles
const styles = StyleSheet.create({
fullScreen: {
flex: 1,
backgroundColor: "black"
},
videoView: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
videoContainerAndroid: {
height: "100%",
width: "100%"
},
videoContainerIOS: {
width: Dimensions.get('window').height,
height: Dimensions.get('window').width,
minWidth: Dimensions.get('window').height,
minHeight: Dimensions.get('window').width,
width: Dimensions.get('screen').height,
height: Dimensions.get('screen').width,
transform: [{ rotate: '90deg' }],
},
videoIcon: {
width: 50,
height: 50
},
pauseImageWrapper: {
alignItems: 'center',
alignSelf: 'center',
position: "absolute",
},
backButtonWrapper: {
backgroundColor: 'red',
position: 'absolute',
zIndex: 1,
alignSelf: "flex-end"
}
});
Try resizeMode="contain" (documentation)
I making a playing card game and i want to add an deck deal animation like this:
Deal Animation
i tried change top value for Animated.Image component but output:
https://pasteboard.co/HiMc6Af.gif
i need create a clone of this component and original component should not move. But i could not put clone component over original component.
import React from 'react';
import { View, Text, Animated, TouchableOpacity } from 'react-native';
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
gameStart: false,
top: new Animated.Value(-175 / 2),
};
}
componentDidMount() {}
shuffleCards(e) {
this.setState({
gameStart: true,
});
this.cycleAnimation();
}
cycleAnimation() {
Animated.loop(
Animated.sequence([
Animated.timing(this.state.top, {
toValue: -900,
duration: 300,
delay: 100,
}),
Animated.timing(this.state.top, {
toValue: -175 / 2,
duration: 1,
delay: 1,
}),
Animated.timing(this.state.top, {
toValue: 900,
duration: 300,
delay: 100,
}),
]),
{
iterations: 4,
},
).start();
}
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
<TouchableOpacity>
<Animated.Image
ref={'deck'}
resizeMode="stretch"
source={require('./assets/card/back.png')}
style={[
{
width: 100,
height: 175,
},
]}
/>
</TouchableOpacity>
<TouchableOpacity onPress={e => this.shuffleCards(e)}>
<Animated.Image
resizeMode="stretch"
source={require('./assets/card/back.png')}
style={[
{
width: 100,
height: 175,
position: 'absolute',
left: -100,
},
{ top: this.state.top },
]}
/>
</TouchableOpacity>
</View>
);
}
}
I noticed that the Modal component's animationType property only allows for it to slide from bottom to top. How could I change the animation and make the modal appear from top to bottom?
Thanks for your time.
It doesn't look like that component allows for that type of configuration.
One thing you could do is use the Animated library to create your own modal. You would set the translateY property to negative of of the height of the device, then animate the translateY value to 0:
openModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: 0
}).start();
},
closeModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: -deviceHeight
}).start();
},
A full implementation is below:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
Animated,
Dimensions
} = React;
let deviceHeight = Dimensions.get('window').height
var deviceWidth = Dimensions.get('window').width
var SampleApp = React.createClass({
openModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: 0
}).start();
},
closeModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: -deviceHeight
}).start();
},
getInitialState(){
return {
modalY: new Animated.Value(-deviceHeight)
}
},
render() {
var Modal = <Animated.View style={[ styles.modal, { transform: [ {translateY: this.state.modalY}] }]}>
<TouchableHighlight onPress={ this.closeModal } underlayColor="green" style={ styles.button }>
<Text style={ styles.buttonText }>Close Modal</Text>
</TouchableHighlight>
</Animated.View>
return (
<View style={styles.container}>
<TouchableHighlight onPress={ this.openModal } underlayColor="green" style={ styles.button }>
<Text style={ styles.buttonText }>Show Modal</Text>
</TouchableHighlight>
{ Modal }
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
button: {
backgroundColor: 'green',
alignItems: 'center',
height: 60,
justifyContent: 'center',
},
buttonText: {
color: 'white'
},
modal: {
height: deviceHeight,
width: deviceWidth,
position: 'absolute',
top:0,
left:0,
backgroundColor: '#ededed',
justifyContent: 'center',
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);
Use react-native-modal community package. It has built in this feature. Set animationIn={'slideInDown'}, animationInTiming={300} properties.