alexbrillant / react-native-deck-swiper

tinder like react-native deck swiper
ISC License
1.57k stars 464 forks source link

Can't adjust when overlay label will appear on Android #385

Closed mickaelcornelli closed 2 years ago

mickaelcornelli commented 2 years ago

Hi,

First of all , thanks a lot for this library, you save me a lot of time to create my tinder like swap.

Let's talk about where i'm stuck. I've created a swiper with left overlay & right overlay (to accept & decline offer) When I swipe on the left & right side on IOS there is no problem (check screen below) but on android there is no way to trigger faster the overlay. I've try to modify inputOverlayLabelsOpacityRangeX overlayOpacityHorizontalThreshold. This works well on IOS but do not works on android.

I've also check a similar issue on this link : https://github.com/alexbrillant/react-native-deck-swiper/issues/267

It helps me to fix my ios version but now still stuck on android.

I've try to modify inputoverlaylabel with separating the Platform.os ios/android with different value without any sucess.

I'm running the app with Expo 44 and React native 0.64.3

Video of IOS Swipe : https://user-images.githubusercontent.com/73282517/179967284-fe16a9ae-2c38-4149-8060-9a0cf1deeda6.mp4

Video of Android Swipe : https://user-images.githubusercontent.com/73282517/179967277-deb27327-d3e0-4e60-b6b9-1b7d7ce070c4.mp4

Thanks for any advice ;)

Code :

import { View, Text, Platform, StyleSheet, ImageBackground, Image, TouchableOpacity, Dimensions } from 'react-native'
import React, { useRef } from 'react'
import Swiper from "react-native-deck-swiper";
import { LinearGradient } from "expo-linear-gradient";
import { Feather } from "@expo/vector-icons";
import sharlockLogo from "../assets/img/sharlockLogo.png"
import swipeRightImg from "../assets/img/swipeRightAccept.png"
import swipeLeftImg from "../assets/img/swipeLeftDeny.png"
import * as Amplitude from "expo-analytics-amplitude";

const SwiperTest = ({ index, products, onTapCard, onSwipeLeft, onSwipeRight, onSwipeAll, onOpenLink, onRefreshSlider }) => {
    const swipeRef = useRef(null);
    const windowWidth = Dimensions.get("window").width;
    return (
        products.length > 0 &&
        <Swiper
            ref={swipeRef}
            containerStyle={{ backgroundColor: "transparent" }
            }
            cards={products}
            stackSize={2}
            cardIndex={index}
            childrenOnTop={true}
            cardVerticalMargin={115}
            key={products.length}
            animateCardOpacity
            verticalSwipe={false}
            onTapCard={(index) => { onTapCard(products[index]) }} // Selected item pop modal
            onSwipedAll={() => onSwipeAll()}    // clear state when all data has been read to get an empty swipe
            onSwipedRight={(index) => {
                Amplitude.logEventAsync(
                    "Validée"
                ).then(() => {
                    onSwipeRight(products[index])
                })
            }}
            onSwipedLeft={(index) => {
                Amplitude.logEventAsync(
                    "Rejetée"
                ).then(() => {
                    onSwipeLeft(products[index])
                })
            }}
            backgroundColor={"#4FD0E9"}
            animateOverlayLabelsOpacity //Effect with opacity on label text
            inputOverlayLabelsOpacityRangeX={Platform.OS === "ios" ? [-windowWidth / 3, -1, 0, 1, windowWidth / 3] : [-windowWidth/3 , -1, 0, 1, windowWidth/3 ]} // Adjust when the overlay label appears
            overlayOpacityHorizontalThreshold={1} // Adjust effect on the overlay
            overlayLabels={{
                left: {
                    element: <Image source={swipeLeftImg} style={{ position: "absolute", top: 50, right: 50, width: 100, height: 100 }} />,
                },
                right: {
                    element: <Image source={swipeRightImg} style={{ position: "absolute", top: 50, left: 50, width: 100, height: 100 }} />,
                },
            }}
            renderCard={(card, index) =>
                <View
                    key={card.id}
                    style={styles.offerCard}
                >
                    <ImageBackground
                        source={{ uri: card.data.picture }}
                        style={styles.offerBackgroundImg}
                    >
                        <LinearGradient
                            style={styles.offerGradient}
                            start={{ x: 0, y: 0.5 }}
                            end={{ x: 0, y: 1 }}
                            colors={["rgba(0,0,0,0)", "rgba(0,0,0,1)"]}
                        >
                            <View
                                style={{
                                    width: "100%",
                                    position: "absolute",
                                    bottom: 20,
                                }}
                            >
                                <View
                                    style={{
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        marginLeft: 15,
                                        marginRight: 15,
                                    }}
                                >
                                    <View
                                        style={styles.offerPartnerContainer}
                                    >
                                        {card.partner.id === "sharlockTutorial" ?
                                            <Image
                                                source={sharlockLogo}
                                                style={styles.offerLogo}
                                            />
                                            :
                                            <Image
                                                source={{ uri: card.partner.data.logo }}
                                                style={styles.offerLogo}
                                            />
                                        }

                                        <Text
                                            style={styles.offerTitle}
                                        >
                                            {card.partner.data.name}
                                        </Text>
                                    </View>
                                    <TouchableOpacity
                                        style={styles.offerLinkBtnContainer}
                                        onPress={() => {
                                            onOpenLink(products[index])
                                        }}
                                    >
                                        <View
                                            style={styles.offerLinkBtn}
                                        >
                                            <Feather
                                                name={"share"}
                                                size={25}
                                                color={"#3300FF"}
                                            />
                                        </View>
                                    </TouchableOpacity>
                                </View>
                                <View
                                    style={styles.offerMargin}
                                >
                                    <Text
                                        style={styles.offerSubTitle}
                                    >
                                        {card.data.name}
                                    </Text>
                                    <Text
                                        style={styles.offerDescription}
                                    >
                                        {card.data.description.substring(0, 110)}...
                                    </Text>
                                </View>
                            </View>
                        </LinearGradient>
                    </ImageBackground>
                </View>
            }
        />

    )
}
const styles = StyleSheet.create({
    container: {
        width: "100%",
        height: "100%",
        backgroundColor: "#ECECFF",
    },
    headerTitle: {
        fontFamily: "HelveticaNeue",
        fontWeight: "700",
        fontSize: 22,
    },
    parentRow: {
        flexDirection: "row",
        justifyContent: "space-between",
        alignItems: "center",
    },
    bubble: {
        position: "absolute",
        right: 10,
        top: -15,
        backgroundColor: "#FF3B30",
        width: 25,
        height: 25,
        borderRadius: 15,
        alignItems: "center",
        justifyContent: "center",
    },
    bubbleText: {
        color: "white",
        fontSize: 15,
        fontWeight: "700",
        fontFamily: "HelveticaNeue",
    },
    modalActionsBtn: {
        width: 60,
        height: 60,
        backgroundColor: "white",
        borderRadius: 30,
        alignItems: "center",
        justifyContent: "center",
        shadowColor: "black",
        shadowOpacity: 0.5,
        shadowRadius: 5,
        shadowOffset: {
            width: 0,
            height: 5,
        },
    },
    offerCard: {
        width: "100%",
        height: "100%",
        shadowColor: "#000",
        shadowOffset: {
            width: 0,
            height: 1,
        },
        shadowOpacity: 0.2,
        shadowRadius: 1.41,
        elevation: 2,
    },
    offerBackgroundImg: {
        flex: 1,
        overflow: "hidden",
        borderRadius: 20,
    },
    offerGradient: {
        flex: 1,
        borderRadius: 20,
    },
    offerPartnerContainer: {
        width: "75%",
        flexDirection: "row",
        alignItems: "center",
    },
    offerLogo: {
        width: 50,
        height: 50,
        borderRadius: 10,
    },
    offerTitle: {
        marginLeft: 15,
        fontWeight: "700",
        fontFamily: "HelveticaNeue",
        fontSize: 24,
        color: "white",
        textTransform: "uppercase",
    },
    offerLinkBtnContainer: {
        zIndex: 99,
        width: "25%",
        flexDirection: "row",
        justifyContent: "flex-end",
    },
    offerLinkBtn: {
        width: 50,
        height: 50,
        borderRadius: 25,
        justifyContent: "center",
        alignItems: "center",
        alignSelf: "center",
        backgroundColor: "white",
    },
    offerSubTitle: {
        fontFamily: "HelveticaNeue",
        fontSize: 22,
        color: "white",
        paddingBottom: 10,
    },
    offerDescription: {
        fontFamily: "HelveticaNeue",
        fontSize: 18,
        color: "white",
    },
    offerMargin: {
        marginTop: 5,
        marginLeft: 15,
        marginRight: 15,
    }
});

export default SwiperTest
mickaelcornelli commented 2 years ago

After searching on internet, forums and other similar issues, I wanted to try putting directly without passing the props into the child component. And I realized that the slide worked perfectly on ios/android. The downside is that I can no longer update my swiper deck by coding like this :

               <View style={{
                  flex: 1,
                  backgroundColor: "#F5FCFF"
                }}>
                  <Swiper
                    ref={swipeRef}
                    containerStyle={{ backgroundColor: "transparent" }
                    }
                    cards={offersLikeTinder}
                    stackSize={2}
                    cardIndex={index}
                    childrenOnTop={true}
                    cardVerticalMargin={115}
                    key={offersLikeTinder.length}
                    animateCardOpacity
                    verticalSwipe={false}                   
                    backgroundColor={"#4FD0E9"}
                    animateOverlayLabelsOpacity //Effect with opacity on label text
                    inputOverlayLabelsOpacityRangeX={Platform.OS === "ios" ? [-windowWidth / 3, -1, 0, 1, windowWidth / 3] : [-windowWidth / 3, -1, 0, 1, windowWidth / 3]} // Adjust when the overlay label appears
                    overlayOpacityHorizontalThreshold={1} // Adjust effect on the overlay
                    overlayLabels={{
                      left: {
                        element: <Image source={swipeLeftImg} style={{ position: "absolute", top: 50, right: 50, width: 100, height: 100 }} />,
                      },
                      right: {
                        element: <Image source={swipeRightImg} style={{ position: "absolute", top: 50, left: 50, width: 100, height: 100 }} />,
                      },
                    }}
                    renderCard={(card) => {
                      return (
                        <View
                          key={card.id}
                          style={styles.offerCard}
                        >
                          <ImageBackground
                            source={{ uri: card.data.picture }}
                            style={styles.offerBackgroundImg}
                          >
                            <LinearGradient
                              style={styles.offerGradient}
                              start={{ x: 0, y: 0.5 }}
                              end={{ x: 0, y: 1 }}
                              colors={["rgba(0,0,0,0)", "rgba(0,0,0,1)"]}
                            >
                              <View
                                style={{
                                  width: "100%",
                                  position: "absolute",
                                  bottom: 20,
                                }}
                              >
                                <View
                                  style={{
                                    flexDirection: "row",
                                    justifyContent: "space-between",
                                    marginLeft: 15,
                                    marginRight: 15,
                                  }}
                                >
                                  <View
                                    style={styles.offerPartnerContainer}
                                  >
                                    {card.partner.id === "sharlockTutorial" ?
                                      <Image
                                        source={sharlockLogo}
                                        style={styles.offerLogo}
                                      />
                                      :
                                      <Image
                                        source={{ uri: card.partner.data.logo }}
                                        style={styles.offerLogo}
                                      />
                                    }

                                    <Text
                                      style={styles.offerTitle}
                                    >
                                      {card.partner.data.name}
                                    </Text>
                                  </View>
                                  <TouchableOpacity
                                    style={styles.offerLinkBtnContainer}
                                    onPress={() => {

                                    }}
                                  >
                                    <View
                                      style={styles.offerLinkBtn}
                                    >
                                      <Feather
                                        name={"share"}
                                        size={25}
                                        color={"#3300FF"}
                                      />
                                    </View>
                                  </TouchableOpacity>
                                </View>
                                <View
                                  style={styles.offerMargin}
                                >
                                  <Text
                                    style={styles.offerSubTitle}
                                  >
                                    {card.data.name}
                                  </Text>
                                  <Text
                                    style={styles.offerDescription}
                                  >
                                    {card.data.description.substring(0, 110)}...
                                  </Text>
                                </View>
                              </View>
                            </LinearGradient>
                          </ImageBackground>
                        </View>
                      )
                    }}
                  >
                  </Swiper>
                </View>

Here the visual of Deck Swiper when it's import directly without any slide function :

IOS : https://user-images.githubusercontent.com/73282517/180807451-19c7f98b-6efb-4d63-9f4a-b252163e72d9.mp4

Android : https://user-images.githubusercontent.com/73282517/180807459-86189be6-e235-4444-bc8c-6bf9c8141558.mp4

StyleSheet is the same on both tries so if anyone got any idea ;)

mickaelcornelli commented 2 years ago

Okay it seems that passing props from parent to children fix the problem :

PARENT

                  <SwiperTest
                      style={styles.offerCard} //Pass StyleSheet to children
                      index={index}
                      products={offersLikeTinder}
                      onTapCard={tapCard}
                      onSwipeLeft={swipeLeft}
                      onSwipeRight={swipeRight}
                      onSwipeAll={swipeAll}
                      onOpenLink={openLink}
                      onRefreshSlider={refreshSlider}
                  /> 

CHILDREN

const SwiperTest = ({ index, products, onTapCard, onSwipeLeft, onSwipeRight, onSwipeAll, onOpenLink, style, onRefreshSlider }) => {
    return (
        <Swiper
            ref={swipeRef}
            containerStyle={{ backgroundColor: "transparent" }}
            cards={products}
            stackSize={2}
            cardIndex={index}
            childrenOnTop={true}
            cardVerticalMargin={115}
            key={products.length}
            animateCardOpacity
            verticalSwipe={false}
            onTapCard={(index) => { onTapCard(products[index]) }} 
            onSwipedAll={() => onSwipeAll()}  
            onSwipedRight={(index) => { onSwipeRight(products[index])  }}
            onSwipedLeft={(index) => {onSwipeLeft(products[index])    }}
            backgroundColor={"#4FD0E9"}
            animateOverlayLabelsOpacity 
            inputOverlayLabelsOpacityRangeX={[-windowWidth / 3, -1, 0, 1, windowWidth / 3]} 
            overlayOpacityHorizontalThreshold={1} // Adjust effect on the overlay
            overlayLabels={{
                left: {
                    element: <Image source={swipeLeftImg} style={{ position: "absolute", top: 50, right: 50, width: 100, height: 100 }} />,
                },
                right: {
                    element: <Image source={swipeRightImg} style={{ position: "absolute", top: 50, left: 50, width: 100, height: 100 }} />,
                },
            }}
            renderCard={(card, index) =>
                <View
                    key={card.id}
                    style={style}  // <---StyleSheet Props here 
                >
                    ...