国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

react-native滑動吸頂效果的實現過程

2019-11-19 11:24:55
字體:
來源:轉載
供稿:網友

前言

最近公司開發方向偏向移動端,于是就被調去做RN(react-native),體驗還不錯,當前有個需求是首頁中間吸頂的效果,雖然已經很久沒寫樣式了,不過這種常見樣式應該是so-easy,沒成想翻車了,網上搜索換了幾個方案都不行,最后去github上復制封裝好的庫來實現,現在把翻車過程記錄下來。

需求效果

翻車過程

第一種方案 失敗

一開始的思路是這樣的,大眾思路,我們需要監聽頁面的滾動狀態,當頁面滾動到要吸頂元素所處的位置的時候,我們設置它為固定定位,不過很遺憾,RN對于position屬性只提供了兩種布局方式:absolute和relative,既沒有fixed也沒有仍處于試驗的api:sticky。尷尬了😅

第二種方案 失敗

不過也不慌,看網上有第二種方案,把圖上第二 三塊地方作為ScrollView,然后ScrollView滑動監聽距離,把第一塊的marginTop設為負值,但是這樣第一部分不能滑動,不符合需求,pass

第三種方案 完全失敗

從網上找到第三種方案,就是一二三部分作為ScrollView,

第一部分position設為absolute,剩下的不設置,默認是relative

第二部分(吸頂部分)marginTop設置(setState)為第一部分高度的state,

添加滑動onScroll事件=》滑動距離y等于第二部分marginTop的state,但是當滑動超過第一部分高度的時候把第二部分(吸頂部分)position設為absolute,并把其marginTop設為0,看起來不錯,實際用ios模擬器一跑就無語了😅,效果很奇葩,手指滑動時不吸頂直接劃上去隱藏掉大半,一松突然吸頂了。。。

見下圖

ios的系統,手指在屏幕上滾動時,onScroll一直在觸發,如果里面有setState方法,也會不停執行并計算state,但是改變react的state是異步的,只要手指不離開屏幕,改變的state就無法生效(觸發界面渲染)

實現方案

我最終意識到由于ios的機制,react的state機制不能滿足需求,RN里面肯定有借助原生渲染的方式,于是github找了現成的代碼實現之后,反過來進行研究,大家有RN豐富經驗的也可以直接看最下面代碼👇

RN的Animator

RN的Animator動畫庫旨在解決動畫問題,由于js橋接過程,動畫通常不能很好展現,最好是把動畫的 數據 和 變化方法 一次性發給原生,由原生進行處理,這就是Animator庫的核心作用。

記得原來RN的動畫一直被吐槽,不過現在效果還挺不錯的,可能與近年來手機硬件提升也越來越大也有關系吧。

簡單用法

由于Animator內部封裝了這四個組件,所以默認可以導出<Animator.View/>,<Animator.Text/>,<Animator.Image/>,<Animator.ScrollView/>

在這幾個組件里面想做一些動畫處理,數據方面也是react的state,但是賦值要給Animated.Value,如下👇

this.state = {  scrollY: new Animated.Value(0)}

這里雖然使用的還是原生state,但是經過Animated處理,渲染機制完全不一樣了

簡單原理

經過Animator包裝后的組件,會遍歷傳入的props和自身的state,查找是否有Animated.Value的實例,并綁定進相應的原生操作。

props和自身的state變化時,將Animated.Value值逐個轉化為普通數值,再交給原生進行渲染,但是值得注意的是,這里并不會觸發react 的 render,更不會有什么domdiff ,是一種特殊處理,類似于Animated.Value改變時每次的shouldUpdateComponent返回都是false(毫秒級的渲染react性能扛不?。?,shouldUpdateComponent函數里面判斷Animated.Value,然后會把數據變化發給原生組件

完整的介紹請移步中文官網Animator庫介紹

實現思路

既然用了Animator組件了,渲染的問題解決了,下面思路是動態設置吸頂組件的translateY屬性。style:{ transform: [{ translateY:translateY }] }

  • 當向下滑動時,不管它
  • 向上滑,但是當頭部還沒有完全隱藏時,也不管它
  • 向上滑,頭部完全不見了,這時向上再滑一點,那么他的translateY就應該 = 上劃總距離 - 頭部高度,這樣越往上滑,把吸頂組件使勁往下推,這樣吸頂組件就牢牢固定在頂部了

下面利用插值來實現

const translateY = ScrollY.interpolate({  inputRange: [-1, 0, headerHeight, headerHeight + 1],  outputRange: [0, 0, 0, 1],});

插值interpolate略難理解,需要一點基礎,這里再細說起來這篇文章就太長了官網介紹

如果還不懂可以去網上找找這方面的資料

實現源碼

實現的圖中第二部分吸頂功能的核心代碼

import * as React from 'react';import { StyleSheet, Animated } from "react-native";/** * 滑動吸頂效果組件 * @export * @class StickyHeader */export default class StickyHeader extends React.Component{  static defaultProps = {    stickyHeaderY: -1,    stickyScrollY: new Animated.Value(0)  }    constructor(props) {    super(props);    this.state = {      stickyLayoutY: 0,    };  }  // 兼容代碼,防止沒有傳頭部高度  _onLayout = (event) => {    this.setState({      stickyLayoutY: event.nativeEvent.layout.y,    });  }  render() {    const { stickyHeaderY, stickyScrollY, children, style } = this.props    const { stickyLayoutY } = this.state    let y = stickyHeaderY != -1 ? stickyHeaderY : stickyLayoutY;    const translateY = stickyScrollY.interpolate({      inputRange: [-1, 0, y, y + 1],      outputRange: [0, 0, 0, 1],    });    return (      <Animated.View        onLayout= { this._onLayout }        style = {          [            style,            styles.container,            { transform: [{ translateY }] }          ]}      >      { children }      </Animated.View>    )  }}const styles = StyleSheet.create({  container: {    zIndex: 100  },});

頁面里實際用法如下

// 在頁面constructor里聲明statethis.state = {  scrollY: new Animated.Value(0),  headHeight:-1};
<Animated.ScrollView   style={{ flex: 1 }}  onScroll={    Animated.event(      [{        nativeEvent: { contentOffset: { y: this.state.scrollY } } // 記錄滑動距離      }],      { useNativeDriver: true }) // 使用原生動畫驅動  }  scrollEventThrottle={1}>  <View onLayout={(e) => {    let { height } = e.nativeEvent.layout;    this.setState({ headHeight: height }); // 給頭部高度賦值  }}>    // 里面放入第一部分組件  </View>    <StickyHeader    stickyHeaderY={this.state.headHeight} // 把頭部高度傳入    stickyScrollY={this.state.scrollY}  // 把滑動距離傳入  >    // 里面放入第二部分組件  </StickyHeader>    // 這是第三部分的列表組件  <FlatList    data={this.state.dataSource}    renderItem={({item}) => this._createListItem(item)}  />  </Animated.ScrollView>

收尾

具體代碼就是這樣實現了,算是比較完美的方案,特別是照顧了性能,各位可以基于這個封裝來實現更復雜的需求,原理大概就是這個原理了,在前端動畫領域,自己確實也就剛入門水平,如有問題,請直接指出。

另外,這是我找的那個 組件 github的代碼地址:https://github.com/jiasongs/react-native-stickyheader,原地址附上,建議如果項目用了給人家一個star

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 孟村| 铜鼓县| 盘山县| 黄山市| 九龙县| 锡林郭勒盟| 房山区| 天门市| 洮南市| 三门峡市| 潼南县| 莎车县| 两当县| 酒泉市| 马尔康县| 措勤县| 淳安县| 宁蒗| 称多县| 鲁山县| 重庆市| 虎林市| 措美县| 雷波县| 芜湖市| 大安市| 赤城县| 海淀区| 南皮县| 科技| 区。| 阳谷县| 深泽县| 海南省| 晋江市| 沁水县| 巢湖市| 萍乡市| 浦东新区| 揭西县| 株洲县|