javascript - Làm thế nào để thay đổi các chế độ xem trong cùng một màn hình (React Native)?
Tôi muốn sao chép những điều sau với react-native-scrollable-tab-view:
Hiện tại mã của tôi như sau, nhưng tôi không chắc cách thực hiện và kết hợp module để mọi thứ trở nên dễ dàng hơn - có ai có ý tưởng nào về cách tôi có thể triển khai việc này không? (Tôi là người mới nên bất kỳ sự giúp đỡ nào cũng được đánh giá cao):
Đây là chính (chế độ xem tab):
'use strict';
var React = require('react-native');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var Icon = require('react-native-vector-icons/FontAwesome');
var Restaurants = require('../Helpers/Restaurants');
var More = require('../Helpers/More');
var api = require('../Api/Api');
var Profile = require('../Helpers/Profile');
var Recipes = require('../Helpers/Recipes');
var Actions = require('react-native-router-flux').Actions;
var Home = require('../Helpers/Home');
var {
StyleSheet,
Text,
View,
Image,
TabBarIOS,
Component
} = React;
class Main extends React.Component{
constructor(props) {
super(props);
this.state = {
selectedTab: 'home',
notifCount: 0,
presses: 0,
};
}
GoBack() {
this.props.navigator.pop();
}
render() {
return (
<TabBarIOS
tintColor="#49B64D"
barTintColor="rgba(255,255,255,0.3)"
selectedTab={this.state.selectedTab}>
<Icon.TabBarItem
selected={this.state.selectedTab === 'home'}
icon={require('image!homeicon')}
onPress={() => {
this.setState({
selectedTab: 'home',
});
}}>
<Home/>
</Icon.TabBarItem>
<Icon.TabBarItem
selected={this.state.selectedTab === 'restaurants'}
icon={require('image!nomicon')}
onPress={() => {
this.setState({
selectedTab: 'restaurants',
});
}}>
<Restaurants/>
</Icon.TabBarItem>
<Icon.TabBarItem
selected={this.state.selectedTab === 'recipes'}
icon={require('image!haticon')}
onPress={() => {
this.setState({
selectedTab: 'recipes',
});
}}>
<Recipes/>
</Icon.TabBarItem>
<Icon.TabBarItem
selected={this.state.selectedTab === 'profile'}
icon={require('image!accounticon')}
onPress={() => {
this.setState({
selectedTab: 'profile',
});
}}>
<Profile/>
</Icon.TabBarItem>
</TabBarIOS>
);
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent'
},
bgImage: {
flex: 1,
width: window.width,
resizeMode: 'cover',
},
});
module.exports = Main;
Đây là giao diện công thức khi bạn nhấp vào tab công thức:
'use strict';
var React = require('react-native');
var Seperator = require('./Seperator');
var api = require('../Api/Api');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var LinearGradient = require('react-native-linear-gradient');
var Swipeout = require('react-native-swipeout');
var List = require('./List');
var RecipeDetails = require('./RecipeDetails');
var Actions = require('react-native-router-flux').Actions;
var {
ScrollView,
Text,
View,
TouchableHighlight,
StyleSheet,
Image,
ListView,
NavigatorIOS,
} = React;
var styles = StyleSheet.create({
description: {
fontSize: 20,
textAlign: 'center',
color: '#FFFFFF'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
linearGradient: {
flex: 1,
paddingLeft: 15,
paddingRight: 15,
borderRadius: 5,
opacity: 0.9,
height: window.width,
},
dietText: {
color:'white',
fontFamily: 'Avenir Next',
alignSelf:'center',
},
title: {
textAlign:'left',
marginTop: (window.width/1.4),
fontSize: 20,
color: 'white',
fontFamily: 'Avenir Next',
fontWeight: '500',
},
dietbuble: {
backgroundColor:'transparent',
height:20,
width:60,
borderRadius: 10,
backgroundColor:'#49B64D',
marginRight:5,
},
nombtn: {
height: 30,
width: 30,
marginBottom: 5,
},
arrow: {
height: 15,
width: 15,
marginRight: 20,
marginTop: 5,
},
upvotenum: {
marginRight: 5,
fontSize: 20,
fontWeight: "600",
color: 'white',
fontFamily: 'Avenir Next'
},
dish_num: {
backgroundColor:'#49B64D',
height: 30,
width: 100,
marginLeft: window.width/1.36,
borderRadius: 5,
},
dishtext: {
fontFamily: "Avenir Next",
fontSize: 20,
fontWeight: "400",
textAlign: 'center',
color:"white",
},
profilebubble: {
width: 40,
height: 40,
borderRadius: 20,
margin: 2,
}
});
var list = [
{
component: <List/>
}
]
class Recipes extends React.Component{
constructor(props) {
super(props);
this.state = {
venues: new Object(),
};
}
activateHome() {
api.getAnything(this.props.paleo,this.props.vegan,this.props.vegetarian,this.props.healthy,this.props.dairyfree,this.props.nutfree,this.props.glutenfree)
.then((res) => {
console.log(res);
return res;
});
}
detailsRecipe() {
this.props.navigator.push ({
component: RecipeDetails,
title: "",
})
}
render(){
return (
<ScrollView
alwaysBounceVertical={true}
scrollEventThrottle={200}>
<Swipeout right={list}>
<View style={styles.container}>
<Image source={{uri: 'http://i.huffpost.com/gadgets/slideshows/404432/slide_404432_5031844_free.jpg'}} style={{width: window.width, height: window.width}}>
<View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
<Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
</View>
</View>
<LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
<TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
<View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
<Text style={styles.title}>Recipe Name | 10 Mins</Text>
</View>
</TouchableHighlight>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegan</Text>
</View>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegie</Text>
</View>
<View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
<Text style={styles.upvotenum} >20</Text>
<Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
<Image style={styles.nombtn} source={require('image!nombtn')}></Image>
</View>
</View>
</LinearGradient>
</View>
</Image>
</View>
</Swipeout>
<Seperator/>
<Swipeout right={list}>
<View style={styles.container}>
<Image source={{uri: 'http://www.funkinutt.com/wp-content/uploads/2013/06/Vegan-Scallops-Sophies-Kitchen.jpg'}} style={{width: window.width, height: window.width}}>
<View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
<Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
</View>
</View>
<LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
<TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
<View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
<Text style={styles.title}>Recipe Name | 10 Mins</Text>
</View>
</TouchableHighlight>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegan</Text>
</View>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegie</Text>
</View>
<View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
<Text style={styles.upvotenum} >20</Text>
<Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
<Image style={styles.nombtn} source={require('image!nombtn')}></Image>
</View>
</View>
</LinearGradient>
</View>
</Image>
</View>
</Swipeout>
<Seperator/>
<Swipeout right={list}>
<View style={styles.container}>
<Image source={{uri: 'http://m5.paperblog.com/i/37/370315/guest-blogger-vegan-richa-samosa-and-onion-bh-L-KmHfF4.jpeg'}} style={{width: window.width, height: window.width}}>
<View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
<Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
</View>
</View>
<LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
<TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
<View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
<Text style={styles.title}>Recipe Name | 10 Mins</Text>
</View>
</TouchableHighlight>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegan</Text>
</View>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegie</Text>
</View>
<View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
<Text style={styles.upvotenum} >20</Text>
<Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
<Image style={styles.nombtn} source={require('image!nombtn')}></Image>
</View>
</View>
</LinearGradient>
</View>
</Image>
</View>
</Swipeout>
<Seperator/>
<Swipeout right={list}>
<View style={styles.container}>
<Image source={{uri: 'http://www.choosingraw.com/wp-content/uploads/2014/09/IMG_8328.jpg'}} style={{width: window.width, height: window.width}}>
<View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
<Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
</View>
</View>
<LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
<TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
<View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
<Text style={styles.title}>Recipe Name | 10 Mins</Text>
</View>
</TouchableHighlight>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegan</Text>
</View>
<View style={styles.dietbuble}>
<Text style={styles.dietText}>Vegie</Text>
</View>
<View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
<Text style={styles.upvotenum} >20</Text>
<Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
<Image style={styles.nombtn} source={require('image!nombtn')}></Image>
</View>
</View>
</LinearGradient>
</View>
</Image>
</View>
</Swipeout>
<Seperator/>
</ScrollView>
)
}
};
module.exports = Recipes;
Và đây là chế độ xem chi tiết công thức:
'use strict';
var React = require('react-native');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var LinearGradient = require('react-native-linear-gradient');
var Tabbar = require('react-native-tabbar');
var Item = Tabbar.Item;
var {
StyleSheet,
View,
Text,
Component,
Image,
ScrollView,
TouchableHighlight,
} = React;
var styles = StyleSheet.create({
description: {
fontSize: 20,
textAlign: 'center',
color: '#FFFFFF'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
venue_image: {
width: window.width,
height: window.height/4,
flex: 1,
},
linearGradient: {
flex: 1,
paddingLeft: 15,
paddingRight: 15,
opacity: 0.9,
height: window.height/3.7,
},
title: {
textAlign:'left',
fontSize: 15,
color: 'white',
fontFamily: 'Avenir Next',
fontWeight: '500',
},
nombtn: {
height: 30,
width: 30,
marginBottom: 5,
},
arrow: {
height: 15,
width: 15,
marginRight: 20,
marginTop: 5,
},
upvotenum: {
marginRight: 5,
fontSize: 20,
fontWeight: "600",
color: 'white',
fontFamily: 'Avenir Next'
},
dietbuble: {
backgroundColor:'transparent',
height:20,
width:60,
borderRadius: 10,
backgroundColor:'#49B64D',
marginRight:5,
},
submenutext: {
fontFamily: 'Avenir Next',
fontSize: 15,
fontWeight: '600',
color: 'white',
alignSelf: 'center',
marginTop: 10,
},
undernum: {
fontFamily: 'Avenir Next',
fontSize: 30,
fontWeight: '400',
color: 'white',
alignSelf: 'center',
},
units: {
fontFamily: 'Avenir Next',
fontSize: 10,
color: 'white',
alignSelf: 'center',
}
});
class VenueDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'ingredients',
};
}
_Directions() {
this.setState({selectedTab: 'directions'});
console.log(this.state.selectedTab);
}
_Nutrition() {
this.setState({selectedTab: 'nutrition'});
console.log(this.state.selectedTab);
}
_Ingredients() {
this.setState({selectedTab: 'ingredients'});
console.log(this.state.selectedTab);
}
makeBackground(btn){
var featurebox = {
flex: 1,
height: window.width/4,
width: window.width/3,
alignItems: 'center',
justifyContent: 'center',
}
if(btn === 0 || btn === 2){
featurebox.backgroundColor = '#49B64D';
} else if (btn === 1){
featurebox.backgroundColor = '#585858';
}
return featurebox;
}
render() {
return (
<View style={styles.container}>
<View style={styles.container}>
<Image source={{uri: 'http://i.huffpost.com/gadgets/slideshows/404432/slide_404432_5031844_free.jpg'}} style={styles.venue_image}>
<LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: window.height/4.3}}>
<View style={{backgroundColor:'transparent', marginRight: window.width/4, marginLeft: 10}}>
<Text style={styles.title}>Recipe Name | 10 Mins</Text>
</View>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<Text style={styles.upvotenum} >20</Text>
<Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
<Image style={styles.nombtn} source={require('image!nombtn')}></Image>
</View>
</View>
</LinearGradient>
</Image>
</View>
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
<TouchableHighlight
onPress={this._Ingredients.bind(this)}
style={this.makeBackground(0)}
underlayColor='transparent'>
<View>
<Text style={styles.submenutext}>Ingredients</Text>
<Text style={styles.undernum}>5</Text>
<Text style={styles.units}>Count</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
onPress={this._Nutrition.bind(this)}
style={this.makeBackground(1)}
underlayColor='transparent'>
<View>
<Text style={styles.submenutext}>Nutrition</Text>
<Text style={styles.undernum}>200</Text>
<Text style={styles.units}>Sugars</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
onPress={this._Directions.bind(this)}
style={this.makeBackground(2)}
underlayColor='transparent'>
<View>
<Text style={styles.submenutext}>Directions</Text>
<Text style={styles.undernum}>10</Text>
<Text style={styles.units}>Hours</Text>
</View>
</TouchableHighlight>
</View>
<ScrollView>
</ScrollView>
</View>
);
}
}
module.exports = VenueDetails;
Hiện tại, tất cả những điều này trông như sau:
Câu trả lời #1
Những gì tôi sẽ làm là tạo một mảng các đối tượng với mỗi đối tượng đại diện cho các chế độ xem/thành phần khác nhau trong thanh trượt chân trang của bạn. Sau đó, hãy có một thuộc tính trong state của bạn là tab đang hoạt động và khi người dùng nhấp vào một tab mới, cập nhật tab đang hoạt động thành bất kỳ chỉ mục mới nào. Những gì chúng ta sẽ làm là, bất cứ tab nào đang hoạt động, lấy thành phần cụ thể đó mà bạn đã có trong tabMap bạn đã tạo ở trên và hiển thị nó. Mã sẽ trông giống như sau.
var tabMap = [
{key: 0, icon: 'ion|ios-contact-outline', state: 'bio', asArray: false, Component: About},
{key: 1, icon: 'ion|ios-paper', state: 'posts', asArray: true, Component: Posts},
{key: 2, icon: 'ion|ios-people', state: 'friends', asArray: false, Component: Friends},
{key: 3, icon: 'ion|ios-heart', state: 'activity', asArray: false, Component: Activity},
];
Vì vậy điều đó đại diện cho các tab khác nhau ở phần dưới.
getInitialState(){
return {
activeTab: 0
}
}
Đó là trạng thái ban đầu của tôi, nó sẽ theo dõi tab mà tôi đang sử dụng.
Sau đó trong phương thức render của tôi, tôi lấy thành phần của tab đang hoạt động hiện tại,
var BodyComponent = tabMap[this.state.activeTabIndex].Component;
Bây giờ tôi đã có thành phần, tôi có thể đơn giản hiển thị BodyComponent truyền vào bất kỳ dữ liệu nào mà tôi muốn.
<BodyComponent
header={tabMap[this.state.activeTabIndex].header}
authedUser={this.props.authedUser}
isGuest={this.props.isGuest}
userToRender={this.state.userToRender}
data={this.state[tabMap[this.state.activeTabIndex].state]} />
Câu trả lời #2
Đó là một tính năng bị thiếu của react-native-router-flux (để chuyển giữa các 'tab' trong cùng một container) và tôi đã thêm nó gần đây, vui lòng kiểm tra phiên bản mới nhất.
Bạn cần sử dụng phần tử Container và định nghĩa các tuyến đường của bạn bên trong nó. Ngoài ra, bạn phải định nghĩa phần triển khai TabBar để sử dụng với container đó (xem ví dụ với TabBarFlux của nó)

