How to modify Scrollview height dynamically in react native - react-native

I have a scroll view with a full-length screen. With one flag I need to show button at the bottom.
Am using Animated.View for showing button at Bottom.
When button visible am unable to change scroll view height.
If I try to manage with marginBottom it is showing unwanted white before getting a button with animation.
Here I need to do either change scroll view height dynamically or transparent unwanted white background.
Below is code snippet:
const modalY = new Animated.Value(Dimensions.get('window').height);
openModal = () => {
Animated.timing(modalY, {
duration: 500,
toValue: Dimensions.get('window').height - 60
}).start();
}
closeModal = () => {
Animated.timing(modalY, {
duration: 300,
toValue: Dimensions.get('window').height
}).start();
}
showButton = () => {
const animationView = <Animated.View style={[ {width: Dimensions.get('window').width,position: 'absolute'}, { transform: [{translateY: modalY}] }]}>
<TouchableHighlight with title height 60/>
</Animated.View>;
return (
animationView
);
};
const marBottom = buttonTitle ? 60 : 0;
here buttonTitle is flag
<View>
<ScrollView contentContainerStyle={{ paddingTop: top }} style={{marginBottom:marBottom}}>
<View style={ [styles.itemscontainer]}>
{ this.myItems()}
</View>
</ScrollView>
{ this.showButton() }
{(buttonTitle) ? this.openModal() : this.closeModal()}
</View>

Related

How to press a component and it rotates 180 degrees in react native?

I have a Pressable component and inside it I have an icon. I want to press it and rotate it 180 degrees, how can I do that?
So to do this you must take use of the Animated library from react-native.
In which you make animated values and make functions to update them. Here's a full sample of you want (https://snack.expo.dev/#heytony01/grumpy-pretzel) and below is the explantion.
First import the library and make an Animated value
import { Text, View, StyleSheet,Animated,TouchableWithoutFeedback } from 'react-native';
const spinValue = React.useState(new Animated.Value(0))[0]; // Makes animated value
Next define functions to change the value
// When button is pressed in, make spinValue go through and up to 1
const onPressIn = () => {
Animated.spring(spinValue, {
toValue: 1,
useNativeDriver: true,
}).start();
};
// When button is pressed out, make spinValue go through and down to 0
const onPressOut = () => {
Animated.spring(spinValue, {
toValue: 0,
useNativeDriver: true,
}).start();
};
The tricky part is that in order to rotate in react-native you need to pass "0deg" or "12deg" etc..
<View style={{
transform: [
{ rotate: "45deg" },
]
}}>
</View>
So what you do is you interpolate the animated value to "0deg" to "360deg"
// spinDeg will be between '0deg' and '360deg' based on what spinValue is
const spinDeg = spinValue.interpolate({
useNativeDriver: true,
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
Lastly you pass in the spinDeg into your button and your done
// The animated style for scaling the button within the Animated.View
const animatedScaleStyle = {
transform: [{rotate: spinDeg}]
};
return (
<View style={{flex:1,justifyContent:"center",alignItems:"center"}}>
<TouchableWithoutFeedback
onPress={()=>{}}
onPressIn={onPressIn}
onPressOut={onPressOut}
>
<View style={{justifyContent:"center",alignItems:"center",backgroundColor:"lightgray",padding:15,borderRadius:20}}>
<Text>PRESS ME</Text>
<Animated.View style={[styles.iconContainer, animatedScaleStyle]}>
<Ionicons name="md-checkmark-circle" size={32} color="green" />
</Animated.View>
</View>
</TouchableWithoutFeedback>
</View>
);

Why is React Native Native Event pageX and pageY appearing inaccurate?

I'm making a simple drag and drop ReactNative component in my application where the component can be dragged from one location to another. I'm trying to figure out why my component is not responding correctly to changes in its position.
Even after setting the X and Y location to be pageX and pageY, it shifts downward first and slightly to the right. What is causing this slight change to happen?
Here's the code:
class Item extends React.Component
{
...
pressItem = (evt) => {
this.setState({shouldRotate: true});
if (evt.nativeEvent) {
let newX = evt.nativeEvent.pageX;
let newY = evt.nativeEvent.pageY;
this.state.x = newX;
this.state.y = newY;
}
};
...
render()
{
return (
<View onStartShouldSetResponder={() => true}
onResponderRelease={this.releaseItem}
onResponderMove={this.pressItem}
style={[
styles.item,
{top: this.state.y,position: 'absolute',
left: this.state.x,
}]}>
<Animated.Image source={this.props.imageURL}
resizeMode='contain'
style={{width: "100%", height: "100%",
transform: [{rotate: this.state.spin}]}}/>
</View>
)
}
}

ScrollView: content image is cropped when phone is in landscape mode

I'm trying to make a book reading experience using some images wrapped in
scrollViews inside a FlatList.
everything is ok in 'portrait' mode but in 'landscape' the images are cropped,
I want to be able to scroll vertically when in 'landscape' so the user can explore the whole image which becomes larger than screen height in 'landscape'
I've tried to modify the dimensions of the image depending on the orientation
but the result is not good.
Here is my code:
states
widthImage:Dimensions.get('window').width,
heightImage: Dimensions.get('window').height,
the content:
const QuranImage = [];
const scrollIsEnabled = this.state.heightImage > this.state.height;
QuranImage.push(
<ScrollView
scrollEnabled = {scrollIsEnabled}
onContentSizeChange = {this.manageScreenFlip}
nestedScrollEnabled={true}
>
<Image style={{
tintColor:'black',
width:this.state.widthImage,
height:this.state.heightImage,
}}
source={require('../Resources/page002.png')}
/>
</ScrollView>
);
QuranImage.push(
<ScrollView>
<Image style={{
tintColor:'black',
width:this.state.width,
height:this.state.height
}}
source={require('../Resources/page003.png')}/>
</ScrollView>
)
this.setState({
pdfViewer:(
<FlatList
horizontal={true}
nestedScrollEnabled={true}
pagingEnabled={true}
data={QuranImage}
keyExtractor={(item, index) => index.toString()}
renderItem={({item,index}) =>item}
/>
)
});
orientation listener fired in another place of the code:
_orientationDidChange = (orientation) => {
if (orientation === 'LANDSCAPE') {
this.setState({
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
heightImage:1000,
widthImage:1000
},() => {
this.renderPdfViewer();
console.log(Dimensions.get('window').height);
console.log(Dimensions.get('window').width);
});
} else {
console.log(orientation);
}
}
portrait with image fully displayed
landscape mode here I want to be able to scroll vertically to see the entire image
Add key prop in your flatlist as given below.
You can store the current orientation in a redux store and use it in your component as
const {orientation}= this.props
then
<FlatList
horizontal={true}
nestedScrollEnabled={true}
pagingEnabled={true}
data={QuranImage}
keyExtractor={(item, index) => index.toString()}
renderItem={({item,index}) =>item}
key= { orientation =='PORTRAIT' ||
orientation =='PORTRAITUPSIDEDOWN'?'portrait':'landscape' }
/>
modify your _orientationDidChange function as
_orientationDidChange = (orientation) => {
if (orientation === 'PORTRAIT' || orientation==
'PORTRAITUPSIDEDOWN') {
this.setState({
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
heightImage:1000,
widthImage:1000
},() => {
this.renderPdfViewer();
console.log(Dimensions.get('window').height);
console.log(Dimensions.get('window').width);
});
} else {
this.setState({
height: Dimensions.get('window').width,
width: Dimensions.get('window').height,
heightImage:1000,
widthImage:1000
},() => {
this.renderPdfViewer();
console.log(Dimensions.get('window').height);
console.log(Dimensions.get('window').width);
});
}
}
I found a solution to my issue by basically rerendering the FlatList every time i change orientation plus modifying height making it higher than screen high to enable scrolling.
here is the orientation function:
_orientationDidChange = (orientation) => {
const $this = this;
setTimeout(function() {
let width = Dimensions.get('window').width;
let height = Dimensions.get('window').height;
if (orientation == 'LANDSCAPE') {
// if LANDSCAPE make image height bigger than screen height to force vertical scroll
// 2.7 is a value chosen after visual testing
height = height * 2.7;
} else if (orientation == 'PORTRAIT' || orientation == 'PORTRAITUPSIDEDOWN') {
// if PORTRAIT make image height smaller than screen height so we can have some marges
height = height * 0.98;
}
$this.setState({renderFlat: null, itemLayout: width,width: width, height: height}, () => {
$this.renderFlat();
});
}, 50);
}
the function that render the Flatlist:
renderFlat() {
this.setState({
renderFlat:
(
<FlatList
horizontal={true}
pagingEnabled={true}
data={QuranImagePathList}
keyExtractor={(item, index) => index.toString()}
renderItem={this._renderItem}
viewabilityConfig={this.state.viewabilityConfig}
initialScrollIndex={this.state.currentPage}
onViewableItemsChanged={this.handlePageChange}
showsHorizontalScrollIndicator={false}
getItemLayout={this.getItemLayout}
removeClippedSubviews={true}
/>
)
})
}

React-Native Flat List columns number depending on screen orientation

I am trying to change numColumns of FlatList on Orientation change.(e.g. For portrait: numColumns=2 and landscape numColumns=3)
But for each Item in list it takes different width
enter image description here
I have tried using Dimensions to change width of each item dynamically
constructor(props) {
super(props);
Dimensions.addEventListener("change", this.updateStyles);
}
componentWillUnmount() {
Dimensions.removeEventListener("change", this.updateStyles);
}
updateStyles = dims => {
this.setState({
viewMode: dims.window.width > 400 ? "landscape" : "portrait"
});
};
For Styling
const styles = StyleSheet.create({
listContainer: {
flex: 1,
flexDirection: "row"
},
landscapeListItem: {
width: Dimensions.get("window").width / 3 - 20
},
portraitListItem: {
width: Dimensions.get("window").width / 2 - 10
}
});
So it looks like this:
in Landscape Mode
after changing orientation to Portrait
on Reload
Reloading screen applies width correctly. But I don't want to reload it.
It should set the width on Orientation Change.
Does anyone knows how can I resolve this issue?
Approach detech Device Oriantation and set numColumns.
<View onLayout={this._onLayout}>
{/* Subviews... */}
</View>
Handle event store orientation on in state
_onLayout(event){
const { width, height } = event.layout; //somewhat similar object
const orientation = (width > height) ? 'LANDSCAPE' : 'PORTRAIT';
this.setState({orientation})
}
Now FlatList
<FlatList
numColumns={this.state.orientation == "LANDSCAPE" ? 3 :2}
renderItem={({item}) => <Text>{item.key}</Text>}
/>

Horizontal FlatList React Native with different height of items

I have a little problem with the FlatList Component in react native. In the FlatList are items with different height. Here is a little example of what i have:
example FlatL
The first problem is that all items are positioned at the top. I want to position all items at the bottom.
The second problem is that the height of the FlatList is always the height of the biggest item. So you can also scroll to another item in the white area of a small item...
here my code:
import React from "react";
import {
Text,
View,
Dimensions,
StyleSheet,
ListView,
TouchableOpacity,
Animated,
Image,
FlatList
} from "react-native";
import glamorous, { ThemeProvider } from "glamorous-native";
import theme from "../theme";
const { height, width } = Dimensions.get("window");
const cards = [
{
id: 1,
color: "red",
height: 400
},
{
id: 2,
color: "blue",
height: 300
},
{
id: 3,
color: "yellow",
height: 200
}
];
class Test extends React.Component {
render() {
return (
<View style={{ bottom: 0 }}>
<FlatList
ref={elm => (this.flatList = elm)}
showsHorizontalScrollIndicator={false}
data={cards}
pagingEnabled={true}
horizontal={true}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View
style={{
height: item.height,
width: width,
backgroundColor: item.color
}}
/>
)}
/>
</View>
);
}
}
export default Test;
Has anyone a solution?
You can change the position of each item by setting the contentContainerStyle property of the FlatList itself. But the height of the FlatList will always have to be the height of the largest component inside it.
I solved this with onViewableItemsChanged prop
viewabilityConfig={{itemVisiblePercentThreshold: 50}}
onViewableItemsChanged={this.onViewableItemsChanged}
onViewableItemsChanged = ({ viewableItems }) => {
let index = viewableItems[0].index;
this.setState({ indexOfImages: index, heightOfImages: SCREEN_WIDTH * (viewableItems[0].item.height / viewableItems[0].item.width) });
}
We have width and height of the items in its data so I'm taking width and height of the visible item on the screen and do some calculations and I'm using this.state.heightOfImages in flatlist height like this
height: this.state.heightOfImages == undefined ? SCREEN_WIDTH * (images[0].height / images[0].width) : this.state.heightOfImages
You can just wrap the content of each card in another <View> element with styles={{ minHeight: 200, maxHeight: 300 }} and it will work fine!