reactjsreact-nativereact-native-deck-swiper

Overlay label shows up behind that card in react native deck swiper


Here is my code. On swipe action, the overlay label shows behind the card on swipe right or left. It has something to do with the zIndex of the overlay label. What's the way to make it show up on top of the card instead of behind it. When it's behind, it actually cuts off and only "Li" or "pe" show up on right/left swipe of "like" and "nope".

import React, { useRef, useCallback, useEffect, useState } from 'react'
import { View, Text, Image, Dimensions, TouchableOpacity } from 'react-native'
import Swiper from 'react-native-deck-swiper'
import { ScaledSheet, scale, verticalScale, moderateScale } from 'react-native-size-matters';
import Icon from 'react-native-vector-icons/Entypo';
import OIcon from 'react-native-vector-icons/Octicons';
import IIcon from 'react-native-vector-icons/Ionicons';
import BrandLogo from '../components/atoms/BrandLogo';
import Header from '../components/atoms/Header';
import Loader from '../components/atoms/Loader';
import Card from '../components/atoms/Card';
import IconButton from '../components/atoms/IconButton';
import OverlayLabel from '../components/atoms/OverlayLabel';
import {COLORS, FONTS, SPACING} from '../constants/theme';
const { height, width } = Dimensions.get('window');
import {useDiscoverProfiles} from '../zustand/useDiscoverProfiles';
import {useFocusEffect} from '@react-navigation/native';
import {useUserAction} from '../zustand/useUserAction';

const HomeScreen = () => {
  const getDiscoverProfiles = useDiscoverProfiles(state => state.getDiscoverProfiles);
  const discoverProfiles = useDiscoverProfiles(state => state.discoverProfiles);
  const discoverProfilesLoader = useDiscoverProfiles(state => state.discoverProfilesLoader);
  const profileCount = useDiscoverProfiles(state => state.profileCount);
  const likeUser = useUserAction(state => state.like);
  const skipUser = useUserAction(state => state.skip);
  const blockUser = useUserAction(state => state.block);
  // const [userId, setuserId] = useState(null);
  const [cardIndexCount, setcardIndexCount] = useState(0);
  const [isSwipeAll, setisSwipeAll] = useState(false);

  const useSwiper = useRef(null);
  const handleOnSwipedLeft = (cardIndex) => {
    // onPressSkip(discoverProfiles[cardIndex].id);
    setcardIndexCount(cardIndex + parseInt(1));
    return useSwiper.current.swipeLeft();
  }
  const handleOnSwipedTop = (cardIndex) => {
    // onPressBlock(discoverProfiles[cardIndex].id);
    setcardIndexCount(cardIndex + parseInt(1));
    return useSwiper.current.swipeTop();
  }
  const handleOnSwipedRight = (cardIndex) => {
    // onPressLike(discoverProfiles[cardIndex].id);
    setcardIndexCount(cardIndex + parseInt(1));
    return useSwiper.current.swipeRight();
  }
  const onPressSkip = async(cardIndex) => {
    // await skipUser(discoverProfiles[cardIndex].id);
  }
  const onPressBlock = async(cardIndex) => {
    // await blockUser(discoverProfiles[cardIndex].id);
  }
  const onPressLike = async(cardIndex) => {
    // await likeUser(discoverProfiles[cardIndex].id);
  }
  const cardDetails = (index) => {
    console.log({'index ID':index, 'user id':discoverProfiles[index].id});
  }

  useEffect(() => {
    getDiscoverProfiles();
    setisSwipeAll(false);
  }, []);

  useFocusEffect(
    useCallback(() => {
      getDiscoverProfiles();
      setisSwipeAll(false);
    }, []),
  );

  return (
    <>
      <Header />
      {discoverProfilesLoader ? 
        <Loader />
      :
        <View
          style={styles.container}
        >
          {isSwipeAll || discoverProfiles.length == 0 ?
            <View style={{justifyContent:'center', alignItems:'center'}}>
              <Text style={styles.payheaderText}>
                Sorry, we didn't find any recommendations for you today.
              </Text>
              <Text style={styles.paysubText}>
                Consider opening up your preferences. Even expanding your search distance by a few miles can make a difference.
              </Text>
              <TouchableOpacity onPress={()=>{}}>
                <Text style={styles.payBtn}>
                  Edit my preferences <IIcon name="arrow-forward-sharp" size={18} color="#fff" style={{ padding: 10 }} />
                </Text>
              </TouchableOpacity>
            </View>
          :
            <View style={styles.swiperContainer}>
              <Swiper
                ref={useSwiper}
                animateCardOpacity
                containerStyle={styles.container}
                cards={discoverProfiles}
                renderCard={(card, index) => <Card card={card} />}
                disableTopSwipe
                disableBottomSwipe
                onSwipedAll={()=>setisSwipeAll(true)}
                onTapCard={(index)=>cardDetails(index)}
                onSwipedLeft={(cardIndex)=>{
                  setcardIndexCount(cardIndex + parseInt(1));
                  onPressSkip(cardIndex);
                }}
                onSwipedRight={(cardIndex)=>{
                  setcardIndexCount(cardIndex + parseInt(1));
                  onPressLike(cardIndex);
                }}
                cardIndex={0}
                backgroundColor="white"
                stackSize={3}
                // infinite
                showSecondCard
                // animateOverlayLabelsOpacity
                overlayOpacityHorizontalThreshold={width/4}
                cardVerticalMargin={50}
                cardHorizontalMargin={30}
                overlayLabels={{
                  left: {
                    title: 'SKIP',
                    element: <OverlayLabel label="SKIP" color="red" />,
                    style: {
                      wrapper: styles.overlayWrapper,
                    },
                  },
                  right: {
                    title: 'LIKE',
                    element: <OverlayLabel label="LIKE" color="green" />,
                    style: {
                      wrapper: {
                        ...styles.overlayWrapper,
                        alignItems: 'flex-start',
                        marginLeft: 30,
                      },
                    },
                  },
                }}
              />
            </View>
          }
          {!isSwipeAll &&
            <View style={styles.buttonsContainer}>
              <IconButton
                name="close"
                onPress={()=>handleOnSwipedLeft(cardIndexCount)}
                color="white"
                backgroundColor="#E5566D"
              />
              <IconButton
                name="star"
                onPress={()=>handleOnSwipedTop(cardIndexCount)}
                color="white"
                backgroundColor="#3CA3FF"
              />
              <IconButton
                name="heart"
                onPress={()=>handleOnSwipedRight(cardIndexCount)}
                color="white"
                backgroundColor="#4CCC93"
              />
            </View>
          }
          <View style={{ flexDirection: 'row', backgroundColor: '#3E1D49' }}>
            <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
              <Icon name="message" size={20} color="#fff" style={{ padding: 10 }} />
            </View>
            <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
              <Icon name="location" size={20} color="#fff" style={{ padding: 10 }} />
            </View>
            <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
              <Icon name="user" size={20} color="#fff" style={{ padding: 10 }} />
            </View>
          </View>
        </View>
      }
    </>
  )
};

const styles = ScaledSheet.create({
  container: {
    backgroundColor:'#fff',
    flex: 1,
    justifyContent: 'space-between',
  },
  swiperContainer: {
    height: '50%',
  },
  buttonsContainer: {
    justifyContent: 'space-between',
    alignItems: 'center',
    flexDirection: 'row',
    paddingHorizontal: '15%',
    paddingTop: '15@ms',
  },
  overlayWrapper: {
    flexDirection: 'column',
    alignItems: 'flex-end',
    justifyContent: 'flex-start',
    marginTop: '30@ms',
    marginLeft: '-30@ms'
  },
  payheaderText: {
    fontFamily: 'Poppins',
    fontSize: '18@ms',
    color:'#000',
    marginTop:'50@ms',
    textAlign:'center',
    paddingHorizontal:'5%'
  },
  paysubText: {
    fontFamily: 'Poppins',
    fontSize: '14@ms',
    width:'80%',
    textAlign:'center',
    marginTop:'20@ms'
  },
  payBtn: {
    fontFamily: 'Poppins',
    fontSize: '15@ms',
    textAlign:'center',
    paddingVertical: '7@ms',
    paddingHorizontal: '20@ms',
    borderRadius: '20@ms',
    marginTop:'25@ms',
    backgroundColor: '#319795',
    color: '#fff',
    fontWeight: '700',
    alignSelf:'center',
  },
});

export default HomeScreen;

    import React, { useRef, useCallback, useEffect, useState } from 'react'
    import { View, Text, Image, Dimensions, TouchableOpacity } from 'react-native'
    import Swiper from 'react-native-deck-swiper'
    import { ScaledSheet, scale, verticalScale, moderateScale } from 'react-native-size-matters';
    import Icon from 'react-native-vector-icons/Entypo';
    import OIcon from 'react-native-vector-icons/Octicons';
    import IIcon from 'react-native-vector-icons/Ionicons';
    import BrandLogo from '../components/atoms/BrandLogo';
    import Header from '../components/atoms/Header';
    import Loader from '../components/atoms/Loader';
    import Card from '../components/atoms/Card';
    import IconButton from '../components/atoms/IconButton';
    import OverlayLabel from '../components/atoms/OverlayLabel';
    import {COLORS, FONTS, SPACING} from '../constants/theme';
    const { height, width } = Dimensions.get('window');
    import {useDiscoverProfiles} from '../zustand/useDiscoverProfiles';
    import {useFocusEffect} from '@react-navigation/native';
    import {useUserAction} from '../zustand/useUserAction';

    const HomeScreen = () => {
      const getDiscoverProfiles = useDiscoverProfiles(state => state.getDiscoverProfiles);
      const discoverProfiles = useDiscoverProfiles(state => state.discoverProfiles);
      const discoverProfilesLoader = useDiscoverProfiles(state => state.discoverProfilesLoader);
      const profileCount = useDiscoverProfiles(state => state.profileCount);
      const likeUser = useUserAction(state => state.like);
      const skipUser = useUserAction(state => state.skip);
      const blockUser = useUserAction(state => state.block);
      // const [userId, setuserId] = useState(null);
      const [cardIndexCount, setcardIndexCount] = useState(0);
      const [isSwipeAll, setisSwipeAll] = useState(false);

      const useSwiper = useRef(null);
      const handleOnSwipedLeft = (cardIndex) => {
        // onPressSkip(discoverProfiles[cardIndex].id);
        setcardIndexCount(cardIndex + parseInt(1));
        return useSwiper.current.swipeLeft();
      }
      const handleOnSwipedTop = (cardIndex) => {
        // onPressBlock(discoverProfiles[cardIndex].id);
        setcardIndexCount(cardIndex + parseInt(1));
        return useSwiper.current.swipeTop();
      }
      const handleOnSwipedRight = (cardIndex) => {
        // onPressLike(discoverProfiles[cardIndex].id);
        setcardIndexCount(cardIndex + parseInt(1));
        return useSwiper.current.swipeRight();
      }
      const onPressSkip = async(cardIndex) => {
        // await skipUser(discoverProfiles[cardIndex].id);
      }
      const onPressBlock = async(cardIndex) => {
        // await blockUser(discoverProfiles[cardIndex].id);
      }
      const onPressLike = async(cardIndex) => {
        // await likeUser(discoverProfiles[cardIndex].id);
      }
      const cardDetails = (index) => {
        console.log({'index ID':index, 'user id':discoverProfiles[index].id});
      }

      useEffect(() => {
        getDiscoverProfiles();
        setisSwipeAll(false);
      }, []);

      useFocusEffect(
        useCallback(() => {
          getDiscoverProfiles();
          setisSwipeAll(false);
        }, []),
      );

      return (
        <>
          <Header />
          {discoverProfilesLoader ? 
            <Loader />
          :
            <View
              style={styles.container}
            >
              {isSwipeAll || discoverProfiles.length == 0 ?
                <View style={{justifyContent:'center', alignItems:'center'}}>
                  <Text style={styles.payheaderText}>
                    Sorry, we didn't find any recommendations for you today.
                  </Text>
                  <Text style={styles.paysubText}>
                    Consider opening up your preferences. Even expanding your search distance by a few miles can make a difference.
                  </Text>
                  <TouchableOpacity onPress={()=>{}}>
                    <Text style={styles.payBtn}>
                      Edit my preferences <IIcon name="arrow-forward-sharp" size={18} color="#fff" style={{ padding: 10 }} />
                    </Text>
                  </TouchableOpacity>
                </View>
              :
                <View style={styles.swiperContainer}>
                  <Swiper
                    ref={useSwiper}
                    animateCardOpacity
                    containerStyle={styles.container}
                    cards={discoverProfiles}
                    renderCard={(card, index) => <Card card={card} />}
                    disableTopSwipe
                    disableBottomSwipe
                    onSwipedAll={()=>setisSwipeAll(true)}
                    onTapCard={(index)=>cardDetails(index)}
                    onSwipedLeft={(cardIndex)=>{
                      setcardIndexCount(cardIndex + parseInt(1));
                      onPressSkip(cardIndex);
                    }}
                    onSwipedRight={(cardIndex)=>{
                      setcardIndexCount(cardIndex + parseInt(1));
                      onPressLike(cardIndex);
                    }}
                    cardIndex={0}
                    backgroundColor="white"
                    stackSize={3}
                    // infinite
                    showSecondCard
                    // animateOverlayLabelsOpacity
                    overlayOpacityHorizontalThreshold={width/4}
                    cardVerticalMargin={50}
                    cardHorizontalMargin={30}
                    overlayLabels={{
                      left: {
                        title: 'SKIP',
                        element: <OverlayLabel label="SKIP" color="red" />,
                        style: {
                          wrapper: styles.overlayWrapper,
                        },
                      },
                      right: {
                        title: 'LIKE',
                        element: <OverlayLabel label="LIKE" color="green" />,
                        style: {
                          wrapper: {
                            ...styles.overlayWrapper,
                            alignItems: 'flex-start',
                            marginLeft: 30,
                          },
                        },
                      },
                    }}
                  />
                </View>
              }
              {!isSwipeAll &&
                <View style={styles.buttonsContainer}>
                  <IconButton
                    name="close"
                    onPress={()=>handleOnSwipedLeft(cardIndexCount)}
                    color="white"
                    backgroundColor="#E5566D"
                  />
                  <IconButton
                    name="star"
                    onPress={()=>handleOnSwipedTop(cardIndexCount)}
                    color="white"
                    backgroundColor="#3CA3FF"
                  />
                  <IconButton
                    name="heart"
                    onPress={()=>handleOnSwipedRight(cardIndexCount)}
                    color="white"
                    backgroundColor="#4CCC93"
                  />
                </View>
              }
              <View style={{ flexDirection: 'row', backgroundColor: '#3E1D49' }}>
                <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
                  <Icon name="message" size={20} color="#fff" style={{ padding: 10 }} />
                </View>
                <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
                  <Icon name="location" size={20} color="#fff" style={{ padding: 10 }} />
                </View>
                <View style={{ justifyContent: 'center', alignItems: 'center', width: '33%' }}>
                  <Icon name="user" size={20} color="#fff" style={{ padding: 10 }} />
                </View>
              </View>
            </View>
          }
        </>
      )
    };

    const styles = ScaledSheet.create({
      container: {
        backgroundColor:'#fff',
        flex: 1,
        justifyContent: 'space-between',
      },
      swiperContainer: {
        height: '50%',
      },
      buttonsContainer: {
        justifyContent: 'space-between',
        alignItems: 'center',
        flexDirection: 'row',
        paddingHorizontal: '15%',
        paddingTop: '15@ms',
      },
      overlayWrapper: {
        flexDirection: 'column',
        alignItems: 'flex-end',
        justifyContent: 'flex-start',
        marginTop: '30@ms',
        marginLeft: '-30@ms'
      },
      payheaderText: {
        fontFamily: 'Poppins',
        fontSize: '18@ms',
        color:'#000',
        marginTop:'50@ms',
        textAlign:'center',
        paddingHorizontal:'5%'
      },
      paysubText: {
        fontFamily: 'Poppins',
        fontSize: '14@ms',
        width:'80%',
        textAlign:'center',
        marginTop:'20@ms'
      },
      payBtn: {
        fontFamily: 'Poppins',
        fontSize: '15@ms',
        textAlign:'center',
        paddingVertical: '7@ms',
        paddingHorizontal: '20@ms',
        borderRadius: '20@ms',
        marginTop:'25@ms',
        backgroundColor: '#319795',
        color: '#fff',
        fontWeight: '700',
        alignSelf:'center',
      },
    });

    export default HomeScreen;

Solution

  • Use elevation on your styles.overlayWrapper