How to Implement Swipable list in react native? - android

I've implemented an app based on react native. This app shows me a list via swipelistview. But I have a Problem. when list add new items after scroll down, swipelistview won't work properly. In fact it works by Accident. I don't know where i've made mistake.
this is my code:
import React , {Component} from 'react';
import { StyleSheet, Text, View, FlatList ,ActivityIndicator,Animated , TouchableOpacity, Alert } from 'react-native';
import { SwipeListView } from 'react-native-swipe-list-view';
import { Container, Header, Content, Accordion ,Icon ,Item, Input , Button ,ActionSheet , Card, CardItem, Body} from "native-base";
var DESTRUCTIVE_INDEX = 3;
var CANCEL_INDEX = 4;
class App extends Component {
constructor(props) {
super(props);
this.actionSheet = null;
}
state = {
data: [],
filteredData: [],
page: 1,
loading: false,
error: null,
spinner: false,
searchText:'',
lety:false,
refreshing: false
};
componentDidMount() {
console.disableYellowBox = true;
this.fetchData();
}
handleLoadMore = () => {
this.setState(
{
page: this.state.page + 1
},
() => {
this.fetchData();
}
);
};
fetchData = () => {
const page = this.state.page;
this.setState({ loading: true });
let response = fetch(
'http://webgispro.ir/home/GetWords/' + page ,
{
method: "POST"
}
).then((response) => response.json())
.then((responseJson) => {
this.setState(
{
data : page === 1 ? Array.from(responseJson): [...this.state.data, ...responseJson] ,
loading: false,
refreshing: false
})
})
.catch((error) => {
this.setState({ error, loading: false });
});
};
searchData = (searchText) => {
this.setState({searchText: searchText.toLowerCase()});
if (searchText =='') {
this.setState({filteredData: []});
this.setState({lety:false})
return false;
}
let filteredData = this.state.data.filter(function (item) {
return item.Word.toLowerCase().includes(searchText.toLowerCase());
});
this.setState({lety : filteredData.length == 0 ? true : false})
this.setState({filteredData: filteredData});
};
renderHeader = () => {
return <Searchbar
style={{ width:'100%' }}
inputStyle={{borderWidth: 0}}
round={false}
lightTheme={true}
placeholder="Search..."
autoCapitalize='none'
autoCorrect={false}
onChangeText={this.searchData}
value={this.state.searchText}
/>
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating ={true} color="blue" style={{height: 80, marginTop: 10, opacity: 1 }} size="large" />
</View>
);
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE",
//marginLeft: "14%"
}}
/>
);
};
handleRefresh = () => {
this.rowHeightAnimatedValues = {};
this.setState(
{
page: 1,
refreshing: true
},
() => {
this.fetchData();
}
);
};
editItem = key => () => {
var example = this.state.data.find(o=>o.Id == key).Example
if ( this.actionSheet !== null ) {
const title = <Text style={{ color: 'black', fontSize: 23 }}>{example}</Text>
this.actionSheet._root.showActionSheet(
{
options: [] ,
cancelButtonIndex: CANCEL_INDEX,
destructiveButtonIndex: DESTRUCTIVE_INDEX,
title:title
}, (i) => console.log(i));
}
}
deleteItem = key => () => {
Alert.alert(
"???",
"??? ???? ??? ????? ????? ??",
[
{
text: "???",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "???", onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
);
}
onRowOpen =() => {
console.log('cfdfdf')
}
render() {
return (
<View style={styles.container}>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input placeholder="Search" onChangeText={this.searchData} />
<Icon name="ios-people" />
</Item>
<Button transparent>
<Text>Search</Text>
</Button>
</Header>
<SwipeListView
useFlatList
extraData={this.state}
data={this.state.filteredData && this.state.filteredData.length > 0 || this.state.lety == true ? this.state.filteredData : this.state.data}
keyExtractor={item => item.Id.toString()}
renderItem={(data, rowMap) => (
<Animated.View
style={[
styles.rowFront,
data.index % 2 === 0 && { backgroundColor: 'white' },
{ height: 100 }
]}
>
<Text style={{position: 'absolute', top: 35 , fontSize:20}}>
{data.item.Word}
</Text>
</Animated.View>
)}
renderHiddenItem={ (data, rowMap) => (
<View style={styles.rowBack}>
<Text style={{fontSize:20}}>{data.item.Meaning}</Text>
<TouchableOpacity style={[styles.backRightBtn, styles.backRightBtnLeft]} onPress={this.editItem(data.item.Id)}>
<Icon name='md-information-circle-outline' />
</TouchableOpacity>
<TouchableOpacity style={[styles.backRightBtn, styles.backRightBtnRight]} onPress={this.deleteItem(data.item.Id)}>
<Icon name='trash-outline' />
</TouchableOpacity>
</View>
)}
leftOpenValue={90}
rightOpenValue={-150}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
initialNumToRender={8}
ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter}
onRefresh={this.handleRefresh}
refreshing={this.state.refreshing}
/>
<ActionSheet ref={(c) => { this.actionSheet = c; }} />
</View>
);
}
}
export default App
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
flex: 1,
//paddingTop: 50,
},
backTextWhite: {
color: '#FFF'
},
rowFront: {
alignItems: 'center',
backgroundColor: '#CCC',
justifyContent: 'center',
},
rowBack: {
alignItems: 'center',
backgroundColor: 'green',
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 15,
},
backRightBtn: {
alignItems: 'center',
bottom: 0,
justifyContent: 'center',
position: 'absolute',
top: 0,
width: 75
},
backRightBtnLeft: {
backgroundColor: 'blue',
right: 75
},
backRightBtnRight: {
backgroundColor: 'red',
right: 0
},
});
The list works properly and comes data but whenever I scroll down or up it doesn't work anymore. Please help me

If you are in mindset to change your package, then you can try react-native-snap-carousel, perfect for your requirement. Thanks

Related

How do you change the entire selection to individual choices in React Native?

We are currently developing based on React Native.
And I received data by GET request through API document,
and I created scroll view through MAP method.
So now I'm trying to make it possible to choose,
but if I choose one, it's all chosen.
How can I make you choose one by one if I choose one from my code?
import React, { useEffect, useState } from "react";
import { SvgCssUri } from "react-native-svg";
import { DeviceEventEmitter } from "react-native";
import {
View,
StyleSheet,
TouchableHighlight,
Text,
ScrollView,
Image,
} from "react-native";
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from "react-native-responsive-screen";
import axios from "axios";
import BouncyCheckbox from "react-native-bouncy-checkbox";
const Select = ({ navigation }) => {
let bouncyCheckboxRef = null;
const [bodyType, setBodyType] = useState([]);
const [standardSelected, setStandardSelected] = useState(false);
const [isSelected, setSelected] = useState(false);
const bodyGetData = async () => {
let body = [];
try {
let config = {
method: "get",
url:
"http://everyweardev-env.eba-azpdvh2m.ap-northeast-2.elasticbeanstalk.com/api/v1/user/bodyType/male",
headers: {},
};
axios(config).then(function (response) {
response.data.data.map((u) => {
switch (u.bodyType) {
case "standard":
body.push({ bodyType: "스탠다드", imgUrl: u.imgUrl, key: 1 });
break;
case "reverseTriangle":
body.push({ bodyType: "역삼각형", imgUrl: u.imgUrl, key: 2 });
break;
case "triangle":
body.push({ bodyType: "삼각형", imgUrl: u.imgUrl, key: 3 });
break;
case "circle":
body.push({ bodyType: "원형", imgUrl: u.imgUrl, key: 4 });
break;
case "hourglass":
body.push({ bodyType: "직사각형", imgUrl: u.imgUrl, key: 5 });
break;
}
});
return setBodyType(body);
});
} catch (err) {
console.log(err);
}
};
useEffect(() => {
const unsubscribe = navigation.addListener("focus", () => {
bodyGetData();
});
return unsubscribe;
}, [navigation]);
const onClick = (e) => {
console.log(e);
bodyType.map((u) => {
switch (u.bodyType) {
case u.bodyType === "스탠다드":
setSelected(!isSelected);
console.log(isSelected);
break;
case "역삼각형":
setSelected(!isSelected);
break;
}
});
};
return (
<View style={styles.container}>
<Text
style={{ fontSize: wp("5.5%"), fontWeight: "bold", marginBottom: 21 }}
>
자신의 체형을 선택해 주세요
</Text>
<View style={{ flexDirection: "row", marginBottom: hp("10%") }}>
<Text style={{ fontSize: wp("4.5%"), marginRight: wp("1%") }}>
더 정확한 평가를 받으실 수 있습니다
</Text>
<Image
source={require("../../images/smile.png")}
style={{ marginTop: hp("0.5%") }}
/>
</View>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={true}>
{bodyType.map((data) => (
<>
<TouchableHighlight
style={styles.bodySelect}
value={data.bodyType}
onPress={onClick}
// onPress={() => bouncyCheckboxRef?.onPress()}
>
<>
<BouncyCheckbox
isChecked={!isSelected}
ref={(ref) => (bouncyCheckboxRef = ref)}
size={25}
fillColor="black"
unfillColor="#FFFFFF"
iconStyle={{ borderColor: "white" }}
textStyle={{ fontFamily: "JosefinSans-Regular" }}
disableBuiltInState
onPress={onClick}
style={{
alignSelf: "flex-start",
marginLeft: wp("3%"),
marginTop: hp("2%"),
}}
/>
<SvgCssUri
uri={data.imgUrl}
width="90%"
height="60%"
marginTop="-5%"
key={data.key}
/>
<Text style={styles.bodytype}>{data.bodyType}</Text>
</>
</TouchableHighlight>
</>
))}
</ScrollView>
<TouchableHighlight
style={styles.button}
onPress={() => {
navigation.navigate("얼굴형 정보 입력");
}}
underlayColor="gray"
>
<>
<Text style={styles.text}>선택 완료</Text>
</>
</TouchableHighlight>
</View>
);
};
const styles = StyleSheet.create({
container: {
justifyContent: "center",
alignItems: "center",
marginTop: hp("5%"),
},
button: {
justifyContent: "center",
alignItems: "center",
width: wp("70%"),
height: hp("7%"),
color: "white",
backgroundColor: "black",
borderRadius: 10,
marginTop: hp("17%"),
},
text: {
color: "white",
fontSize: wp("5.2%"),
fontWeight: "bold",
},
bodySelect: {
marginLeft: 16,
marginRight: 16,
width: wp("70%"),
height: hp("35%"),
alignItems: "center",
borderRadius: 30,
backgroundColor: "#ffffff",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
bodytype: {
marginTop: hp("3%"),
fontWeight: "bold",
fontSize: wp("8%"),
},
});
export default Select;
this example explain how to select individual choice.
do these steps :
//define state to save selected value inside it
const [selected, setSelected] = React.useState();
//handle item onPress
const onPress = (item) => {
setSelected(item);
}
//check if item selected
const isSelected = (item) => {
return selected?.unique_id === item.unique_id;
}
//and in render function
<ScrollView>
{
data.map((item, index) => {
return(
<ItemComponent
onPress={() => setSelected(item)}
style={isSelected(item) ? selectedStyle : defaultStyle}>
</ItemComponent>
)
})
}
</ScrollView>
full code try snack here
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, TouchableOpacity} from 'react-native';
export default function App() {
const [selected, setSelected] = React.useState();
const data = [
{
unique_id : 1,
text : "item one"
},
{
unique_id : 2,
text : "item two"
},
{
unique_id : 3,
text : "item three"
},
{
unique_id : 4,
text : "item four"
}
];
const onPress = (item) => {
setSelected(item);
}
const isSelected = (item) => {
return selected?.unique_id === item.unique_id;
}
return (
<ScrollView>
{
data.map((item, index) => {
return(
<TouchableOpacity
key={item.unique_id}
onPress={() => {
setSelected(item);
}}
style={{
padding : 25,
margin : 10,
backgroundColor : isSelected(item) ? "red" : "#eee"
}}
>
<Text>{item.text}</Text>
</TouchableOpacity>
)
})
}
</ScrollView>
);
}

Text disappeared after select next input - React Native Android

I create Sign In page in React Native for Android Phones. And now I get a little problem with displaying text. When the user opens Sign In screen and type his Email or Username and then clicks on the password field all from previously field will be "removed" or 'hidden'. This is code for the screen Sign In:
import React from 'react'
import {
View,
TextInput,
StyleSheet,
TouchableOpacity,
Dimensions,
// AsyncStorage
} from 'react-native';
import AsyncStorage from '#react-native-community/async-storage';
import { SafeAreaConsumer } from 'react-native-safe-area-context';
import axios from 'axios';
import {getAppLangCode} from '../helpers/store';
import {mediumFontFamily} from '../constants/Colors';
import {translate} from "../helpers/i18n";
import {getUserDatas} from '../helpers/user';
import BackButton from '../components/inners/BackButton';
import TextRegular from '../components/ui/TextRegular';
import TextMedium from '../components/ui/TextMedium';
import TextHeavy from '../components/ui/TextHeavy';
import Loader from '../components/Loader';
import ErrorSuccessPopup from '../components/ErrorSuccessPopup';
// const wHeight = Dimensions.get('window').height;
export default class SignInScreen extends React.Component {
static navigationOptions = {
headerShown: false,
headerTransparent: true,
title: 'Please sign in',
};
constructor(props){
super(props);
this.state = {
log: '',
password: '',
validating: false,
focus: '',
isSuccess: false,
title: translate('login_wrong'),
message: '',
isError: false,
}
this._ismounted = true;
}
componentWillUnmount() {
this._ismounted = false;
}
// static navigationOptions = ({ navigation }) => {
// return {
// title: translate('chat_screen'),
// headerLeft: () => {
// return <BackButton isBlack={true} onPress={navigation.goBack} style={{marginLeft: 10}}/>
// },
// };
// };
toForgetPwd = ()=>{
this.props.navigation.navigate('ForgetPwd');
}
toRegister = () => {
this.props.navigation.navigate('Register');
}
onInputChange = (name)=>(text)=>{
this.setState({[name]:text})
}
onFucusInput = (name) =>{
this.setState({focus: name})
}
_signInAsync = async () => {
const _self = this
const {log,password} = _self.state
if(log.length < 3 || password.length < 3){
_self.setState({ isError: true, message:translate('login_enter_email'), title:translate('login_wrong') })
return;
}
_self.setState({ validating: true });
const lang = await getAppLangCode();
axios({
method: 'POST',
url: `/login`,
data: {
log,
password,
lang: lang,
},
}).then(res => {
//Set the results to the people array.
// console.log(res.data);
const {success} = res.data
const title = null != res.data.title ? res.data.title : '';
const message = null != res.data.message ? res.data.message : '';
if( success ){
_self.saveToStorage(res.data.data).then(rt=>{
if( _self._ismounted ){
if( rt == true ){
_self.setState({ isSuccess: true, validating: false, message, title })
}else{
_self.setState({ isSuccess: true, validating: false, message:'Failed to store auth', title:translate('login_wrong') })
}
}
});
}else{
_self.setState({ isError: true, validating: false, message, title })
}
//Error handle the promise and set your errorMessage
}).catch(err => {
_self.setState({ validating: false, isError: true });
console.log(err)
} );
}
saveToStorage = async (userData) => {
let rt = false;
//if (userData) {
try {
await AsyncStorage.setItem('user', JSON.stringify({
isLoggedIn: true,
authToken: userData.auth_token,
id: userData.user_id,
name: userData.user_login
}));
// await getUserDatas() // .then(rt=>console.log(rt))
getUserDatas() // .then(rt=>console.log(rt))
rt = true
} catch (error) {
// Error saving data
rt = false;
// if( null != error.message )
}
// return true;
//}
return rt;
}
nextField = ()=>{
this.password.focus()
}
errorButton(){
const {apColors} = this.props;
return (
<TouchableOpacity onPress={()=>{this.setState({ isError: false });}}>
<View style={[styles.popupButton,{backgroundColor: apColors.appColor,}]}>
<TextHeavy style={styles.loginButtonText}>{translate('login_try_again')}</TextHeavy>
</View>
</TouchableOpacity>
)
}
successButton(){
const {apColors} = this.props;
return (
<TouchableOpacity onPress={() => this._onPressDone() }>
<View style={[styles.popupButton,{backgroundColor: apColors.appColor,}]}>
<TextHeavy style={styles.loginButtonText}>{translate('login_done')}</TextHeavy>
</View>
</TouchableOpacity>
)
}
_onPressDone(){
this.setState({ isSuccess: false });
const {route,navigation} = this.props;
const loggedInRoute = route.params?.loggedInRoute ?? 'Home';
const backRoute = route.params?.backRoute ?? 'Home';
switch (loggedInRoute){
case 'Profile':
navigation.navigate( 'ProfileStack', { screen: 'Profile', params: {backRoute} } )
break;
case 'Bookings':
navigation.navigate( 'BookingsStack', { screen: 'Bookings', params: {backRoute} } )
break;
case 'Bookmarks':
navigation.navigate( 'BookmarksStack', { screen: 'Bookmarks', params: {backRoute} } )
break;
default:
navigation.navigate( loggedInRoute, {backRoute} )
}
}
_renderGreeting(){
const {apColors} = this.props;
return (
<>
<TextHeavy style={[styles.loginGreeting,{color: apColors.hText,}]}>{translate('login_hi')}</TextHeavy>
<TextHeavy style={[styles.loginGreeting,{color: apColors.hText,}]}>{translate('login_welcome')}</TextHeavy>
</>
)
}
_onGoBack(){
// const backRoute = this.props.navigation.getParam('backRoute', 'Home');
const backRoute = this.props.route.params?.backRoute ?? 'Home';
this.props.navigation.navigate(backRoute)
}
_renderHeader(cstyle = {}){
// {top: 30 + insets.top}
const {apColors} = this.props;
return (
<View style={[styles.navBar,cstyle]}>
<BackButton color={apColors.backBtn} onPress={ () => this._onGoBack() }/>
</View>
)
}
_renderFooter(){
const {apColors} = this.props;
return (
<View style={styles.signUp}>
<TextRegular style={[styles.signUpText,{color: apColors.pText,}]}>{translate('dont_have_account')}</TextRegular>
<TouchableOpacity onPress={this.toRegister}>
<TextMedium style={[styles.signUpButton,{color: apColors.pText,}]}>{translate('sign_up')}</TextMedium>
</TouchableOpacity>
</View>
)
}
render() {
const {apColors} = this.props;
const {focus,validating,isSuccess,isError,title,message} = this.state
let logStyle = [styles.textInput,{borderColor: apColors.separator,color: apColors.pText}],
pwdStyle = [styles.textInput,{borderColor: apColors.separator,color: apColors.pText}];
if( focus == 'log' ) logStyle = [logStyle,{borderColor: apColors.inputFocus,}]
if( focus == 'password' ) pwdStyle = [pwdStyle,{borderColor: apColors.inputFocus,}]
// return null;
return (
<SafeAreaConsumer style={{flex: 1}}>
{insets => <View style={[styles.container,{backgroundColor: apColors.appBg,paddingTop: insets.top,paddingBottom: insets.bottom,paddingLeft: insets.left,paddingRight: insets.right}]}>
{this._renderHeader()}
<Loader loading={validating}/>
<ErrorSuccessPopup isSuccess={isSuccess} isError={isError} title={title} message={message} successButton={this.successButton()} errorButton={this.errorButton()}/>
<View style={styles.loginInner}>
{this._renderGreeting()}
<TextRegular style={[styles.fieldLabel,{color: apColors.fieldLbl,marginTop:40}]}>{translate('user_email')}</TextRegular>
<TextInput
// placeholder="Username or Email"
style={logStyle}
onChangeText={this.onInputChange('log')}
onFocus={e=>this.onFucusInput('log')}
returnKeyType='next'
onSubmitEditing = {this.nextField}
autoCorrect={false}
underlineColorAndroid='transparent'
autoCapitalize="none"
autoCompleteType="off"
keyboardType="email-address"
/>
<TextRegular style={[styles.fieldLabel,{color: apColors.fieldLbl,}]}>{translate('password')}</TextRegular>
<TextInput
// placeholder="Password"
style={pwdStyle}
onChangeText={this.onInputChange('password')}
onFocus={e=>this.onFucusInput('password')}
secureTextEntry={true}
returnKeyType='done'
ref={input=>this.password = input}
autoCorrect={false}
autoCapitalize="none"
underlineColorAndroid='transparent'
// autoCompleteType="off"
// keyboardType="visible-password"
/>
<TouchableOpacity onPress={this.toForgetPwd}>
<TextRegular style={[styles.forgetPassword,{color: apColors.appColor,}]}>{translate('forget_password')}</TextRegular>
</TouchableOpacity>
<View style={styles.spacer}/>
<TouchableOpacity onPress={this._signInAsync}>
<View style={[styles.loginButton,{backgroundColor: apColors.appColor,}]}>
<TextHeavy style={styles.loginButtonText}>{translate('login')}</TextHeavy>
</View>
</TouchableOpacity>
</View>
{this._renderFooter()}
</View>}
</SafeAreaConsumer>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
// alignItems:'center',
// justifyContent:'center'
minHeight: Dimensions.get('window').height - 200,
},
navBar: {
// position: 'absolute',
// top: 52,
// // marginTop: 52,
// left: 0,
// right: 0,
// zIndex: 200,
paddingLeft: 15,
paddingRight: 15,
flexDirection: 'row',
alignItems: 'center',
// backgroundColor: 'red',
paddingTop: 8,
paddingBottom: 7,
},
loginInner: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 30,
// backgroundColor: 'red',
},
loginGreeting: {
fontSize: 34,
},
fieldLabel:{
fontSize: 17,
marginTop: 20,
},
textInput:{
// margin:0,
// marginTop:20,
// height:40,
// backgroundColor:'red',
// // borderRadius:20,
// paddingLeft:15,
// // fontSize: AppFontSize,
// // fontFamily: AppFontFamily,
// borderRadius: 4,
// width: 150,
// flex: 1,
height: 35,
// marginTop: 5,
paddingVertical: 5,
borderBottomWidth: 1,
borderStyle: 'solid',
fontSize: 17,
fontFamily: mediumFontFamily,
},
forgetPassword: {
marginTop: 35,
fontSize: 17,
textAlign: 'right',
},
spacer: {
height: 60,
},
loginButton: {
height: 44,
borderRadius: 8,
justifyContent: 'center',
// marginTop: 60,
},
loginButtonText: {
color: '#fff',
fontSize: 15,
textAlign: 'center',
},
signUp: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
// alignSelf: 'flex-end'
// position: 'absolute',
// bottom: 30,
// left: 0,
// right: 0,
marginBottom: 15,
},
signUpText: {
fontSize: 15,
lineHeight: 20,
},
signUpButton: {
fontSize: 15,
lineHeight: 17,
marginLeft: 5,
},
popupButton: {
height: 35,
borderRadius: 8,
justifyContent: 'center',
paddingHorizontal: 30,
marginTop: 20
},
})
Where I have a mistake? How to solve this problem? Thanks all for help.

react native - collapse table

I plan to make a collapse table. You can find it in this link
I tried:
Using a Custom Component for column name and FlatList for the first column
Using Section list for the rest column
=============================================================
| _____Custom Component_____ | __________Section list header__________ |
|============================================================|
| _________Flat List___________| __________ Section list body____________|
|============================================================|
I am able to make the list scroll together. However, if the list has 450+ rows, the performance will be reduced dramatically.
Please let me know if you have any solution.
Thank you in advanced!
I found a way to do it. The idea is.
Use Animated.ScrollView to control the horizontal scroll
Use FlatList to control the vertical scroll
When we do horizontal scroll, keep the first element of the FlatList and move the rest of them.
Below is the code:
import React, {Component} from 'react';
import {Animated, FlatList, StyleSheet, Text, View,} from 'react-native';
import * as UIConfig from "../../../../configs/UIConfig";
import * as ColorConfig from "../../../../configs/ColorConfig";
export interface CollapseTableColumnType {
name: string,
accessName: string,
width: number,
visible: boolean,
}
interface CollapseTableType {
normalColumns: Array<CollapseTableColumnType>,
collapseColumns: Array<CollapseTableColumnType>,
data: Array<any>
}
interface State {
scrollX: Animated.Value,
}
class CollapseTable extends Component<CollapseTableType, State> {
// Data
private _scrollView: any = null;
private _flatList: FlatList<any> | null = null;
static defaultProps: CollapseTableType = {
normalColumns: [],
collapseColumns: [],
data: [],
};
state: State = {
scrollX: new Animated.Value(0),
};
private _HEADER_SCROLL_DISTANCE = this.props.collapseColumns.concat(this.props.normalColumns)
.reduce((totalWidth, currentWidth) => currentWidth.width + totalWidth, 0);
private _headerTranslate = this.state.scrollX.interpolate({
inputRange: [0, this._HEADER_SCROLL_DISTANCE],
outputRange: [0, this._HEADER_SCROLL_DISTANCE],
extrapolate: 'clamp',
});
scrollToTop = () => {
if (this._flatList) {
this._flatList.scrollToOffset({ animated: false, offset: 0 });
}
};
scrollToLeft = () => {
if (this._scrollView) {
this._scrollView.getNode().scrollTo({x: 0, y: 0, animated: false});
}
};
render() {
return (
<Animated.ScrollView
ref={(ref: any) => this._scrollView = ref}
style={styles.fill}
horizontal={true}
removeClippedSubviews={true}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={1}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this.state.scrollX}}}],
{useNativeDriver: true},
)}
>
<FlatList
ref={(ref: any) => this._flatList = ref}
removeClippedSubviews={true}
showsVerticalScrollIndicator={false}
data={this.props.data}
renderItem={this.renderRow}
keyExtractor={(item, index) => 'item_' + index}
stickyHeaderIndices={[0]}
ListHeaderComponent={this.renderHeader}
/>
</Animated.ScrollView>
);
}
renderHeader = () => {
return (
<View style={[styles.cellContainer, {backgroundColor: ColorConfig.PRIMARY_90}]}>
<View style={styles.normalCellContainer}>
{
this.props.normalColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.normalColumns[indexConfig].width,
this.props.normalColumns[indexConfig].name,
this.props.normalColumns[indexConfig].visible,
);
})
}
</View>
<Animated.View style={[
styles.collapseCellContainer,
{
position: 'absolute',
transform: [{translateX: this._headerTranslate}],
backgroundColor: ColorConfig.PRIMARY_90,
},
]}>
{
this.props.collapseColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.collapseColumns[indexConfig].width,
this.props.collapseColumns[indexConfig].name,
this.props.collapseColumns[indexConfig].visible,
);
})
}
</Animated.View>
</View>
);
};
renderRow = ({item, index}: { item: any, index: number }) => {
return (
<View key={index} style={styles.cellContainer}>
<View style={styles.normalCellContainer}>
{
this.props.normalColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.normalColumns[indexConfig].width,
item[this.props.normalColumns[indexConfig].accessName],
this.props.normalColumns[indexConfig].visible,
);
})
}
</View>
<Animated.View style={[
styles.collapseCellContainer,
{
position: 'absolute',
transform: [{translateX: this._headerTranslate}],
backgroundColor: ColorConfig.PRIMARY_97
},
]}>
{
this.props.collapseColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.collapseColumns[indexConfig].width,
item[this.props.collapseColumns[indexConfig].accessName],
this.props.collapseColumns[indexConfig].visible,
);
})
}
</Animated.View>
</View>
);
};
renderCell = (index: number, width: number, text: string, visible: boolean) => {
return (
<View key={index} style={[styles.cell, {width: width, opacity: visible ? 1 : 0}]}>
<Text style={styles.cellText}>{text}</Text>
</View>
);
};
}
const styles = StyleSheet.create({
fill: {
flex: 1,
},
// Header
cellContainer: {
overflow: 'hidden',
},
normalCellContainer: {
flexDirection: 'row',
},
collapseCellContainer: {
flexDirection: 'row',
},
cell: {
paddingTop: 8 * UIConfig.RATIO,
paddingBottom: 8 * UIConfig.RATIO,
paddingLeft: 8 * UIConfig.RATIO,
paddingRight: 8 * UIConfig.RATIO,
borderRightColor: ColorConfig.PRIMARY_ALPHA_10,
borderRightWidth: UIConfig.RATIO,
borderBottomColor: ColorConfig.PRIMARY_ALPHA_10,
borderBottomWidth: UIConfig.RATIO,
justifyContent: 'center',
alignItems: 'center',
},
cellText: {
textAlign: 'center',
color: ColorConfig.PRIMARY,
fontSize: 14 * UIConfig.RATIO,
}
});
export default CollapseTable;
Hope this answer can help you like it did to me!

I can try create login page but getting error on state email

import React, { Component } from 'react';
import {
SafeAreaView,
Text,
View,
Image,
ScrollView,
StyleSheet,
StatusBar,
TextInput,
TouchableOpacity
} from 'react-native';
export default class LoginFrom extends React. Component {
state = {
isLoading: false,
strEmail: "test#example.com", isEmailValid: true, errMsgEmail: "",
strPassword: "test#123", isPasswordValid: true, errMsgPassword: "",
strErrMsg: ""
}
login() {
setTimeout(() => {
fetch("url", {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
'email': this.state.strEmail,
'password': this.state.strPassword
})
}).then((response) => {
if (response.status == 200) {
return response.json()
} else {
return null
}
}).then((responseJson) => {
console.log(responseJson);
if (responseJson != null) {
this.setState({
strErrMsg: ""
})
} else {
this.setState({
strErrMsg: "Email and password does not match."
})
}
})
}, 100);
}
txtEmailChangeHangler = (val) => {
this.setState({
strEmail: val.trim()
})
}
txtPasswordChangeHangler = (val) => {
this.setState({
strPassword: val.trim()
})
}
render() {
return (
<View style={styles.container}>
<TextInput style={styles.inputbox}
onSubmitEditing={() => { this.secondTextInput.focus(); }}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder='Email'
selectionColor='#fff'
value={this.state.strEmail}
onChangeText={this.txtEmailChangeHangler}
keyboardType='email-address' />
<TextInput
secureTextEntry={true}
style={styles.inputbox}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder='password'
onChangeText={this.txtPasswordChangeHangler}
value={this.state.strPassword}
ref={(input) => { this.secondTextInput = input; }} />
<TouchableOpacity onPress={this.login} style={styles.button}>
<Text style={styles.buttontext}>{this.props.type}</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#D3EDFA',
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center'
},
inputbox: {
width: 300,
backgroundColor: 'rgba(255,255,255,1)',
borderRadius: 25,
paddingHorizontal: 16,
marginVertical: 10
},
button: {
width: 300,
backgroundColor: '#ED6825',
borderRadius: 25,
paddingVertical: 16,
marginVertical: 10
},
buttontext:
{
fontSize: 16,
color: '#ffffff',
fontWeight: '100',
textAlign: 'center',
paddingHorizontal: 16,
}
})
Just try replacing login function with fat arrow function
login() {
// your code here
}
to
login = () => {
// your code here
}
hope it helps, this is done because fat arrow functions implicty binds this keyword

React Native - Modal is showing on a different FlatList screen

I'am having trouble with modal because I have some in a "Datails screen" with Flatlist and it is working fine, actually. But the thing is, before navigating to my "Datails screen" the user will first see the "Category screen", and here is where the problem. Because I didn't type any modal at my "Category screen", but whenever I click on any button in there a modal is showing, it looks very tricky for me.
Here is my code
Details.js (this is the only screen where I want to display my modal)
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, Modal
} from 'react-native';
export default class Details extends Component {
static navigationOptions = {
title: ''
};
constructor()
{
super ()
this.state = {
showModal: true
}
}
state = {
data: [],
refreshing: false
};
fetchData = async() => {
const { params } = this.props.navigation.state;
const response_Cat = await fetch('http://192.168.254.100:3307/categories/' + params.id);
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
_onRefresh() {
this.setState({ refreshing: true });
this.fetchData().then(() => {
this.setState({ refreshing: false })
});
};
render() {
const { params } = this.props.navigation.state;
return (
<View style = { styles.container }>
<FlatList
data = { this.state.data }
renderItem = {({ item }) =>
<TouchableOpacity style = { styles.buttonContainer }>
<Text style = { styles.buttonText }
onPress = { () => { this.setState({showModal:true}) } }>{ item.menu_desc } { item.menu_price }</Text>
</TouchableOpacity>
}
keyExtractor={(item, index) => index.toString()}
/*refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh = { this._onRefresh.bind(this) }
/>
}*/
/>
<View>
<Modal
onRequestClose={() => console.warn('no warning')}
visible={this.state.showModal}
>
<TouchableOpacity style = { styles.buttonContainer }>
<Text style = { styles.buttonText }
onPress = { () => { this.setState({ showModal:false }) } }>Hello</Text>
</TouchableOpacity>
</Modal>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
},
pageName:{
margin:10,fontWeight:'bold',
color:'#000', textAlign:'center'
},
productBox:{
padding:5,margin:10,borderColor:'orange',borderBottomWidth:1
},
price:{
padding:5, color:'orange',fontWeight:'bold',textAlign:'center'
},
proName:{
padding:5,color:'blue',textAlign:'center'
},
buttonContainer: {
backgroundColor: '#f7c744',
paddingVertical: 10,
borderRadius: 30,
marginBottom: 10,
},
buttonText: {
textAlign: "center",
color: 'rgb(32, 53, 70)',
fontWeight: 'bold',
fontSize: 18
},
modalView: {
backgroundColor: "#aaa",
height: 150,
justifyContent: 'center',
alignItems: 'center'
},
closeText: {
backgroundColor: '#333',
color: '#bbb',
padding: 5,
margin: 20
}
})
//AppRegistry.registerComponent('Details', () => Details);
categories.js (this is the page where I don't type any modal code, I guess)
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl
} from 'react-native';
export default class Categories extends Component {
state = {
data: [],
refreshing: false
};
fetchData = async() => {
const { params } = this.props.navigation.state;
const response_Cat = await fetch('http://192.168.254.100:3307/categories/');
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
_onRefresh() {
this.setState({ refreshing: true });
this.fetchData().then(() => {
this.setState({ refreshing: false })
});
}
render() {
const { params } = this.props.navigation.state;
return (
<View style = { styles.container }>
<FlatList
data = { this.state.data }
renderItem = {({ item }) =>
<TouchableOpacity style = {styles.buttonContainer}>
<Text style = {styles.buttonText}
onPress = { () => this.props.navigation.navigate('Details', { id: item.cat_id }) }>{ item.cat_name }</Text>
</TouchableOpacity>
}
keyExtractor={(item, index) => index.toString()}
refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh = { this._onRefresh.bind(this) }
/>
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
},
pageName:{
margin:10,fontWeight:'bold',
color:'#000', textAlign:'center'
},
productBox:{
padding:5,margin:10,borderColor:'orange',borderBottomWidth:1
},
price:{
padding:5, color:'orange',fontWeight:'bold',textAlign:'center'
},
proName:{
padding:5,color:'blue',textAlign:'center'
},
buttonContainer: {
backgroundColor: '#f7c744',
paddingVertical: 10,
borderRadius: 30,
marginBottom: 10,
},
buttonText: {
textAlign: "center",
color: 'rgb(32, 53, 70)',
fontWeight: 'bold',
fontSize: 18
},
})
AppRegistry.registerComponent('Categories', () => Categories);
In your details.js you kept showModal: true in constructor itself.
Change it to false, and make it true whenever you want to show a modal.
I guess you should make it true after you have successfully fetched data. i.e keep it in fetchData()
this.setState({data: category_Cat, showModal:true});

Categories

Resources