React Native填坑之旅--ListView篇

列表顯示數(shù)據(jù)狈定,基本什么應(yīng)用都是必須。筆者寫(xiě)作的時(shí)候RN版本是0.34习蓬。今天就來(lái)從淺到深的看看React Native的ListView怎么使用纽什。

首先是使用寫(xiě)死的數(shù)據(jù),之后會(huì)使用網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)在界面中顯示友雳。最后加上一個(gè)ActivityIndicator稿湿,網(wǎng)絡(luò)請(qǐng)求的過(guò)程中顯示Loading圖標(biāo)铅匹,加載完成之后顯示數(shù)據(jù)押赊,隱藏Loading圖標(biāo)。

最簡(jiǎn)單的

//@flow

import React from 'react';
import {
  Text,
  View,
  ListView
} from 'react-native';

export default class DemoList extends React.Component {
  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows(['row 1', 'row 2'])
    };
  }

  render() {
    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={(rowData) => <Text>{rowData}</Text>} />
    );
  }
}

引入所需要的內(nèi)置組件之類(lèi)的就不多說(shuō)了包斑。

第一步流礁,在constructor里設(shè)置數(shù)據(jù)源,并同時(shí)指定什么時(shí)候重新繪制一行罗丰,就是在這個(gè)時(shí)候(r1, r2) => r1 !== r2}重繪神帅。

之后,在state里面設(shè)置數(shù)據(jù)源萌抵。下面從網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)的時(shí)候state的作用就更加明顯了找御。RN的組件在state發(fā)生改變的時(shí)候就會(huì)重繪元镀。這個(gè)下面會(huì)詳細(xì)解釋。

最后霎桅,在render方法里返回ListView栖疑,這里的props里有一個(gè)renderRow。在這里指定的代碼就是把數(shù)據(jù)源中每一行的數(shù)據(jù)繪制在Text里滔驶。

一步一步接近實(shí)際產(chǎn)品開(kāi)發(fā)

下面就把繪制行的部分抽象出來(lái)遇革。在Native應(yīng)用的開(kāi)發(fā)中,無(wú)論是iOS還是Android揭糕,行繪制的部分都是單獨(dú)出來(lái)的萝快。在RN里雖然可以不獨(dú)立出來(lái),但是你也看到了著角,這樣的寫(xiě)法遇到稍微復(fù)雜一點(diǎn)的行內(nèi)容的時(shí)候就捉襟見(jiàn)肘了揪漩。不獨(dú)立出來(lái)行繪制部分代碼會(huì)很難維護(hù)。

這部分不復(fù)雜雇寇,獨(dú)立出來(lái)以后是這樣的:

import //...略...

export default class DemoList extends React.Component {
  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows(['row 1', 'row 2'])
    };

    //bind
    this._renderRow = this._renderRow.bind(this);
  }

  _renderRow(rowData) {
    return (
      <View style={{height: 50}}>
        <Text>{rowData}</Text>
      </View>
    );
  }

  render() {
    return (
      <ListView dataSource={this.state.dataSource}
        renderRow={this._renderRow} />
    );
  }
}

這個(gè)例子和上例基本上一樣氢拥。只是多了一個(gè)_renderRow(rowData)方法。

注意:在使用這個(gè)方法以前锨侯,一定要綁定:this._renderRow = this._renderRow.bind(this);嫩海。綁定也可以這樣<ListView dataSource={this.state.dataSource} renderRow={this._renderRow.bind(this)} />

在繪制行的時(shí)候囚痴,比之前稍微有一點(diǎn)改動(dòng)叁怪。行文本的外面套了一個(gè)View,并指定這個(gè)View的高度為50深滚。

加上裝飾

從現(xiàn)在來(lái)看奕谭,數(shù)據(jù)只有兩行。如果不滑動(dòng)一下的話痴荐,看起來(lái)和兩個(gè)上下排列的Text沒(méi)有什么區(qū)別血柳。

首先我們加一個(gè)分割線:

export default class DemoList extends React.Component {
  constructor() {
    //記得使用方法之前綁定
    this._renderSeparator = this._renderSeparator.bind(this);
  }
  _renderRow(rowData) {
    // ...略...
  }

  _renderSeparator(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
    return (
      <View key={`{sectionID}-${rowID}`}
        style={{height: 1, backgroundColor: 'black'}}>
      </View>
    );
  }
  render() {
    return (
      <ListView dataSource={this.state.dataSource}
        renderRow={this._renderRow}
        renderSeparator={this._renderSeparator}
        />
    );
  }
}

這里需要額外說(shuō)明一些,在方法里_renderSeparator(sectionID: number, rowID: number, adjacentRowHighlighted: bool)我看看到了在參數(shù)的名稱(chēng)后面都有類(lèi)型的說(shuō)明生兆。這個(gè)不是ES6的也不是js里的难捌,而是FB自己搞的一套靜態(tài)類(lèi)型檢查工具里的定義。這個(gè)工具叫Flow鸦难。

如果你從一開(kāi)始就沒(méi)打算跟flow扯上任何關(guān)系根吁,那么就按照ES標(biāo)準(zhǔn)寫(xiě)就好。

至于分割線也是非常簡(jiǎn)單合蔽。我們這就返回了一個(gè)高度一個(gè)像素的击敌,背景色為黑色的view。

點(diǎn)擊和高亮

Row的點(diǎn)擊不想Native那樣拴事,默認(rèn)的一般就有了沃斤。在RN里圣蝎,我們需要手動(dòng)賦予一行可以被點(diǎn)擊的功能。

  _renderRow(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
    return (
      <TouchableHighlight onPress={() => {
        this._pressRow(rowID);
        highlightRow(sectionID, rowID);
      }}>
        <View style={styles.row}>
          <Text style={styles.text}>{rowData}</Text>
        </View>
      </TouchableHighlight>
    );
  }

在RN里處理一般點(diǎn)擊的不二選擇就是TouchableHighlight衡瓶。在TouchableHighlight里的onPress里調(diào)用自定義的_pressRow方法處理點(diǎn)擊捅彻,highlightRow方法高亮行。

當(dāng)然鞍陨,這里就少不了用到樣式了:

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    justifyContent: 'center',
    padding: 10,
    backgroundColor: '#F6F6F6',
  },
  text: {
    flex: 1,
  },
  seperator: {
    height: 1,
    backgroundColor: '#CCCCCC'
  }
});

把Cell分離

在實(shí)際的開(kāi)發(fā)中步淹,一般沒(méi)有人會(huì)把Row(或者行)的繪制和ListView放在一起。我們這里就演示如何把Row的繪制分離出去诚撵。

首先創(chuàng)建一個(gè)單獨(dú)的文件缭裆,定義Cell:

import React from 'react';
import {
  View,
  Text,
  TouchableHighlight,
  StyleSheet
} from 'react-native';


export default class DemoCell extends React.Component {
  render() {
    return (
      <View>
        <TouchableHighlight onPress={this.props.onSelect}>
          <View style={styles.row}>
            <Text style={styles.text}>{this.props.rowData}</Text>
          </View>
        </TouchableHighlight>
      </View>
    );
  }
};

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    justifyContent: 'center',
    padding: 10,
    backgroundColor: '#F6F6F6',
  },
  text: {
    flex: 1,
  },
});

Row也是一個(gè)組件,是一個(gè)組件就可以在另外的組建里渲染寿烟。所以澈驼,單獨(dú)定義的Row就是這么用的。

回到demoList.js文件筛武。在_renderRow方法中修改代碼:

  _renderRow(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
    return (
      // <TouchableHighlight onPress={() => {
      //   this._pressRow(rowID);
      //   highlightRow(sectionID, rowID);
      // }}>
      //   <View style={styles.row}>
      //     <Text style={styles.text}>{rowData}</Text>
      //   </View>
      // </TouchableHighlight>
      <DemoCell onSelect={() => {
         this._pressRow(rowID);
         highlightRow(sectionID, rowID);
       }} rowData={rowData}/>
    );
  }

結(jié)合網(wǎng)絡(luò)請(qǐng)求

ListView在實(shí)戰(zhàn)中缝其,除非是Settings之類(lèi)的界面,數(shù)據(jù)都是從網(wǎng)絡(luò)請(qǐng)求得到的徘六。上一節(jié)中正好已經(jīng)講述了如何使用RN內(nèi)置的fetch請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)内边。這一節(jié)中就是用fetch來(lái)請(qǐng)求dribbble的數(shù)據(jù)。

在使用dribbble的數(shù)據(jù)之前你需要注冊(cè)待锈,獲得Access Token漠其。這是請(qǐng)求認(rèn)證所必須的。

export default class DemoList extends React.Component {

  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      isLoading: false,
      isLoadingTail: false,
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      filter: this.props.filter,
      queryNumber: 0,
    };
    //...略...
  }

  //...略...

  _getShots(query: string) {
    this.setState({
      isLoading: true,
      queryNumber: this.state.queryNumber + 1,
      isLoadingTail: false,
    });

    api.getShotsByType(query, 1).then((responseData) => {
      this.setState({
        isLoading: false,
        dataSource: this._getDataSource(responseData),
      });
    }).catch((error) => {
      this.LOADING[query] = false;
      this.resultsCache.dataForQuery[query] = undefined;

      this.setState({
          dataSource: this._getDataSource([]),
          isLoading: false,
      });
    });
  }

還是在類(lèi)DemoList里竿音,其他無(wú)關(guān)緊要的代碼先略去和屎。要緊的地方是需要注意在constructor里設(shè)置state的時(shí)候dataSource如何設(shè)置的。

state的改變會(huì)影響到組件的繪制春瞬。所以柴信,在_getShots方法里,開(kāi)始請(qǐng)求之前先設(shè)置一個(gè)默認(rèn)的state狀態(tài)宽气。在請(qǐng)求成功之后使用setState設(shè)置一個(gè)随常,在catch到異常的時(shí)候再顯示另外一個(gè)。

state里還有一個(gè)屬性叫做isLoading: false,抹竹。這個(gè)是影控制Loading視圖的线罕。在false的時(shí)候隱藏止潮,在true的時(shí)候顯示窃判。

那么loading界面是什么樣呢?

<View style={{alignItems: 'center', justifyContent: 'center', flex: 1, backgroundColor: 'white'}}>
    <ActivityIndicator animating={true}
      style={[styles.centering]}
      size="large"
      color="#cccccc"
    />
</View>

組合起來(lái)

在類(lèi)DemoList里組合相關(guān)代碼:

  _renderView() {
    if (this.state.isLoading) {
      return (
        <UNActivityIndicator loadingType={LOADING_TYPE.Large} />
      );
    }

    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={this._renderRow}
          renderSeparator={this._renderSeparator}
          automaticallyAdjustContentInsets={false}
          />
      </View>
    );
  }

在renderView的時(shí)候喇闸,先檢查state.isLoading袄琳,如果需要loading視圖询件,那么返回loading視圖,其他的不返回唆樊。數(shù)據(jù)加載成功之后state.isLoading被設(shè)置為false宛琅,那么顯示ListView。

填坑完畢

以上就是處理ListView和其中的Cell的一些常見(jiàn)問(wèn)題的方法逗旁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘿辟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子片效,更是在濱河造成了極大的恐慌红伦,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淀衣,死亡現(xiàn)場(chǎng)離奇詭異昙读,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)膨桥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)蛮浑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人只嚣,你說(shuō)我怎么就攤上這事沮稚。” “怎么了册舞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵壮虫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我环础,道長(zhǎng)囚似,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任线得,我火速辦了婚禮饶唤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贯钩。我一直安慰自己募狂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布角雷。 她就那樣靜靜地躺著祸穷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勺三。 梳的紋絲不亂的頭發(fā)上雷滚,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音吗坚,去河邊找鬼祈远。 笑死呆万,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的车份。 我是一名探鬼主播谋减,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扫沼!你這毒婦竟也來(lái)了出爹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缎除,失蹤者是張志新(化名)和其女友劉穎以政,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體伴找,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盈蛮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了技矮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抖誉。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖衰倦,靈堂內(nèi)的尸體忽然破棺而出袒炉,到底是詐尸還是另有隱情,我是刑警寧澤樊零,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布我磁,位于F島的核電站,受9級(jí)特大地震影響驻襟,放射性物質(zhì)發(fā)生泄漏夺艰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一沉衣、第九天 我趴在偏房一處隱蔽的房頂上張望郁副。 院中可真熱鬧,春花似錦豌习、人聲如沸存谎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)既荚。三九已至,卻和暖如春栋艳,著一層夾襖步出監(jiān)牢的瞬間恰聘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憨琳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓旬昭,卻偏偏與公主長(zhǎng)得像篙螟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子问拘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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