Am trying to animate an image to shrink when the onscreen keyboard is called (see code below). Got it working on IOS but not on Android :(
I have searched the web for solutions, but so far nothing works. Any suggestions?
Thanks in advance
constructor(props) {
super(props);
this.imageSize = new Animated.Value(imageSizeNormal);
}
componentWillMount() {
this.keyboardWillShowSub = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
this.keyboardWillHideSub = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
}
componentWillUnmount() {
this.keyboardWillShowSub.remove();
this.keyboardWillHideSub.remove();
}
keyboardWillShow = (event) => {
Animated.timing(this.imageSize, {
toValue: imageSizeSmall
}).start();
};
keyboardWillHide = (event) => {
Animated.timing(this.imageSize, {
toValue: imageSize
}).start();
};
render() {
return (
<Animated.Image
source={require('../../assets/circle.png')}
resizeMode="contain"
style={[styles.logo, { height: this.imageSize, width: this.imageSize}]}
/>
)
}
const imageSizeNormal = Dimensions.get("window").width/2;
const imageSizeSmall = Dimensions.get("window").width/4;
Here's how I solved it.
First thing I did was change the keywords "keyboardWill..." to "keyboardDid...""
Second, I added the following to AndroidManifest.xml
android:fitsSystemWindows="true"
android:windowSoftInputMode="adjustResize"
Sources:
windowSoftInputMode="adjustResize" not working with translucent action/navbar
https://medium.freecodecamp.org/how-to-make-your-react-native-app-respond-gracefully-when-the-keyboard-pops-up-7442c1535580
Related
I built simple light box by Animated.View . on my light box I put Button to close light box .How can do that.I dont want to use package like react native router flux
class Baselightbox extends Component {
constructor(props) {
super(props);
this.state = {
opacity:new Animated.Value(0)
};
}
close(){ //here => how to close light box
Animated.timing(
this.state.opacity,{
duration:3000,
toValue:0
}).start()
}
renderlightbox(){
const {width=deviceWidth,height=deviceHeight/2,children,backgroundColor,Btitle}=this.props
return(<View style={{flex:1,justifyContent:'center'}}>
{children}
<Button title={Btitle} onPress={()=>{this.close()}} />
</View>)
}
componentWillMount(){
Animated.timing(
this.state.opacity,{
duration:3000,
toValue:1
}).start()
}
render() {
const { height : deviceHeight , width : deviceWidth} = Dimensions.get('window');
const {width=deviceWidth,height=deviceHeight/2,children,backgroundColor,Btitle}=this.props
return (
<Animated.View style={{opacity:this.state.opacity,borderRadius: 10,width,height,backgroundColor,padding:30}}>
{this.renderlightbox()}
</Animated.View>
);
}
}
My Code
Take a look at my codes :)
Being a newbie in RN programming, I'm trying to handle android hardware button. But pressing it on screen leads to simultaneously going to previous screen and closing app.
My StackNavigator looks like:
const navigatorApp = StackNavigator({
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
Screen3: { screen: Screen3 },
Screen4: { screen: Screen4 }
})
I tried to make a global backpress handling for screens like
class HandleHavigation extends React.Component {
componentWillMount () {
if (Platform.OS === 'android') return
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Screen1')) {
return false
}
dispatch({ type: 'Navigation/BACK' })
return true
})
}
componentWillUnmount () {
if (Platform.OS === 'android') return
BackHandler.removeEventListener('hardwareBackPress')
}
render () {
return <navigatorApp navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
addListener: createReduxBoundAddListener('root')
})} />
}
}
const mapStateToProps = state => ({ nav: state.reducer })
export default connect(mapStateToProps)(HandleNavigation)
I also tried some given in other questions solutions, but nothing helped to prevent app closing.
I also thought about realizing backHandler on every screen.
In my app every screen contains function onPress for top button. That is why I tried to copy this action to hardware button using Backhandler. But all I get - screen goes back, and the app hides at the same time.
Is there any solution in my case to prevent closing app by pressing hw backbutton?
You can use BackHandler to exit/close the application:
import { BackHandler } from 'react-native';
BackHandler.exitApp();
Use react-navigation it has inbuilt backhandler.
I use React Native Element's SearchBar component for my app.
I set the autoFocus = {true}.
It works fine on iOS, but not on Android.
Any idea how to solve this ?
Here the working code sample.
// imports
....
....
class Abc extends Component {
componentDidMount() {
this.searchBar = true; // Manual Method
}
render() {
return (
<View>
<SearchBar
autoFocus // Automatic Method
ref={(searchBar) = { this.searchBar = searchBar; }}
/>
</View>
);
}
}
Your approach is correct. I have given the manual method but I suggest you go with your method. Also make sure you have passed the autoFocus prop to your <TextInput /> wrapped inside your SearchBar component.
Eg:
const SearchBar = (props) => {
const { prop1, prop2, ...txtIpProps } = props;
return (
<SearchBar>
<TextInput {...txtInpProps}/>
</SearchBar>
)
};
(Android React-Native 0.47)
How could i do to give the two PopularTab diff params and get this params in PopularTab, I've try many times ,but failed.
the only params i can get is navigation.key and navigation.routeName:
const Popular = TabNavigator({
IOS: {
screen: PopularTab,
//I try to code here to set the params but fail.
//eg: data: 'param1'
},
Android: {
screen: PopularTab,
},
},
{
tabBarPosition: 'bottom',
tabBarOptions: {
activeTintColor: '#e91e63',
}
}
);
There are three ways to achieve this, see which suits your need.
1. Suggest to do this official way, via screenProps
screenProps seems also suit your needs, with unidirectional design pattern.
helper function
function ScreenWithDefaultParams(Comp, defaultParams) {
return class extends Component {
render() {
return (<Comp {...this.props} screenProps={defaultParams} />)
}
}
}
TabNavigation definition
IOS: {
screen: ScreenWithDefaultParams(PopularTab, {test: 'default'})
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
/* get default screenProps */
console.log('default screenProps here!', this.props.screenProps);
}
}
2. Workaround for set default navigation params
Although it works, there's some problem with it. Firstly, as you see you got warning about Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, that is because every time you call setParams, navigationOptions will be trigger again so react-native warn you that might be an anti-pattern, or might cause an infinite loop.
Although we know it won't be an infinite loop, the warning won't disappear because react-native compiler never satisfied with it.
helper function
function setDefaultParams(nav, defaultParams) {
const { state, setParams } = nav.navigation;
const params = state.params || {};
let token = btoa(JSON.stringify(defaultParams));
if (params[token]) return;
setParams({ [token]: true, ...defaultParams });
}
TabNavigation definition
IOS: {
screen: PopularTab,
navigationOptions: (nav) => {
setDefaultParams(nav, {test: 'default'});
}
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
const { state, setParams, navigate } = this.props.navigation;
const params = state.params || {};
/* get default set params */
console.log('default param here!', params.test);
}
}
3. set component props in navigators
If you want to make it happens with normal Component props:
TabNavigation definition
IOS: {
screen: (props) => <PopularTab {...props} test='default' />,
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
/* get default props */
console.log('default props here!', this.props.test);
}
}
I'm trying to animate the height of a View in react native. The animation is working as expected in iOS but is not working in Android. The animated View seems to always be full height regardless of the animation value. Relevant code is below:
var Facets = React.createClass({
getInitialState: function() {
return {
h: new Animated.Value(0),
};
},
_animate: function(newHeight) {
Animated.timing(this.state.h, {
duration: 300,
toValue: newHeight
}).start();
},
render: function() {
var facetComponents = [];
if (this.props.shown) {
this._animate(MAX_HEIGHT);
}
else {
this._animate(0);
}
facets.map( (facet, idx) => {
facetComponents.push(
<Facet
key={idx}
facet={facet}
filterBy={this.props.filterBy} />);
});
return (
<Animated.View style={{ maxHeight: this.state.h }}>
{facetComponents}
</Animated.View>
);
}
});
Try moving your Animated Value out of state:
componentDidMount() {
this.h = new Animated.Value(0)
}
Then, refer to it as this.h as opposed to this.state.h