如何使用react native ui组件Android 实现本地组件的安装

如何使用React Native Android 实现本地组件的安装_百度知道react-native —— 在Windows下搭建React Native Android开发环境 - 推酷
react-native —— 在Windows下搭建React Native Android开发环境
在Windows下搭建React Native Android开发环境
前段时间在
收藏了 @天地之灵_邓鋆 分享的《
的抓取内容可以看到一部分,由于一直在休假就没有仔细学习,今天再次回顾我的收藏时却发现链接打不开(其实当时也有发现,只是这么说一下罢了)。于是,你应该知道怎么做的,最好的工具莫过于搜索而不是一味的抱怨说只能在mac上玩。之前因为react native ios肯定是只能在mac上玩,Android就不那么必须了。好了,我来开始搭建一下环境试试。
React Native Android
下载JDK并安装。请注意选择
版本。我在这里直接接受了 @天地之灵_邓鋆 的推荐将JDK的bin目录加入到了系统PATH环境变量。注意:下载链接不能直接使用,需要先接受协议(这里有存入cookies),可以通过
设置环境变量PATH:jdk的位置。例如:(PATH =& D:\Program Files\Java\jdk1.8.0_60\bin)
安装Android SDK
单独安装Android SDK,在墙的环境下,为了速度我选择了使用
设置环境变量ANDROID_HOME:Android SDK Manager的位置 例如:(PATH =& D:\Program Files\Android SDK Tools)设置环境变量PATH:例如:(PATH =& %ANDROID_HOME%\%ANDROID_HOME%\platform-tools)
安装React-native-cli
npm install -g react-native-cli
初始化项目
react-native init reactNative
This will walk you through creating a new React Native project in d:\www\project
\reactNative
events.js:85
// Unhandled 'error' event
Error: spawn npm ENOENT
at exports._errnoException (util.js:746:11)
at Process.ChildProcess._handle.onexit (child_process.js:1053:32)
at child_process.js:1144:20
at process._tickCallback (node.js:355:11)
at Function.Module.runMain (module.js:503:11)
at startup (node.js:129:16)
at node.js:814:3
windows下执行到这里就会报错,原因是npm在windows下的bug(来源于参考资料)。解决办法,直接clone项目主分支master。
git clone /facebook/react-native.git
cd react-native/react-native-cli && npm install -g
接下来就可以初始化项目了
react-native init reactNative
运行packager
这里最新的版本已经修复了 @天地之灵_邓鋆 提到的BUG。
在工程目录下运行
node node_modules/react-native/packager/packager.js
这条命令会看见程序开启了8081端口,并且运行
可以看见项目代码输出。
Run android app
cd reactNative
react-native run-android
如果没有安装安卓模拟器,这里可以直接使用真机安装测试。这个过程很漫长,等等等……
目前Windows下无法自动打开chrome进行调试,所以手动打开chrome,访问如下地址:
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':app'.
& failed to find target with hash string 'android-23' in: D:\Program Files\Andro
id SDK Tools
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
BUILD FAILED
Total time: 10 mins 42.463 secs
Could not install the app on the device, see the error above.
解决办法就是安装Android-23,对于上一篇关于ionic的文是需要Android-22。
Could not find com.android.support:appcompat-v7:版本号.
安装 Android Support Libraries 和 Android Support Repository
build成功,安装上apk后界面红了
选择菜单:Dev settings
选择项:Debug server host for device
设置编译环境PC的IP地址,例如:192.168.25.121
确保手机与编译环境在同一WIFI环境下(IP段相同),packager在运行状态下,重启APP
初始化欢迎界面就出来了,后面继续学习中……
这个hello world过程一波三折,主要归结为以下几点:
墙。我使用的是ss,但是这个过程中还是会有问题,主要是家用环境下。这个关系到npm的使用,这个可以使用淘宝镜像。Android环境搭建,这个我是在Androiddevtools上找的方法,公司环境下轻松安装,家用环境到现在还是没有搞定。
bug。这个过程中本身就有一些问题,关于node版本的问题(手动升级4.1.1),react-native版本的问题(手动clone 0.12-rc)。
如果以上问题解决了,我想这个过程还是很愉快的。只想吐槽一下学习不容易啊。接下来主要的内容就是学习,同时学习ionic与react-native其实就是表层在同时在学习angular与react,至于深层次的我还不懂,暂时也不必细节。学知识,我是先学会用,再学习为什么要这么用,你呢?交流很关键,总结很重要。不是随时都有时间来重新学习,珍惜眼下充裕的时间,学习,学习,学习。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致如何使用React Native Android 实现本地组件的安装_百度知道Android React Native使用原生UI组件
Android React Native 已经将几个常用的原生组件进行了封装,比如 ScrollView 和 TextInput,但是并不是所有系统的原始组件都被封装了,因此有的时候我们不得不自己动手封装一下,从而能够使用那些React Native没有为我们封装的原生组件,比如WebView,官方并没有提供Android端的实现,那么我们现在就动手封装一下WebView。
之前写过一篇文章Android React Native使用原生模块,而使用原生UI组件的方法和使用原生模块的方法十分类似。
首先,我需要继承SimpleViewManager这个泛型类,和原生模块类似,需要重写getName()方法,将UI组件名称暴露给javascript层,接着需要重写createViewInstance方法,在里面返回我们需要使用的原生UI组件的实例,这里就是WebView。然后就是暴露一些必要属性给javascript层,为了简单起见,我们这里只暴露两个属性,一个是url,一个是html,一旦javascript层设置了url,就会加载一个网页,而一旦设置了html,则会去加载这段html,而属性的暴露是使用注解,将注解设置在对应的set方法上,之后再set方法中处理UI的更新,比如一旦设置了url,在setUrl里面就要加载网页。最终我们的ViewManager就是这样子的
public static final String REACT_CLASS = &RCTWebView&;
public String getName() {
return REACT_CLASS;
protected WebView createViewInstance(ThemedReactContext reactContext) {
WebView webView= new WebView(reactContext);
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return webV
@ReactProp(name = &url&)
public void setUrl(WebView view,@Nullable String url) {
Log.e(&TAG&, &setUrl&);
view.loadUrl(url);
@ReactProp(name = &html&)
public void setHtml(WebView view,@Nullable String html) {
Log.e(&TAG&, &setHtml&);
view.loadData(html, &text/ charset=utf-8&, &UTF-8&);
}& data-snippet-id=&ext.329b12fecf9cb& data-snippet-saved=&false& data-csrftoken=&YovcNaBu-lenjyfTe3r17RMPlzP81oURyVgs& data-codota-status=&done&&public class ReactWebViewManager extends SimpleViewManager {
public static final String REACT_CLASS = &RCTWebView&;
public String getName() {
return REACT_CLASS;
protected WebView createViewInstance(ThemedReactContext reactContext) {
WebView webView= new WebView(reactContext);
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return webV
@ReactProp(name = &url&)
public void setUrl(WebView view,@Nullable String url) {
Log.e(&TAG&, &setUrl&);
view.loadUrl(url);
@ReactProp(name = &html&)
public void setHtml(WebView view,@Nullable String html) {
Log.e(&TAG&, &setHtml&);
view.loadData(html, &text/ charset=utf-8&, &UTF-8&);
和原生模块一样,原生UI组件也需要进行注册,实现ReactPackage接口,进行WebView的注册。
createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();;
public List<class& createJSModules() {
return Collections.emptyList();
public List createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList(
new ReactWebViewManager());
& data-snippet-id=&ext.b3c26f8f90dc93c90cac& data-snippet-saved=&false& data-csrftoken=&pAWMZxSf-LITk3G4glq3DgVmMEiqiHgeAN6k& data-codota-status=&done&&public class AppReactPackage implements ReactPackage {
public List createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();;
public List<class& createJSModules() {
return Collections.emptyList();
public List createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList(
new ReactWebViewManager());
</class</class
将这个ReactPackage添加到ReactInstanceManager实例中去
.addPackage(new AppReactPackage())
然后在javascript层新建一个WebView.js文件。输入下面的内容
&#39;use strict&#39;;
var { requireNativeComponent,PropTypes
} = require(&#39;react-native&#39;);
var iface = {
name: &#39;WebView&#39;,
propTypes: {
url: PropTypes.string,
html: PropTypes.string,
module.exports = requireNativeComponent(&#39;RCTWebView&#39;, iface);
可以看到,我们只是在里面指定了属性的类型。
到目前为止,你已经可以使用这个WebView组件了。
var WebView=require(&#39;./WebView&#39;);
render: function() {
这里只是简单加载了一下百度首页,有一点需要特别注意,就是组件的宽度高度一定要设置,否则你会看不到这个组件。最终效果如下。
这还只是最基础的将原始UI组件显示出来,而更为常见的却是事件,比如我们需要在javascript层处理这个WebView的滚动事件,这时候又要怎么做呢。
这时候我们就需要继承WebView,重写对应的事件,然后将事件传递给javascript层了
public class RTCWebView extends WebView{
public RTCWebView(Context context) {
super(context);
public RTCWebView(Context context, AttributeSet attrs) {
super(context, attrs);
public RTCWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
Log.e(&TAG&,&onScrollChanged&);
WritableMap event = Arguments.createMap();
event.putInt(&ScrollX&, l);
event.putInt(&ScrollY&, t);
ReactContext reactContext = (ReactContext)getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
getId(), &topChange&, event);
我们重写了滚动时回调的onScrollChanged方法,构造了一个WritableMap 对象,将ScrollX和ScrollY传入,然后调用reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(getId(), &topChange&, event);将事件发生到javascript层,注意topChange对应着javascript层的onChange方法,这个映射关系在UIManagerModuleConstants类中。
然后我们需要修改ReactWebViewManager 中的createViewInstance方法,在里面返回我们实现的子类,就像这样子
protected WebView createViewInstance(ThemedReactContext reactContext) {
WebView webView= new RTCWebView(reactContext);
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return webV
而javascript层也需要进行一定程度的改造,最终的代码如下
WebView.propTypes = {
url: PropTypes.string,
html: PropTypes.string,
onScrollChange: PropTypes.func,
var RCTWebView = requireNativeComponent(&#39;RCTWebView&#39;, WebView,{
nativeOnly: {onChange: true}
module.exports = WebView& data-snippet-id=&ext.dd3fbda2fc1aea163b84& data-snippet-saved=&false& data-csrftoken=&M7VXVSiz-JsluEvZfqm_oyONV-uHimEkfOvM& data-codota-status=&done&&&#39;use strict&#39;;
var React = require(&#39;react-native&#39;);
requireNativeComponent,
class WebView ponent {
constructor() {
this._onChange = this._onChange.bind(this);
_onChange(event: Event) {
if (!this.props.onScrollChange) {
this.props.onScrollChange({ScrollX:event.nativeEvent.ScrollX,ScrollY:event.nativeEvent.ScrollY});
render() {
WebView.propTypes = {
url: PropTypes.string,
html: PropTypes.string,
onScrollChange: PropTypes.func,
var RCTWebView = requireNativeComponent(&#39;RCTWebView&#39;, WebView,{
nativeOnly: {onChange: true}
module.exports = WebView
不要问我为什么是这样子的,因为官方文档上就是在这么写的,你只需要复制代码,进行修改即可,详见文档Native UI Components
这里需要注意的就是function.bind(this)的语法了,有兴趣的自己去网上搜,这块我也讲不清楚,毕竟没怎么学过javascript和React,怕误人子弟。在onChange函数中,我们进行判断,如果属性onScrollChange没有设置,就直接return,否则就调用设置的onScrollChange属性值(该值是一个函数类型),将Java层传入的两个参数传到该函数中去,{ScrollX:event.nativeEvent.ScrollX,ScrollY:event.nativeEvent.ScrollY}
然后我们来进行调用
var WebView=require(&#39;./WebView&#39;);
render: function() {
onWebViewScroll:function(event){
console.log(event);
这时候等待WebView加载处理,你再上下滑动,就会看到控制台的输出,如下
以上就是使用原生UI组件的全部流程,可以看出React Native官方已经为我们做了很好的封装,我们只需要编写少量的代码,就可以使用原生UI组件了。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'React Native:用JavaScript搭建iOS应用
招聘信息:
本篇文章的作者是 Joyce Echessa,渥合数位服务创办人,毕业于台湾大学,近年来专注于协助客户进行 App 软体以及网站开发。本篇文章中,作者介绍通过 React Native框架构建一个示例应用的开发过程,使得网络技术和移动开发碰撞出绚丽火花。我们已经了解像 Titanium 和 PhoneGap 等框架,它们能让开发者用 Web 技术构建移动应用。这是一个优势,支持开发者使用原先网络和移动开发的相关技术。不仅如此,相同的代码库经过小幅度的修改便能适用多个平台——这就是著名的「一次编写,到处运行」。然而,当涉及到构建应用的性能时,这些框架的缺点显露无遗,尽管它们有一些吸引力,但却一直更适用于构建原生应用。React Native 却与众不同。像 PhoneGap 这样的框架是将网页内容包装成 WebView,导致 UI 元素并没有原生的感觉,而 React Native 则使用原生 iOS 或 Android 组件支持的 JavaScript 组件,所以你构建的应用是完全原生的。Facebook 的汤姆 Occhino 在文章末尾链接视频中说,React Native 并非是「一次编写,到处运行」的框架。正如本教程所介绍,你使用特定平台的组件来构造 UI,所以并不能直接将同样的代码放到 Android 上运行。React Native 是让你学习这套技能,并可以用它在多种平台上搭建应用,Occhino 更进一步阐明,这其实是「一次编写,到处运行」的框架。在本文中,作者将介绍利用 React Native 框架构建一个简单应用的完整开发过程。开始吧!首先,介绍一下在开发机器上安装 React Native 的流程。开始之前,应该提醒大家:你可以从 GitHub 获取框架代码。接着运行其中的示例项目,比如2048(游戏)、Movies (电影浏览器应用)、SampleApp(空白的 React Native 应用)、TicTacToe (游戏)和 UIExplorer(这个应用展现了所有可能用到的 React Native 组件,比如 ListView、TabBar、MapView、Slider 等)。这些应用能帮助你学习使用 React Native 构建 UI 元素,尤其是 UIExplorer 应用程序,它提供了你可能需要用到的每个 UI 元素。但是,有些应用程序还有 Bug,笔者在尝试运行时也出现过几次崩溃。尽管如此,它们仍然非常值得学习,如需详情,你可以了解下相关文档。现在开始安装。React native 利用 Node.js 来搭建 JavaScript 代码。如果你电脑上已经安装过,则可以跳过以下步骤,否则请继续以下步骤。我们选择使用 Homebrew 来安装 Node.js 框架。虽然这不是安装 Node 的唯一方式,但我发现,Homebrew 是非常好用的包管理器。你可以用它很容易地安装最新或特定版本的包、使用不同版本的软件包、选择要使用的版本、更新和卸载包等。想要安装 Homebrew,可以直接去官网,按照网页页面顶部指令即可。由于链接可能会变,这里就不贴出下载链接了。在 Homebrew 安装好后,粘贴以下指令到终端窗口以安装 Node.js。brew&install&node接着安装 watchman。brew&install&watchmanWatchman 是 Facebook 的文件监控器。React Native 用它来检测代码变化,以便重新编译。接着用下列指令安装 React Native CLI 工具。npm&install&-g&react-native-cliNPM 是 Node 的包管理器。你可以将它想象成 Ruby 中的 RubyGems、iOS 的 CocoaPods,以及 Java 中的 Gradle/Maven 等。它能够让你更容易地下载和管理项目所需的任何相关项。在终端窗口,切换到你想要保存项目的文件夹,然后运行以下命令。react-native&init&BookSearch以上是用 CLI 工具来构建一个可以编译和运行的 React Native 项目。当这个过程完成后,你会收到来自终端窗口的消息,在 Xcode 中打开 BookSearch.xcodeproj,并照常运行该应用程序。接下来模拟器将启动你的应用,此外,将再打开一个终端窗口。当一个 React Native 应用启动时,它将从以下网址加载 JavaScript 程序。http://localhost:8081/index.ios.bundle终端窗口打开后,会启动 React Packager,并由服务器处理以上请求。React Packager 负责读取并构建 JSX(之后会介绍)和 JavaScript 代码。运行应用时,你会看到下图的模拟器。如果你要在设备上运行,应该按照以下几个步骤。顺便说一句,你应该注意欢迎界面给出的关键指令:通过编辑创建项目时生成的 index.ios.js 文件,编辑应用的用户界面,如果你修改了 JavaScript 代码,用 Command-R 加载应用程序,看看有什么变化。如果你想要更多选择,使用 Command-Control-Z 打开开发者功能表,它提供启用时重新加载、浏览器调试等选项。当你按照本文操作,模拟器上却突然出现一个红色屏幕时,不妨检查一下模拟器上的错误消息。通过检查可以排查出问题是出自代码还是服务器。作者也曾经遇到几次服务器连接失败的情况,由模拟器反馈的错误消息是「无法连接到服务器」,然而检查终端时得到「进程终止」的错误消息。面对这种情况时,需要关闭终端窗口,停止在 Xcode 上的应用,并重新运行。对于其他错误比如代码中的语法错误、网络请求超时错误(如果你的应用是从网络获取数据),在修正错误后再重新加载应该就可以了。如果在键盘上按下 Command-R 没什么用,那么键盘可能没能连接到模拟器。从模拟器功能表中选择硬件>键盘>连接硬件键盘,便能成功连接。如果你已经完成以上步骤,却仍没有重新加载,那么可能需要重新启动计算机。笔者曾经遇到过一次奇葩经历,项目运行一切正常,但却突然停止工作,重新启动后又恢复正常。现在开始构建我们的应用。打开 index.ios.js 文件。作者推荐使用适用于 Web 开发的 IDE。当然你也可以使用 Xcode,但不久你会发现它并不是很适合。当你需要代码格式化时,它的用处不大,无法自动填充或语法错误高亮。对于适合的 JavaScriptIDE,你可以通读本文后再做决定。我用的是 RubyMine,事实上只要是支持 JavaScript 的任何 IDE 都行,如果你选择一个还能支持 JSX 的那会更好。当打开 index.ios.js 文件时,你会发现这些代码构建的是执行应用时所看到的 UI。&#39;use&strict&#39;;上述代码开启了 Strict Mode,这将为 React Native 中的 JavaScript 代码加入了改良的错误处理能力。var&React&=&require(&#39;react-native&#39;);上述代码载入 react-native 模块,并将其分配给 React 变量。在你可以调用模块的所有功能之前,必须加载外部模块到项目文件。就像在 Swift 和 Objective-C 中导入库。var&{&&
&&AppRegistry,
&&StyleSheet,
}&=&R以上代码被称作解构赋值,能够让你分配多个对象属性到一个单变量。使得这些属性可以在整个文件范围中引用。以上代码是可选的,但如果你省略不要,那么每当你在代码中使用一个组件时,你必须使用其完整名称,例如「React.AppRegistry」、「React.StyleSheet」而不是 「AppRegistry」、「StyleSheet」。var&BookSearch&=&React.createClass({&&
&&render:&function()&{
&&&&return&(
&&&&&&&&&&Welcome&to&React&Native!
&&&&&&&&&&To&get&started,&edit&index.ios.js
&&&&&&&&&&Press&Cmd+R&to&reload,{&#39;\n&#39;}
&&&&&&&&&&Cmd+Control+Z&for&dev&menu
});上面代码创建了只有单一函数 render()的类。无论 render 中定义了什么,都将被输出到屏幕。上述代码使用 JSX(JavaScript 语法扩展)来构建应用的用户界面。如果你之前已经使用 XML(甚至 HTML),那么对 JSX 应该不陌生。它同样需要使用开始、结束标记,在标记中使用属性来设置数值。React Native 不必非得使用 JSX,你可以用普通的 JavaScript,但笔者更推荐 JSX,因为它简化了定义的树结构的过程。如果你需要大量的代码构建 UI,通过庞大的 JSX 树结构使代码可读性更强。var&styles&=&StyleSheet.create({&&
&&container:&{
&&&&flex:&1,
&&&&justifyContent:&&#39;center&#39;,
&&&&alignItems:&&#39;center&#39;,
&&&&backgroundColor:&&#39;#F5FCFF&#39;,
&&welcome:&{
&&&&fontSize:&20,
&&&&textAlign:&&#39;center&#39;,
&&&&margin:&10,
&&instructions:&{
&&&&textAlign:&&#39;center&#39;,
&&&&color:&&#39;#;,
&&&&marginBottom:&5,
});以上代码是应用于视图内容的样式。如果你以前做过网络开发,而且使用过 CSS(层叠样式表),那么这应该很熟悉。React Native 使用 CSS 设定应用的用户界面。再看一眼 JSX 代码,你会发现每个样式都各有用途,例如 style={} styles.container 为容器定义样式,容器是用来容纳其他 UI 组件的外部视图。AppRegistry.registerComponent(&#39;BookSearch&#39;,&()&=>&BookSearch);上行代码定义了应用的入口。也就是 JavaScript 代码开始执行的地方。这是 React Native 用户界面的基础结构。每个定义的视图将会遵循这一基础结构。在本篇文章中,我们将创建一个示例应用,可以浏览书籍,并看到详细信息比如作者、标题、该书简介。你也可以在应用中搜索书名和作者。下图是该应用的成品图,数据用的是 Google 书籍 API。添加标签栏示例应用将有两个项目的标签栏——精选和搜索。我们首先添加该功能。虽然你可以在 index.ios.js 中编写所有代码,但这种做法并不推荐,随着应用代码量的增加,整个框架容易变得混乱不堪。为了更便于管理,我们在不同的文件中创建类。在项目中根目录中创建两个 JavaScript 文件(与 index.ios.js 文件在相同位置)。命名这两个文件为 Search.js 和 Featured.js。打开 Featured.js 并添加以下代码。&#39;use&strict&#39;;&&
var&React&=&require(&#39;react-native&#39;);&&
&&&&StyleSheet,
&&&&Component
var&styles&=&StyleSheet.create({&&
&&&&description:&{
&&&&&&&&fontSize:&20,
&&&&&&&&backgroundColor:&&#39;white&#39;
&&&&container:&{
&&&&&&&&flex:&1,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&alignItems:&&#39;center&#39;
class&Featured&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&Featured&Tab
&&&&&&&&);
module.exports&=&F这段代码你应该非常熟悉,非常类似于我们前面的代码。我们设置 Strict Mode、加载 react-native 模块、创建视图样式并用 render()函数渲染输出到用户界面。代码的最后一行输出精选类,从而使其可用于其他文件。请注意,我们声明类和函数的方式,略微不同于示例 inindex.ios.js 文件。JavaScript 有不同的声明类和函数的方式。随意选择你喜欢的风格。本篇文章接下来,我们将一直沿用上面所使用的样式。在样式表定义中,我们可以看到基本的 CSS 属性。我们为外部视图中的文本和中心内容,设置字体大小和背景颜色。但你可能不熟悉 flex: 1 这行,这是最近才增加到 CSS 规范中的 flexbox。这里的 flex: 1 使得标记为容器的元素只占用的屏幕中的剩余空间,也就是只占用适应其内容的足够空间。之后我们会进一步介绍 Flex。要了解更多关于 Flexbox 样式,你可以参考这个指南。在 Search.js 中添加下面代码。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);
&&&&StyleSheet,
&&&&Component
var&styles&=&StyleSheet.create({&&
&&&&description:&{
&&&&&&&&fontSize:&20,
&&&&&&&&backgroundColor:&&#39;white&#39;
&&&&container:&{
&&&&&&&&flex:&1,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&alignItems:&&#39;center&#39;
class&Search&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&&&Search&Tab
&&&&&&&&);
module.exports&=&S上面的代码与 Featured.js 的代码很像,除了文本控件中的文字。删除 index.ios.js 中的所有内容,将下面的代码粘贴进去。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);&&
var&Featured&=&require(&#39;./Featured&#39;);&&
var&Search&=&require(&#39;./Search&#39;);
&&&&AppRegistry,
&&&&TabBarIOS,
&&&&Component
class&BookSearch&extends&Component&{
&&&&constructor(props)&{
&&&&&&&&super(props);
&&&&&&&&this.state&=&{
&&&&&&&&&&&&selectedTab:&&#39;featured&#39;
&&&&&&&&};
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&this.setState({
&&&&&&&&&&&&&&&&&&&&&&&&&&&&selectedTab:&&#39;featured&#39;
&&&&&&&&&&&&&&&&&&&&&&&&});
&&&&&&&&&&&&&&&&&&&&}}>
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&this.setState({
&&&&&&&&&&&&&&&&&&&&&&&&&&&&selectedTab:&&#39;search&#39;
&&&&&&&&&&&&&&&&&&&&&&&&});
&&&&&&&&&&&&&&&&&&&&}}>
&&&&&&&&);
AppRegistry.registerComponent(&#39;BookSearch&#39;,&()&=>&BookSearch);此时,我们需要之前创建文件中导出的两个模块,并将它们分配给变量。在类中,我们指定一个构造函数,用来设置类的状态。所使用的组件均有状态变量,然后创建一个名为 selectedTab 的属性,并将其值赋给「featured」。我们将利用「featured」来确定选项卡是否有效。最后为 Featured 标签设定默认值。在 render()函数中,使用 TabBarIOS 组件创建一个分页列。别忘了添加你使用的组件到解构赋值中,否则以后调用都需要使用完整名称,比如 React.TabBarIOS。我们创建了两个分页列项目。我们为每一个项目设置选中状态,并定义一个该项目被点击时所调用的函数。以精选标签为例,我们之前定义的 selectedTab 状态为「featured」,那么 selected 设置为 true,否则将被设置为 false。对于搜索标签页也一样,需要检查 selectedTab 是否为「search」。一旦项目的 selected 设置为true,将成为激活状态标签。我们用系统图标表示标签栏项目。需要注意的是,我们使用的自定义组件标签,和其他的组件一样。例如,我们需要相应的模块,并将其分配给一个变量,你可以使用变量来调用模块。结果如同组件类的 render()函数一样,成为文件代码的一部分。提醒一下,作者习惯使用变量名作为各自的类名,但这并不是必须,你可以用你喜欢的名称。当一个标签栏项目点击时,会调用在组件的 onPress 属性中定义的回调函数。函数会为 selectedTab 属性设置数值,这个属性将最终确定哪个是活动标签。调用模拟器,按下 Command-R 重载该应用。正如下图所示。添加导航栏下一步,我们将添加一个导航栏,并将两个文件添加到项目中。这些都将作为相应标签出现在导航堆栈的根视图。分别命名文件为 BookList.js 和 SearchBooks.js。在 BookList.js 添加以下代码。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);
&&&&StyleSheet,
&&&&Component
var&styles&=&StyleSheet.create({
class&BookList&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&);
module.exports&=&BookL在 SearchBooks.js 中添加以下代码。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);
&&&&StyleSheet,
&&&&Component
var&styles&=&StyleSheet.create({
class&SearchBooks&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&);
module.exports&=&SearchB在这两个文件中创建空白视图模块,并导出该模块。按照以下代码修改 Featured.js。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);&&
var&BookList&=&require(&#39;./BookList&#39;);
&&&&StyleSheet,
&&&&NavigatorIOS,
&&&&Component
var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&flex:&1
class&Featured&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&);
module.exports&=&F以上代码使用 NavigatorIOS 组件来构造一个导航控制器。我们将其初始路径设定为 BookList 组件(这意味着 BookList 为其根视图),并设置导航栏上方的标题。 接着用以下代码修改 Search.js。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);&&
var&SearchBooks&=&require(&#39;./SearchBooks&#39;);
&&&&StyleSheet,
&&&&NavigatorIOS,
&&&&Component
var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&flex:&1
class&Search&extends&Component&{&&
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&);
module.exports&=&S正如在 Featured.js 一样,以上代码创建导航控制器,再设置其初始路径,接着为它设置标题。重载应用,你可以看到以下界面。获取并显示数据现在,我们开始将数据添加到视图中。起初,我们用虚构数据构建视图,之后再从 API 获取真实的数据。在 BookList.js 中其他变量声明的文件顶部,添加以下代码。var&FAKE_BOOK_DATA&=&[&&
&&&&{volumeInfo:&{title:&&#39;The&Catcher&in&the&Rye&#39;,&authors:&"J.&D.&Salinger",&
&&&&imageLinks:&{thumbnail:&&#39;/books/content?id=PCDengEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api&#39;}}}
];如下图所示修改解构赋值,以添加更多组件。var&{&&
&&&&Image,
&&&&StyleSheet,
&&&&Component,
&&&}&=&R添加如下样式。var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&flex:&1,
&&&&&&&&flexDirection:&&#39;row&#39;,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&alignItems:&&#39;center&#39;,
&&&&&&&&backgroundColor:&&#39;#F5FCFF&#39;,
&&&&&&&&padding:&10
&&&&thumbnail:&{
&&&&&&&&width:&53,
&&&&&&&&height:&81,
&&&&&&&&marginRight:&10
&&&&rightContainer:&{
&&&&&&&&flex:&1
&&&&title:&{
&&&&&&&&fontSize:&20,
&&&&&&&&marginBottom:&8
&&&&author:&{
&&&&&&&&color:&&#39;#;
});如下图所示,修改 BookList 类。class&BookList&extends&Component&{&&
&&&&render()&{
&&&&var&book&=&FAKE_BOOK_DATA[0];
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.title}
&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.authors}
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&);
}重新加载应用,可以看到下图界面。在上面的代码中,我们创建一个 JSON 对象,非常类似于从 API 调用的对象。我们为一本书的对象创建属性和值。在类文件中,我们使用虚构数据,只为了得到第一个元素,并用它来填充我们的视图。我们使用图像组件来加载图像到视图。需要注意的是,我们在样式表中设定其宽度和高度。如果在样式表中指定图像的尺寸,那么在视图中将看不到图像。我们为容器指定了 flexDirection 为「row」的样式。这样的话,元素的子代也将继承该风格,默认值是水平布局而不是纵向布局。请注意,我们是如何在组件内包装其他组件的。在上面代码中,主容器中有两个子元素——图像和视图。视图也有自己的子类——两个文本组件。先布局图像组件,然后再将视图(rightContainer)水平放置在它旁边。我们为 rightContainer 指定的 flex 风格为1。这使得该视图组件占据剩余空间,而不会遮挡图像组件。如果你想看 flex 样式的效果,可以为 rightContainer 添加以下代码。backgroundColor:&&#39;red&#39;重新加载应用,你会看到空间被 rightContainer 样式组件占满。但它不会遮挡到其他组件。之所以没有延伸到整个屏幕,是因为外容器设定了留白,而图片也设置了右边界。删除 rightContainer 的 flex 设定,再重新加载 App。现在组件只会占据适应其内容的足够空间。如果将 thumbnail 和 rightContainer 的 flex 样式设置为2,它们将会占据同样的宽度,比例为2:2(或者1:1)。你可以将其设置为任何需要的数值,比例会做出相应的改变。你可以尝试不同的比例以得到你想要的结果。让我们回到之前为 rightContainer 添加红色背景的那一步,继续下面的步骤。添加列表视图React Native 有一个 ListView 组件,显示数据的滚动行——也就是 iOS 中的表视图。首先,修改解构语句显示我们添加的更多的组件。var&{&&
&&&&Image,
&&&&StyleSheet,
&&&&Component,
&&&&ListView,
&&&&TouchableHighlight
&&&}&=&R添加以下代码到样式表中。separator:&{&&
&&&&&&&height:&1,
&&&&&&&backgroundColor:&&#39;#dddddd&#39;
&&&}添加以下构造函数到 BookList 类。constructor(props)&{&&
&&&&&&&super(props);
&&&&&&&this.state&=&{
&&&&&&&&&&&dataSource:&new&ListView.DataSource({
&&&&&&&&&&&&&&&rowHasChanged:&(row1,&row2)&=>&row1&!==&row2
&&&&&&&&&&&})
&&&}最后添加以下函数。componentDidMount()&{&&
&&&&var&books&=&FAKE_BOOK_DATA;
&&&&this.setState({
&&&&&&&&dataSource:&this.state.dataSource.cloneWithRows(books)
&&&}在构造函数中,我们创建了一个 ListView.DataSource 对象,并将其分配给 dataSource 属性。DataSource 是一个接口,ListView 用它来确定在更新 UI 过程中哪些行发生了变化。我们提供了一个可以比较两列是否相同的函数,用于确定数据列表是否变化。当组件被加载到 UI 视图时,会调用 componentDidMount()函数。该函数一旦被调用,我们用数据对象中的数据来设置 datasource 属性。你可以使用下面的代码来修改 render()函数。render()&{&&
&&&&return&(
}将下面的函数添加到 BookList 类。renderBook(book)&{&&
&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.title}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.authors}
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&
&&&}以上代码在 render()函数中创建了一个 ListView 组件。这里的 datasource 属性与之前设定的数值一致。然后调用 renderBook()函数显示 ListView 中的各列数据。在 renderBook()函数中,我们使用 TouchableHighlight 组件。这是一个包装组件,能让视图正确响应点击行为。一旦点击,该包装组件的透明度就会降低,可以允许底层颜色透过,使得视图变暗或变色。这样的话,如果你点击一个 ListView 行,你会看到高亮色,就像之前设置的选择表格视图单元格时的响应一样。我们在分离器的底部添加一个样式为 separator 的空视图组件。这样的设定下,视图会出现一个灰色的水平线,便于分割每行项目。重载该应用,你会看到只有一个单元的表格视图。现在将真实数据加载到应用中。从文件中移除 FAKEBOOKDATA 变量,并添加以下代码。这是加载数据的网址。var&REQUEST_URL&=&&#39;/books/v1/volumes?q=subject:fiction&#39;;修改解析声明。var&{&&
&&&&Image,
&&&&StyleSheet,
&&&&Component,
&&&&ListView,
&&&&TouchableHighlight,
&&&&ActivityIndicatorIOS
&&&}&=&R添加以下样式设定。listView:&{&&
&&&&&&&backgroundColor:&&#39;#F5FCFF&#39;
&&&loading:&{
&&&&&&&flex:&1,
&&&&&&&alignItems:&&#39;center&#39;,
&&&&&&&justifyContent:&&#39;center&#39;
&&&}用下面的代码修改构造函数。我们为组件的状态对象添加另一个属性,用来判断视图是否成功加载。constructor(props)&{&&
&&&&&&&super(props);
&&&&&&&this.state&=&{
&&&&&&&&&&&isLoading:&true,
&&&&&&&&&&&dataSource:&new&ListView.DataSource({
&&&&&&&&&&&&&&&rowHasChanged:&(row1,&row2)&=>&row1&!==&row2
&&&&&&&&&&&})
&&&}按下列代码修改 componentDidMount()函数,并添加 fetchData()函数。 fetchData()将调用 Google 图书 API,当它响应操作时,会将获取的数据设置为 DataSource 属性,同时将 isLoading 设置为 true。componentDidMount()&{&&
&&&&&&&this.fetchData();
&&&fetchData()&{
&&&&&&&fetch(REQUEST_URL)
&&&&&&&.then((response)&=>&response.json())
&&&&&&&.then((responseData)&=>&{
&&&&&&&&&&&this.setState({
&&&&&&&&&&&&&&&dataSource:&this.state.dataSource.cloneWithRows(responseData.items),
&&&&&&&&&&&&&&&isLoading:&false
&&&&&&&&&&&});
&&&&&&&.done();
&&&}修改 render()函数并添加 renderLoadingView()。我们添加一个检查 isLoading,如果它的值为 true,就回到由 renderLoadingView()返回的视图。这个视图显示活动指示灯(一个转盘),以及「正在载入书籍...」的字样。当加载完成后,你应该看到表中的图书清单。render()&{&&
&&&&&&&if&(this.state.isLoading)&{
&&&&&&&&&&&return&this.renderLoadingView();
&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&);
renderLoadingView()&{&&
&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&Loading&books...
&&&&&&&&&&&&
}重新加载应用,你会看到类似下图的界面。添加详情视图如果你点击表中的一个单元格,单元格将会突出显示,但不会响应其它操作。我们将添加一个详情视图,以显示选择当前书的详细信息。在项目中新建文件,并命名为 BookDetail.js。将下面的代码贴在该文件中。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);
&&&&StyleSheet,
&&&&Component,
var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&marginTop:&75,
&&&&&&&&alignItems:&&#39;center&#39;
&&&&image:&{
&&&&&&&&width:&107,
&&&&&&&&height:&165,
&&&&&&&&padding:&10
&&&&description:&{
&&&&&&&&padding:&10,
&&&&&&&&fontSize:&15,
&&&&&&&&color:&&#39;#;
class&BookDetail&extends&Component&{&&
&&&&render()&{
&&&&&&&&var&book&=&this.props.
&&&&&&&&var&imageURI&=&(typeof&book.volumeInfo.imageLinks&!==&&#39;undefined&#39;)&?&book.volumeInfo.imageLinks.thumbnail&:&&#39;&#39;;
&&&&&&&&var&description&=&(typeof&book.volumeInfo.description&!==&&#39;undefined&#39;)&?&book.volumeInfo.description&:&&#39;&#39;;
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&{description}
&&&&&&&&&&&&
&&&&&&&&);
module.exports&=&BookD上述代码的大部分内容,我们之前已经讨论过,这里不再赘述。之前没接触过的是 props 属性,其用途是获取数据。通过设置 props 属性,将数据传递到这个类。在代码中,我们先获得数据,随后用数据填充视图。需要注意的是,我们设置了容器的上边界。如果不这样的话,视图将从屏幕的最顶部开始,从而导致某些元素被导航栏遮挡。在 BookList.js 中添加以下代码。var&BookDetail&=&require(&#39;./BookDetail&#39;);修改 BookList 类中 render()函数的 TouchableHighlight。&this.showBookDetail(book)}&&underlayColor=&#39;#dddddd&#39;>上述代码指定了当某列书籍被点击时响应一个回调函数。粘贴下面的函数到该类。这将 BookDetail 视图推送到导航堆栈中,并设置导航栏上的标题可见。然后将该选中行有关的图书对象传递给 BookDetail 类。showBookDetail(book)&{&&
&&&&&&&this.props.navigator.push({
&&&&&&&&&&&title:&book.volumeInfo.title,
&&&&&&&&&&&component:&BookDetail,
&&&&&&&&&&&passProps:&{book}
&&&&&&&});
&&&}重载该 App,你能看到当前选中书籍的详细信息。搜索现在已经完成了精选标签的主从视图,我们将继续完善搜索选项卡,使用户能够利用 API 查询想要的书籍。打开 SearchBooks.js 并按下面的代码修改。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);&&
var&SearchResults&=&require(&#39;./SearchResults&#39;);&&
&&&&StyleSheet,
&&&&Component,
&&&&TextInput,
&&&&TouchableHighlight,
&&&&ActivityIndicatorIOS
var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&marginTop:&65,
&&&&&&&&padding:&10
&&&&searchInput:&{
&&&&&&&&height:&36,
&&&&&&&&marginTop:&10,
&&&&&&&&marginBottom:&10,
&&&&&&&&fontSize:&18,
&&&&&&&&borderWidth:&1,
&&&&&&&&flex:&1,
&&&&&&&&borderRadius:&4,
&&&&&&&&padding:&5
&&&&button:&{
&&&&&&&&height:&36,
&&&&&&&&backgroundColor:&&#39;#f39c12&#39;,
&&&&&&&&borderRadius:&8,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&marginTop:&15
&&&&buttonText:&{
&&&&&&&&fontSize:&18,
&&&&&&&&color:&&#39;white&#39;,
&&&&&&&&alignSelf:&&#39;center&#39;
&&&&instructions:&{
&&&&&&&&fontSize:&18,
&&&&&&&&alignSelf:&&#39;center&#39;,
&&&&&&&&marginBottom:&15
&&&&fieldLabel:&{
&&&&&&&&fontSize:&15,
&&&&&&&&marginTop:&15
&&&&errorMessage:&{
&&&&&&&&fontSize:&15,
&&&&&&&&alignSelf:&&#39;center&#39;,
&&&&&&&&marginTop:&15,
&&&&&&&&color:&&#39;red&#39;
class&SearchBooks&extends&Component&{
&&&&constructor(props)&{
&&&&&&&&super(props);
&&&&&&&&this.state&=&{
&&&&&&&&&&&&bookAuthor:&&#39;&#39;,
&&&&&&&&&&&&bookTitle:&&#39;&#39;,
&&&&&&&&&&&&isLoading:&false,
&&&&&&&&&&&&errorMessage:&&#39;&#39;
&&&&&&&&};
&&&&render()&{
&&&&&&&&var&spinner&=&this.state.isLoading&?
&&&&&&&&&&&&(&&)&:
&&&&&&&&&&&&(&);
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&&&&&Search&by&book&title&and/or&author
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&Book&Title:
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&Author:
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&Search
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&{spinner}
&&&&&&&&&&&&&&&&{this.state.errorMessage}
&&&&&&&&&&&&
&&&&&&&&);
&&&&bookTitleInput(event)&{
&&&&&&&&this.setState({&bookTitle:&event.nativeEvent.text&});
&&&&bookAuthorInput(event)&{
&&&&&&&&this.setState({&bookAuthor:&event.nativeEvent.text&});
&&&&searchBooks()&{
&&&&&&&&this.fetchData();
&&&&fetchData()&{
&&&&&&&&this.setState({&isLoading:&true&});
&&&&&&&&var&baseURL&=&&#39;/books/v1/volumes?q=&#39;;
&&&&&&&&if&(this.state.bookAuthor&!==&&#39;&#39;)&{
&&&&&&&&&&&&baseURL&+=&encodeURIComponent(&#39;inauthor:&#39;&+&this.state.bookAuthor);
&&&&&&&&if&(this.state.bookTitle&!==&&#39;&#39;)&{
&&&&&&&&&&&&baseURL&+=&(this.state.bookAuthor&===&&#39;&#39;)&?&encodeURIComponent(&#39;intitle:&#39;&+&this.state.bookTitle)&:&encodeURIComponent(&#39;+intitle:&#39;&+&this.state.bookTitle);
&&&&&&&&console.log(&#39;URL:&>>>&&#39;&+&baseURL);
&&&&&&&&fetch(baseURL)
&&&&&&&&&&&&.then((response)&=>&response.json())
&&&&&&&&&&&&.then((responseData)&=>&{
&&&&&&&&&&&&&&&&this.setState({&isLoading:&false});
&&&&&&&&&&&&&&&&if&(responseData.items)&{
&&&&&&&&&&&&&&&&&&&&this.props.navigator.push({
&&&&&&&&&&&&&&&&&&&&&&&&title:&&#39;Search&Results&#39;,
&&&&&&&&&&&&&&&&&&&&&&&&component:&SearchResults,
&&&&&&&&&&&&&&&&&&&&&&&&passProps:&{books:&responseData.items}
&&&&&&&&&&&&&&&&&&&&});
&&&&&&&&&&&&&&&&}&else&{
&&&&&&&&&&&&&&&&&&&&this.setState({&errorMessage:&&#39;No&results&found&#39;});
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&})
&&&&&&&&&&&&.catch(error&=>
&&&&&&&&&&&&&&&&this.setState({
&&&&&&&&&&&&&&&&&&&&isLoading:&false,
&&&&&&&&&&&&&&&&&&&&errorMessage:&error
&&&&&&&&&&&&&&&&}))
&&&&&&&&&&&&.done();
module.exports&=&SearchB述代码中,我们在构造函数中设置了一些属性:bookAuthor、bookTitle、isLoading 和 errorMessage。下面简要介绍下如何使用。在 render()方法中,我们需要检查 isLoading 值是否为 true,如果是则建立一个活动指示器,否则则创建一个空视图(后面会用到)。然后,我们创建一个被用来插入查询的搜索表单。TextInput 用于接收输入。当组件的值改变时(例如用户键入一些文本),将会调用 TextInput 组件,同时为组件指定一个回调函数。在调用时,回调函数 bookTitleInput()和 bookAuthorInput()利用用户输入的数据将设置 bookAuthor 和 bookTitles 属性。当用户按下搜索按钮时,searchBooks()被调用。需要注意的是,React Native 没有按钮组件。所以,我们使用 TouchableHighlight 来代替,并用文本包装,使它的样式看起来像一个按钮。当按下搜索按钮时,根据输入的数据构成一个 URL。用户可以通过书名、作者或书名+作者进行搜索。如果结果成功返回,SearchResult 将被推到导航堆栈,否则提示错误消息。我们还将响应数据传递给 SearchResults 类。创建一个文件并命名为 SearchResults.js,将下列代码贴进去。&#39;use&strict&#39;;
var&React&=&require(&#39;react-native&#39;);&&
var&BookDetail&=&require(&#39;./BookDetail&#39;);&&
&&&&StyleSheet,
&&&&Component,
&&&&TouchableHighlight,
&&&&Image,
&&&&ListView
var&styles&=&StyleSheet.create({&&
&&&&container:&{
&&&&&&&&flex:&1,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&alignItems:&&#39;center&#39;
&&&&title:&{
&&&&&&&&fontSize:&20,
&&&&&&&&marginBottom:&8
&&&&author:&{
&&&&&&&&color:&&#39;#;
&&&&separator:&{
&&&&&&&&height:&1,
&&&&&&&&backgroundColor:&&#39;#dddddd&#39;
&&&&listView:&{
&&&&&&&&backgroundColor:&&#39;#F5FCFF&#39;
&&&&cellContainer:&{
&&&&&&&&flex:&1,
&&&&&&&&flexDirection:&&#39;row&#39;,
&&&&&&&&justifyContent:&&#39;center&#39;,
&&&&&&&&alignItems:&&#39;center&#39;,
&&&&&&&&backgroundColor:&&#39;#F5FCFF&#39;,
&&&&&&&&padding:&10
&&&&thumbnail:&{
&&&&&&&&width:&53,
&&&&&&&&height:&81,
&&&&&&&&marginRight:&10
&&&&rightContainer:&{
&&&&&&&&flex:&1
class&SearchResults&extends&Component&{
&&&&constructor(props)&{
&&&&&&&&super(props);
&&&&&&&&var&dataSource&=&new&ListView.DataSource(
&&&&&&&&&&&&{rowHasChanged:&(row1,&row2)&=>&row1&!==&row2});
&&&&&&&&this.state&=&{
&&&&&&&&&&&&dataSource:&dataSource.cloneWithRows(this.props.books)
&&&&&&&&};
&&&&render()&{
&&&&&&&&return&(
&&&&&&&&&&&&
&&&&&&&&);
&&&&renderBook(book)&{
&&&&&&&&var&imageURI&=&(typeof&book.volumeInfo.imageLinks&!==&&#39;undefined&#39;)&?&book.volumeInfo.imageLinks.thumbnail&:&&#39;&#39;;
&&&&&&&&return&(
&&&&&&&&&&&&&this.showBookDetail(book)}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&underlayColor=&#39;#dddddd&#39;>
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.title}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&{book.volumeInfo.authors}
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&);
&&&&showBookDetail(book)&{
&&&&&&&&this.props.navigator.push({
&&&&&&&&&&&&title:&book.volumeInfo.title,
&&&&&&&&&&&&component:&BookDetail,
&&&&&&&&&&&&passProps:&{book}
&&&&&&&&});
module.exports&=&SearchR以上代码之前已经讨论过,也不再赘述。代码中获得数据,并将数据通过 props 属性传递到类,同时创建填充了数据的 ListView。作者注意到,在 API中,当你按作者搜索时,结果不一定是书的数据,而是作者自身的信息。这意味着某些行的 book.volumeInfo.imageLinks.thumbnail 和 book.volumeInfo.description 有未定义的值。所以我们稍作检查,如果没有图像则显示一个空视图。否则,我们的应用将试图加载不存在的图像,这样会容易引发崩溃。我们使用之前用过的 BookDetail 组件,来显示每本书的详细信息。如图所示,打开 BookDetail.js 并修改 render()函数。在用数据填充视图之前,检查传入的数据是否有相关图像和详细信息。如果尝试载入的书籍没有详情或图片,对应的区域将是空白。你可以向用户提示一个错误信息,在此我们省略该步骤。render()&{&&
&&&&var&book&=&this.props.
&&&&var&imageURI&=&(typeof&book.volumeInfo.imageLinks&!==&&#39;undefined&#39;)&?&book.volumeInfo.imageLinks.thumbnail&:&&#39;&#39;;
&&&&var&description&=&(typeof&book.volumeInfo.description&!==&&#39;undefined&#39;)&?&book.volumeInfo.description&:&&#39;&#39;;
&&&&return&(
&&&&&&&&&&&&
&&&&&&&&&&&&{description}
}重载应用,会看到搜索书籍的界面。结束语尽管仍在不断完善,React Native 看起来很有希望成为构建移动应用的另一种选择。它为 Web 开发人员开启了一扇门,让他们能够在移动开发领域一探究竟。同时为移动开发者提供了一种简化开发流程的新方式。随着项目的发展,让我们拭目以待 React Native 和应用开发(iOS和Android ——或者别的平台)将会碰撞出什么样的火花。同时,如果你需要进一步确认网络技术是否能用于实现真正的原生体验,你可以看看这些由 React Native 构建的应用:Facebook Ads Manager(完全由 React Native 构建)以及 Facebook Groups(React Native 和 Objective-C 构建的混合应用)。「学习一次,在任何地方应用」。单这一句足以证明学习 React Native 框架的意义。你可以在这里下载完整示例项目。为了更进一步了解 React Native,你可以参考下列视频和资料。(需翻墙观看视频)(需翻墙观看视频)你可以在这下载,仅供参考。(完结)
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量5807点击量5516点击量4479点击量4081点击量4005点击量3905点击量3802点击量3594点击量3520
&2016 Chukong Technologies,Inc.
京公网安备89

我要回帖

更多关于 react native ui组件 的文章

 

随机推荐