Center alignment of React-Native ScrollView with custom starting position - react-native

Could you please look into what i'm missing with scrollview configuration.
I'm trying to create a scrollview animation with starting card-child offset by half of device-width, then when the user scrolls, it should align center and as should other rest of the scrollview-children
Basically all children when scrolled should align in center. Also first child should start at the end of the device width.
progress so far -> https://snack.expo.io/#sefeniyuk/scrollview-alignment
thank you.
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, Dimensions, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
const { width } = Dimensions.get('window');
const cardPaddingHorizontal = 2;
const cardWidth = width - cardPaddingHorizontal * 2;
const cardleftOffset = width - cardWidth / 3.5;
const initialCardShown = width - cardleftOffset;
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
scrollEventThrottle={1}
style={styles.style}
contentContainerStyle={styles.contentContainerStyle}
snapToAlignment="center"
decelerationRate="fast"
>
{[1, 2, 3, 4].map((num, i) => {
return (
<TouchableOpacity key={i} style={styles.card}>
<View style={styles.content}>
<Text style={styles.text}>{num}</Text>
</View>
</TouchableOpacity>
);
})}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
contentContainerStyle: {
width: cardWidth * 4
},
style: {
paddingLeft: cardleftOffset
},
card: {
backgroundColor: 'red',
width: cardWidth,
height: cardWidth,
margin: cardPaddingHorizontal,
elavation: 10
},
content: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
text: {
fontSize: 40,
color: 'white'
}
});

You can use react state hooks in functional components. You can either a give width for the starting scroll position or the best way is to use
scrollViewRef.current.scrollToIndex({ index: "index-of-item" })
import React, {useRef} from 'react'
const App = () => {
const scrollViewRef = useRef();
return (
<ScrollView horizontal={true} ref={scrollViewRef}
onContentSizeChange=
{() => scrollViewRef.current.scrollTo({x: giveWidth, y:
giveHeight, animated: true})}>
.
.
.
.
</ScrollView>
);
}

Related

How to swipe content in React Native

I am new to React Native and I have given a swipe task.
Swipe should change only the content of a view not the entire page
The swipe action should be tracked in dots bar.
I found two packages which are React Native Tab View and react-page-transitions. I am thinking about manipulating one of them to achieve such action or is there a better way? What is the best practice in swipe?
First Content
Second Content (frist content swiped)
I responded to a similar question and recommended react-native-swiper as it has the swiping functionality built in out of the box (this isnt enabled for web):
import React, { useState } from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import Swiper from 'react-native-swiper';
import {
colorGenerator,
colorManipulators,
} from '#phantom-factotum/colorutils';
const totalItems = 4;
export default function App() {
const DATA = colorGenerator(totalItems).map((color, index) => ({
color,
textColor: colorManipulators.darkenColor(color, 0.45),
title: 'Item' + (index + 1),
}));
return (
<View style={styles.container}>
<Swiper style={styles.wrapper} showsButtons={true} horizontal={true}>
{DATA.map((item, i) => {
return (
<View
style={[styles.item, { backgroundColor: item.color }]}
key={item.title}>
<Text style={[styles.text, { color: item.textColor }]}>
{item.title}
</Text>
</View>
);
})}
</Swiper>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
wrapper: {
// flex: 1,
},
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 30,
fontWeight: 'bold',
},
});
Here's the demo

React Native FlatList with columns does not allow horizontal scrolling on Android, but it does on iOS

I'm working on a minesweeper game with React Native. On iOS, I am able to scroll horizontally and vertically. But on Android, I can only scroll vertically.
I've tried modifying the layout and justification of content of the different views, but nothing seems to work.
Here is a shortened version of the code:
const Board = (
{game}: {game: Game}
) => {
//...
return (
<SafeAreaView
style={styles.main}
>
<FlatList
style={styles.flatList}
contentContainerStyle={styles.contentContainer}
data={game.board.grid.flat()}
numColumns={game.size} // n x n grid, so n columns
columnWrapperStyle={{ flexWrap: "nowrap" }}
renderItem={({ item: square }) => {
return (
<TouchableOpacity style={Styles.square}>
{/* ... */}
</TouchableOpacity>
);
}}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
main: {
flex: 1,
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
backgroundColor: "black"
},
flatList: {
},
contentContainer: {
flexGrow: 1,
justifyContent: "center"
},
square: {
width: 35,
height: 35,
justifyContent: "center",
alignItems: "center",
margin: 1
}
});
What could I be missing?
You can add a ScrollView with property horizontal to wrap the FlatList. The code should be like this:
import React from 'react';
import { View, FlatList, ScrollView, StyleSheet } from 'react-native';
/**
* This function creates an array based on the `quantity` value
*/
const placeholderData = (quantity = 16) => (
Array.from(Array(quantity).keys()).map((item) => ({ id: item }))
)
const NUMBER_OF_COLUMNS = 60
const NUMBER_OF_ROWS = 60
const NUMBER_OF_ELEMENTS = NUMBER_OF_COLUMNS * NUMBER_OF_ROWS
export default function App() {
const renderItem = () => (
<View style={styles.square} />
)
return (
<ScrollView
style={styles.container}
horizontal
showsHorizontalScrollIndicator={false}
>
<FlatList
data={placeholderData(NUMBER_OF_ELEMENTS)}
keyExtractor={({id}) => id.toString()}
renderItem={renderItem}
numColumns={NUMBER_OF_COLUMNS}
showsVerticalScrollIndicator={false}
/>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
square: {
width: 20,
height: 20,
backgroundColor: '#696969',
margin: 1,
},
});
If you prefer, I create a snack on Expo for you to see the complete example running. Just scan the QR Code from your smartphone using the Expo Go App.

How do you use flex inside a scrollView React Native

When I use the ScrollView with contents that have flex they don't show and flex doesn't seem to work. How do you get flex to work inside a ScrollView?
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Dimensions,
} from 'react-native';
const App = (props) => {
return (
<ScrollView style={styles.body}>
<View style={styles.box1} />
<View style={styles.box2} />
<View style={styles.box1} />
</ScrollView>
);
};
const styles = StyleSheet.create({
body: {
flex: 1,
flexDirection: 'column',
backgroundColor: '#fff',
borderColor: 'red',
borderWidth: 5
},
box1: {
flex: 1,
backgroundColor: 'blue',
},
box2: {
flex: 2,
backgroundColor: 'purple',
}
});
export default App;
I've created a snack. The inner views/boxes don't show.
I managed to figure it out. You create another view inside the scrollView and fix the height. The only problem is that the size of the content views depends on the height of this view instead of the height of the scrollView.
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Dimensions,
} from 'react-native';
// import { useHeaderHeight } from '#react-navigation/stack';
const App = (props) => {
let screenHeight = Dimensions.get('window').height;
// let headerHeight = useHeaderHeight();
let headerHeight = 0
let bodyHeight = screenHeight - headerHeight + 500;
return (
<ScrollView style={styles.body}>
<View style={[styles.innerBody, { height: bodyHeight }]}>
<View style={styles.box1} />
<View style={styles.box2} />
<View style={styles.box1} />
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
body: {
flex: 1,
flexDirection: 'column',
backgroundColor: '#fff',
},
innerBody: {
borderColor: 'red',
borderWidth: 5
},
box1: {
flex: 1,
backgroundColor: 'blue',
},
box2: {
flex: 2,
backgroundColor: 'purple',
}
});
export default App;
Heres a snack showing it working.

How do I make TouchableOpacity only clickable within its shape on mobile?

On web, shaping a TouchableOpacity makes it so only the shape is clickable, however on mobile the entire "box" surrounding the shape is clickable. Is there any way at all to make it so just the shape is clickable?
I have tried shaping the view and setting the style on both View and TouchableOpacity to overflow: 'hidden' but this also fails to contain the area which is touchable.
import React, { Component } from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
onPress = () => {
this.setState({
count: this.state.count + 1,
});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={this.onPress}>
<Text> Touch Here </Text>
</TouchableOpacity>
<View style={[styles.countContainer]}>
<Text style={[styles.countText]}>
{this.state.count !== 0 ? this.state.count : null}
</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10,
overflow: 'hidden',
},
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
borderRadius: 640,
height: 320,
width: 320,
overflow: 'hidden',
},
countContainer: {
alignItems: 'center',
padding: 10,
},
countText: {
color: '#FF00FF',
},
});
Here's a snack example of my problem

Image becoming transparent when placed within view

My app has a background image which has a slightly transparent view placed over it to provide a blue tint to the background image. I am now trying to place the app logo on top of these views but when I do so the logo appears to take on the opacity of the view providing the tint.
I am very new to react native but what I basically need is to have: background image > view > logo.
To demonstrate what I mean, the app logo should look like this:
But it currently looks washed out, like this:
App.js
import React, { Component } from 'react';
import { View, Text, ImageBackground } from 'react-native';
import Logo from './Logo';
class App extends Component {
render() {
return (
<ImageBackground
source={require('./images/city.png')}
style={styles.backgroundStyle}
>
<View style={styles.backgroundOverlayStyle}>
<Logo />
</View>
</ImageBackground>
);
}
}
const styles = {
backgroundStyle: {
flex: 1,
backgroundColor: '#000000',
width: '100%',
height: '100%'
},
backgroundOverlayStyle: {
flex: 1,
backgroundColor: '#003284',
opacity: 0.5
}
};
export default App;
Logo.js
import React from 'react';
import { View, Image } from 'react-native';
const Logo = () => {
const { logoStyle } = styles;
return (
<View style={styles.container}>
<Image style={logoStyle} source={require('./images/request-first-logo-white.png')} />
</View>
);
};
const styles = {
container: {
alignItems: 'center',
justifyContent: 'center',
opacity: 1,
},
logoStyle: {
width: '70%',
height: '65%',
resizeMode: 'contain',
//backgroundColor: 'blue'
}
};
export default Logo;
Thank you for any help.
you need you define blurRadius for ImageBackground
import React, { Component } from 'react';
import { View, Text, ImageBackground,Image } from 'react-native';
const Logo = () => {
const { logoStyle } = styles;
return (
<View style={styles.container}>
<Image style={logoStyle} source={{uri:'https://www.what-dog.net/Images/faces2/scroll001.jpg'}} />
</View>
);
};
export default class App extends Component {
render() {
return (
<ImageBackground
source={{uri : 'https://pngstocks.com/wp-content/uploads/2018/03/cb-background-10.jpeg'}}
style={styles.backgroundStyle}
blurRadius={30}
>
<Logo />
</ImageBackground>
);
}
}
const styles = {
backgroundStyle: {
flex: 1,
backgroundColor: '#000000',
width: '100%',
height: '100%'
},
backgroundOverlayStyle: {
flex: 1,
backgroundColor: '#003284',
},
container: {
alignItems: 'center',
justifyContent: 'center',
},
logoStyle: {
width: 100,
height: 100,
resizeMode: 'contain',
//backgroundColor: 'blue'
}
};