Kureev / react-native-blur

React Native Blur component
MIT License
3.76k stars 556 forks source link

BlurView on top of scrollview #317

Open minuitagency opened 5 years ago

minuitagency commented 5 years ago

Hi,

I'm using this library for a header that is absolutely positioned and I'd like to have a scrollview underneath.

Problem is the blur is not updated in real time, only when I change tab or switch apps.

Does anybody knows a workaround?

Thanks,

Théo

Dexwell commented 5 years ago

Anyone? @charpeni?

Dexwell commented 4 years ago

This is a pretty common use case. @Kureev?

charro0407 commented 4 years ago

any response?

Bricktheworld commented 4 years ago

This really needs to be addressed. For a library with this many downloads which ALREADY has the invalidate() function built in, it really shouldn't be that hard to update. If anyone gets word on a workaround for this please tell. @Kureev @charpeni

devmanny commented 3 years ago

First of all, I apologize for the horrible workaround you will see.

I used a createAnimatableComponent to create an animatable BlurView

import {Animated} from 'react-native';

const AnimatedBlurView = Animated.createAnimatedComponent (BlurView);

Then declare an animatable variable, I named it as: forceRender

const forceRender = new Animated.Value(0);

AnimatedBlurView will replace your BlurView

<AnimatedBlurView
  style={{
    ... StyleSheet.absoluteFill,
    opacity: forceRender.interpolate ({
      inputRange: [-300, 0], // 😢 you can play with these values
      outputRange: [1, 2], // 😓 this is the only way I made opacity work
      // it should only accept values between 0 and 1, but otherwise it doesn't give me the result I expect
    }),
  }}
  blurType="dark"
  reducedTransparencyFallbackColor="black"
/>

You will have to change your ScrollView or FlatList to an Animated.ScrollView or Animated.FlatList

<Animated.FlatList
  scrollEventThrottle={30}
  onScroll={Animated.event(
    [
      {
        nativeEvent: {
          contentOffset: {
            y: forceRender,
          },
        },
      },
    ],
    {
      useNativeDriver: true,
    },
  )}
  ...
/>

Let me know if it worked for you

Laurent888 commented 3 years ago

I tested your workaround and it is working! I wonder how strong the impact is on the performance though.

adbl commented 3 years ago

Inspired by @devmanny 's workaround, here a more generic but still ugly workaround:


  // blur gets stuck otherwise
  const workaroundValue = useRef<Animated.Value>(new Animated.Value(0));
  const workaroundStyle = useRef<AnimatedStyleSheet>({
    opacity: workaroundValue.current.interpolate({
      inputRange: [0, 1],
      outputRange: [1, 2],
    }),
  });

  useEffect(() => {
    Animated.loop(
      Animated.sequence([
        Animated.timing(workaroundValue.current, {
          toValue: 1,
          duration: 1000,
          useNativeDriver: true,
        }),
        Animated.timing(workaroundValue.current, {
          toValue: 0,
          duration: 1000,
          useNativeDriver: true,
        }),
      ]),
    ).start();
  }, []);

  return (
    <AnimatedBlurView
      style={[StyleSheet.absoluteFill, workaroundStyle.current]}
      blurType="light"
      blurAmount={6}
    />
  );

// type
type AnimatedStyleSheet = Animated.AnimatedProps<
  React.ComponentPropsWithRef<typeof View>
>['style'];

For a normal Animated.View I wouldn't be concerned with performance at all but I don't understand the implications for BlurView...

daveyjones commented 2 years ago

This problem isn't limited to ScrollView—I'm also seeing it with FlatList and MapView.

However, I'm using React Navigation and I found that this problem only occurs when the BlurView component and the component it overlays (e.g. ScrollView, FlatList, MapView) are within the same Screen. If you're using React Navigation, you can avoid this problem entirely by adding the BlurView to the navigator. Below is an example.

<Tab.Navigator
  screenOptions={{headerShown: false}}
  tabBar={() => {
    return (
      <View style={styles.tabs}>
        <BlurView
            style={{position: "absolute", top: 0, right: 0, bottom: 0, left: 0}}
            ...
        />
        <Pressable
          style={styles.tab}
          onPress={() => navigation.navigate("Screen 1")}
        />
        <Pressable
          style={styles.tab}
          onPress={() => navigation.navigate("Screen 2")}
        />
      </View>
    )
  }}
>
  <Tab.Screen name="Screen 1" component={Screen1} />
  <Tab.Screen name="Screen 2" component={Screen2} />
</Tab.Navigator>
Gregoirevda commented 2 years ago

@daveyjones You're talking about a bottom-tab navigator correct? That doesn't work with a top-tab navigator.

I realised the reason it's not in sync with the underlying view is because of it's position and z-index.

This will not work

<BlurView  style={{position: "absolute", top: 0, right: 0, bottom: 0, left: 0, zIndex: 10}}/>
<ScrollView>
  {content}
</ScrollView>

This works (removing zIndex and placing it under the ScrollView)

<ScrollView>
  {content}
</ScrollView>
<BlurView  style={{position: "absolute", top: 0, right: 0, bottom: 0, left: 0}}/>

This was happening to me in a material-top-tabs navigator, where tabBar={() => <TabBarWithBlur />} had to have z-index because it's rendered before the scroll content inside the tab view. My solution was to set the BlurView inside the tab view.

Could you try that @devmanny ?

beqramo commented 2 years ago

@Gregoirevda answer is correct according to the docs too. this is the working mechanism of this lib.Thanks

filippobarcellos commented 1 year ago

@Gregoirevda I'm having the same problem as yours. Can you share how you solve it? I'm not sure I understand placing the Blur View inside the tab view. Do you mean inside each scrollable item of the tab? Thanks

Gregoirevda commented 1 year ago

Inside each tab component, you can have a wrapper called BlurredTabView which looks like this

function BlurredTabView({children}) { 
return <>
  {children}
  <BlurView  style={{position: "absolute", top: 0, right: 0, bottom: 0, left: 0}}/>
</>
arled commented 1 year ago

@Gregoirevda 's solution is what worked for me and works like a charm