Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> React Native之ViewPagerAndroid仿淘寶首頁頂部分類布局效果實現

React Native之ViewPagerAndroid仿淘寶首頁頂部分類布局效果實現

編輯:關於android開發

React Native之ViewPagerAndroid仿淘寶首頁頂部分類布局效果實現


大家好,趁著現在別人都去吃飯的時間,來給大家講一講React Native中Android部分的控件ViewPagerAndroid的講解,這裡特別提醒一下,我寫的博客都是基於大家有一些React Native基礎的前提下,因為關於React Native這一系列的博文我是最近開始更新,由於自身工作繁重(每天早上10點干到晚上10點,是不是很慘?),所以暫時還沒有那麼多的精力從基礎(比如安裝啊,運行初始程序啊)開始寫,以後有時間的話一定會將這部分給補回來,並給出鏈接,這裡希望大家諒解一下哈!

首先我們來看看最終效果:
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

(一)基本概念

首先我們要知道這是個什麼玩意兒,其實它就相當於Android原生的ViewPager,效果是一樣一樣的,只不過使用方式有點不相同,下面我們慢慢介紹。那麼它能干什麼,以及如何干,這都是我們了解一個控件需要知道的東西,那麼第一步,我們去看官網是如何介紹這個控件的,官網給出的解釋是醬紫的:

Container that allows to flip left and right between child views. Each child view of the ViewPagerAndroid will be treated as a separate page and will be stretched to fill the ViewPagerAndroid.

It is important all children are s and not composite components. You can set style properties like padding or backgroundColor for each child.

翻譯成白話文的意思就是:

一個允許在子視圖之間左右翻頁的容器。每一個ViewPagerAndroid的子容器會被視作一個單獨的頁,並且會被拉伸填滿ViewPagerAndroid。

注意所有的子視圖都必須是純View,而不能是自定義的復合容器。你可以給每個子視圖設置樣式屬性譬如padding或backgroundColor。

這裡要特別的注意一下,ViewPagerAndroid的所有子視圖都必須是純View,而不能是自定義的復合容器。什麼意思呢?意思就是說他的子節點必須是以< View >開頭,以< /View >結尾,來看看官網給出的簡單實例:
render: function() {
  return (
    
      
        First page
      
      
        Second page
      
    
  );
}

...

var styles = {
  ...
  pageStyle: {
    alignItems: 'center',
    padding: 20,
  }
}

運行效果也很簡單,和安卓原生的ViewPager的兩個簡單左右滑動的View布局一樣,這裡就不做演示了。

(二)它的屬性

initialPage number

初始選中的頁的下標。你可以用setPage 函數來翻頁,並且用onPageSelected來監聽頁的變化。

keyboardDismissMode enum(‘none’, “on-drag”)

決定在滑動的時候是否要讓軟鍵盤消失。

none (默認值),拖拽不會讓鍵盤消失。

on-drag, 當拖拽開始的時候會讓鍵盤消失。

onPageScroll function

當在頁間切換時(不論是由於動畫還是由於用戶在頁間滑動/拖拽)執行。

回調參數中的event.nativeEvent對象會包含如下數據:

position 從左數起第一個當前可見的頁面的下標。

offset 一個在[0,1)(大於等於0,小於1)之間的范圍,代表當前頁面切換的狀態。值x表示現在”position”所表示的頁有(1 -
x)的部分可見,而下一頁有x的部分可見。

onPageScrollStateChanged function

頁面滑動狀態變化時調用此回調函數。頁面滑動狀態可能為以下三種之一:

idle 空閒,意味著當前沒有交互。

dragging 拖動中,意味著當前頁面正在被拖動。

settling 處理中,意味著當前頁面發生過交互,且正在結束開頭或收尾的動畫。

onPageSelected function

這個回調會在頁面切換完成後(當用戶在頁面間滑動)調用。

回調參數中的event.nativeEvent對象會包含如下的字段:

position 當前被選中的頁面下標

ok,它的一些屬性也寫的比較明白,大家在使用過程中就可以去仔細體會了,下面我們正式進入主題,仿照美團首頁頂部的viewpager輪播圖,來用React Native實現。

(三)我的實例

1.首先,打開電腦的終端(windows平台是輸入cmd就可以進入命令行工具),新建一個項目:react-native init ViewPagerDemo,等待新項目的創建。

2.項目創建完成後,打開目錄下的index.android.js文件,這裡介紹一下,我開發的編輯器是Atom,目前來說還是比較好用的,大家因人而異,這個沒有關系。
這裡寫圖片描述

打開後在安卓模擬上按Menu鍵(通常是F2,在Genymotion模擬器中是?+M)然後選擇 Reload JS 就可以看到你的最新修改。初始運行效果如下:
這裡寫圖片描述vcqxuvLI57rO0N64xMTYo6zL+dLUztLDx9C0tPrC69K7tqjSqsHpu+6jrLK7xNyw0dfUvLq+1s/exvDAtKGjPC9wPg0KPHA+vdPPwsC0ztLDx8C0seDQtNb30rPD5rXEs6G+sKOs1eLA79PJ09rS1Lrzv8nE3LvhtuC0zsq508O1vbjDz+7Ev6Oosru/ycTcztLDv7TO0LTSu7j2ZGVtb77N0MK9qNK7uPa5pLPMsMmjrNXi0fnMq9TjzKPBy6Osy/nS1M7Svva2qL2ry/nT0LXEz+7Ev9C01NrNrNK7uPa5pLPMwre+ts/Co6zV4sDvzai5/VJlYWN0IE5hdGl2Zczhuam1xE5hdmlnYXRvcsC0v9jWxs7Sw8fSqs/Uyr7ExNK7uPbSs8Pmo6jgxaOsy7W1vdXiwO/O0r71tcNOYXZpZ2F0b3LSsr/J0tS1pbbA0LTSu8aqsqm/zcHLoaOho6Gjo6mjrM/Cw+bKx2luZGV4LmFuZHJvaWQuanPOxLz+tcS0+sLro7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> import React, { AppRegistry, StyleSheet, Text, Navigator, BackAndroid, View } from 'react-native'; import ViewPagerScreen from './pages/ViewPagerScreen.js'; var _navigator; BackAndroid.addEventListener('hardwareBackPress', function() { if (_navigator && _navigator.getCurrentRoutes().length > 1) { _navigator.pop(); return true; } return false; }); var DemosApplication = React.createClass({ RouteMapper:function(route, navigationOperations, onComponentRef){ _navigator = navigationOperations; switch (route.name) { case 'viewpagerscreen': return ( ); } }, getInitialState: function() { return { splashed: true, }; }, render() { if (this.state.splashed) { var initialRoute = {name: 'viewpagerscreen'}; return( Navigator.SceneConfigs.FadeAndroid} renderScene={this.RouteMapper} /> ); } } }); var styles = StyleSheet.create({ wrapper: { borderRadius: 5, marginBottom: 5, }, container: { flex: 1, flexDirection: 'column', }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('DemosApplication', () => DemosApplication);

這裡簡單的說明一下,我是通過Navigator來控制頁面顯示效果的

 Navigator.SceneConfigs.FadeAndroid}
          renderScene={this.RouteMapper} />

然後路由在這裡進行分發顯示:

RouteMapper:function(route, navigationOperations, onComponentRef){
    _navigator = navigationOperations;
    switch (route.name) {
      case 'viewpagerscreen':
        return (
          
            
          
        );
    }
  },

由於我指定的路由名稱為viewpagerscreen,所以這裡會返回ViewPagerScreen組件,也就是我們今天的項目,接下來,我們來編寫ViewPagerScreen頁面。

我們在ViewPagerScreen.js頁面首先定義一個數組模擬服務器返回的數據:

var source = [
  {title:'長途',icon:require('../asset/01.png')},
  {title:'交通',icon:require('../asset/02.png')},
  {title:'住宿',icon:require('../asset/03.png')},
  {title:'餐飲',icon:require('../asset/04.png')},
  {title:'補助',icon:require('../asset/05.png')},
  {title:'辦公',icon:require('../asset/06.png')},
  {title:'福利',icon:require('../asset/07.png')},
  {title:'市場',icon:require('../asset/08.png')},
  {title:'研發',icon:require('../asset/09.png')},
  {title:'廣告',icon:require('../asset/10.png')},
  {title:'促銷',icon:require('../asset/11.png')},
  {title:'宣傳',icon:require('../asset/12.png')},
  {title:'購物',icon:require('../asset/13.png')},
  {title:'其他',icon:require('../asset/14.png')},
  {title:'備用',icon:require('../asset/15.png')},
  {title:'火車',icon:require('../asset/16.png')},
  {title:'招待',icon:require('../asset/17.png')},
  {title:'通訊',icon:require('../asset/18.png')},
  {title:'材料',icon:require('../asset/19.png')}
];

然後我們聲明一個組件,用於顯示單個條目的布局,代碼如下:

var PagerItem = React.createClass({
  render(){
    return(
      
        this.itemOnClick()}>
          
        
        {this.props.item.title}
      
    );
  },

  itemOnClick(){
    this.props.onItemClick();
  }
});

接著我們就來編寫ViewPagerScreen組件,代碼如下:

class ViewPagerScreen extends Component {

  renderPagerItem(item,index){
    return  this.onItemClick(item)}/>;
  }

  onItemClick(item){
    this.toastMessage(item.title);
  }

  render() {
    return(
      
        
          {
            this.getAllPager()
          }
        
      
    );
  }

  //返回ViewPager的所有View
  getAllPager(){
    var viewArray = [];
    var data1 = [],data2 = [],data = [];
    var page = 0;
    var result = Math.floor(source.length / 10);
    var rest = source.length % 10;
    if (result > 0) {
      page = rest > 0 ? result + 1 : result;
    }else{
      page = rest > 0 ? 1 : 0;
    }
    var num = page;
    for (var i = 0; i < page; i++) {
      data = num > 1 ? source.slice(i * 10,(i + 1) * 10) : source.slice(i * 10,source.length);
      viewArray.push(this.getPagerView(i,data));
      num--;
    }
    return viewArray;
  }

  //返回ViewPager的頁面
  getPagerView(i,data){
    return(
      
        {
          this.getRowView(data)
        }
      
    );
  }

  //返回ViewPager一頁View對象
  getRowView(array){
    if (array.length > 0) {
      return(
        
          {
            array.map((item,i) => this.renderPagerItem(item,i))
          }
        
      );
    }
  }

  toastMessage(msg){
    ToastAndroid.show(msg,ToastAndroid.SHORT);
  }
}

這裡最主要的方法就是對數據進行分析,一頁最多展示10個數據,所以對於超出部分需要另起一頁,所以我的做法是:

getAllPager(){
    var viewArray = [];
    var data1 = [],data2 = [],data = [];
    var page = 0;
    var result = Math.floor(source.length / 10);
    var rest = source.length % 10;
    if (result > 0) {
      page = rest > 0 ? result + 1 : result;
    }else{
      page = rest > 0 ? 1 : 0;
    }
    var num = page;
    for (var i = 0; i < page; i++) {
      data = num > 1 ? source.slice(i * 10,(i + 1) * 10) : source.slice(i * 10,source.length);
      viewArray.push(this.getPagerView(i,data));
      num--;
    }
    return viewArray;
  }

對於每一頁數據是如何加載的,我們將數組通過map方法生成單個View對象並返回:

getRowView(array){
    if (array.length > 0) {
      return(
        
          {
            array.map((item,i) => this.renderPagerItem(item,i))
          }
        
      );
    }
  }

到這裡我們的工作就完成了,重新Reload JS,看看發生的奇妙變化吧,這裡我們對單個條目的點擊也做了處理,點擊單個條目時,會返回當前條目的名稱,好了,讓我們來看看效果圖吧:
這裡寫圖片描述

這裡寫圖片描述

這是第二頁的效果:

這裡寫圖片描述

效果是不是還可以呢?好了,如果有問題,歡迎大家在下方留言,看到我會回復大家,一起進步才是最重要的。

ViewPagerScreen.js完整代碼
'use strict';

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

var WINDOW_WIDTH = Dimensions.get('window').width;
var WINDOW_HEIGHT = Dimensions.get('window').height;

var source = [
  {title:'長途',icon:require('../asset/01.png')},
  {title:'交通',icon:require('../asset/02.png')},
  {title:'住宿',icon:require('../asset/03.png')},
  {title:'餐飲',icon:require('../asset/04.png')},
  {title:'補助',icon:require('../asset/05.png')},
  {title:'辦公',icon:require('../asset/06.png')},
  {title:'福利',icon:require('../asset/07.png')},
  {title:'市場',icon:require('../asset/08.png')},
  {title:'研發',icon:require('../asset/09.png')},
  {title:'廣告',icon:require('../asset/10.png')},
  {title:'促銷',icon:require('../asset/11.png')},
  {title:'宣傳',icon:require('../asset/12.png')},
  {title:'購物',icon:require('../asset/13.png')},
  {title:'其他',icon:require('../asset/14.png')},
  {title:'備用',icon:require('../asset/15.png')},
  {title:'火車',icon:require('../asset/16.png')},
  {title:'招待',icon:require('../asset/17.png')},
  {title:'通訊',icon:require('../asset/18.png')},
  {title:'材料',icon:require('../asset/19.png')}
];

var PagerItem = React.createClass({
  render(){
    return(
      
        this.itemOnClick()}>
          
        
        {this.props.item.title}
      
    );
  },

  itemOnClick(){
    this.props.onItemClick();
  }
});

class ViewPagerScreen extends Component {

  renderPagerItem(item,index){
    return  this.onItemClick(item)}/>;
  }

  onItemClick(item){
    this.toastMessage(item.title);
  }

  render() {
    return(
      
        
          {
            this.getAllPager()
          }
        
      
    );
  }

  //返回ViewPager的所有View
  getAllPager(){
    var viewArray = [];
    var data1 = [],data2 = [],data = [];
    var page = 0;
    var result = Math.floor(source.length / 10);
    var rest = source.length % 10;
    if (result > 0) {
      page = rest > 0 ? result + 1 : result;
    }else{
      page = rest > 0 ? 1 : 0;
    }
    var num = page;
    for (var i = 0; i < page; i++) {
      data = num > 1 ? source.slice(i * 10,(i + 1) * 10) : source.slice(i * 10,source.length);
      viewArray.push(this.getPagerView(i,data));
      num--;
    }
    return viewArray;
  }

  //返回ViewPager的頁面
  getPagerView(i,data){
    return(
      
        {
          this.getRowView(data)
        }
      
    );
  }

  //返回ViewPager一頁View對象
  getRowView(array){
    if (array.length > 0) {
      return(
        
          {
            array.map((item,i) => this.renderPagerItem(item,i))
          }
        
      );
    }
  }

  toastMessage(msg){
    ToastAndroid.show(msg,ToastAndroid.SHORT);
  }
}

var styles = StyleSheet.create({
  //消費類型部分
  imageStyle:{
    alignSelf:'center',
    width:45,
    borderRadius:22.5,
    height:45
  },
  textStyle:{
   marginTop:5,
   alignSelf:'center',
   fontSize:14,
   color:'#555555',
   textAlign:'center'
  },
});

module.exports = ViewPagerScreen;

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved