Как мы можем сделать вид вкладок липким с помощью response-native-tab-view с помощью ScrollView и FlatList? - PullRequest
1 голос
/ 05 мая 2020

Я новичок 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 дальше

Пожалуйста, помогите мне. Спасибо большое!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...