PedroBern / react-native-collapsible-tab-view

A cross-platform Collapsible Tab View component for React Native
MIT License
830 stars 161 forks source link

how to do this #214

Closed star-heng closed 2 years ago

star-heng commented 2 years ago

https://user-images.githubusercontent.com/8955903/141935243-1decf63e-df57-4719-9f7a-f5e5b5d7d0ff.mp4

import * as React from 'react';
import {
  View,
  Text,
  StyleSheet,
  Platform,
  TouchableOpacity,
  ScrollView,
} from 'react-native';
import * as Tabs from 'react-native-collapsible-tab-view';
import Animated, {
  interpolate,
  useAnimatedStyle,
  useDerivedValue,
} from 'react-native-reanimated';

import {useRefresh} from './useRefresh';

type Item = {name: string; number: number};

const CONTACTS: Item[] = [
  {name: 'Marissa Castillo', number: 7766398169},
  {name: 'Denzel Curry', number: 9394378449},
  {name: 'Miles Ferguson', number: 8966872888},
  {name: 'Desiree Webster', number: 6818656371},
  {name: 'Samantha Young', number: 6538288534},
  {name: 'Irene Hunter', number: 2932176249},
  {name: 'Annie Ryan', number: 4718456627},
  {name: 'Sasha Oliver', number: 9743195919},
  {name: 'Jarrod Avila', number: 8339212305},
  {name: 'Griffin Weaver', number: 6059349721},
  {name: 'Emilee Moss', number: 7382905180},
  {name: 'Angelique Oliver', number: 9689298436},
  {name: 'Emanuel Little', number: 6673376805},
  {name: 'Wayne Day', number: 6918839582},
  {name: 'Lauren Reese', number: 4652613201},
  {name: 'Kailey Ward', number: 2232609512},
  {name: 'Gabrielle Newman', number: 2837997127},
  {name: 'Luke Strickland', number: 8404732322},
  {name: 'Payton Garza', number: 7916140875},
  {name: 'Anna Moss', number: 3504954657},
  {name: 'Kailey Vazquez', number: 3002136330},
  {name: 'Jennifer Coleman', number: 5469629753},
  {name: 'Cindy Casey', number: 8446175026},
  {name: 'Dillon Doyle', number: 5614510703},
  {name: 'Savannah Garcia', number: 5634775094},
  {name: 'Kailey Hudson', number: 3289239675},
  {name: 'Ariel Green', number: 2103492196},
  {name: 'Weston Perez', number: 2984221823},
  {name: 'Kari Juarez', number: 9502125065},
  {name: 'Sara Sanders', number: 7696668206},
  {name: 'Griffin Le', number: 3396937040},
  {name: 'Fernando Valdez', number: 9124257306},
  {name: 'Taylor Marshall', number: 9656072372},
  {name: 'Elias Dunn', number: 9738536473},
  {name: 'Diane Barrett', number: 6886824829},
  {name: 'Samuel Freeman', number: 5523948094},
  {name: 'Irene Garza', number: 2077694008},
  {name: 'Devante Alvarez', number: 9897002645},
  {name: 'Sydney Floyd', number: 6462897254},
  {name: 'Toni Dixon', number: 3775448213},
  {name: 'Anastasia Spencer', number: 4548212752},
  {name: 'Reid Cortez', number: 6668056507},
  {name: 'Ramon Duncan', number: 8889157751},
  {name: 'Kenny Moreno', number: 5748219540},
  {name: 'Shelby Craig', number: 9473708675},
  {name: 'Jordyn Brewer', number: 7552277991},
  {name: 'Tanya Walker', number: 4308189657},
  {name: 'Nolan Figueroa', number: 9173443776},
  {name: 'Sophia Gibbs', number: 6435942770},
  {name: 'Vincent Sandoval', number: 2606111495},
];

class ContactItem extends React.PureComponent<{
  item: {name: string; number: number};
}> {
  render() {
    const {item} = this.props;

    return (
      <TouchableOpacity>
        <View style={styles.item}>
          <View style={styles.avatar}>
            <Text style={styles.letter}>
              {item.name.slice(0, 1).toUpperCase()}
            </Text>
          </View>
          <View style={styles.details}>
            <Text style={styles.name}>{item.name}</Text>
            <Text style={styles.number}>{item.number}</Text>
          </View>
        </View>
      </TouchableOpacity>
    );
  }
}

const ItemSeparator = () => <View style={styles.separator} />;

const renderItem = ({item}: {item: Item}) => <ContactItem item={item} />;

const ListEmptyComponent = () => {
  const {top, height} = Tabs.useHeaderMeasurements();
  const translateY = useDerivedValue(() => {
    return interpolate(-top.value, [0, height], [-height / 2, 0]);
  }, [height]);

  const stylez = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: translateY.value,
        },
      ],
    };
  });

  return (
    <Animated.View style={[styles.listEmpty, stylez]}>
      <Text>Centered Empty List!</Text>
    </Animated.View>
  );
};

const Contacts: React.FC<{
  emptyContacts?: boolean;
  nestedScrollEnabled?: boolean;
}> = ({emptyContacts, nestedScrollEnabled}) => {
  const [isRefreshing, startRefreshing] = useRefresh();

  return (
    <Tabs.FlatList
      data={emptyContacts ? [] : CONTACTS}
      keyExtractor={(_, i) => String(i)}
      stickyHeaderIndices={[0]}
      renderItem={renderItem}
      ItemSeparatorComponent={ItemSeparator}
      ListEmptyComponent={ListEmptyComponent}
      ListHeaderComponent={() => {
        return (
          <ScrollView
            horizontal
            contentContainerStyle={{
              height: 100,
              flexDirection: 'row',
              justifyContent: 'flex-start',
              alignItems: 'flex-start',
              paddingLeft: 16,
            }}>
            {CONTACTS.map((item, index) => {
              return (
                <View
                  key={index.toString()}
                  style={{
                    width: 60,
                    height: 90,
                    backgroundColor: 'green',
                    marginRight: 10,
                    justifyContent: 'center',
                    alignItems: 'center',
                  }}>
                  <Text>{item.name}</Text>
                </View>
              );
            })}
          </ScrollView>
        );
      }}
      // see https://github.com/software-mansion/react-native-reanimated/issues/1703
      onRefresh={Platform.OS === 'ios' ? startRefreshing : undefined}
      refreshing={Platform.OS === 'ios' ? isRefreshing : undefined}
      nestedScrollEnabled={nestedScrollEnabled}
    />
  );
};

export default Contacts;

const styles = StyleSheet.create({
  item: {
    backgroundColor: 'white',
    flexDirection: 'row',
    alignItems: 'center',
    padding: 8,
  },
  avatar: {
    height: 36,
    width: 36,
    borderRadius: 18,
    backgroundColor: '#e91e63',
    alignItems: 'center',
    justifyContent: 'center',
  },
  letter: {
    color: 'white',
    fontWeight: 'bold',
  },
  details: {
    margin: 8,
  },
  name: {
    fontWeight: 'bold',
    fontSize: 14,
    color: 'black',
  },
  number: {
    fontSize: 12,
    color: '#999',
  },
  separator: {
    height: StyleSheet.hairlineWidth,
    backgroundColor: 'rgba(0, 0, 0, .08)',
  },
  listEmpty: {
    alignItems: 'center',
    flex: 1,
    justifyContent: 'center',
    borderColor: 'black',
    borderWidth: 10,
  },
});
star-heng commented 2 years ago

just do it~~~

import {ScrollView} from 'react-native-gesture-handler';