swift添加下拉刷新_React Native自定义下拉刷新组件
React Native 自定義下拉刷新組件 PullToRefresh
針對猴急一些的同學,可以先在這個 Expo網站在線運行下demo看看效果 。
完整的代碼,在 Github倉庫 。
下拉刷新,是一個很常見的交互方式。React-Native(以下簡稱RN)內置的 FlatList 是支持下拉刷新組件的,通過設置 refreshControl 屬性即可。通常我們不僅僅需要定制下拉組件,還需要在下拉過程中,下拉組件執行一些動畫,比如在我們場景下,公司logo會隨著下拉的幅度,不同的筆畫還是顯現出顏色。這就需要我們的下拉組件,知道當前下拉的幅度,以此來計算我們動畫執行的進度。顯然,RN官方的 refreshControl并不能滿足我們的需求。
看到有兩個已經存在的開源包 react-native-pull-refresh 和 react-native-ptr-control ,基本都有2年左右歷史了,而且我也確實沒看懂,為什么要用到 兩個 ScrollView 嵌套來實現。
直觀上來看,我應該只需要有一個 ScrollView 就可以了,我監聽下拉距離,重新render自定義的下拉組件。嗯,按照這個思路,嘗試擼一個試試。
一步步實現自定義下拉
首先,我們提供的是一個容器(命名為 PullToRefresh 吧 ),內部是用戶通過 children 傳進來的 FlatList,這樣也方便用戶修改,在需要自定義下拉刷新的場景下,用我們這個容器把已經存在的 FlatList 包起來就可以了,改動也挺小。當然,因為是自定義下拉刷新header,肯定還需要用戶把自定義的下拉刷新header組件傳進來,就命名為 props.HeaderComponent 吧,到這一步,我們容器內render出來的DOM結構,大概是這樣的:
<View><Animated.View><HeaderComponent /></Animated.View><FlatList /> </View>最外層的 View 的展示區域,和用戶自己的 FlatList 完全一樣。那么問題來了,我們的下拉刷新 HeaderComponent 在默認情況下,應該是不可見的,是在用戶下拉過程中,逐漸的從上到下進入容器的可視區域。那就默認把 HeaderComponent 絕對定位到容器可視區域的外邊吧,可是往上移動多大呢,這就需要用戶告訴我們容器一個下拉組件的高度了,props.headerHeight ,到這一步,容器渲染出來的樣式大概如下:
<View><Animated.View style={{position: 'absolute', top: - this.props.headerHeight}}><HeaderComponent /></Animated.View><FlatList /> </View>完成了初始的DOM結構樣式,接下來容器下拉時機的問題。
首先,什么時候用戶下拉,是觸發我們容器的下拉操作,而不是內部的 FlatList 的默認下拉呢?這個好像比較直接,當內部的 FlatList 已經下拉到頂部,不能再繼續下拉時,用戶的下拉動作,就應該觸發容器的下拉。那么,我們就需要知道內部的 FlatList 的當前下拉位置,這可以通過 FlatList 的 onScroll 屬性來獲取當前 FlatList 的滾動距離。
什么時機觸發容器的下拉確定了,那在容器下拉過程中,我們需要更新哪些組件呢?1) 自定義header組件肯定要更新,將最新的下拉距離傳給header組件。2) 如果只是將header組件往下移動,我們的 FlatList 不動,那么自定義header會遮擋住 FlatList 的內容,這不是我們想要的;因此,在容器下拉過程中,內部的 FlatList 位置也需要響應的往下移動。
如果我們用容器的 state.containerTop 這個 Animated.Value 來保存當前容器下拉的距離,那么目前我們容器render的DOM結果大概如下:
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>這樣,基本就完成了容器下拉過程中,自定義header和內部的FlatList同步下拉了。
下拉動作實現了,那下拉到什么位置,可以觸發刷新呢?這就需要用戶再傳遞一個觸發刷新的下拉距離,就叫 props.refreshTriggerHeight 吧,當用戶松開時,如果當前下拉距離 >= props.refreshTriggerHeight ,就會調用用戶傳入的刷新函數 props.onRefresh 。通常,用戶如果下拉的距離比較大,松開手指時觸發了刷新動作,這時候會整個組件會先回跳到一個刷新中的位置,這個位置,用戶可以通過 props.refreshingHoldHeight 來指定。props.refreshTriggerHeight 和 props.refreshingHoldHeight 都是可選的,如果用戶不傳,默認為 props.headerHeight。
One More Thing
上面其實還省略了一些工作,最重要的,就是在容器下拉過程中,怎么把下拉距離(下拉進度)傳給用戶的自定義 HeaderComponent ?上面容器上的 state.containerTop 其實就是當前容器下拉距離,只不過這是一個 Animated.Value ,我們 不能 讀取到它當前的值。因此,我在容器上添加了一個 實例屬性 this.containerTranslateY 來保存當前容器下拉的距離,我們會監聽 state.containerTop 值的變化,在回調函數里,修改 this.containerTranslateY。
等等!!containerTranslateY為什么沒有放到容器的 state 上呢?不應該是 this.state.containerTranslateY 么??嗯,剛開始我確實是放在 state 上的,然后在用戶下拉容器過程中,通過在容器上 setState,觸發容器重新render,然后把 containerTranslateY 傳遞過header。但是,這樣通過容器上 setState 觸發header更新的方式,在我測試中,發現頁面會比較卡頓。因此,在用戶下拉容器過程中,并沒有去修改容器的 state ,而是通過 方法調用 的命令方式,將用戶當前下拉距離傳給了header組件。這里可能還可以怎么優化一下吧。I'm not sure.
因此,用戶的自定義header組件,必須 暴露一個實例方法 setProgress 來接收容器下拉過程中的一些參數,目前這個方法的簽名是這樣的:
// pullDistance 表示容器下拉的距離;percent 代表下拉的進度,[0, 1] setProgress({pullDistance, percent}){}完整的 header 組件demo,請參考 expo上的運行demo 。
The End
最后,聽說,微交互動畫,使用 lottie 和 RN 更配哦。
本來想嘗試用 AE 做一個公司logo的 lottie 動畫的,奈何沒hold住……
完整的代碼在github上:https://github.com/sophister/react-native-pull-to-refresh-custom 。
相關鏈接
- React Native PanResponder官方文檔
- PanResponder demo in Navigator
- 使用 Animated.event 自動映射ScrollView的滾動位置
- lottie-react-native
總結
以上是生活随笔為你收集整理的swift添加下拉刷新_React Native自定义下拉刷新组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 商城html源码_延边小程序商城
- 下一篇: python 网页登录selenium_