Coder Social home page Coder Social logo

Comments (12)

njdancer avatar njdancer commented on July 28, 2024 7

@songxiaoliang @jcatink It's probably even a little simpler in a class cause you don't need the ref's. I think something like this would work.

import Animated from "react-native-reanimated"
import BottomSheet from "reanimated-bottom-sheet"
import React from "react"

import Header from "somewhere"
import Content from "somewhere"

const {
  Extrapolate,
  block,
  call,
  cond,
  greaterOrEq,
  interpolate,
  lessOrEq,
  onChange,
} = Animated

class MyComponent extends React.Component {
  constructor() {
    super()
    this.drawerCallbackNode = new Animated.Value(0)
    this.clampedDrawerCallbackNode = interpolate(this.drawerCallbackNode, {
      extrapolate: Extrapolate.CLAMP,
      inputRange: [0, 1],
      outputRange: [0, 1],
    })
  }

  render() {
    return (
      <>
        <Animated.Code
          exec={onChange(
            this.clampedDrawerCallbackNode,
            block([
              cond(
                greaterOrEq(this.clampedDrawerCallbackNode, 1),
                call([], () => {
                  console.log(`[${new Date()}] Drawer closed`)
                })
              ),
              cond(
                lessOrEq(this.drawerCallbackNode, 0),
                call([], () => {
                  console.log(`[${new Date()}] Drawer opened`)
                })
              ),
            ])
          )}
        />
        <BottomSheet
          callbackNode={this.drawerCallbackNode}
          renderContent={() => <Content />}
          renderHeader={() => <Header />}
          snapPoints={[230, 0]}
        />
      </>
    )
  }
}

Let me explain this a little. At the top we're importing reanimated and destructuring the required nodes so we can call them directly later on. In the constructor we're creating an Animated Value that we can pass to the BottomSheet as a callback node. This value will always contain the current relative position of the drawer with 0 being fully open and 1 being fully closed. On the next line we create another value that references the first but we clamp the value between 0 and 1 so that the overshoot animation doesn't take the value outside of this range. With this current code it may not be necessary but I was getting some weirdness when I was first playing with this.

Finally in the render method we're creating an Animated node that will execute certain callbacks based on the outcome of the conditionals on our clamped value. Normally this node would need to be provided to an animated view component to be used within its style. The view will then(in native code) evaluate the value and update the style attribute with the nodes return value. This would in our case evaluate the conditional nodes we configure. However, as we're not passing this to a component we need to use Animated.Code to arbitrarily execute this node and get the desired callback effect.

I haven't tried this code so it may not be 100% correct but I hope that helps get you going😄

If you need to customise the callback behaviour further it may be worth looking at the reanimated docs directly.

from react-native-reanimated-bottom-sheet.

njdancer avatar njdancer commented on July 28, 2024 2

I'm still becoming familiar with reanimated and this library but I've managed to get something like this working.

const drawerCallbackNode = useRef(new Animated.Value(0)).current
const clampedDrawerCallbackNode = useRef(
  interpolate(drawerCallbackNode, {
    extrapolate: Extrapolate.CLAMP,
    inputRange: [0, 1],
    outputRange: [0, 1],
  })
).current

useCode(
  onChange(
    clampedDrawerCallbackNode,
    block([
      cond(
        greaterOrEq(clampedDrawerCallbackNode, 1),
        call([], () => {
          console.log(`[${new Date()}] Drawer closed`)
        })
      ),
      cond(
        lessOrEq(drawerCallbackNode, 0),
        call([], () => {
          console.log(`[${new Date()}] Drawer opened`)
        })
      ),
    ])
  )
)

I'm using functional components hence the use of hooks so you may need to adapt this slightly. Essentially I'm creating and animated value and later on passing that to bottom sheet. This value updates with the relative snap position on every frame including when it overshoots. By calling interpolate on the next line I'm able to clamp this value between 0 and 1. Then inside useCode I'm combining some nodes to say when that value changes check if it's either 0 or 1 and call the appropriate callback.

I only have 2 snap points so can pretty easily deal with 0 and 1. You would obviously need more conditional nodes if you wanted to detect more snap points.

from react-native-reanimated-bottom-sheet.

alamothe avatar alamothe commented on July 28, 2024 1

Hello! Great library, but I have the same requirement.

Is it possible to add onSnapTo event callback?

from react-native-reanimated-bottom-sheet.

songxiaoliang avatar songxiaoliang commented on July 28, 2024 1

@njdancer When I put the bottomsheet into Modal, iOS can slide normally, Android can't slide。
<Modal
onRequestClose={() => this.close()}
supportedOrientations={['landscape', 'portrait']}
transparent
visible={visible}
>
<>
<Animated.Code
exec={onChange(
this.clampedDrawerCallbackNode,
block([
cond(
greaterOrEq(this.clampedDrawerCallbackNode, 1),
call([], () => {
console.log([${new Date()}] Drawer closed)
})
),
cond(
lessOrEq(this.drawerCallbackNode, 0),
call([], () => {
console.log([${new Date()}] Drawer opened)
})
),
])
)}
/>
<BottomSheet
callbackNode={this.drawerCallbackNode}
renderContent={() => <Content />}
renderHeader={() => <Header />}
snapPoints={[230, 0]}
/>
</>

from react-native-reanimated-bottom-sheet.

songxiaoliang avatar songxiaoliang commented on July 28, 2024

@njdancer Hello, can you give it a way without a hook? Thank you

from react-native-reanimated-bottom-sheet.

songxiaoliang avatar songxiaoliang commented on July 28, 2024

@njdancer Looking forward to your reply

from react-native-reanimated-bottom-sheet.

paranoia5 avatar paranoia5 commented on July 28, 2024

Thanks @njdancer this works great with me.

from react-native-reanimated-bottom-sheet.

songxiaoliang avatar songxiaoliang commented on July 28, 2024

@paranoia5 怎么解决的呢?

from react-native-reanimated-bottom-sheet.

paranoia5 avatar paranoia5 commented on July 28, 2024

@songxiaoliang exactly like @njdancer solution

import BottomSheet from 'reanimated-bottom-sheet';
import Animated from 'react-native-reanimated';

const {useCode, onChange, block, cond, greaterOrEq, lessOrEq, call} = Animated;

const ScreenX = ():React.ReactElement<any> => {

const bottomSheetRef = React.useRef<BottomSheet>().current;
const drawerCallbackNode = React.useRef<any>(new Animated.Value(0)).current;
const clampedDrawerCallbackNode = React.useRef<Animated.Adaptable<any>>(
    Animated.interpolate(drawerCallbackNode, {
      extrapolate: Animated.Extrapolate.CLAMP,
      inputRange: [0, 1],
      outputRange: [0, 1],
    })
  ).current;

 useCode(
    onChange(
      clampedDrawerCallbackNode,
      block([
        cond(
          greaterOrEq(clampedDrawerCallbackNode, 1),
          call([], () => {
            console.log("Sheet is closed")
          })
        ),
      ])
    ), 
   null
  );

return (
    <View style={styles.container}>
      <BottomSheet
        ref={e => (bottomSheetRef = e)}
        snapPoints={[
          Screen.height - (Screen.statusBar + Screen.tabBarHeight * 2),
          PANEL_MINIMUM_HEIGHT,
        ]}
        callbackNode={drawerCallbackNode}
        renderContent={renderInner}
        initialSnap={1}
      />
   </View>
  )
}

from react-native-reanimated-bottom-sheet.

jcatalaamat avatar jcatalaamat commented on July 28, 2024

That solution is not without Hooks @paranoia5, it fails with hooks warning inside my component. Any ideas?

from react-native-reanimated-bottom-sheet.

alamothe avatar alamothe commented on July 28, 2024

What is the purpose of clampedDrawerCallbackNode ? Seems like it works by using only drawerCallbackNode

from react-native-reanimated-bottom-sheet.

njdancer avatar njdancer commented on July 28, 2024

@alamothe when the drawer animation overshoots so does the callback node. When I was initially fiddling with this I think I was having some issues because of that and clamping the value to between 0 and 1 helped. As the example sits though it probably isn’t required. The same interpolation technique could be used to convert the relative callback node value to the actual number of points of that position.

Sent with GitHawk

from react-native-reanimated-bottom-sheet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.