React Native Custom PullToRefresh component

For those who are anxious, you can run a demo in this Expo website to see the effect.

Complete code in Github repository.

Pull-down refresh is a very common interaction. The Built-in FlatList of React-Native supports the pull-down refresh component by setting the refreshControl property. Usually not only do we need to customize the dropdown component, but the dropdown component performs some animation during the dropdown process, such as in our scenario, the company logo will show color depending on the size of the dropdown stroke. This requires our pull-down component to know the current pull-down magnitude in order to calculate the progress of our animation. Obviously, RN’s official refreshControl does not meet our requirements.

React-native pull-refresh and React-native Ptr-Control are two existing open source packages, both of which are about two years old. I do not understand why two scrollViews are nested.

Intuitively, ALL I need is a ScrollView, I listen for the pull-down distance, and I re-render the custom pull-down component. Well, along those lines, try a wank.

Step by step to implement a custom drop down

First, we provide a container (call it PullToRefresh) with a FlatList that the user passed in via children, which makes it easy for the user to modify. In case of a custom pull-refresh scenario, Use our container to wrap the existing FlatList, and the changes are quite small. If you want to pass in a custom drop-down refresh header component, call it props.HeaderComponent. If you want to pass in a custom drop-down refresh header component, call it props.

<View>
  <Animated.View><HeaderComponent /></Animated.View>
	<FlatList />
</View>
Copy the code

The outermost View display area is exactly the same as the user’s own FlatList. The problem is that our pull-down refresh HeaderComponent should be invisible by default, gradually moving from top to bottom into the visible area of the container as the user drops down. By default, the HeaderComponent should definitely be positioned outside the viewable area of the container, but to move it up, the user needs to tell us the props. HeaderHeight. At this point, the container renders something like this:

<View>
  <Animated.View style={{position: 'absolute', top: - this.props.headerHeight}} >
    <HeaderComponent />
  </Animated.View>
	<FlatList />
</View>
Copy the code

With the initial DOM structure style completed, the question of container pull-down timing is next.

First, when does the user pull down trigger our container’s pull down instead of the internal FlatList’s default pull down? This seems straightforward. When the inner FlatList has been pulled down to the top and can no longer be pulled down, the user’s pull-down action should trigger the container’s pull-down. Then, we need to know the current drop-down position of the inner FlatList, which can be obtained through the onScroll property of the FlatList to obtain the scrolling distance of the current FlatList.

When does the container pull down happen, and what components do we need to update during the container pull down? 1) The custom header component must be updated. Pass the latest pull-down distance to the header component. 2) If we just move the header component down and our FlatList does not move, then the custom header will block the content of the FlatList, which is not what we want; Therefore, the inner FlatList position also needs to be moved down in response to the container pull-down process.

If we use state.containerTop to store the pull-down distance of the current container, then the DOM result of our current container render would look something like this:

const headerStyle = {
  position: 'absolute'.left: 0.width: '100%'.top: -this.props.headerHeight,
  transform: [{ translateY: this.state.containerTop }],
};
<View>
  <Animated.View style={[{ flex: 1, transform: [{ translateY: this.state.containerTop }] }]}>
  	<FlatList />
  </Animated.View>
  <Animated.View style={headerStyle}>
  	<HeaderComponent />
  </Animated.View>
</View>
Copy the code

This is basically the end of the container pull-down, with the custom header and the inner FlatList being pulled down in sync.

The pull-down implementation is implemented, but to what point does the pull-down trigger a refresh? This would require the user to pass a trigger to refresh the drop-down distance, is called props. RefreshTriggerHeight, when a user loosen, > = props. If the current drop-down distance refreshTriggerHeight, The refresh function passed by the user is called props. OnRefresh. Typically, the user if the drop-down distance is larger, loosen the fingers touched off the refresh action, this time will be the whole component will be back to a refresh of the position, the position, the user can through the props. RefreshingHoldHeight to specify. Props. RefreshTriggerHeight and props. RefreshingHoldHeight are optional, and if the user doesn’t pass, the default for props. HeaderHeight.

One More Thing

Most importantly, how do I pass the pull-down distance (progress) to the user’s custom HeaderComponent during the container pull-down? The state. ContainerTop on the container above is actually the current container pull-down distance, except that this is an Animated.Value and we can’t read its current Value. So, I’m adding an instance property on the container to hold the current container dropdown distance, and we’re listening for state.containerTop, and in the callback, Modify the enclosing containerTranslateY.

Wait!! Why isn’t containerTranslateY on the state of the container? Should not be this. State. ContainerTranslateY?? Well, I did put it on state initially, and then when the user pulls down the container, I trigger the container to rerender by setState on the container, and then I pass the containerTranslateY over the header. However, this way the header updates are triggered by setState on the container, and in my tests I found the page to be stuttering. Therefore, when the user drops the container, the state of the container is not changed. Instead, the user’s current pull-down distance is passed to the Header component through the command of the method call. Maybe we can optimize this a little bit. I’m not sure.

Therefore, the user’s custom header component must expose an instance method, setProgress, to receive some of the parameters in the container’s dropdown, which is currently signed like this:

// pullDistance indicates the pullDistance of the container; Percent represents pull-down progress,[0, 1]
setProgress({pullDistance, percent}){}
Copy the code

For the full header component demo, see running demo at Expo.

The End

Finally, I heard that micro-interactive animation works better with Lottie and RN.

I was trying to do a Lottie animation for the company logo with AE, but I couldn’t hold it…

The full code is on Github: github.com/sophister/r… .

A link to the

  • React Native PanResponder official document
  • PanResponder demo in Navigator
  • Use Animated. Event to automatically map the scroll position of the ScrollView
  • lottie-react-native

AD time

Renrendai Dandan Technology Blog Center

And finally broadcast it. Welcome to renrendai Front End Technology Blog Center

Nodejs react React Native applet front-end engineering, etc