Я новичок ie в React Native и пытаюсь сделать вид вкладки с помощью react-native-tab-view
. То, что я хочу достичь, похоже на пользовательский интерфейс профиля Twitter.
Вот что я сделал до сих пор:
Прилепленный заголовок
То, что я хочу Достижение - когда пользователь прокручивает страницу вниз, панели вкладок прилипают к анимированному заголовку. И когда пользователи снова прокручивают страницу вверх, вкладка медленно возвращается в предыдущее положение.
Я пробовал много способов сделать это, но не мог хорошо обдумать это.
Вот код
import ...
const WIDTH = Dimensions.get('screen').width;
const initialLayout = WIDTH;
const HEADER_MAX_HEIGHT = 120;
const HEADER_MIN_HEIGHT = 70;
const PROFILE_IMAGE_MAX_HEIGHT = 80;
const PROFILE_IMAGE_MIN_HEIGHT = 40;
const imgData = [
// ...
];
const NUM_COLUMNS = 3;
const ProfileScreen = (props) => {
const [index, setIndex] = useState(0);
const [isFollowed, setIsFollowed] = useState(false);
const [enableScrollView, setEnableScrollView] = useState(false);
const [routes] = React.useState([
{ key: 'post', title: 'Posts'},
{ key: 'trip', title: 'Blogs'},
]);
const renderScene = SceneMap({
post: PostView,
trip: TripView,
});
const scrollY = useRef(new Animated.Value(0)).current;
const headerHeight = scrollY.interpolate({
inputRange: [0, HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT], // [0, 50]
outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT], // [120,70]
extrapolate: 'clamp'
});
const profileImageHeight = scrollY.interpolate({
inputRange: [0, HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT],
outputRange: [PROFILE_IMAGE_MAX_HEIGHT, PROFILE_IMAGE_MIN_HEIGHT],
extrapolate: 'clamp'
});
const profileImageMarginTop = scrollY.interpolate({
inputRange: [0, HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT],
outputRange: [
HEADER_MAX_HEIGHT - PROFILE_IMAGE_MAX_HEIGHT / 2,
HEADER_MAX_HEIGHT + 5
],
extrapolate: 'clamp'
});
const headerZindex = scrollY.interpolate({
inputRange: [0, HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT, 120],
outputRange: [0, 0, 1000],
extrapolate: 'clamp'
});
const profile = useSelector(state => state.profile.userProfile );
return(
<SafeAreaView style={styles.container}>
<Animated.View style={[styles.backgroundImage, {
height: headerHeight,
zIndex: headerZindex,
elevation: headerZindex, //required for android
}]}>
</Animated.View>
<ScrollView
style={{flex: 1}}
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: scrollY}}}],
)}
bounces={true}
nestedScrollEnabled={true}
>
<View style={{overflow: 'hidden', position: 'absolute', top: HEADER_MIN_HEIGHT/2, left: HEADER_MIN_HEIGHT*2.6}}>
<TouchableOpacity><Icon color='white' name='camera-retro' size={30} /></TouchableOpacity>
</View>
<Animated.View style={[styles.profileImgContainer,{
height: profileImageHeight,
width: profileImageHeight,
marginTop: profileImageMarginTop,
borderRadius: PROFILE_IMAGE_MAX_HEIGHT/2,
}]}>
<Image source={{uri: profile.userAvatar}} style={styles.profileImg} />
</Animated.View>
[...]
<TabView
style={{
flex: 4.2,
}}
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
renderTabBar={props => {
return(
<Animated.View style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
zIndex: headerZindex,
elevation: headerZindex,
// transform: [{ translateY: tabBarHeader }],
// marginTop: tabBarHeader
}}>
<TabBar {...props} />
</Animated.View>
)
}}
/>
</ScrollView>
</SafeAreaView>
);
};
const PostView = props => {
return(
<View>
<FlatList
style={{marginTop: 53}}
data={imgData}
numColumns={NUM_COLUMNS}
keyExtractor={item => item.id}
renderItem={(itemData) => (
<TouchableOpacity>
<Image source={itemData.item.source} style={{height:WIDTH/3, width:WIDTH/3, borderColor: 'white', borderWidth: 2}}/>
</TouchableOpacity>
)}
/>
</View>
)
}
const TripView = props => {
return(
<Button title="Trip Display" />
)
}
export default ProfileScreen;
const styles = StyleSheet.create({
//...
})
Я также обнаружил ошибку: «Виртуализированный список никогда не должен быть вложен в простой ScrollView» и обнаружил такие реквизиты, как ListHeaderComponent
, или используйте onStartShouldSetResponderCapture
.
Но я не могу понять, как правильно их реализовать, или, если быть точным, я не знаю, куда go дальше
Пожалуйста, помогите мне. Спасибо большое!