React Native (四):加載新聞列表

React Native (一):基礎(chǔ)
React Native (二):StatusBar 、 NavigationBar 與 TabBar
React Native (三):自定義視圖
React Native (四):加載新聞列表
React Native (五):上下拉刷新加載
React Native (六):加載所有分類與詳情頁

1.標(biāo)簽與內(nèi)容頁聯(lián)動(dòng)

上一節(jié)做到了點(diǎn)擊標(biāo)簽自動(dòng)移動(dòng)洼滚,還差跟下面的視圖進(jìn)行聯(lián)動(dòng)。

首先創(chuàng)建 NewsList.js :

import React from 'react'
import {
    View,
    Text,
    ListView,
    Image,
    StyleSheet,
    Dimensions
} from 'react-native'
const {width, height} = Dimensions.get('window')

export default class NewsList extends React.Component {
    render() {
        const {style} = this.props
        return (
            <View style={[styles.view,style]}>

            </View>
        )
    }
}

const styles = StyleSheet.create({
    view: {
        flex: 1,
        backgroundColor:'red'
    }
})

然后在 Home.js 引入宵蕉,再加入 ScrollView ,現(xiàn)在 Home.jsredner() 是這樣子的,這里加入的 ScrollView 我們?cè)诤笪闹蟹Q為 NewsScrollView

render() {
        return (
            <View style={styles.view}>
                <NavigationBar
                    title="首頁"
                    unLeftImage={true}
                />

                <SegmentedView
                    ref="SegmentedView"
                    list={this.state.list}
                    style={{height: 30}}
                />

                <ScrollView
                    style={styles.view}
                    ref="ScrollView"
                    horizontal={true}
                    showsHorizontalScrollIndicator={false}
                    pagingEnabled={true}
                >
                    { this._getNewsLists()}
                </ScrollView>
           </View>
        )
    }


_getNewsLists() 方法:

_getNewsLists() {
    let lists = []
    if (this.state.list) {
        for (let index in this.state.list) {
            let dic = this.state.list[index]
            lists.push(
                <NewsList
                    key={index}
                    style={{backgroundColor:'#' + this._getColor('',0), width: width, height: height - 49 - 64 - 30}}
                    dic={dic}
                />
            )
        }
    }

    return lists
}

_getColor(color, index) {

    index ++

    if (index == 7) {
        return color
    }

    color = color + '0123456789abcdef'[Math.floor(Math.random()*16)]
    return  this._getColor(color, index)
}

根據(jù)返回的數(shù)據(jù)創(chuàng)建對(duì)應(yīng)數(shù)量的視圖候醒,給隨機(jī)顏色方便看效果为牍。

先設(shè)置滑動(dòng) NewsScrollView 讓標(biāo)簽跟著移動(dòng)哼绑。

我們把 SegmentedViewitems.push 中的 onPress 方法的實(shí)現(xiàn)單獨(dú)寫到一個(gè)方法里,然后在這里調(diào)用:

_moveTo(index) {
    const { list } = this.props  //獲取到 傳入的數(shù)組

    this.state.selectItem && this.state.selectItem._unSelect()
    this.state.selectItem = this.refs[index]
    

    if (list.length > maxItem) {
        let meiosis = parseInt(maxItem / 2)
        this.refs.ScrollView.scrollTo({x: (index - meiosis < 0 ? 0 : index - meiosis > list.length - maxItem ? list.length - maxItem : index - meiosis ) * this.state.itemWidth, y: 0, animated: true})
    }
}

這里會(huì)發(fā)現(xiàn)我們給 this.state 加了一個(gè) itemWidth 碉咆,原來我們獲取 itemWidth 是在 _getItems() 中計(jì)算的抖韩,但是在渲染的過程中無法調(diào)用 setState() ,我們把計(jì)算 itemWidth 的方法移動(dòng)到 :

componentWillReceiveProps(props) {
    const { list } = props  //獲取到 傳入的數(shù)組
    if (!list || list.length == 0) return

    // 計(jì)算每個(gè)標(biāo)簽的寬度
    let itemWidth = width / list.length

    if (list.length > maxItem) {
        itemWidth = width / maxItem
    }

    this.setState({
        itemWidth
    })
}
    

componentWillReceiveProps(props) 方法會(huì)在屬性更新后調(diào)用疫铜,參數(shù) props 是新的屬性茂浮。

現(xiàn)在運(yùn)行會(huì)發(fā)現(xiàn)點(diǎn)擊標(biāo)簽可以正常改變標(biāo)簽的狀態(tài),然而拖動(dòng) NewsScrollView 只會(huì)讓上一個(gè)選中的變?yōu)槲催x中壳咕,新的標(biāo)簽并沒有變?yōu)檫x中励稳,這是因?yàn)檫x中狀態(tài)只在標(biāo)簽被點(diǎn)擊的時(shí)候進(jìn)行了設(shè)置,我們需要給 Item 添加一個(gè)選中的方法 :

 _select() {
    this.setState({
        isSelect: true
    })
}

然后在 _moveTo(index) 進(jìn)行調(diào)用:

this.state.selectItem && this.state.selectItem._unSelect()
this.state.selectItem = this.refs[index]
this.state.selectItem._select()

現(xiàn)在運(yùn)行滑動(dòng) NewsScrollView 上面的 SegmentedView 可以正常運(yùn)行了囱井。

最后設(shè)置點(diǎn)擊標(biāo)簽可以讓 NewsScrollView 滑動(dòng)到對(duì)應(yīng)的位置驹尼,我們需要給 SegmentedView 加入一個(gè)回調(diào)函數(shù),在標(biāo)簽被點(diǎn)擊的時(shí)候調(diào)用返回點(diǎn)擊的 index

<SegmentedView
    ref="SegmentedView"
    list={this.state.list}
    style={{height: 30}}
    selectItem={(index) => {
        this.refs.ScrollView.scrollTo({x: width * index, y: 0, animated: true})
    }}
/>

SegmentedView 進(jìn)行調(diào)用:

_getItems() {
    const { list, selectItem } = this.props  //獲取到 傳入的數(shù)組

    if (!list || list.length == 0) return []

    let items = []
    for (let index in list) {
        let dic = list[index]
        items.push(
            <Item
                ref={index}
                key={index}
                isSelect={index == 0}
                itemHeight={this.state.itemHeight}
                itemWidth={this.state.itemWidth}
                dic={dic}
                onPress={() => {
                    this._moveTo(index)
                    selectItem && selectItem(index)
                }}
            />
        )
    }



    return items
}

2.加載新聞列表第一頁數(shù)據(jù)

Home.js 中已經(jīng)給 NewsList 傳入了數(shù)據(jù)庞呕,我們?cè)俳o傳入一個(gè)參數(shù)識(shí)別是否是第一頁新翎,初始只加載第一頁的數(shù)據(jù)程帕,也方便調(diào)試:

_getNewsLists() {
    let lists = []
    if (this.state.list) {
        for (let index in this.state.list) {
            let dic = this.state.list[index]
            lists.push(
                <NewsList
                    key={index}
                    style={{backgroundColor:'white'}}
                    dic={dic}
                    isRequest={index == 0}
                />
            )
        }
    }

    return lists
}

然后去 NewsList.js 進(jìn)行請(qǐng)求數(shù)據(jù):


 // 構(gòu)造
constructor(props) {
    super(props);
    // 初始狀態(tài)
    this.state = {
        page: 1,
        rn: 1,
    };
}


componentDidMount() {
    if (!this.props.isRequest) return
    this._onRefresh()
}
    
 _onRefresh(page) {
    if (this.props.dic) {
        let url = 'http://api.iapple123.com/newspush/list/index.html?clientid=1114283782&v=1.1&type='
            + this.props.dic.NameEN
            + '&startkey=&newkey=&index='
            + (page ? page : this.state.page)
            + '&size=20&ime=6271F554-7B2F-45DE-887E-4A336F64DEE6&apptypeid=ZJZYIOS1114283782&rn='
            + this.state.rn

        LOG('url=》', url)
        fetch(url, {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
        })
            .then((res) => {

                res.json()
                    .then((json) => {
                        LOG('GET SUCCESSED then =>', url, json)

                        })
                    })
                    .catch((e) => {
                        LOG('GET ERROR then =>', url, e)

                    })
            })
            .catch((error) => {

                LOG('GET ERROR=>', url, '==>', error)
            })
    }
}

請(qǐng)求到數(shù)據(jù)后我們需要用 ListView (官方文檔) 來顯示, 所以導(dǎo)入 ListView 地啰,然后去 render() 加入:

render() {
    const {style} = this.props
    return (
        <View style={[styles.view,style]}>
            <ListView
                style={{flex:1}}
                dataSource={this.state.dataSource} //設(shè)置數(shù)據(jù)源
                renderRow={this.renderRow} //設(shè)置cell
            />
        </View>
    )
}

然后加入 dataSourcerenderRow:

// 構(gòu)造
constructor(props) {
    super(props);

    var getRowData = (dataBlob, sectionID, rowID) => {

        return dataBlob[sectionID][rowID]
    };
    // 初始狀態(tài)
    this.state = {

        page: 1,
        rn: 1,
        dataSource: new ListView.DataSource({
            getRowData: getRowData,
            rowHasChanged: (r1, r2) => r1 !== r2,
        }),
    };

    this.renderRow = this.renderRow.bind(this)

}
    
    
    
renderRow(rowData, rowID, highlightRow) {
    return (
        <View />
    )
}

我們要做的界面是這個(gè)樣子

從上圖可以看出來新聞分為 3 種樣式愁拭,輪播圖、有一張圖片的和二亏吝、三張圖片的岭埠。

接下來開始解析數(shù)據(jù),解析完 json 數(shù)據(jù)發(fā)現(xiàn)只有一個(gè)數(shù)組蔚鸥,輪播圖是取了前四個(gè)惜论,剩下的根據(jù) ImagesList 里圖片的個(gè)數(shù)來判斷,

.then((json) => { 加入

let list = json.NewsList

let swipers = []
let news = []

for (let index in list) {
    let dic = list[index]
    index < 4 ? swipers.push(dic) : news.push(dic)
}

news.splice(0, 0, swipers)


this.setState({
    dataSource: this.state.dataSource.cloneWithRows(news)
})

現(xiàn)在 news 的數(shù)據(jù)結(jié)構(gòu)為:

[
    [
        {},
        {}
    ],
    
    {},
    {}
}

然后去 renderRow 處理數(shù)據(jù)

如果是數(shù)組止喷,那么返回輪播圖:

if (Object.prototype.toString.call(rowData) === '[object Array]') {
    return (
        <CarousePicture
            index={2}
            ref="ScrollView"
            rowData={rowData}
            style={{width, height: 200}}
            touchIn={this.props.touchIn}
        >
        </CarousePicture>
    )
}

這里的輪播圖本來用的 Swiper馆类,但是在 Android 上有很多 BUG,我只好自己寫了一個(gè)弹谁,但是在 Android 上的體驗(yàn)差強(qiáng)人意乾巧,源碼在這里,把文件導(dǎo)入項(xiàng)目即可预愤。

具體的可以看這里

touchIn 是由于在 Andoird 上兩個(gè) ScrollView 重疊時(shí)沟于,處于頂部的 ScrollView 滑動(dòng)事件不會(huì)響應(yīng),因?yàn)榈撞康?ScrollView 進(jìn)行了響應(yīng)并攔截了事件植康,我們需要在手指接觸到輪播圖的時(shí)候禁用底部 ScrollView 的滑動(dòng)屬性社裆,再手指離開的時(shí)候再進(jìn)行恢復(fù),所以還需要去 Home.js 加入:

 _getNewsLists() {
    let lists = []
    if (this.state.list) {
        for (let index in this.state.list) {
            let dic = this.state.list[index]
            lists.push(
                <NewsList
                    key={index}
                    style={{backgroundColor:'white', width: width, height: height - 64 - 49 - 30}}
                    dic={dic}
                    isRequest={index == 0}
                    touchIn={(scrollEnabled) => {
                        this.refs.ScrollView.setNativeProps({scrollEnabled: !scrollEnabled})
                    }}
                />
            )
        }
    }
  return lists
}

然后根據(jù) ImagesList 的個(gè)數(shù)來區(qū)分:

let imagesList = rowData.ImagesList

if (imagesList && imagesList.length == 1) {
    return (
        <TouchableOpacity style={{width,  backgroundColor:'white'}}>
            <View
                style={{width, backgroundColor:'white', flexDirection:'row', justifyContent:'space-between', flex:1}}>
                <Image
                    resizeMode="cover"
                    style={{marginTop: 10, marginBottom:10, marginLeft: 10, width: 80, height: 80, backgroundColor:'#EEEEEE'}}
                    source={{uri:imagesList[0].ImgPath}}
                />

                <View
                    style={{ marginRight: 10,backgroundColor:'white', marginTop: 10, height: 80, width: width - 110}}
                >
                    <Text>{rowData.Title}</Text>
                    <View style={{flex:1, flexDirection: 'row', justifyContent: 'space-between'}}>
                        <Text style={{marginTop:10, fontSize: 13, color: '#999999'}}>{rowData.Source}</Text>
                        <Text style={{marginRight:0,marginTop:10,fontSize: 13, color: '#999999'}}>{rowData.PublishTime}</Text>
                    </View>
                </View>
            </View>
            <View style={{width, height:1, backgroundColor: '#EEEEEE'}}></View>
        </TouchableOpacity>
    )
}

let images = []

for (let index in imagesList) {
    let dic = imagesList[index]
    images.push(
        <Image
            resizeMode="cover"
            key={index}
            style={{marginRight: 10, marginLeft: index == 0 ? 10 : 0, marginTop:10, marginBottom: 10,flex:1, height: 90}}
            source={{uri:dic.ImgPath}}
        />
    )
}

return (
    <TouchableOpacity style={{width,  backgroundColor:'white'}}>

        <View style={{width,backgroundColor:'white'}}>
            <Text style={{marginLeft: 10, marginTop: 10}}>{rowData.Title}</Text>
        </View>
        <View style={{flexDirection:'row'}}>
            {images}
        </View>
        <View style={{flex:1, flexDirection: 'row', justifyContent: 'space-between'}}>
            <Text style={{marginLeft: 10, marginBottom: 10,fontSize: 13, color: '#999999'}}>{rowData.Source}</Text>
            <Text style={{marginRight:10,fontSize: 13, marginBottom: 10,color: '#999999'}}>{rowData.PublishTime}</Text>
        </View>
        <View style={{width, height:1, backgroundColor: '#EEEEEE'}}></View>
    </TouchableOpacity>
)

我這里的 style 沒有進(jìn)行整理向图,所以看著比較亂,正式開發(fā)中應(yīng)該整理到 styles 里标沪,看起來就簡(jiǎn)潔多了榄攀。

現(xiàn)在運(yùn)行就可以顯示第一頁的數(shù)據(jù)了。

下篇文章處理上下拉刷新加載金句。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末檩赢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子违寞,更是在濱河造成了極大的恐慌贞瞒,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趁曼,死亡現(xiàn)場(chǎng)離奇詭異军浆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)挡闰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門乒融,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掰盘,“玉大人,你說我怎么就攤上這事赞季±⒉叮” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵申钩,是天一觀的道長(zhǎng)次绘。 經(jīng)常有香客問我,道長(zhǎng)撒遣,這世上最難降的妖魔是什么邮偎? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮愉舔,結(jié)果婚禮上钢猛,老公的妹妹穿的比我還像新娘。我一直安慰自己轩缤,他們只是感情好命迈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著火的,像睡著了一般壶愤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馏鹤,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天征椒,我揣著相機(jī)與錄音,去河邊找鬼湃累。 笑死勃救,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的治力。 我是一名探鬼主播蒙秒,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼宵统!你這毒婦竟也來了晕讲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤马澈,失蹤者是張志新(化名)和其女友劉穎瓢省,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊班,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勤婚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涤伐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛔六。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荆永,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出国章,到底是詐尸還是另有隱情具钥,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布液兽,位于F島的核電站骂删,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏四啰。R本人自食惡果不足惜宁玫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柑晒。 院中可真熱鬧欧瘪,春花似錦、人聲如沸匙赞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涌庭。三九已至芥被,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坐榆,已是汗流浹背拴魄。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留席镀,地道東北人匹中。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像豪诲,于是被迫代替她去往敵國和親顶捷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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