React Native基礎(chǔ)教程—實(shí)現(xiàn)微信精選列表

從本章開始我們將一起來開發(fā)一個(gè)簡(jiǎn)單的微信精選列表應(yīng)用按厘。主要包括兩個(gè)界面,主界面是微信精選列表钱慢,點(diǎn)擊每一條信息可以進(jìn)入到詳細(xì)信息展示的界面逮京。通過這個(gè)應(yīng)用我們將學(xué)習(xí)如何從網(wǎng)絡(luò)獲取數(shù)據(jù)、怎樣對(duì)UI組件進(jìn)行布局及設(shè)置樣式束莫、以及常用UI組件的使用懒棉。

可以在React NativeReact的官方網(wǎng)站查看到更多ReactNative及React的相關(guān)內(nèi)容。對(duì)應(yīng)的中文社區(qū):React NativeReact览绿。

項(xiàng)目完整源碼

項(xiàng)目的完整源碼下載地址策严。

注意
一、教程以開放IOS應(yīng)用為基礎(chǔ)講解饿敲。
二妻导、涉及到的原生代碼采用Objective-C語言完成。

微信精選

單條內(nèi)容

可以將微信精選列表看做一個(gè)tableview怀各,那么每一條內(nèi)容就是一個(gè)cell倔韭。我們將從搭建單條內(nèi)容的界面開始講解。先看一下最終完成的樣子:

單條內(nèi)容.jpeg

這個(gè)界面主要包括文本和圖片瓢对,采用文本堆疊在圖片之上的布局方式寿酌。

開發(fā)React Native應(yīng)用主要需要JavaScript、CSS和JSX三種技術(shù)硕蛹。其中JavaScript負(fù)責(zé)業(yè)務(wù)邏輯醇疼;CSS負(fù)責(zé)UI樣式和布局;JSX將UI組件封裝為標(biāo)簽語言妓美,使我們可以通過JSX標(biāo)簽構(gòu)建UI。React Native的這種開發(fā)模式借鑒了傳統(tǒng)的web開發(fā)鲤孵。這樣做主要的優(yōu)勢(shì)是可以將內(nèi)容和表現(xiàn)分離壶栋,JSX負(fù)責(zé)內(nèi)容,CSS負(fù)責(zé)表現(xiàn)普监。代碼邏輯更加清晰贵试。

JSX

相信大部分同學(xué)對(duì)于JavaScript和CSS肯定不陌生。如果沒有使用React的經(jīng)驗(yàn)可能不了解JSX是什么凯正。那么就來說一說JSX毙玻,先來看一段代碼:

<View>
  <Text>
    JSX,JavaScript語法擴(kuò)展
  </Text>
</View>

上面就是一段JSX代碼廊散。

每一個(gè)UI閉合的標(biāo)簽都稱之為組件,<View/>組件可以認(rèn)為代表UIView桑滩,<Text/>組件可以認(rèn)為代表UILabel。ReactNative就是通過這些JSX組件與原生UI一一對(duì)應(yīng)起來的允睹。

JSX运准,本質(zhì)是JavaScript的語法擴(kuò)展幌氮。React在運(yùn)行期將JSX轉(zhuǎn)換為JavaScript代碼。

JSX以<起始胁澳,以/>結(jié)束的閉合標(biāo)簽该互。JSX級(jí)能夠解析HTML標(biāo)簽,也能夠解析React組件韭畸。規(guī)定HTML標(biāo)簽必須以小寫字母開頭表示宇智,React組件以大寫字母開頭。

JSX胰丁,在構(gòu)建ReactNative應(yīng)用并不是必須的随橘,也可以直接通過JavaScript創(chuàng)建UI組件。但是使用JSX能夠讓我們的代碼更加直觀清晰隘马,并且JSX支持與JavaScript混編太防,這也賦予其非常大的靈活性。

Flexbox彈性盒

搭建UI界面必須解決的一個(gè)問題就是屏幕適配的問題酸员。在IOS開發(fā)中我們使用autolayout進(jìn)行布局蜒车,ReactNative也為我們提供了它解決布局問題的技術(shù)——Flexbox彈性盒。Flexbox本身是CSS3的技術(shù)標(biāo)準(zhǔn)幔嗦,ReactNative因?yàn)槭褂肅SS進(jìn)行布局和樣式設(shè)置酿愧,所以也就順理成章的使用Flexbox彈性盒技術(shù)。

可以通過下面的代碼在組件中聲明樣式:

<View style = {styles.container}>
  <Text style = {styles.content}>
    JSX邀泉,JavaScript語法擴(kuò)展
  </Text>
</View>

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
});

ReactNative并沒有支持全部的CSS屬性嬉挡,ReactNative支持的CSS屬性可以看這里。關(guān)于Flexbox彈性盒詳細(xì)的屬性可以查看這里汇恤。

關(guān)于Flexbox的教程推薦這兩篇文章:Flex 布局教程:語法篇庞钢、Flex 布局教程:實(shí)例篇

編寫單條內(nèi)容界面

了解了JSX與Flexbox之后因谎,我們就可以正式開始編寫單條內(nèi)容的界面基括。下面是完整的代碼:

'use strict';

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image,
} from 'react-native'

class ReactNativeLearn extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Image 
          style={{
            width: 300,
            height: 200,
          }}
          resizeMode={"contain"}
          source={{uri:'http://facebook.github.io/react/img/logo_og.png'}}
        />
        <Text
          style={{
            color: 'black',
            fontSize: 16,
            fontWeight: 'normal',
            fontFamily: 'Helvetica Neue',
          }}>
          新聞內(nèi)容
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
});

AppRegistry.registerComponent('ReactNativeLearn', () => ReactNativeLearn);

啟動(dòng)Xcode,運(yùn)行工程:

單條內(nèi)容.jpeg

可以看到我們已經(jīng)實(shí)現(xiàn)簡(jiǎn)單的上下布局的圖片和文本财岔。

現(xiàn)在我們來分析一下上面的代碼风皿。首先是'use strict',這是JavaScript的嚴(yán)格模式匠璧,在嚴(yán)格模式下一些可能會(huì)帶來安全隱患的JavaScript語言特性將被禁用(ES6標(biāo)準(zhǔn)Module默認(rèn)采用嚴(yán)格模式)桐款。然后是import React, { Component } from 'react'這行代碼的意思是將React庫的Component組件導(dǎo)入到當(dāng)前作用域中。這是采用ES6標(biāo)準(zhǔn)的寫法夷恍。之后的代碼就是我們創(chuàng)建界面的主要代碼魔眨。我們可以看到render()函數(shù),render是渲染的意思,我們?cè)趓ender函數(shù)中創(chuàng)建我們的UI組件渲染到屏幕冰沙。

關(guān)于組件的詳細(xì)信息可以在ReactNative官網(wǎng)找到侨艾。AppRegistry.registerComponent('ReactNativeLearn', () => ReactNativeLearn),表示將ReactNativeLearn組件作為整個(gè)ReactNative應(yīng)用的入口拓挥。ReactNativeLearn的名稱與AppDelegate中的moduleName對(duì)應(yīng):

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"ReactNativeLearn"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];

現(xiàn)在我們可以通過修改組件的style屬性和組件的包裹方式唠梨,實(shí)現(xiàn)我們想要的最終效果。代碼如下:

class ReactNativeLearn extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Image 
          style={{
            width:  Dimensions.get('window').width - 40,
            height: 300,
            marginLeft: 20,
            marginRight: 20,
            marginTop: 10,
            marginBottom: 10,
            borderColor: "rgb(0,0,0)",
            borderWidth: 2,
            borderRadius: 8,
            justifyContent: 'flex-end',
          }}
          resizeMode={"stretch"}
          source={{uri:'http://facebook.github.io/react/img/logo_og.png'}}
        >
          <View
            style={{
              flex: 0,
              justifyContent: 'flex-start',
              alignItems: 'stretch',
              backgroundColor: "rgba(0,0,0,0.4)",
            }}>
            <Text
              style={{
                color: "rgb(255,255,255)",
                fontSize: 20,
                fontWeight: 'normal',
                fontFamily: 'Helvetica Neue',
                marginLeft: 10,
                marginRight: 10,
                marginTop: 10,
                marginBottom: 10,
              }}
              numberOfLines={3}
            >
              A React component for displaying different types of images, including network images, static resources, temporary local images, and images from local disk, such as the camera roll.
            </Text>
          </View>
        </Image>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
});

最終效果:

最終效果.jpeg

我們不應(yīng)該將全部代碼都寫在index.ios.js文件侥啤,而是應(yīng)該分成不同的模塊当叭,方便管理。我們新建一個(gè)名為newsCell的js文件盖灸,將代碼復(fù)制到該文件當(dāng)中蚁鳖。最后將newsCell聲明為一個(gè)可以被其他模塊引用的組件:

export default NewsCell;

微信精選列表

完成單條內(nèi)容的UI搭建,現(xiàn)在我們就來實(shí)現(xiàn)列表的界面赁炎。在React Native應(yīng)用中列表通常使用ListView組件醉箕。ListView的功能類似于UITableView。先實(shí)現(xiàn)最基本的ListView徙垫,代碼如下:

class ReactNativeLearn extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (r1, r2) => r1 !== r2
      })
    };
    this.renderRow = this.renderRow.bind(this);
  }
  
  componentDidMount() {
    this.fetchNewsData();
  }
  
  //  設(shè)置數(shù)據(jù)
  fetchNewsData() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows([{'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'},
                                                        {'content':'ReactNativeLearn ListView'}])
    });
  }
  
  //  渲染cell
  renderRow(rowData) {
    return (
      <View
       style={{
         height: 80,
         justifyContent: 'flex-start',
         alignItems: 'stretch',
         backgroundColor: "rgba(74,144,226,1)",
       }}>
        <Text
          style={{
            color: 'black',
            fontSize: 28,
            fontWeight: 'normal',
            fontFamily: 'Helvetica Neue',
          }}>
          {rowData.content}
        </Text>
      </View>
    );
  }

  //  渲染cell的分割
  renderSeparator(
    sectionID,
    rowID
  ) {
      return (
        <View key = {'cell_'+ sectionID + '_' + rowID} style = {styles.rowSeparator}/>
      );
  }
  
  render() {
    return (
      <View style={styles.container}>
        <ListView
         style = {styles.listContainer}
         dataSource = {this.state.dataSource}
         renderRow = {this.renderRow}
         renderSeparator = {this.renderSeparator}
         enableEmptySections={true}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
  listContainer: {
    flex:1,
    marginTop: 64,
    backgroundColor: 'rgb(237, 240, 235)',
  },
  rowSeparator: {
    backgroundColor: 'rgb(223, 218, 223)',
    height: 1,
  },
});

最終效果:

ListView.jpeg

現(xiàn)在我們已經(jīng)完成一個(gè)最簡(jiǎn)單的ListView讥裤。可以看到我們?yōu)長(zhǎng)istView組件設(shè)置了三個(gè)屬性:dataSource姻报,renderRow和renderSeparator己英。dataSource是ListView的數(shù)據(jù)源類似于UITableView的數(shù)據(jù)源方法,這里我們手動(dòng)設(shè)置了一個(gè)數(shù)組吴旋;renderRow接收一個(gè)渲染cell的函數(shù)回調(diào)损肛,類似于UITableView的cellForRowAtIndexPath∪偕可以在這個(gè)函數(shù)里我們可以創(chuàng)建cell的UI界面治拿,即我們之前創(chuàng)建的單條內(nèi)容界面。還有一個(gè)renderSeparator笆焰,可以用于創(chuàng)建分割cell的UI劫谅。

目前為止ListView的每一個(gè)cell的數(shù)據(jù)都是我們手動(dòng)設(shè)置的。實(shí)際開發(fā)中仙辟,這些數(shù)據(jù)往往來自于服務(wù)器同波。下面我們來實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求鳄梅,代碼如下:

fetchNewsData() {
    fetch(newsULR,{
        headers: {
            "apikey": "f589f2834aeab120eef2e750e4fb1dfb"
          }
        }).then((response) => response.json())
                .catch((error) => {
            console.error('error request!');
                })
                .then((responseData) => {
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(responseData.newslist)
                    });
                })
                .done();
}

React Native使用Fetch進(jìn)行網(wǎng)絡(luò)請(qǐng)求叠国。Fetch是新的異步網(wǎng)絡(luò)請(qǐng)求標(biāo)準(zhǔn),相較于AJAX提供更強(qiáng)大高效的網(wǎng)絡(luò)請(qǐng)求API戴尸。關(guān)于ReactNative的網(wǎng)絡(luò)內(nèi)容可以看這里粟焊。

我們已經(jīng)實(shí)現(xiàn)ListView的基本功能,現(xiàn)在需要將之前單條新聞的界面newsCell作為組件,添加到ListView中项棠,實(shí)現(xiàn)完整的列表悲雳。引入newsCell的方式與引入ReactNative原生組件的方式相同,都是通過import進(jìn)行導(dǎo)入香追。

import NewsCell from './News/newsCell';

我們可以通過下面的方式向NewsCell傳遞數(shù)據(jù)或者回調(diào)函數(shù):

renderRow(rowData) {
    return (
      <NewsCell newsData={rowData}/>
    );
  }

然后在NewsCell組件可以通過如下的方式獲得數(shù)據(jù):

{this.props.newsData.title}

到此我們完成完整的微信精選列表合瓢。最終列表界面:

微信精選.jpeg

像newsCell一樣,我們把列表也封裝為一個(gè)單獨(dú)的組件透典,命名為newsMain晴楔,然后直接在index.ios.js文件導(dǎo)入即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末峭咒,一起剝皮案震驚了整個(gè)濱河市税弃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凑队,老刑警劉巖则果,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漩氨,居然都是意外死亡西壮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門才菠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茸时,“玉大人,你說我怎么就攤上這事赋访】啥迹” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蚓耽,是天一觀的道長(zhǎng)渠牲。 經(jīng)常有香客問我,道長(zhǎng)步悠,這世上最難降的妖魔是什么签杈? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮鼎兽,結(jié)果婚禮上答姥,老公的妹妹穿的比我還像新娘。我一直安慰自己谚咬,他們只是感情好鹦付,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著择卦,像睡著了一般敲长。 火紅的嫁衣襯著肌膚如雪郎嫁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天祈噪,我揣著相機(jī)與錄音泽铛,去河邊找鬼。 笑死辑鲤,一個(gè)胖子當(dāng)著我的面吹牛盔腔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播月褥,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铲觉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了吓坚?” 一聲冷哼從身側(cè)響起撵幽,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎礁击,沒想到半個(gè)月后盐杂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哆窿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年链烈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挚躯。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡强衡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出码荔,到底是詐尸還是另有隱情漩勤,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布缩搅,位于F島的核電站越败,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏硼瓣。R本人自食惡果不足惜究飞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望堂鲤。 院中可真熱鬧亿傅,春花似錦、人聲如沸瘟栖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慢宗。三九已至坪蚁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間镜沽,已是汗流浹背敏晤。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缅茉,地道東北人嘴脾。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔬墩,于是被迫代替她去往敵國和親译打。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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