標籤:
上次發布了我的慢牛股票APP之後,有園友反饋有點卡,這個APP是基於Sencha Touch + Cordova開發的,Sencha本身是一個比較重的架構,在Chrome裡運行效能還是不錯的,但是在Android的WebView裡,效能受限於機器的配置,在我的小米2s裡表現還行,在小米4s裡開起來比較流暢,但是Android機型相比IOS太多樣了,Sencha Touch在iOS裡表現不錯,不過我還沒編譯iOS版本。
後來我又試著用了下Ionic架構,基於AngularJs開發,這個架構要輕量,在慢牛股票的公眾號裡試著開發了幾個頁面,感覺很不錯,本來想用AngularJs重新做一個APP,但是後來又接觸了React Native,試著用了下,React Native的編程體驗類似於Sencha Touch,完全的組件化,JSX的文法很有意思,逐步習慣以後,用起來也很順手。
有興趣的朋友可以對比下這三個方案,我留下這個三個方案的:
慢牛股票APP(Sencha Touch+ Cordova)方案
慢牛公眾號(Ionic方案)
Demo(React Native方案)
動畫:
React Native相比上面兩種,體驗更順暢,當然,原生的應用肯定是比在WebView裡體驗好的,ReactNative結合了原生開發和Web開發優勢,不過,React Native現在對Android的支援不算太好,比如動畫。
ReactNative的Flex布局,組件化思想很不錯,上手快,不過因為最終顯示的是原生,所以還是要多瞭解下原生的開發,必要時自己做橋接,比如我在做K線圖,苦於找不到相關的組件,只有自己橋接了MPAndroidChart。
Demo主要實現了幾個我認為比較關鍵功能:
1、導航
2、列表
3、下拉重新整理
4、圖表
這幾個功能點實現以後,後面的工作就輕鬆得多了,比如表單提交,第三方登入,設定等等頁面。
下面說下這幾個點的實現方式,
1、導航:
側滑菜單:
熟悉原生開發的同學一看就知道,這是原生的DrawerLayout,通過RN橋接過來,
很滑,很順,之前用CSS3在WebView裡做過側滑菜單,當然比不上這個啦!
頁面切換:
利用了RN的Navigator組件,這個組件實現了一個Stack,每次新開頁面就是向Stack裡Push新的UI導航資訊,然後在Render時判斷要顯示哪個UI組件,這個導航組件會把曆史UI移動可視範圍之外,利用Opacity把UI設定為透明,然後絕對位置到可視範圍之外,返回時,再把曆史UI移動可視範圍,這樣,曆史UI的狀態還是保持的,這樣的導航在Web上也是可以借鑒的。
這個導航還可以設定轉場動畫,看原始碼,確實是實現了不少的動畫,包括PushFromRight,FloatFromRight,FadeAndroid等,但是設定後不起作用,只有FadeAndroid有效果,但是動畫一閃而過,不順滑,這裡對Android的支援不太好,或者是我的哪裡設定不對?
Tab切換:
Tab切換做起來比較容易,不過有一點,在頁面切換過程中,不要重新Render每個Tab對應的內容,重新Render會清除頁面的當前的狀態,比如捲軸的位置等,而且效能差,借鑒Navigator,把非焦點的Tab頁面移動可視範圍之外即可。
Demo中按鈕的表徵圖都是向量的,表徵圖字型的優點不用說了,原生系統也可以用表徵圖字型了,對不喜歡用圖片的同學真是一個喜訊,一想到要做那麼多圖片,要考慮每種解析度,就頭腦哇,這裡用了github上的一個開源組件react-native-icons。
貼段代碼:
render: function() { var navigationView = ( <SideMenu onItemSelected={this.onItemSelected}/> ); return ( <DrawerLayout ref="drawerMenu" drawerWidth={300} drawerPosition={DrawerLayout.positions.Left} renderNavigationView={() => navigationView}> <Navigator ref=‘navigator‘ debugOverlay={false} style={styles.appContainer} configureScene={(route) =>Navigator.SceneConfigs.FloatFromRight} initialRoute={{name:‘main‘,component:(<TabPanel/>)}} renderScene={(route, navigator) => { return (route.component); }} /> </DrawerLayout>);
2、列表:
Demo裡我實現了一個股票的列表,列表拆分成了List組件和ListItem組件,利用React開發,組件化思想很重要,這在之前用Sencha時也有這樣的體驗。
列表這裡沒有用ListView組件,是用ScrollVIew包了一個ListTtem的列表,如果資料量比較大,或者比較複雜列表,可以用官方的ListView來做,效能會比較好,每次更新只會更新變化的清單項目,也提供了分類,設定表頭和表尾等等。
貼段代碼:
createRows:function(){ return this.state.myStockList.map(function (obj) { return (<StockItem key={obj.code} id={obj.code} data={obj}></StockItem>); }); }, render: function() { return ( <SwipeRefreshLayout ref={(control)=>{this._view=control}} style={styles.scrollView} onRefresh={this.reloadData}> <ScrollView style={{flex:1}}> {this.createRows()} </ScrollView> </SwipeRefreshLayout> ); }
3、下拉重新整理:
在github上,有不少的下拉重新整理組件,比如;react-native-gifted-listview,但是都是iOS上可以下拉,在Android上有Bug,文檔上這樣解釋:
Pull-to-refresh in Android (tried to implement it but it seems that onResponderRelease event is not catchable yet in Android ListView - React-Native
關於如何在RN裡響應手勢,我還沒怎麼瞭解,後面再動畫方面多研究下,因為瞭解下原生控制項的橋接,所有就偷懶了,把原生的SwipeRefreshLayout控制項做了橋接,包裹上ScrollVIew,就可以實現下拉重新整理了,在JS裡響應SwipeRefreshLayout發送的重新整理事件,同時開放一個關閉重新整理的介面,JS端擷取資料更新後,關閉重新整理狀態。
4、圖表
圖表這裡,我花的時間最多,目前也不是很完善,只不過,可以顯示K線了,但是在互動上還是要加強。
之前在Web端做過兩次K線圖,一個是Sencha的,一個是D3的,用了RN以後,之前的圖表都用不上了,也考慮過套個WebView,用D3來做,但是效果肯定不好哇,最後還是學習了原生開發,學習了原生UI的布局,組件的繼承架構,學習使用MPAndroidChart組件,如何橋接原生組件等等,收穫不小,現在開發一邊開啟Android Studio,一邊開啟Sublime。。。
原生的組件,View是所有UI組件的基類,而 ViewGroup是容納這些組件的容器,其本身也是從View派生出來的,RN提供了兩種ViewManager類用來橋接這兩類組件,ViewManager管理組件的建立,布局,以及屬性設定,事件觸發。
貼段代碼:
android端(橋接圖表程式碼片段):
public class MPBarLineChartManager extends SimpleViewManager<BarLineChartBase> { private String CLASS_NAME="MPBarChart"; @Override public String getName() { return this.CLASS_NAME; } @Override protected BarLineChartBase createViewInstance(ThemedReactContext reactContext) { BarChart chart=new BarChart(reactContext); return chart; } @ReactProp(name="touchEnabled",defaultBoolean = true) public void setTouchEnabled(BarLineChartBase chart,boolean enable){ chart.setTouchEnabled(enable); }
......}
js端:
var { requireNativeComponent,PropTypes } = require(‘react-native‘);var iface = { name: ‘BarChart‘, propTypes: { data:PropTypes.object, touchEnabled:PropTypes.bool, ......scaleX: PropTypes.number,scaleY: PropTypes.number,translateX: PropTypes.number,translateY: PropTypes.number,rotation: PropTypes.number, },};module.exports = requireNativeComponent(‘MPBarChart‘, iface);
這個圖表的橋接項目我發布到了github上,目前實現了對柱狀圖,線形圖,以及組合圖的橋接。
https://github.com/hongyin163/react-native-mpchart
有希望用圖表的同學可以利用下,要是能繼續幫忙增強就更好啦!
學會了橋接原生組件以後,我就陷入了一種模式,只要在RN裡實現有難度的,我就想橋接一個原生的Android組件,雖然知道這樣不太好,因為如果用了太多原生的組件,後續的遷移麻煩了,當然最好利用官方提供的Android和IOS都支援的組件,最好是用平台無關的方式來做,這裡最大的感觸是,RN提供了一種途徑,讓js可以和原生組件互動,商務邏輯寫在js裡,利用原生組件呈現,如果有原生開發的同學支援,那麼利用RN開發就方便多了,提供一致的組件庫,一套代碼就可以在兩個系統上運行了,這樣就不僅僅是learn once write anywhere了。
關於效能最佳化:
1、消極式載入
如果一次載入太多的組件,RN需要等全部組件渲染完成才顯示出來,會有白屏,所有每次載入組件最好少一些,比如先構建頁面的架構,架構渲染完成後再載入資料,建立基於資料的組件,或者利用setTimeout消極式載入其他的組件。
2、使用setNativeProps
React把組件當成狀態機器,通常是用setState方法,改變組件狀態,頁面會重新渲染,但是重新渲染效能比較差,setNativeProps可以繞過這個過程,直接修改原生組件的屬性,或者調用原生的組件的API,效能就好多了,但是狀態同步方面就要多考慮下了。
3、實現shouldComponentUpdate方法
React在組件渲染時會有個diff演算法,如果前後Virtual DOM狀態改變,會重新渲染組件,如果實現shouldComponentUpdate方法,返回false,就會避免不必要的diff計算和渲染。
關於React,這篇文章把他的前世今生都說了,寫得很好:通往全棧工程師的捷徑 —— react
React真是無所不在了,React-DOM,React-Canvas,React-Native,看起來前途無量哇!
最後,大家可以關注慢牛股票的公眾號:
發送react,可以擷取demo的apk檔案,安裝體驗。
這個項目的源碼後續會提交到github上,文章寫的一般,見諒!歡迎大家評論留名^_^
關於我的兼職創業曆程
慢牛系列一:如何抓取股票資料
慢系系列二:前端技術選擇
慢牛系列三:React Native實踐