React Native 組件學(xué)習(xí)-FlatList

高性能的簡單列表組件溅呢,支持下面這些常用的功能:

  • 完全跨平臺披蕉。
  • 支持水平布局模式。
  • 行組件顯示或隱藏時可配置回調(diào)事件伞访。
  • 支持單獨的頭部組件掂骏。
  • 支持單獨的尾部組件。
  • 支持自定義行間分隔線厚掷。
  • 支持下拉刷新弟灼。
  • 支持上拉加載。
  • 支持跳轉(zhuǎn)到指定行(ScrollToIndex)冒黑。

如果需要分組/類/區(qū)(section)田绑,請使用<SectionList>.

一個最簡單的例子:

<FlatList
  data={[{key: 'a'}, {key: 'b'}]}
  renderItem={({item}) => <Text>{item.key}</Text>}
/>

下面是一個較復(fù)雜的例子,其中演示了如何利用PureComponent來進(jìn)一步優(yōu)化性能和減少 bug 產(chǎn)生的可能(以下這段文字需要你深刻理解 shouldComponentUpdate 的機(jī)制抡爹,以及 Component 和 PureComponent 的不同掩驱,所以如果不了解就先跳過吧)。

  • 對于MyListItem組件來說,其onPressItem屬性使用箭頭函數(shù)而非 bind 的方式進(jìn)行綁定欧穴,使其不會在每次列表重新 render 時生成一個新的函數(shù)民逼,從而保證了 props 的不變性(當(dāng)然前提是 idselectedtitle也沒變)涮帘,不會觸發(fā)自身無謂的重新 render拼苍。換句話說,如果你是用 bind 來綁定onPressItem调缨,每次都會生成一個新的函數(shù)疮鲫,導(dǎo)致 props 在===比較時返回 false,從而觸發(fā)自身的一次不必要的重新 render弦叶。
  • FlatList指定extraData={this.state}屬性俊犯,是為了保證state.selected變化時,能夠正確觸發(fā)FlatList的更新湾蔓。如果不指定此屬性瘫析,則FlatList不會觸發(fā)更新,因為它是一個PureComponent默责,其 props 在===比較中沒有變化則不會觸發(fā)更新贬循。
  • keyExtractor屬性指定使用 id 作為列表每一項的 key。
class MyListItem extends React.PureComponent {
  _onPress = () => {
    this.props.onPressItem(this.props.id);
  };

  render() {
    const textColor = this.props.selected ? "red" : "black";
    return (
      <TouchableOpacity onPress={this._onPress}>
        <View>
          <Text style={{ color: textColor }}>
            {this.props.title}
          </Text>
        </View>
      </TouchableOpacity>
    );
  }
}

class MultiSelectList extends React.PureComponent {
  state = {selected: (new Map(): Map<string, boolean>)};

  _keyExtractor = (item, index) => item.id;

  _onPressItem = (id: string) => {
    // updater functions are preferred for transactional updates
    this.setState((state) => {
      // copy the map rather than modifying state.
      const selected = new Map(state.selected);
      selected.set(id, !selected.get(id)); // toggle
      return {selected};
    });
  };

  _renderItem = ({item}) => (
    <MyListItem
      id={item.id}
      onPressItem={this._onPressItem}
      selected={!!this.state.selected.get(item.id)}
      title={item.title}
    />
  );

  render() {
    return (
      <FlatList
        data={this.props.data}
        extraData={this.state}
        keyExtractor={this._keyExtractor}
        renderItem={this._renderItem}
      />
    );
  }
}

本組件實質(zhì)是基于<VirtualizedList>組件的封裝桃序,繼承了其所有 props(也包括所有<ScrollView>)的 props)杖虾,但在本文檔中沒有列出。此外還有下面這些需要注意的事項:

  • 當(dāng)某行滑出渲染區(qū)域之外后媒熊,其內(nèi)部狀態(tài)將不會保留奇适。請確保你在行組件以外的地方保留了數(shù)據(jù)。
  • 本組件繼承自PureComponent而非通常的Component芦鳍,這意味著如果其props淺比較中是相等的嚷往,則不會重新渲染。所以請先檢查你的renderItem函數(shù)所依賴的props數(shù)據(jù)(包括data屬性以及可能用到的父組件的 state)柠衅,如果是一個引用類型(Object 或者數(shù)組都是引用類型)皮仁,則需要先修改其引用地址(比如先復(fù)制到一個新的 Object 或者數(shù)組中),然后再修改其值菲宴,否則界面很可能不會刷新贷祈。(譯注:這一段不了解的朋友建議先學(xué)習(xí)下js 中的基本類型和引用類型。)
  • 為了優(yōu)化內(nèi)存占用同時保持滑動的流暢喝峦,列表內(nèi)容會在屏幕外異步繪制势誊。這意味著如果用戶滑動的速度超過渲染的速度,則會先看到空白的內(nèi)容谣蠢。這是為了優(yōu)化不得不作出的妥協(xié)粟耻,你可以根據(jù)自己的需求調(diào)整相應(yīng)的參數(shù)查近,而我們也在設(shè)法持續(xù)改進(jìn)。
  • 默認(rèn)情況下每行都需要提供一個不重復(fù)的 key 屬性挤忙。你也可以提供一個keyExtractor函數(shù)來生成 key嗦嗡。

本組件如果嵌套在其他同滾動方向的 FlatList 中,則不會繼承ScrollView 的 Props饭玲。


文檔

Props

renderItem

renderItem({ item: Object, index: number, separators: { highlight: Function, unhighlight: Function, updateProps: Function(select: string, newProps: Object) } }) => ?React.Element

data中挨個取出數(shù)據(jù)并渲染到列表中。

Provides additional metadata like index if you need it, as well as a more generic separators.updateProps function which let you set whatever props you want to change the rendering of either the leading separator or trailing separator in case the more common highlight and unhighlight (which set the highlighted: boolean prop) are insufficient for your use case.

類型 必填
function

示例:

<FlatList
  ItemSeparatorComponent={Platform.OS !== 'android' && ({highlighted}) => (
    <View style={[style.separator, highlighted && {marginLeft: 0}]} />
  )}
  data={[{title: 'Title Text', key: 'item1'}]}
  renderItem={({item, separators}) => (
    <TouchableHighlight
      onPress={() => this._onPress(item)}
      onShowUnderlay={separators.highlight}
      onHideUnderlay={separators.unhighlight}>
      <View style={{backgroundColor: 'white'}}>
        <Text>{item.title}</Text>
      </View>
    </TouchableHighlight>
  )}
/>

data

為了簡化起見叁执,data 屬性目前只支持普通數(shù)組茄厘。如果需要使用其他特殊數(shù)據(jù)結(jié)構(gòu),例如 immutable 數(shù)組谈宛,請直接使用更底層的VirtualizedList組件次哈。

類型 必填
array

ItemSeparatorComponent

行與行之間的分隔線組件。不會出現(xiàn)在第一行之前和最后一行之后吆录。 By default, highlighted and leadingItem props are provided. renderItem provides separators.highlight/unhighlight which will update the highlighted prop, but you can also add custom props with separators.updateProps.

類型 必填
component

ListEmptyComponent

列表為空時渲染該組件窑滞。可以是 React Component, 也可以是一個 render 函數(shù)恢筝,或者渲染好的 element哀卫。

類型 必填
component, function, element

ListFooterComponent

尾部組件∏瞬郏可以是 React Component, 也可以是一個 render 函數(shù)此改,或者渲染好的 element。

類型 必填
component, function, element

ListHeaderComponent

頭部組件侄柔」部校可以是 React Component, 也可以是一個 render 函數(shù),或者渲染好的 element暂题。

類型 必填
component, function, element

columnWrapperStyle

如果設(shè)置了多列布局(即將numColumns值設(shè)為大于 1 的整數(shù))移剪,則可以額外指定此樣式作用在每行容器上。

類型 必填
style object

extraData

如果有除data以外的數(shù)據(jù)用在列表中(不論是用在renderItem還是頭部或者尾部組件中)薪者,請在此屬性中指定纵苛。同時此數(shù)據(jù)在修改時也需要先修改其引用地址(比如先復(fù)制到一個新的 Object 或者數(shù)組中),然后再修改其值啸胧,否則界面很可能不會刷新赶站。

類型 必填
any

getItemLayout

(data, index) => {length: number, offset: number, index: number}

getItemLayout是一個可選的優(yōu)化,用于避免動態(tài)測量內(nèi)容尺寸的開銷纺念,不過前提是你可以提前知道內(nèi)容的高度贝椿。如果你的行高是固定的,getItemLayout用起來就既高效又簡單陷谱,類似下面這樣:

  getItemLayout={(data, index) => (
    {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
  )}

對于元素較多的列表(幾百行)來說烙博,添加getItemLayout可以極大地提高性能瑟蜈。注意如果你指定了ItemSeparatorComponent,請把分隔線的尺寸也考慮到 offset 的計算之中渣窜。

類型 必填
function

horizontal

設(shè)置為 true 則變?yōu)樗讲季帜J健?/p>

類型 必填
boolean

initialNumToRender

指定一開始渲染的元素數(shù)量铺根,最好剛剛夠填滿一個屏幕,這樣保證了用最短的時間給用戶呈現(xiàn)可見的內(nèi)容乔宿。注意這第一批次渲染的元素不會在滑動過程中被卸載位迂,這樣是為了保證用戶執(zhí)行返回頂部的操作時,不需要重新渲染首批元素详瑞。

類型 必填
number

initialScrollIndex

開始時屏幕頂端的元素是列表中的第 initialScrollIndex個元素, 而不是第一個元素掂林。如果設(shè)置了這個屬性,則第一批initialNumToRender范圍內(nèi)的元素不會再保留在內(nèi)存里坝橡,而是直接立刻渲染位于 <code>initialScrollIndex</code> 位置的元素泻帮。需要先設(shè)置 <code>getItemLayout</code> 屬性。

類型 必填
number

inverted

翻轉(zhuǎn)滾動方向计寇。實質(zhì)是將 scale 變換設(shè)置為-1锣杂。

類型 必填
boolean

keyExtractor

(item: object, index: number) => string;

此函數(shù)用于為給定的 item 生成一個不重復(fù)的 key。Key 的作用是使 React 能夠區(qū)分同類元素的不同個體番宁,以便在刷新時能夠確定其變化的位置元莫,減少重新渲染的開銷。若不指定此函數(shù)蝶押,則默認(rèn)抽取item.key作為 key 值柒竞。若item.key也不存在,則使用數(shù)組下標(biāo)播聪。

類型 必填
function

numColumns

多列布局只能在非水平模式下使用朽基,即必須是horizontal={false}。此時組件內(nèi)元素會從左到右從上到下按 Z 字形排列离陶,類似啟用了flexWrap的布局稼虎。組件內(nèi)元素必須是等高的——暫時還無法支持瀑布流布局。

類型 必填
number

onEndReached

(info: {distanceFromEnd: number}) => void

當(dāng)列表被滾動到距離內(nèi)容最底部不足onEndReachedThreshold的距離時調(diào)用招刨。

類型 必填
function

onEndReachedThreshold

決定當(dāng)距離內(nèi)容最底部還有多遠(yuǎn)時觸發(fā)onEndReached回調(diào)霎俩。注意此參數(shù)是一個比值而非像素單位。比如沉眶,0.5 表示距離內(nèi)容最底部的距離為當(dāng)前列表可見長度的一半時觸發(fā)打却。

類型 必填
number

onRefresh

() => void

如果設(shè)置了此選項,則會在列表頭部添加一個標(biāo)準(zhǔn)的RefreshControl控件谎倔,以便實現(xiàn)“下拉刷新”的功能柳击。同時你需要正確設(shè)置refreshing屬性。

類型 必填
function

onViewableItemsChanged

(info: {
    viewableItems: array,
    changed: array,
  }) => void

在可見行元素變化時調(diào)用片习“齐龋可見范圍和變化頻率等參數(shù)的配置請設(shè)置viewabilityConfig屬性蹬叭。

類型 必填
function

progressViewOffset

當(dāng)需要在指定的偏移處顯示加載指示器的時候,就可以設(shè)置這個值状知。

類型 必填 平臺
number Android

legacyImplementation

May not have full feature parity and is meant for debugging and performance comparison.

類型 必填
boolean

refreshing

在等待加載新數(shù)據(jù)時將此屬性設(shè)為 true秽五,列表就會顯示出一個正在加載的符號。

類型 必填
boolean

removeClippedSubviews

對于大列表啟用本屬性可能可以提高性能饥悴。

注意:有些情況下會有 bug(比如內(nèi)容無法顯示)坦喘。請謹(jǐn)慎使用。

類型 必填
boolean

viewabilityConfig

請參考ViewabilityHelper.js的源碼來了解具體的配置西设。

類型 必填
ViewabilityConfig

viewabilityConfig takes a type ViewabilityConfig an object with following properties

Property Required Type
minimumViewTime No number
viewAreaCoveragePercentThreshold No number
itemVisiblePercentThreshold No number
waitForInteraction No boolean

At least one of the viewAreaCoveragePercentThreshold or itemVisiblePercentThreshold is required. This needs to be done in the constructor to avoid following error (ref):

  Error: Changing viewabilityConfig on the fly is not supported`
constructor (props) {
  super(props)

  this.viewabilityConfig = {
      waitForInteraction: true,
      viewAreaCoveragePercentThreshold: 95
  }
}
<FlatList
    viewabilityConfig={this.viewabilityConfig}
  ...

minimumViewTime

Minimum amount of time (in milliseconds) that an item must be physically viewable before the viewability callback will be fired. A high number means that scrolling through content without stopping will not mark the content as viewable.

viewAreaCoveragePercentThreshold

Percent of viewport that must be covered for a partially occluded item to count as "viewable", 0-100. Fully visible items are always considered viewable. A value of 0 means that a single pixel in the viewport makes the item viewable, and a value of 100 means that an item must be either entirely visible or cover the entire viewport to count as viewable.

itemVisiblePercentThreshold

Similar to viewAreaPercentThreshold, but considers the percent of the item that is visible, rather than the fraction of the viewable area it covers.

waitForInteraction

Nothing is considered viewable until the user scrolls or recordInteraction is called after render.


viewabilityConfigCallbackPairs

List of ViewabilityConfig/onViewableItemsChanged pairs. A specific onViewableItemsChanged will be called when its corresponding ViewabilityConfig's conditions are met. 請參考ViewabilityHelper.js的源碼來了解具體的配置起宽。

類型 必填
array of ViewabilityConfigCallbackPair

方法

scrollToEnd()

scrollToEnd([params]);

滾動到底部。如果不設(shè)置getItemLayout屬性的話济榨,可能會比較卡。

參數(shù):

名稱 類型 必填 說明
params object 看下面的說明

Valid params keys are:

  • 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to true.

scrollToIndex()

scrollToIndex(params);

將位于指定位置的元素滾動到可視區(qū)的指定位置绿映,當(dāng)viewPosition 為 0 時將它滾動到屏幕頂部擒滑,為 1 時將它滾動到屏幕底部,為 0.5 時將它滾動到屏幕中央叉弦。

注意:如果不設(shè)置getItemLayout屬性的話丐一,無法跳轉(zhuǎn)到當(dāng)前渲染區(qū)域以外的位置。

參數(shù):

名稱 類型 必填 說明
params object 看下面的說明

Valid params keys are:

  • 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to true.
  • 'index' (number) - The index to scroll to. Required.
  • 'viewOffset' (number) - A fixed number of pixels to offset the final target position. Required.
  • 'viewPosition' (number) - A value of 0 places the item specified by index at the top, 1 at the bottom, and 0.5 centered in the middle.

scrollToItem()

scrollToItem(params);

這個方法會順序遍歷元素淹冰。盡可能使用scrollToIndex代替库车。

注意:如果不設(shè)置getItemLayout屬性的話,無法跳轉(zhuǎn)到當(dāng)前渲染區(qū)域以外的位置樱拴。

參數(shù):

名稱 類型 必填 說明
params object 看下面的說明

Valid params keys are:

  • 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to true.
  • 'item' (object) - The item to scroll to. Required.
  • 'viewPosition' (number)

scrollToOffset()

scrollToOffset(params);

滾動列表到指定的偏移(以像素為單位),等同于ScrollViewscrollTo方法。

參數(shù):

名稱 類型 必填 說明
params object 看下面的說明

Valid params keys are:

  • 'offset' (number) - The offset to scroll to. In case of horizontal being true, the offset is the x-value, in any other case the offset is the y-value. Required.
  • 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to true.

recordInteraction()

recordInteraction();

主動通知列表發(fā)生了一個事件曼振,以使列表重新計算可視區(qū)域侵状。比如說當(dāng)waitForInteractions為 true 并且用戶沒有滾動列表時。一般在用戶點擊了列表項或發(fā)生了導(dǎo)航動作時調(diào)用正罢。


flashScrollIndicators()

flashScrollIndicators();

短暫地顯示滾動指示器阵漏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市翻具,隨后出現(xiàn)的幾起案子履怯,更是在濱河造成了極大的恐慌,老刑警劉巖裆泳,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叹洲,死亡現(xiàn)場離奇詭異,居然都是意外死亡工禾,警方通過查閱死者的電腦和手機(jī)疹味,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門仅叫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糙捺,你說我怎么就攤上這事诫咱。” “怎么了洪灯?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵坎缭,是天一觀的道長。 經(jīng)常有香客問我签钩,道長掏呼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任铅檩,我火速辦了婚禮憎夷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昧旨。我一直安慰自己拾给,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布兔沃。 她就那樣靜靜地躺著蒋得,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乒疏。 梳的紋絲不亂的頭發(fā)上额衙,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音怕吴,去河邊找鬼窍侧。 笑死,一個胖子當(dāng)著我的面吹牛转绷,可吹牛的內(nèi)容都是我干的疏之。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼暇咆,長吁一口氣:“原來是場噩夢啊……” “哼锋爪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起爸业,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤其骄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扯旷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拯爽,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年钧忽,在試婚紗的時候發(fā)現(xiàn)自己被綠了毯炮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逼肯。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖桃煎,靈堂內(nèi)的尸體忽然破棺而出篮幢,到底是詐尸還是另有隱情,我是刑警寧澤为迈,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布三椿,位于F島的核電站,受9級特大地震影響葫辐,放射性物質(zhì)發(fā)生泄漏搜锰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一耿战、第九天 我趴在偏房一處隱蔽的房頂上張望蛋叼。 院中可真熱鬧,春花似錦剂陡、人聲如沸狈涮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至顽爹,卻和暖如春纤泵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背镜粤。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工捏题, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肉渴。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓公荧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親同规。 傳聞我的和親對象是個殘疾皇子循狰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案券勺? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,748評論 1 92
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,080評論 25 707
  • 剛剛結(jié)束关炼,我們小組的分享會程腹。每一次分享,都有很多收獲儒拂,每次聆聽?wèi)?zhàn)友寸潦,不同的人生經(jīng)歷色鸳,都有很多感觸。 今天突然聊到了...
    云成鵬閱讀 742評論 2 4
  • 一只刺猬见转,根據(jù)刺猬家族的生活習(xí)性命雀,這只小刺猬已經(jīng)到了該去外面闖蕩的年紀(jì),他應(yīng)該走出家門池户。 性格開朗的它咏雌,也有朋友。...
    芽嘟閱讀 269評論 1 0