diff --git a/docs/about.md b/docs/about.md
index 34dcc77..449fd16 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -8,7 +8,7 @@ React Native及相关标识版权由©Facebook Inc.所有。本网站并非隶
## 需要帮助? ##
-### 免费QQ群 ###
+### QQ群 ###
“React Native中文网”的维护人员和其他参与者都在
> 1群: 439022088(已满)
@@ -18,14 +18,19 @@ React Native及相关标识版权由©Facebook Inc.所有。本网站并非隶
5群: 138811944(已满)
6群: 446548027(已满)
7群: 115487854(已满)
-8群: 317323710
-
+8群: 317323710(已满)
+9群: 128731649
+
讨论交流。所有群里都会经常发布许多新的教程和资讯。
### 付费技术支持 ###
需要量身订做、随叫随到的完善技术支持?请联络[QQ:402740419](tencent://message/?uin=402740419&Site=react-native.cn&Menu=yes) 或[通过猪八戒平台对我们进行雇佣](http://shop.zbj.com/14338306/)
+### 高级商务合作 ###
+
+如果您想要更深入地定制化服务,比如技术内部培训、项目技术咨询管理、项目解决方案 等,请联系:__王先生 [18513831297](tel:18513831297) [wuxieken@qq.com](mailto:wuxieken@qq.com)__
+
## 捐助
本网站目前流量压力巨大,服务器成本较高。如果您认为本网站对您有所帮助,希望支持本网站的持续发展和维护,可以使用支付宝`转账`到下面地址对我们进行捐助。谢谢!
@@ -87,6 +92,4 @@ React Native中文网是由杭州欧石南网络科技有限公司创办的,
地址:杭州市西湖区古墩路616号同人精华大厦2座1516室
-联系电话:王先生 [18513831297](tel:18513831297)
-
-QQ:[402740419](tencent://message/?uin=402740419&Site=react-native.cn&Menu=yes)
+邮箱:[eliza@hzerica.cn](mailto:eliza@hzerica.cn)
diff --git a/docs/ads/ads.js b/docs/ads/ads.js
index 064cb93..9eaf764 100644
--- a/docs/ads/ads.js
+++ b/docs/ads/ads.js
@@ -1,19 +1,18 @@
export default {
index: {
banner: {
- img: require('./img/122live.jpg'),
- text: '1月22日天地之灵直播MobX案例精讲',
- link: 'http://reactnative.cn/post/3337',
- gainfo: '122live/index'
+ img: require('./img/course01.png'),
+ text: '听晴明老师从头讲React Native',
+ link: '/post/3798',
+ gainfo: 'post3798/index'
}
},
docs: {
banner: {
- img: require('./img/122live.jpg'),
- text: '1月22日天地之灵直播MobX案例精讲',
- link: 'http://reactnative.cn/post/3337',
- gainfo: '122live/docs'
+ img: require('./img/course01.png'),
+ text: '听晴明老师从头讲React Native',
+ link: '/post/3798',
+ gainfo: 'post3798/docs'
}
}
-
-}
\ No newline at end of file
+}
diff --git a/docs/ads/img/classmates.png b/docs/ads/img/classmates.png
new file mode 100644
index 0000000..551903a
Binary files /dev/null and b/docs/ads/img/classmates.png differ
diff --git a/docs/ads/img/course01.png b/docs/ads/img/course01.png
new file mode 100644
index 0000000..c878edb
Binary files /dev/null and b/docs/ads/img/course01.png differ
diff --git a/docs/cases/cases.json b/docs/cases/cases.json
index ffb32fc..ca82dcf 100644
--- a/docs/cases/cases.json
+++ b/docs/cases/cases.json
@@ -1,7 +1,62 @@
[
+ {
+ "name": "京东金融",
+ "desc": "金融生活服务平台",
+ "ios": "https://itunes.apple.com/cn/app/id895682747?mt=8",
+ "android": "https://download.jr.jd.com/downapp/jrapp_jr464.apk",
+ "icon": "http://is5.mzstatic.com/image/thumb/Purple127/v4/5f/bd/de/5fbdde01-36e5-5d52-9b38-e82de0faa8cb/source/175x175bb.jpg"
+ },
+ {
+ "name": "漂漂共享书",
+ "desc": "与朋友同事分享纸质图书",
+ "ios": "https://itunes.apple.com/cn/app/id1201678520?ls=1&mt=8",
+ "android": "http://sj.qq.com/myapp/detail.htm?apkName=com.jubing.piaopiaoshu",
+ "icon": "http://pp.myapp.com/ma_icon/0/icon_52416269_1494393330/96"
+ },
+ {
+ "name": "若爱",
+ "desc": "免费实名制相亲婚恋平台",
+ "ios": "",
+ "android": "http://android.myapp.com/myapp/detail.htm?apkName=com.ruoaiwang",
+ "icon": "http://pp.myapp.com/ma_icon/0/icon_52449613_1521015507/96"
+ },
+ {
+ "name": "立刻说",
+ "desc": "在线英语学习网站",
+ "ios": "https://itunes.apple.com/us/app/立刻说/id1190202556?ls=1&mt=8",
+ "android": "http://android.myapp.com/myapp/detail.htm?apkName=com.lks",
+ "icon": "https://attach.likeshuo.com/content/images/other/logo/logo_app.png"
+ },
+ {
+ "name": "农眼",
+ "desc": "农业大数据平台",
+ "ios": "https://itunes.apple.com/cn/app/nonyang/id1177902411?mt=8",
+ "android": "http://app.airag.cn/app/update/farmer/visionfarmer.apk",
+ "icon": "http://app.airag.cn/app/icon/icon_vision_512.png"
+ },
+ {
+ "name": "一键康",
+ "desc": "您的公立医院体检平台",
+ "ios": "https://itunes.apple.com/cn/app/id1100633202?mt=8",
+ "android": "http://www.touchealth.com.cn/",
+ "icon": "http://ol3l72k79.bkt.clouddn.com/20170512172843_jXH13w_logo512.jpeg"
+ },
+ {
+ "name": "找车场",
+ "desc": "简单方便的帮你找车场",
+ "ios": "https://itunes.apple.com/us/app/id1223491793?l=zh&ls=1&mt=8",
+ "android": "http://a.app.qq.com/o/simple.jsp?pkgname=com.zcc",
+ "icon": "https://images.vmartaw.com/2017/04/07/icon.png"
+ },{
+ "name": "幕布",
+ "desc": "管理你的大脑",
+ "ios": "https://itunes.apple.com/app/id1214302139",
+ "android": "https://mubu.com/app-dl",
+ "icon": "https://img.mubu.com/static/wechat-share-icon.png"
+ },
{
"name": "大浙惠生活",
- "desc": "腾讯大浙网旗下,浙江省本地吃喝玩乐活动、优惠福利信息的推荐平台",
+ "desc": "大浙网优惠福利信息",
"ios": "https://itunes.apple.com/app/apple-store/id1184729110??l=zh&ls=1&mt=8",
"android": "",
"icon": "http://is4.mzstatic.com/image/thumb/Purple122/v4/8f/87/30/8f873055-d51e-ec43-a57c-2057a8cb95a8/source/175x175bb.jpg"
@@ -175,13 +230,6 @@
"android": "",
"icon": "http://img2.yhwj168.com/1024.png"
},
- {
- "name": "16直播",
- "desc": "土豪离不开的直播",
- "ios": "https://itunes.apple.com/us/app/mei-nu-zha-jin-hua-zhi-bo/id1151272467?l=zh&ls=1&mt=8",
- "android": "http://zhushou.360.cn/detail/index/soft_id/3438248?recrefer=SE_D_16%E7%9B%B4%E6%92%AD",
- "icon": "http://p17.qhimg.com/t012e5fe09adb1d0ffa.png"
- },
{
"name": "水稻汽车",
"desc": "平价放心的超级4S店",
@@ -228,7 +276,49 @@
"name": "红包圈",
"desc": "红包交友同城聊天应用",
"ios": "https://itunes.apple.com/cn/app/hong-bao-quan-hong-bao-jiao/id1193509121?mt=8",
- "android": "http://h5.down.bwgame.com.cn/redpackage.apk",
+ "android": "http://h5.down.bwgame.com.cn/redenvelope2017041916.apk",
"icon": "http://ohg9m5uoq.bkt.clouddn.com/1024.png"
- }
+ },
+ {
+ "name": "万颗商城",
+ "desc": "针对农村的电商平台",
+ "ios": "https://itunes.apple.com/cn/app/%E4%B8%87%E9%A2%97%E5%95%86%E5%9F%8E/id1136517970?mt=8",
+ "android": "http://zhushou.360.cn/detail/index/soft_id/3349739?recrefer=SE_D_%E4%B8%87%E9%A2%97%E5%95%86%E5%9F%8E",
+ "icon": "http://is1.mzstatic.com/image/thumb/Purple122/v4/75/db/c9/75dbc963-7696-1583-d2f8-055596654daf/source/175x175bb.jpg"
+ },
+ {
+ "name": "花匠铺",
+ "desc": "家庭园艺种植交流平台",
+ "ios": "https://itunes.apple.com/app/id1219173067",
+ "android": "https://huajiangpu.com/m",
+ "icon": "http://oiifzbqya.bkt.clouddn.com/hjplogo128.png"
+ },
+ {
+ "name": "鲜易商城",
+ "desc": "鲜易商城是国内领先的B2B生鲜电商",
+ "ios": "https://itunes.apple.com/us/app/鲜易商城/id1039746711?l=zh&ls=1&mt=8",
+ "android": "http://a.app.qq.com/o/simple.jsp?pkgname=com.xebest.b2c",
+ "icon": "http://pp.myapp.com/ma_icon/0/icon_12159939_1493113253/96"
+ },
+ {
+ "name": "澳門手遊",
+ "desc": "澳門手遊平台",
+ "ios": "https://www.gaaamee.com/download-app.html",
+ "android": "https://www.gaaamee.com/download-app.html",
+ "icon": "https://www.gaaamee.com/download/images/download/code.png"
+ },
+ {
+ "name": "宾得相机伴侣",
+ "desc": "更好的宾得相机同步助手",
+ "ios": "https://itunes.apple.com/us/app/pentax-photo-sync/id1260957200?l=zh&ls=1&mt=8",
+ "android": "https://play.google.com/apps/publish/?account=7528363839997010893#ManageReleasesPlace:p=com.luckyxmobile.pentaxphotosync",
+ "icon": "https://raw.githubusercontent.com/SleetShang/SomeMaterial/master/PentaxPhotoSync/AppIcon120x120.png"
+ },
+ {
+ "name": "我来贷银行版",
+ "desc": "年轻人的口袋银行",
+ "ios": "https://itunes.apple.com/us/app/id218618489?ls=1&mt=8",
+ "android": "http://web.wolaidai.com/webapp/qxsd/download/download.html?channel=bd_qxsd_share",
+ "icon": "https://web.wolaidai.com/webapp/qxsd/img/login/logo.png"
+ }
]
diff --git a/docs/docs/0.34/permissionsandroid.md b/docs/docs/0.34/permissionsandroid.md
index e2d6386..6970110 100644
--- a/docs/docs/0.34/permissionsandroid.md
+++ b/docs/docs/0.34/permissionsandroid.md
@@ -9,8 +9,8 @@
```js
async function requestCameraPermission() {
try {
- const granted = await AndroidPermissions.requestPermission(
- AndroidPermissions.PERMISSIONS.CAMERA,
+ const granted = await PermissionsAndroid.requestPermission(
+ PermissionsAndroid.PERMISSIONS.CAMERA,
{
'title': '申请摄像头权限',
'message': '一个很牛逼的应用想借用你的摄像头,' +
@@ -53,4 +53,4 @@ async function requestCameraPermission() {
其中rationale参数是可选的,其结构为包含title和message)的对象。此方法会和系统协商,是弹出系统内置的权限申请对话框,还是显示rationale中的信息以向用户进行解释。具体原理请参阅android官方文档
(https://developer.android.com/training/permissions/requesting.html#explain )。
-
\ No newline at end of file
+
diff --git a/docs/docs/0.40/appstate.md b/docs/docs/0.40/appstate.md
index 47034c0..e678151 100644
--- a/docs/docs/0.40/appstate.md
+++ b/docs/docs/0.40/appstate.md
@@ -27,8 +27,11 @@ componentDidMount() {
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
-_handleAppStateChange(currentAppState) {
- this.setState({ currentAppState, });
+_handleAppStateChange = (nextAppState) => {
+ if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
+ console.log('App has come to the foreground!')
+ }
+ this.setState({appState: nextAppState});
}
render() {
return (
diff --git a/docs/docs/0.40/getting-started.md b/docs/docs/0.40/getting-started.md
index 202609b..05237b3 100644
--- a/docs/docs/0.40/getting-started.md
+++ b/docs/docs/0.40/getting-started.md
@@ -89,7 +89,7 @@ sudo chown -R `whoami` /usr/local
brew install node
```
-安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
```
npm config set registry https://registry.npm.taobao.org --global
@@ -104,6 +104,14 @@ npm config set disturl https://npm.taobao.org/dist --global
npm install -g yarn react-native-cli
```
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+
如果你看到`EACCES: permission denied`这样的权限报错,那么请参照上文的homebrew译注,修复`/usr/local`目录的所有权:
```bash
@@ -114,7 +122,7 @@ sudo chown -R `whoami` /usr/local
#### Xcode
-React Native目前需要[Xcode](https://developer.apple.com/xcode/downloads/) 7.0 或更高版本。你可以通过App Store或是到[Apple开发者官网](https://developer.apple.com/xcode/downloads/)上下载。这一步骤会同时安装Xcode IDE和Xcode的命令行工具。
+React Native目前需要[Xcode](https://developer.apple.com/xcode/downloads/) 8.0 或更高版本。你可以通过App Store或是到[Apple开发者官网](https://developer.apple.com/xcode/downloads/)上下载。这一步骤会同时安装Xcode IDE和Xcode的命令行工具。
> 虽然一般来说命令行工具都是默认安装了,但你最好还是启动Xcode,并在`Xcode | Preferences | Locations`菜单中检查一下是否装有某个版本的`Command Line Tools`。Xcode的命令行工具中也包含一些必须的工具,比如`git`等。
@@ -151,13 +159,13 @@ Android Studio包含了运行和测试React Native应用所需的Android SDK和

-- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`。(必须是这个版本)
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.

#### ANDROID_HOME环境变量
-确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。具体的做法是把下面的命令加入到`~/.bash_profile`文件中:(__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这个文件有可能并不存在。请在终端下使用`sudo vi ~/.bash_profile`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。具体的做法是把下面的命令加入到`~/.bash_profile`文件中:(__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这个文件有可能并不存在。请在终端下使用`vi ~/.bash_profile`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
```
# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
@@ -172,7 +180,8 @@ source ~/.bash_profile
可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
-
+
+
### 推荐安装的工具
@@ -203,10 +212,6 @@ brew install flow
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
```
-#### Gradle Daemon
-
-开启[Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)可以极大地提升java代码的增量编译速度。
-
### 其他可选的安装项
#### Git
@@ -234,43 +239,13 @@ brew install git
比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
-1. 下载和安装[Genymotion](https://www.genymotion.com/)(译注:你需要先注册登录,然后才能找到免费下载的链接!另外,genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
3. 创建一个新模拟器并启动。
4. 启动React Native应用后,可以按下⌘+M来打开开发者菜单。
-### 常见问题
-
-#### 安装Android Studio时无法创建虚拟设备
-
-某些版本的Android Studio可能存在一个[已知的bug](https://code.google.com/p/android/issues/detail?id=207563),导致在安装时无法创建虚拟设备。安装过程中可能看到如下报错:
-
-```
-Creating Android virtual device
-Unable to create a virtual device: Unable to create Android virtual device
-```
-
-如果你碰到了这个问题,可以运行`android avd`来手工创建虚拟设备。
-
-
-
-然后在AVD管理器(AVD Manager)窗口中选择新设备并点击`Start...`来启动。
-
-#### Shell命令无响应的异常
-
-如果你碰到了下面这样的异常):
-
-```
-Execution failed for task ':app:installDebug'.
- com.android.builder.testing.api.DeviceException: com.android.ddmlib.ShellCommandUnresponsiveException
-```
-
-试着将`项目目录/android/build.gradle`中的Gradle版本改为1.2.3。
-
-
-
-
-
+
+
## 安装
@@ -324,7 +299,7 @@ sudo ln -s /usr/bin/nodejs /usr/bin/node
choco install nodejs.install
```
-安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
```
npm config set registry https://registry.npm.taobao.org --global
@@ -341,6 +316,12 @@ npm config set disturl https://npm.taobao.org/dist --global
npm install -g yarn react-native-cli
```
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
> 如果你遇到`EACCES: permission denied`权限错误,可以尝试运行下面的命令(限linux系统):
> `sudo npm install -g yarn react-native-cli`.
@@ -412,7 +393,7 @@ Android Studio包含了运行和测试React Native应用所需的Android SDK和
-- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`。(必须是这个版本)
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
@@ -491,25 +472,29 @@ sudo make install
npm install -g flow-bin
```
-
+
+
#### Gradle Daemon
开启[Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)可以极大地提升java代码的增量编译速度。
-
+
+
```
touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties
```
-
+
+
```
(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo org.gradle.daemon=true >> "%USERPROFILE%/.gradle/gradle.properties")
```
-
+
+
#### Android模拟器加速器
@@ -583,7 +568,7 @@ choco install git
比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
-1. 下载和安装[Genymotion](https://www.genymotion.com/)(译注:你需要先注册登录,然后才能找到免费下载的链接!另外,genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
3. 创建一个新模拟器并启动。
4. 启动React Native应用后,可以按下F1来打开开发者菜单。
@@ -593,7 +578,6 @@ choco install git
#### Visual Studio Emulator for Android
[Visual Studio Emulator for Android](https://www.visualstudio.com/zh-cn/features/msft-android-emulator-vs.aspx#中国 (简体中文))是利用了Hyper-V技术进行硬件加速的免费android模拟器。也是Android Studio自带的原装模拟器之外的一个很好的选择。而且你并不需要安装Visual Studio。
-
在用于React Native开发前,需要先在注册表中进行一些修改:
1. 打开运行命令(按下Windows+R键)
@@ -603,7 +587,8 @@ choco install git
5. 名称设为`Path`
6. 双击`Path`,将其值设为你的Android SDK的路径。(例如`C:\Program Files\Android\sdk`)
-
+
+
## 测试安装
@@ -675,11 +660,8 @@ cd AwesomeProject
react-native start
```
-
-
-如果你碰到了`ERROR Watcher took too long to load`的报错,请尝试将[这个文件](https://github.com/facebook/react-native/blob/5fa33f3d07f8595a188f6fe04d6168a6ede1e721/packager/react-packager/src/DependencyResolver/FileWatcher/index.js#L16)中的MAX_WAIT_TIME值改得更大一些 (文件在`node_modules/react-native/`目录下)。
-
-
+
+
### 修改项目
diff --git a/docs/docs/0.40/linking.md b/docs/docs/0.40/linking.md
index f7f08ad..b8b25a4 100644
--- a/docs/docs/0.40/linking.md
+++ b/docs/docs/0.40/linking.md
@@ -28,7 +28,7 @@ componentDidMount() {
对于iOS来说,如果要在App启动后也监听传入的App链接,那么首先需要在项目中链接`RCTLinking`,具体步骤请参考[使用链接库](linking-libraries-ios.html)这篇文档,然后需要在`AppDelegate.m`中增加以下代码:
```objective-c
-#import "RCTLinkingManager.h"
+#import
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
diff --git a/docs/docs/0.40/mapview.md b/docs/docs/0.40/mapview.md
index dedb012..75ad320 100644
--- a/docs/docs/0.40/mapview.md
+++ b/docs/docs/0.40/mapview.md
@@ -46,8 +46,7 @@
ios overlays [{coordinates: [{latitude: number, longitude: number}], lineWidth: number, strokeColor: ColorPropType, fillColor: ColorPropType, id: string}] #
-
<
- /div>
+
onAnnotationPress function #
diff --git a/docs/docs/0.40/native-component-ios.md b/docs/docs/0.40/native-component-ios.md
index c278fa6..828c6e4 100644
--- a/docs/docs/0.40/native-component-ios.md
+++ b/docs/docs/0.40/native-component-ios.md
@@ -18,7 +18,7 @@
// RCTMapManager.m
#import
-#import "RCTViewManager.h"
+#import
@interface RCTMapManager : RCTViewManager
@end
@@ -214,7 +214,7 @@ var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
#import
-#import "RCTComponent.h"
+#import
@interface RCTMap: MKMapView
@@ -239,7 +239,7 @@ var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
#import
#import "RCTMap.h"
-#import "UIView+React.h"
+#import
@interface RCTMapManager()
@end
diff --git a/docs/docs/0.40/navigatorios.md b/docs/docs/0.40/navigatorios.md
index 0a649a2..cc888be 100644
--- a/docs/docs/0.40/navigatorios.md
+++ b/docs/docs/0.40/navigatorios.md
@@ -361,7 +361,9 @@ In the example above the navigation bar color is changed when the new route is p
const React = require('react');
const ReactNative = require('react-native');
const ViewExample = require('./ViewExample');
+
const createExamplePage = require('./createExamplePage');
+const nativeImageSource = require('nativeImageSource');
const {
AlertIOS,
NavigatorIOS,
@@ -372,8 +374,8 @@ const {
View,
} = ReactNative;
-const EmptyPage = React.createClass({
- render: function() {
+class EmptyPage extends React.Component {
+ render() {
return (
@@ -381,11 +383,11 @@ const EmptyPage = React.createClass({
);
- },
-});
+ }
+}
-const NavigatorIOSExamplePage = React.createClass({
- render: function() {
+class NavigatorIOSExamplePage extends React.Component {
+ render() {
var recurseTitle = 'Recurse Navigation';
if (!this.props.depth || this.props.depth === 1) {
recurseTitle += ' - more examples here';
@@ -408,6 +410,13 @@ const NavigatorIOSExamplePage = React.createClass({
component: createExamplePage(null, ViewExample),
});
})}
+ {this._renderRow('Custom title image Example', () => {
+ this.props.navigator.push({
+ title: 'Custom title image Example',
+ titleImage: require('./relay.png'),
+ component: createExamplePage(null, ViewExample),
+ });
+ })}
{this._renderRow('Custom Right Button', () => {
this.props.navigator.push({
title: NavigatorIOSExample.title,
@@ -419,13 +428,52 @@ const NavigatorIOSExamplePage = React.createClass({
}
});
})}
+ {this._renderRow('Custom Right System Button', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ rightButtonSystemIcon: 'bookmarks',
+ onRightButtonPress: () => this.props.navigator.pop(),
+ passProps: {
+ text: 'This page has a right system button in the nav bar',
+ }
+ });
+ })}
{this._renderRow('Custom Left & Right Icons', () => {
this.props.navigator.push({
title: NavigatorIOSExample.title,
component: EmptyPage,
leftButtonTitle: 'Custom Left',
onLeftButtonPress: () => this.props.navigator.pop(),
- rightButtonIcon: require('image!NavBarButtonPlus'),
+ rightButtonIcon: nativeImageSource({
+ ios: 'NavBarButtonPlus',
+ width: 17,
+ height: 17
+ }),
+ onRightButtonPress: () => {
+ AlertIOS.alert(
+ 'Bar Button Action',
+ 'Recognized a tap on the bar button icon',
+ [
+ {
+ text: 'OK',
+ onPress: () => console.log('Tapped OK'),
+ },
+ ]
+ );
+ },
+ passProps: {
+ text: 'This page has an icon for the right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Left & Right System Icons', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ leftButtonSystemIcon: 'cancel',
+ onLeftButtonPress: () => this.props.navigator.pop(),
+ rightButtonSystemIcon: 'search',
onRightButtonPress: () => {
AlertIOS.alert(
'Bar Button Action',
@@ -457,9 +505,9 @@ const NavigatorIOSExamplePage = React.createClass({
);
- },
+ }
- _renderReplace: function() {
+ _renderReplace = () => {
if (!this.props.depth) {
// this is to avoid replacing the top of the stack
return null;
@@ -477,9 +525,9 @@ const NavigatorIOSExamplePage = React.createClass({
}
});
});
- },
+ };
- _renderReplacePrevious: function() {
+ _renderReplacePrevious = () => {
if (!this.props.depth || this.props.depth < 2) {
// this is to avoid replacing the top of the stack
return null;
@@ -494,9 +542,9 @@ const NavigatorIOSExamplePage = React.createClass({
wrapperStyle: styles.customWrapperStyle,
});
});
- },
+ };
- _renderReplacePreviousAndPop: function() {
+ _renderReplacePreviousAndPop = () => {
if (!this.props.depth || this.props.depth < 2) {
// this is to avoid replacing the top of the stack
return null;
@@ -511,9 +559,9 @@ const NavigatorIOSExamplePage = React.createClass({
wrapperStyle: styles.customWrapperStyle,
});
});
- },
+ };
- _renderRow: function(title: string, onPress: Function) {
+ _renderRow = (title: string, onPress: Function) => {
return (
@@ -526,17 +574,15 @@ const NavigatorIOSExamplePage = React.createClass({
);
- },
-});
+ };
+}
-const NavigatorIOSExample = React.createClass({
- statics: {
- title: '',
- description: 'iOS navigation capabilities',
- external: true,
- },
+class NavigatorIOSExample extends React.Component {
+ static title = '';
+ static description = 'iOS navigation capabilities';
+ static external = true;
- render: function() {
+ render() {
const {onExampleExit} = this.props;
return (
);
- },
-});
+ }
+}
const styles = StyleSheet.create({
container: {
diff --git a/docs/docs/0.40/performance.md b/docs/docs/0.40/performance.md
index 061cdc2..cdb88cc 100644
--- a/docs/docs/0.40/performance.md
+++ b/docs/docs/0.40/performance.md
@@ -28,17 +28,20 @@
在运行打好了离线包的应用时,控制台打印语句可能会极大地拖累JavaScript线程。注意有些第三方调试库也可能包含控制台打印语句,比如[redux-logger](https://github.com/evgenyrodionov/redux-logger),所以在发布应用前请务必仔细检查,确保全部移除。
-> 有个[babel插件](https://babeljs.io/docs/plugins/transform-remove-console/)可以帮你移除所有的`console.*`调用。首先需要使用`npm install babel-plugin-transform-remove-console --save`来安装,然后在项目根目录下编辑(或者是新建)一个名为`.babelrc`的文件,在其中加入:
-```json
-{
- "env": {
- "production": {
- "plugins": ["transform-remove-console"]
- }
- }
+> 这里有个小技巧可以在发布时屏蔽掉所有的`console.*`调用。React Native中有一个全局变量`__DEV__`用于指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的console实现。
+
+```js
+if (!__DEV__) {
+ global.console = {
+ info: () => {},
+ log: () => {},
+ warn: () => {},
+ error: () => {},
+ };
}
```
-这样在打包发布时,所有的控制台语句就会被自动移除,而在调试时它们仍然会被正常调用。
+
+这样在打包发布时,所有的控制台语句就会被自动替换为空函数,而在调试时它们仍然会被正常调用。
### 开发模式 (dev=true)
diff --git a/docs/docs/0.40/permissionsandroid.md b/docs/docs/0.40/permissionsandroid.md
index b8d314a..b002c58 100644
--- a/docs/docs/0.40/permissionsandroid.md
+++ b/docs/docs/0.40/permissionsandroid.md
@@ -1,10 +1,6 @@
`PermissionsAndroid`可以访问Android M(也就是6.0)开始提供的权限模型。有一些权限写在`AndroidManifest.xml`就可以在安装时自动获得。但有一些“危险”的权限则需要弹出提示框供用户选择。本API即用于后一种情形。
-<<<<<<< Updated upstream
在低于Android 6.0的设备上,权限只要写在`AndroidManifest.xml`里就会自动获得,此情形下`check`和`request` 方法将始终返回true。
-=======
-在低于Android 6.0的设备上,权限只要写在`AndroidManifest.xml`里就会自动获得,此情形下`checkPermission`和`requestPermission` 方法将始终返回true。
->>>>>>> Stashed changes
如果用户之前拒绝过你的某项权限请求,那么系统会建议你显示一个为什么需要这个权限的“详细解释”(rationale参数)。如果用户之前拒绝过,那么当你再次申请的时候,弹出的就可能不是原先的申请信息,而是`rationale`参数里提供的进一步解释。
@@ -13,11 +9,7 @@
```js
async function requestCameraPermission() {
try {
-<<<<<<< Updated upstream
const granted = await AndroidPermissions.request(
-=======
- const granted = await AndroidPermissions.requestPermission(
->>>>>>> Stashed changes
AndroidPermissions.PERMISSIONS.CAMERA,
{
'title': '申请摄像头权限',
@@ -25,11 +17,7 @@ async function requestCameraPermission() {
'然后你就可以拍出酷炫的皂片啦。'
}
)
-<<<<<<< Updated upstream
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
-=======
- if (granted) {
->>>>>>> Stashed changes
console.log("现在你获得摄像头权限了")
} else {
console.log("用户并不屌你")
@@ -50,41 +38,24 @@ async function requestCameraPermission() {
-<<<<<<< Updated upstream
check(permission)
#
-=======
- checkPermission(permission)
- #
->>>>>>> Stashed changes
返回一个promise,最终值为用户是否授权过的布尔值。
-<<<<<<< Updated upstream
request(permission, rationale?)
#
-=======
- requestPermission(permission, rationale?)
- #
->>>>>>> Stashed changes
-<<<<<<< Updated upstream
requestMultiple(permissions)
#
-
Prompts the user to enable multiple permissions in the same dialog and
-returns an object with the permissions as keys and strings as values
-indicating whether the user allowed or denied the request
+
在一个弹出框中向用户请求多个权限。返回值为一个object,key为各权限名称,对应值为用户授权与否。
-=======
->>>>>>> Stashed changes
\ No newline at end of file
diff --git a/docs/docs/0.40/running-on-device-android.md b/docs/docs/0.40/running-on-device-android.md
index 592ca5e..5bc930b 100644
--- a/docs/docs/0.40/running-on-device-android.md
+++ b/docs/docs/0.40/running-on-device-android.md
@@ -17,6 +17,10 @@ __译注__:如果你连接了多个设备(包含模拟器在内),后续
__译注__:在真机上运行时可能会遇到白屏的情况,请找到并开启`悬浮窗权限`。比如miui系统的设置[在此处](http://jingyan.baidu.com/article/f25ef25466c0fc482d1b824d.html)。
+> 提示
+>
+> 你还可以运行`react-native run-android --variant=release`来安装release版的应用。当然你需要[先配置好签名](signed-apk-android.html),且此时无法再开启开发者菜单。注意在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
## 从设备上访问开发服务器。
在启用开发服务器的情况下,你可以快速的迭代修改应用,然后在设备上查看结果。按照下面描述的任意一种方法来使你的运行在电脑上的开发服务器可以从设备上访问到。
diff --git a/docs/docs/0.40/signed-apk-android.md b/docs/docs/0.40/signed-apk-android.md
index 895f5c8..32e7036 100644
--- a/docs/docs/0.40/signed-apk-android.md
+++ b/docs/docs/0.40/signed-apk-android.md
@@ -77,6 +77,7 @@ Gradle的`assembleRelease`参数会把所有用到的JavaScript代码都打包
生成的APK文件位于`android/app/build/outputs/apk/app-release.apk`,它已经可以用来发布了。
+
### 测试应用的发行版本
在把发行版本提交到Play Store之前,你应该做一次最终测试。输入以下命令可以在设备上安装发行版本:
@@ -88,6 +89,8 @@ $ cd android && ./gradlew installRelease
注意`installRelease`参数只能在你完成了上面的签名配置之后才可以使用。
你现在可以关掉运行中的packager了,因为你所有的代码和框架依赖已经都被打包到apk包中,可以离线运行了。
+> 在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
### 启用Proguard代码混淆来缩小APK文件的大小(可选)
Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少APK的大小。
diff --git a/docs/docs/0.40/text.md b/docs/docs/0.40/text.md
index 7ace7df..d21d1be 100644
--- a/docs/docs/0.40/text.md
+++ b/docs/docs/0.40/text.md
@@ -22,7 +22,7 @@ var styles = StyleSheet.create({
fontSize: 20,
fontWeight: 'bold',
},
-};
+});
```
### 截图
@@ -40,7 +40,7 @@ var styles = StyleSheet.create({
allowFontScaling bool #
-
控制字体是否要根据iOS的“文本大小”辅助选项来进行缩放。
+
控制字体是否要根据系统的“字体大小”辅助选项来进行缩放。
@@ -1076,4 +1076,4 @@ var styles = StyleSheet.create({
});
module.exports = TextExample;
-```
\ No newline at end of file
+```
diff --git a/docs/docs/0.40/upgrading.md b/docs/docs/0.40/upgrading.md
index 5349dea..d21a305 100644
--- a/docs/docs/0.40/upgrading.md
+++ b/docs/docs/0.40/upgrading.md
@@ -1,4 +1,4 @@
-时刻将React Native更新到最新的版本,可以获得更多API、视图、开发者工具以及其他一些好东西(译注:官方开发任务繁重,人手紧缺,几乎不会对旧版本提供维护支持,所以即便更新可能带来一些兼容上的变更,但建议开发者还是尽一切可能第一时间更新)。由于一个完整的React Native项目是由Android项目、iOS项目和JavaScript项目组成的,且都打包在一个npm包中,所以升级可能会有一些麻烦。我们会尽量简化这一流程。以下是目前所需的升级步骤:
+时刻将React Native更新到最新的版本,可以获得更多API、视图、开发者工具以及其他一些好东西(译注:官方开发任务繁重,人手紧缺,几乎不会对旧版本提供维护支持,所以即便更新可能带来一些兼容上的变更,但建议开发者还是尽一切可能第一时间更新)。由于一个完整的React Native项目是由Android项目、iOS项目和JavaScript项目组成的,且都打包在一个npm包中,所以升级可能会有一些麻烦。我们会尽量简化这一流程。你可以在项目目录下使用`react-native -v`命令查看当前的版本。以下是目前所需的升级步骤:
__译注__:[更新日志点这里查看](http://bbs.reactnative.cn/category/1)
@@ -12,10 +12,6 @@ __译注__:[更新日志点这里查看](http://bbs.reactnative.cn/category/1)
### 2. 安装`react-native-git-upgrade`工具模块
-注意:如果你的React Native版本已经大于等于0.40的话,则`不需要安装此模块`。你可以在项目目录下使用`react-native -v`命令查看当前的版本。
-
-如果你的React Native版本低于0.40,则需要全局安装此命令行工具模块:
-
```sh
$ npm install -g react-native-git-upgrade
```
@@ -27,20 +23,6 @@ $ npm install -g react-native-git-upgrade
### 3. 运行更新命令
-如果你的React Native版本已经大于等于0.40的话,则运行:
-
-```sh
-$ react-native upgrade
-# 这样会直接把react native升级到最新版本
-
-# 或者是:
-
-$ react-native upgrade X.Y.Z
-# 这样把react native升级到指定的X.Y.Z版本
-```
-
-如果你的React Native版本低于0.40,则运行:
-
```sh
$ react-native-git-upgrade
# 这样会直接把react native升级到最新版本
diff --git a/docs/docs/0.41/accessibility.md b/docs/docs/0.41/accessibility.md
new file mode 100644
index 0000000..2ed438c
--- /dev/null
+++ b/docs/docs/0.41/accessibility.md
@@ -0,0 +1,161 @@
+## iOS与Android原生App的无障碍功能(accessibility)
+__译注__:accessibility一词常见多种译法:可访问性、无障碍性、辅助功能等等,其中文意思都不太能准确表达其功能的本质——即为残障人士提供便利。本文主要采用“无障碍功能”和“辅助技术/服务”的说法。如果你或你的公司暂时没有资源和精力去服务这些用户,那么你可以跳过本文。但是,`译者个人希望借本文档,呼吁有能力有资源的商业公司/组织/个人,重视残障人士使用智能手机的权利`。
+
+iOS和Android都提供了便于残障人士无障碍使用App的API。此外,两个平台都提供了整套的辅助技术,比如都有针对视力受损人士的读屏软件(iOS的VoiceOver和Android的TalkBack)。同样地,在React Native中我们也封装了对应的API,使开发者能够在App中集成无障碍功能。注意:iOS与Android在具体方法上会有所区别,因此React Native的实现也会因平台而异。
+
+## 使App能够无障碍使用
+
+### 无障碍功能属性
+
+#### accessible (iOS, Android)
+
+设置为`true`时表示当前视图是一个“无障碍元素”(accessibility element)。无障碍元素会将其所有子组件视为一整个可以选中的组件。默认情况下,所有可点击的组件(Touchable系列组件)都是无障碍元素。
+
+在Android上,React Native视图的‘accessible={true}’属性会被转译为原生视图对应的‘focusable={true}’属性。
+
+```javascript
+
+ text one
+ text two
+
+```
+
+在上面这个例子中,当父视图开启无障碍属性后,我们就无法单独选中'text one'和'text two',而只能选中整个父视图。
+
+
+
+#### 无障碍标签accessibilityLabel (iOS, Android)
+
+当一个视图启用无障碍属性后,最好再加上一个accessibilityLabel(无障碍标签),这样可以让使用VoiceOver的人们清楚地知道自己选中了什么。VoiceOver会读出选中元素的无障碍标签。
+
+设定`accessibilityLabel`属性并赋予一个字符串内容即可在视图中启用无障碍标签:
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+在上面这段示例代码中,如果不在TouchableOpacity上设置无障碍标签,那么其默认值就会是"Press me!"(即Text子组件的文本值)。此时无障碍标签是通过自动取所有Text子节点的值,然后用空格连起来生成。
+
+#### 无障碍元素特性accessibilityTraits (iOS)
+
+无障碍元素特性可以使VoiceOver的用户知道自己选中的是什么类型的元素。是文本标签?是按钮?还是头部?`accessibilityTraits`回答了这一问题。
+
+设定`accessibilityTraits`属性并赋予以下一个或多个(以数组的形式)特性字符串即可启用无障碍元素特性:
+
+* **none** 无特性元素。
+* **button** 具有按钮特性。
+* **link** 具有链接特性。
+* **header** 作为内容区域的头部(比如导航栏的标题)。
+* **search** 用作搜索框的文本框。
+* **image** 具有图片特性。可以和按钮或链接等连用。
+* **selected** 元素被选中时使用。比如表格中被选中的一行或是[segmented control](segmentedcontrolios.html)中被选中的一个按钮。
+* **plays** 在元素被点击后播放音效时使用。
+* **key** 元素作为虚拟键盘的一个键使用。
+* **text** 具有不可修改的文本的特性。
+* **summary** 在App冷启动(指完全退出后台后再进入)时提供当前的简要总结信息的元素。比如当天气应用冷启动时,显示当前天气情况的元素就会被标记为**summary**。
+* **disabled** 在元素被禁用,不接受用户输入时使用。
+* **frequentUpdates** 有些元素会频繁更新其标签或值,但我们又不希望太频繁地接受到通知,那么就使用这一特性标记。这一特性标记会使无障碍功能的客户端隔一段时间后再去检查变化(避免频繁打扰用户)。秒表就是个典型的例子。
+* **startsMedia** 在元素启动一个多媒体会话时使用(比如播放电影或是录音),此时不应该被VoiceOver这样的辅助技术打断。
+* **adjustable** 元素具有可调整的特性(比如一个滑块)。
+* **allowsDirectInteraction** 在元素可以接受VoiceOver用户的直接触摸交互时使用(比如展示钢琴键盘的视图)。
+* **pageTurn** 用于通知VoiceOver当前页面已经阅读完毕,可以滚动到下一个页面了。
+
+#### 无障碍元素的点击事件onAccessibilityTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户双击某个已经选中的无障碍元素时调用。
+
+#### MagicTap双指双击事件onMagicTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户执行"magic tap"操作(即使用两个指头来双击)时调用。magic tap的事件处理函数应该做与当前组件相关性最高的操作,比如在电话应用中,magic tap的操作就应该接通电话,或是挂断已经接通的电话。如果当前选中的元素并没有`onMagicTap`函数,则系统会自动遍历视图层,直到找到一个可以响应此操作的。
+
+#### 无障碍组件类型accessibilityComponentType (Android)
+
+在某些情况下,我们也希望告知用户他选中的组件的类型(比如是个按钮)。如果我们使用的是原生按钮,这一行为会自动进行。但既然我们主要是使用javascript,则还需要为Android的TalkBack技术提供更多信息。要实现这一点,就必须为所有UI组件指定`accessibilityComponentType`属性。比如可以指定`button`,`radiobutton_checked`以及`radiobutton_unchecked`等值。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+上面这个例子里,TouchableWithoutFeedback在TalkBack中被声明为一个原生按钮。
+
+#### 无障碍的动态区域accessibilityLiveRegion (Android)
+
+组件发生动态变化时,我们希望TalkBack能够提醒用户。这一行为可以通过设置`accessibilityLiveRegion`属性来实现。具体值可以设置为`none`,`polite`以及`assertive`:
+
+* **none** 辅助服务不应该提醒用户当前视图的变化。
+* **polite** 辅助服务应该提醒用户当前视图的变化。
+* **assertive** 辅助服务应该立即打断当前的语音会话,提醒用户当前视图的变化。
+
+```javascript
+
+
+ Click me
+
+
+
+ Clicked {this.state.count} times
+
+```
+
+上面这个例子中,_addOne方法会改变state.count这个变量。那么只要用户点击了 TouchableWithoutFeedback,TalkBack就会读出Text组件中的值,因为它设置了`accessibilityLiveRegion=”polite”`属性。
+
+#### 无障碍功能优先级importantForAccessibility (Android)
+
+如果有两个UI组件同时层叠覆盖在父视图之上,那么默认的无障碍功能的焦点位置就可能难以预料。`importantForAccessibility`属性解决了这一问题,它可以控制某个视图是否触发无障碍功能事件,以及是否将其报告给辅助服务。具体值可以设置为`auto`,`yes`,`no`和`no-hide-descendants`(最后一个值会强制辅助服务忽略当前组件及其所有子组件)。
+
+```javascript
+
+
+ First layout
+
+
+ Second layout
+
+
+```
+
+上面这个例子里,第二个View的组件对于TalkBack和其他一些辅助服务来说是完全不可见的。这样我们就可以轻易地把两个视图覆盖到同一个父容器上,而不用担心影响TalkBack服务。
+
+
+
+### 发送无障碍功能的相关事件 (Android)
+
+有时候需要在UI组件上主动触发一个无障碍功能的事件(比如当某个自定义的视图出现在屏幕上或是某个自定义的单选框被选中)。为此Native UIManager模块提供了一个`sendAccessibilityEvent`方法。它接受两个参数:view标签和事件类型。
+
+```javascript
+_onPress: function() {
+ this.state.radioButton = this.state.radioButton === “radiobutton_checked” ?
+ “radiobutton_unchecked” : “radiobutton_checked”;
+ if (this.state.radioButton === “radiobutton_checked”) {
+ RCTUIManager.sendAccessibilityEvent(
+ React.findNodeHandle(this),
+ RCTUIManager.AccessibilityEventTypes.typeViewClicked);
+ }
+}
+
+
+```
+
+在上面这个例子里我们创建了一个自定义的单选框(CustomRadioButton),并且使其具有了和原生单选框一样的无障碍功能。具体来说,也就是TalkBack可以正确地通知用户当前选项的变更了。
+
+
+## 测试VoiceOver (iOS)
+
+要开启VoiceOver功能,先打开iOS设备的设置选项。点击“通用”,然后是“辅助选项”,你会看到很多为残障人群使用手机减少障碍的工具,比如更大的字体、更高的对比度以及VoiceOver。
+
+在“视觉”菜单下点击VoiceOver,将开关置为打开状态即可启用。
+
+在辅助选项的最底部,有一个“辅助选项快捷键”,开启之后可以通过点击三次Home按钮来快速关闭或打开VoiceOver工具。
diff --git a/docs/docs/0.41/actionsheetios.md b/docs/docs/0.41/actionsheetios.md
new file mode 100644
index 0000000..a9764ea
--- /dev/null
+++ b/docs/docs/0.41/actionsheetios.md
@@ -0,0 +1,249 @@
+### 截图
+
+
+
+
+### 方法
+
+
+
static showActionSheetWithOptions(options: Object, callback: Function) #
+
+
在iOS设备上显示一个ActionSheet弹出框,其中options参数为一个对象,其属性必须包含以下一项或多项:
+
+ options(字符串数组) - 一组按钮的标题(必选)
+ cancelButtonIndex(整型) - 选项中取消按钮所在的位置(索引)
+ destructiveButtonIndex(整型) - 选项中删除按钮所在的位置(索引)
+ title(字符串) - 弹出框顶部的标题
+ message(字符串) - 弹出框顶部标题下方的信息
+
+
+
+
static showShareActionSheetWithOptions(options: Object, failureCallback: Function, successCallback: Function) #
+
+
+
在iOS设备上显示一个分享弹出框,其中options参数为一个对象,其属性包含以下几项(必须至少有message或url):
+
+ message(字符串) - 要分享的信息
+ url(字符串) - 要分享的URL地址
+ subject(字符串) - 要分享的信息主题
+ excludedActivityTypes(数组) - 指定在actionsheet中不显示的活动
+
+
注:如果url指向本地文件,或者是一个base64编码的url,则会直接读取并分享相应的文件。你可以用这样的方式来分享图片、视频以及PDF文件等。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActionSheetIOS,
+ StyleSheet,
+ Text,
+ UIManager,
+ View,
+} = ReactNative;
+
+var BUTTONS = [
+ 'Option 0',
+ 'Option 1',
+ 'Option 2',
+ 'Delete',
+ 'Cancel',
+];
+var DESTRUCTIVE_INDEX = 3;
+var CANCEL_INDEX = 4;
+
+var ActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ActionSheetTintExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ tintColor: 'green',
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ShareActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: this.props.url,
+ message: 'message to go with the shared url',
+ subject: 'a subject to go in the email heading',
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }
+});
+
+var ShareScreenshotExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ // Take the snapshot (returns a temp file uri)
+ UIManager.takeSnapshot('window').then((uri) => {
+ // Share image data
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: uri,
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }).catch((error) => alert(error));
+ }
+});
+
+var style = StyleSheet.create({
+ button: {
+ marginBottom: 10,
+ fontWeight: '500',
+ }
+});
+
+exports.title = 'ActionSheetIOS';
+exports.description = 'Interface to show iOS\' action sheets';
+exports.examples = [
+ {
+ title: 'Show Action Sheet',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Action Sheet with tinted buttons',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Share Action Sheet',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Local Image',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Screenshot',
+ render(): ReactElement {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.41/activityindicator.md b/docs/docs/0.41/activityindicator.md
new file mode 100644
index 0000000..0092a18
--- /dev/null
+++ b/docs/docs/0.41/activityindicator.md
@@ -0,0 +1,196 @@
+显示一个圆形的loading提示符号。
+
+### 属性
+
+
+
+
+
animating bool #
+
+
是否要显示指示器,默认为true,表示显示。
+
+
+
+
+
ios hidesWhenStopped bool #
+
+
在没有动画的时候,是否要隐藏指示器(默认为true)。
+
+
+
+
size enum('small', 'large') #
+
+
指示器的大小。small的高度为20,large为36。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ ActivityIndicator,
+ StyleSheet,
+ View,
+} = ReactNative;
+const TimerMixin = require('react-timer-mixin');
+
+const ToggleAnimatingActivityIndicator = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState() {
+ return {
+ animating: true,
+ };
+ },
+
+ setToggleTimeout() {
+ this.setTimeout(() => {
+ this.setState({animating: !this.state.animating});
+ this.setToggleTimeout();
+ }, 2000);
+ },
+
+ componentDidMount() {
+ this.setToggleTimeout();
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Animated loading indicators.';
+
+exports.examples = [
+ {
+ title: 'Default (small, white)',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Gray',
+ render() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Large',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Large, custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Start/stop',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom size',
+ render() {
+ return (
+
+ );
+ }
+ },
+];
+
+const styles = StyleSheet.create({
+ centering: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 8,
+ },
+ gray: {
+ backgroundColor: '#cccccc',
+ },
+ horizontal: {
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ padding: 8,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/next/adsupportios.md b/docs/docs/0.41/adsupportios.md
similarity index 100%
rename from docs/docs/next/adsupportios.md
rename to docs/docs/0.41/adsupportios.md
diff --git a/docs/docs/0.41/alert.md b/docs/docs/0.41/alert.md
new file mode 100644
index 0000000..9925778
--- /dev/null
+++ b/docs/docs/0.41/alert.md
@@ -0,0 +1,146 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+本接口可以在iOS和Android上显示一个静态的提示框。如果要在显示提示框的同时接受用户输入一些信息,那你可能需要[`AlertIOS`](alertios.html)。
+
+### iOS
+在iOS上你可以指定任意数量的按钮。每个按钮还都可以指定自己的样式,此外还可以指定提示的类别。参阅[AlertIOS](alertios.html)来了解更多细节。
+
+### Android
+在Android上最多能指定三个按钮,这三个按钮分别具有“中间态”、“消极态”和“积极态”的概念:
+
+如果你只指定一个按钮,则它具有“积极态”的属性(比如“确定”);两个按钮,则分别是“消极态”和“积极态”(比如“取消”和“确定”);三个按钮则意味着“中间态”、“消极态”和“积极态”(比如“稍候再说”,“取消”,“确定”)。
+
+### 方法
+
+
+
static alert(title: string, message?: string, button?: Buttons, type?: AlertType) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Alert,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+
+// corporate ipsum > lorem ipsum
+var alertMessage = 'Credibly reintermediate next-generation potentialities after goal-oriented ' +
+ 'catalysts for change. Dynamically revolutionize.';
+
+/**
+ * Simple alert examples.
+ */
+var SimpleAlertExampleBlock = React.createClass({
+
+ render: function() {
+ return (
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ )}>
+
+ Alert with message and default button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with one button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'Cancel', onPress: () => console.log('Cancel Pressed!')},
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with two buttons
+
+
+ Alert.alert(
+ 'Alert Title',
+ null,
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ {text: 'Baz', onPress: () => console.log('Baz Pressed!')},
+ ]
+ )}>
+
+ Alert with three buttons
+
+
+ Alert.alert(
+ 'Foo Title',
+ alertMessage,
+ '..............'.split('').map((dot, index) => ({
+ text: 'Button ' + index,
+ onPress: () => console.log('Pressed ' + index)
+ }))
+ )}>
+
+ Alert with too many buttons
+
+
+
+ );
+ },
+});
+
+var AlertExample = React.createClass({
+ statics: {
+ title: 'Alert',
+ description: 'Alerts display a concise and informative message ' +
+ 'and prompt the user to make a decision.',
+ },
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+
+module.exports = {
+ AlertExample,
+ SimpleAlertExampleBlock,
+};
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/alertios.md b/docs/docs/0.41/alertios.md
new file mode 100644
index 0000000..a078b66
--- /dev/null
+++ b/docs/docs/0.41/alertios.md
@@ -0,0 +1,204 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+这个API主要用于需要iOS特有功能的场景,比如提示用户输入一些信息等。其他情况下,尤其是仅仅显示一个静态的提示框时,应该使用跨平台的[`Alert`](alert.html)接口。
+
+```javascript
+AlertIOS.alert(
+ 'Foo Title',
+ 'My Alert Msg',
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ ]
+)
+```
+### 截图
+
+
+
+
+### 方法
+
+
+
static alert(title: string, message?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, type?: AlertType) #
+
static prompt(title: string, value?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, callback?: Function) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ AlertIOS,
+} = ReactNative;
+
+var { SimpleAlertExampleBlock } = require('./AlertExample');
+
+exports.framework = 'React';
+exports.title = 'AlertIOS';
+exports.description = 'iOS alerts and action sheets';
+exports.examples = [{
+ title: 'Alerts',
+ render() {
+ return ;
+ }
+},
+{
+ title: 'Prompt Options',
+ render(): ReactElement {
+ return ;
+ }
+},
+{
+ title: 'Prompt Types',
+ render() {
+ return (
+
+ AlertIOS.prompt('Plain Text Entry')}>
+
+
+
+ plain-text
+
+
+
+
+ AlertIOS.prompt('Secure Text', null, null, 'secure-text')}>
+
+
+
+ secure-text
+
+
+
+
+ AlertIOS.prompt('Login & Password', null, null, 'login-password')}>
+
+
+
+ login-password
+
+
+
+
+
+ );
+ }
+}];
+
+class PromptOptions extends React.Component {
+ state: any;
+ customButtons: Array;
+
+ constructor(props) {
+ super(props);
+
+ // $FlowFixMe this seems to be a Flow bug, `saveResponse` is defined below
+ this.saveResponse = this.saveResponse.bind(this);
+
+ this.customButtons = [{
+ text: 'Custom OK',
+ onPress: this.saveResponse
+ }, {
+ text: 'Custom Cancel',
+ style: 'cancel',
+ }];
+
+ this.state = {
+ promptValue: undefined,
+ };
+ }
+
+ render() {
+ return (
+
+
+ Prompt value: {this.state.promptValue}
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse)}>
+
+
+
+ prompt with title & callback
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons)}>
+
+
+
+ prompt with title & custom buttons
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse, undefined, 'Default value')}>
+
+
+
+ prompt with title, callback & default value
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons, 'login-password', 'admin@site.com')}>
+
+
+
+ prompt with title, custom buttons, login/password & default value
+
+
+
+
+ );
+ }
+
+ saveResponse(promptValue) {
+ this.setState({ promptValue: JSON.stringify(promptValue) });
+ }
+}
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/android-building-from-source.md b/docs/docs/0.41/android-building-from-source.md
new file mode 100644
index 0000000..6eefebe
--- /dev/null
+++ b/docs/docs/0.41/android-building-from-source.md
@@ -0,0 +1,117 @@
+如果你想使用新的功能,获得官方的修复补丁,尝试还没发布的最新特性,或者维护你自己的不能合并到核心版本的补丁,你可能需要自己从源代码编译React Native。
+
+# 预备条件
+
+如果你已经安装了安卓SDK,那么运行`android`命令打开安卓SDK管理器。
+
+确保你已经安装了以下模块:
+
+* Android SDK version 23 (编译SDK版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* SDK build tools version 23.0.1(编译工具版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* Android Support Repository >= 17
+* Android NDK(下载及解压指南看[这里](http://developer.android.com/ndk/downloads/index.html))
+
+将Gradle指向你的安卓SDK: 设置`$ANDROID_SDK`和`$ANDORID_NDK`为对应的目录,或者按照以下内容在react-native根目录下创建local.properties文件(注意:windows下需要使用反双斜杠)。
+
+```
+sdk.dir=指向android sdk目录的绝对路径
+ndk.dir=指向android ndk目录的绝对路径
+```
+例如:
+
+```
+sdk.dir=/Users/your_unix_name/android-sdk-macosx
+ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
+```
+# 从下载链接安装Android NDK
+
+1. Mac OS (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip
+2. Linux (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip
+3. Windows (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip
+4. Windows (32-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86.zip
+
+更多参考您可以访问官网NDK界面 [official page](http://developer.android.com/ndk/downloads/index.html).
+
+__译注__:建议安装r10e版本,否则在编译过程可能会出错
+# 编译源代码:
+
+## 1.在你的分支代码中进行安装
+
+首先,在你的分支代码中安装react-native。例如从官方地址安装主干版本:
+
+```
+npm install --save github:facebook/react-native#master
+```
+
+或者,你也可以把仓库克隆到你的`node_modules`目录,然后运行`npm install`进行安装
+
+## 2.添加gradle依赖
+
+在`android/build.gradle`中添加`gradle-download-task`依赖
+
+```
+...
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.1'
+ classpath 'de.undercouch:gradle-download-task:3.1.2'
+
+ // 注意:不要把你的应用的依赖放在这里;
+ // 它们应该放在各自模块的build.gradle文件中
+ }
+...
+```
+
+## 添加`:ReactAndroid `项目
+
+在`android/settings.gradle`中添加`:ReactAndroid`项目
+
+```
+...
+include ':ReactAndroid'
+
+project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
+...
+```
+
+修改你的`android/app/build.gradle`文件,使用`:ReactAndroid`替换预编译库。例如用`compile project(':ReactAndroid'):`替换`compile 'com.facebook.react:react-native:0.16.+'`
+
+```
+...
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.android.support:appcompat-v7:23.0.1'
+
+ compile project(':ReactAndroid')
+
+ ...
+}
+...
+```
+
+## 让第三方模块使用你的分支
+如果你使用第三方的React Native模块,你需要重写它们的依赖以避免它们仍然打包官方的预编译库。否则当你编译时会报错-`Error: more than one library with package name 'com.facebook.react'.`(错误:有几个重名的'com.facebook.react'的包)
+
+修改你的`android/app/build.gradle`文件,添加如下内容:
+
+```
+configurations.all {
+ exclude group: 'com.facebook.react', module: 'react-native'
+}
+```
+
+# 在Android Studio中构建您的项目
+
+在Android Studio欢迎页中选择`Import project`,随后选择您应用所在的文件夹。
+
+您还需要使用_Run_按钮(__译注__:Android Studio中绿色的运行按钮)来在设备上运行您的app,此外Android Studio不会自动开启服务,你还需要通过`npm start`来启动。
+
+# 其他注意事项
+从源码进行编译将会花费很长时间,尤其是第一次编译,需要下载接近200M的文件然后编译原生代码。每次你在自己的仓库更新`react-native`版本时,构建的目录可能会被删除,所有的文件都需要重新下载。为了避免构建目录被删,你需要编辑`~/.gradle/init.gradle`文件来修改构建目录路径。
+
+```
+gradle.projectsLoaded {
+ rootProject.allprojects {
+ buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+ }
+}
+```
diff --git a/docs/docs/0.41/android-setup.md b/docs/docs/0.41/android-setup.md
new file mode 100644
index 0000000..549954c
--- /dev/null
+++ b/docs/docs/0.41/android-setup.md
@@ -0,0 +1,86 @@
+本指南主要介绍在Android模拟器上运行React Native Android应用所必须的准备步骤。
+
+### 安装Git
+
+ - **Mac**上如果你已经安装了[XCode](https://developer.apple.com/xcode/),那么Git也就随之安装了,否则请使用homebrew进行安装:
+
+ brew install git
+
+ - **Linux**上请使用你系统对应的[包管理器](https://git-scm.com/download/linux)来安装Git。
+
+ - **Windows**上请下载并安装[Git for Windows](https://git-for-windows.github.io/)。在安装过程中,请务必记得勾选`Run Git from Windows Command Prompt`,这样会把Git的可执行程序加入到`PATH`环境变量中,这样其他程序才能在命令行中正确调用Git。
+
+
+### 安装Android SDK(已安装的请跳过这一步)
+
+1. [安装最新版的JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+
+2. 安装Android SDK:
+ - **Mac**: `brew install android-sdk`
+ - **Linux或Windows**: [从Android开发者官网下载](https://developer.android.com/sdk/installing/index.html)
+__译注__:国内用户推荐从[AndroidDevTools](http://androiddevtools.cn/)下载。
+
+### 定义ANDROID_HOME环境变量
+
+__重要__: 确保`ANDROID_HOME`环境变量指向你已经安装的Android SDK目录:
+
+ - **Mac**, 往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+ (__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这两个文件有可能还没有被创建。请在终端下使用`sudo vi ~/.bashrc`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+ # 如果你是通过Homebrew安装SDK的,则加入下列路径
+ export ANDROID_HOME=/usr/local/opt/android-sdk
+ # 否则可能是(当然具体视你把SDK放在哪):
+ export ANDROID_HOME=~/Library/Android/sdk
+ - **Linux**,往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+
+ export ANDROID_HOME=<你把Android SDK解压后放置的位置>
+
+ - **Windows**,打开控制面板,选择`系统和安全`->`系统`->`高级系统设置`->`高级`->`环境变量`->`新建`,变量名填写ANDROID_HOME,变量值填写你把Android SDK解压后放置的位置。
+
+__译注__: 如果你在windows下找不到对应的控制面板项,也可以右键点击`我的电脑`,然后在菜单中选择`属性`,然后选择`高级系统设置`->`高级`->`环境变量`->`新建`。__注意__:必须将现有的CMD窗口全部关闭,重新打开后新的环境变量才能生效。
+
+
+### 开启gradle daemon
+
+React Native Android使用的构建系统是[gradle](https://docs.gradle.org)。我们建议你开启gradle daemon功能,它可以带来高达50%的java编译速度提升。点击[这里](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)来了解如何针对你的平台开启这一功能。
+
+
+### 设置SDK
+
+1. 打开Android SDK Manager(**Mac**用户在终端下输入`android`)。
+2. 选中以下项目:
+ * Android SDK Build-tools version 23.0.1(这个必须版本严格匹配23.0.1)
+ * Android 6.0 (API 23)
+ * Local Maven repository for Support Libraries(之前叫做Android Support Repository)
+3. 点击"Install Packages"
+ (__译注__:国内用户推荐使用[腾讯Bugly的镜像](http://android-mirror.bugly.qq.com:8080/include/usage.html)来加速下载)
+ 
+
+### 安装Genymotion
+
+Genymotion是一个第三方模拟器,它比Google官方的模拟器更易设置且性能更好。但是,它只针对个人用户免费。如果你想使用Google模拟器,请往下看。
+
+1. 下载并安装[Genymotion](https://www.genymotion.com/)。
+2. 打开Genymotion。如果你尚未安装VirtualBox,它有可能会提示你安装。
+3. 创建一个模拟器并启动。
+4. 按下`⌘+M`可以打开开发者菜单(在安装并启动了React Native应用之后)。
+
+### 备选方案:使用Google官方模拟器
+
+1. 打开Android SDK Manager(参见"设置SDK"一步)
+2. 选中以下项目:
+ * Intel x86 Atom System Image (for Android 5.1.1 - API 22)
+ * Intel x86 Emulator Accelerator (HAXM installer)
+3. 点击"Install Packages"
+4. [配置硬件加速(HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac),否则模拟器会运行的相当缓慢。
+5. 创建Android虚拟设备(AVD):
+ 1. 运行`android avd`并且点击**Create...**
+ (__译注__:在Windows系统下,android.bat在Android SDK的`tools`文件夹下,请注意设置PATH环境变量以便于使用)
+ 
+ 2. 选中新创建的虚拟设备,并点击`Start...`
+
+__译注__:对于Windows用户而言,Intel x86 Emulator Accelerator和HyperV(系统内置的虚拟机功能)不能同时启用。所以要么选择关闭HyperV(控制面板-程序-启动和关闭Windows功能,取消选择HyperV并点确定),要么选择Genymotion、Bluestacks或Visual Studio Emulator for Android作为模拟器。
+
+### 在Android Studio中编辑Java代码
+
+对于JavaScript代码,你可以使用任何编辑器来编辑。如果你想在Android Studio中编辑原生Java代码的话,请在Android Studio的欢迎屏幕上选择"Import project",然后选择你的项目目录中的`android`文件夹即可。
diff --git a/docs/docs/0.41/android-ui-performance.md b/docs/docs/0.41/android-ui-performance.md
new file mode 100644
index 0000000..842da69
--- /dev/null
+++ b/docs/docs/0.41/android-ui-performance.md
@@ -0,0 +1,147 @@
+我们尽最大的努力来争取使UI组件的性能如丝般顺滑,但有的时候这根本不可能做到。要知道,Android有超过一万种不同型号的手机,而在框架底层进行软件渲染的时候是统一处理的,这意味着你没办法像iOS那样自由。不过有些时候,你还是可以想办法提升应用的性能(有的时候问题根本不是出在原生代码上!)
+
+要想解决应用的性能问题,第一步就是搞明白在每个16毫秒的帧中,时间都去哪儿了。为此,我们会使用一个标准的Android性能分析工具`systrace`,不过在此之前……
+
+> 请先确定JS的开发者模式已经关闭!
+>
+> 你应该在应用的日志里看到`__DEV__ === false, development-level warning are OFF, performance optimizations are ON`等字样(你可以通过adb logcat来查看应用日志)
+
+## 使用Systrace进行性能分析
+
+Systrace是一个标准的基于标记的Android性能分析工具(如果你安装了Android platform-tool包,它也会一同安装)。被调试的代码段在开始和结束处加上标记,在执行的过程中标记会被记录,最后会以图表形式展现统计结果。包括Android SDK自己和React Native框架都已经提供了标准的标记供你查看。
+
+### 收集一次数据
+
+> 注意:
+>
+> Systrace从React Native `v0.15`版本开始支持。你需要在此版本下构建项目才能收集相应的性能数据。
+
+首先,把你想分析的、运行不流畅的设备使用USB线链接到电脑上,然后操作应用来到你想分析的导航/动画之前,接着这样运行systrace:
+
+```
+$ /platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a <你的应用包名>
+```
+
+对于此命令做一个简单的说明:
+
+- `time`参数控制本次数据收集的持续时间,单位是秒。
+- `schd`, `gfx`, 和`view`是我们所关心的Android SDK内置的tag(标记的集合):`schd`提供了你的设备的每个CPU核心正在做什么的信息,`gfx`提供了你的图形相关信息,譬如每帧的时间范围,而`view`提供了一些关于视图布局和渲染相关性能的信息。
+- `-a <你的应用包名>`启用了针对应用的过滤。在这里填写你用React Native创建的应用包名。`你的应用包名`可以在你应用中的`AndroidManifest.xml`里找到,形如`com.example.app`
+
+_译注_:实际上,AndroidManifest.xml里的应用包名会被`app/build.gradle`里的`applicationId`取代。如果二者不一致,应当以`app/build.gradle`里的为准。
+
+一旦systrace开始收集数据,你可以操作应用执行你所关心的动画和操作。在收集结束后,systrace会给你提供一个链接,你可以在浏览器中打开这个链接来查看数据收集的结果。
+
+## 查看性能数据
+
+在浏览器中打开数据页面(建议使用Chrome),你应该能看到类似这样的结果:
+
+
+
+**提示**: 你可以使用WSAD键来滚动和缩放性能数据图表。
+
+### 启用垂直同步高亮
+
+接下来你首先应该启用16毫秒帧区间的高亮。在屏幕顶端点击对应的复选框:
+
+
+
+然后你应该能在屏幕上看到类似上图的斑马状条纹。如果你无法看到这样的条纹,可以尝试换一台设备来进行分析:部分三星手机显示垂直同步高亮存在已知问题,而Nexus系列大部分情况都相当可靠。
+
+### 找到你的进程
+
+滚动图表直到你找到你的应用包名。在上面的例子里,我正在分析`com.facebook.adsmanager`,由于内核的线程名字长度限制,它会显示成`book.adsmanager`。
+
+在左侧,你应该能看到一系列线程对应着右边的时间轴。有3到4个线程是我们必须关注的:UI线程(名字可能是`UI Thread`或者是你的包名), `mqt_js`和`mqt_native_modules`。如果你在Android 5.0以上版本运行,我们还需要关注`Render`(渲染)线程。
+
+### UI 线程
+
+标准的Android布局和绘制都在UI线程里发生。右侧显示的线程名字会是你的包名(在我的例子里是book.adsmanager)或者UI Thread.你在这个线程里看到的事件可能会是一些`Choreographer`, `traversals`或者`DispatchUI`:
+
+
+
+### JS线程
+
+这是用于执行JavaScript代码的线程。根据Android系统版本或者设备的不同,线程名可能是`mqt_js`或者`<...>`。如果看不到对应的名字的话,寻找类似`JSCall`,`Bridge.executeJSCall`这样的事件。
+
+
+
+### 原生模块线程
+
+这里是用于原生模块执行代码(譬如`UIManager`)的线程,线程名可能是`mqt_native_modules`或`<...>`。在后一种情况下,寻找类似`NativeCall`, `CallJavaModuleMethod`, 还有`onBatchComplete`这样的事件名:
+
+
+
+### 额外的:渲染线程
+
+如果你在使用Android L(5.0)或者更高版本,你应该还会在你的应用里看到一个渲染线程。这个线程真正生成OpenGL渲染序列来渲染你的UI。这个线程的名字可能为`RenderThread`或者`<...>`,在后一种情况下,寻找类似`DrawFrame`或`queueBuffer`这样的事件:
+
+
+
+## 寻找导致卡顿的罪魁祸首
+
+一个流畅的动画应该看起来像这样:
+
+
+
+每个背景颜色不同的部分我们称作“一帧”——记住要渲染一个流畅的帧,我们所有的界面工作都需要在16毫秒内完成。注意没有任何一个线程在靠近帧的边界处工作。类似这样的一个应用程序就正在60FPS(帧每秒)的情况下流畅表现。
+
+如果你发现一些起伏的地方,譬如这样:
+
+
+
+注意在上图中JS线程基本上一直在执行,并且超越了帧的边界。这个应用就没法以60FPS渲染了。在这种情况下,**问题出在JS中**。
+
+你还有可能会看到一些类似这样的东西:
+
+
+
+在这种情况下,UI和渲染线程有一些重负荷的工作,以至于超越了帧的边界。这可能是由于我们每帧试图渲染的UI太多了导致的。在这种情况下,**问题出在需要渲染的原生视图上**。
+
+并且,你还应该能看到一些可以指导接下来优化工作的有用的信息。
+
+## JS的问题
+
+如果你发现问题出在JS上,在你正在执行的JS代码中寻找线索。在上面的图中,我们会发现`RCTEventEmitter`每帧被执行了很多次。这是上面的数据统计放大后的内容:
+
+
+
+这看起来不是很正常,为什么事件被调用的如此频繁?它们是不同的事件吗?具体的答案取决于你的产品的代码。在许多情况下,你可能需要看看[shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate)的介绍。
+
+> **TODO**: 我们还在准备更多的JS性能分析的工具,会在将来的版本中加入。
+
+## 原生UI问题
+
+如果你发现问题出在原生UI上,有两种常见的情况:
+
+1. 你每帧在渲染的UI给GPU带来了太重的负载,或者:
+2. 你在动画、交互的过程中不断创建新的UI对象(譬如在scroll的过程中加载新的内容)
+
+### GPU负担过重
+
+在第一种情况下,你应该能看到UI线程的图表类似这样:
+
+
+
+注意`DrawFrame`花费了很多时间,超越了帧的边界。这些时间用来等待GPU获取它的操作缓存。
+
+要缓解这个问题,你应该:
+
+- 检查`renderToHardwareTextureAndroid`的使用,有这个属性的View的子节点正在进行动画或变形会导致性能大幅下降(譬如`Navigator`提供的滑动、淡入淡出动画)。
+- 确保你**没有**使用`needsOffscreenAlphaCompositing`,这个默认是关闭的,因为它在大部分情况下都会带来GPU消耗的大幅提升。
+
+如果这还不能帮你解决问题,你可能需要更深入的探索GPU到底在做什么。参见[Tracer for OpenGL ES](http://developer.android.com/tools/help/gltracer.html)。
+
+### 在UI线程创建大量视图
+
+如果是第二种情况,你可能会看到类似这样的结果:
+
+
+
+注意一开始JS线程工作了很久,然后你看到原生模块线程干了些事情,最后带来了UI线程的巨大开销。
+
+这个问题并没有什么简单直接的优化办法,除非你能把创建UI的步骤推迟到交互结束以后去进行,或者你能直接简化你所要创建的UI。React Native小组正在架构层设法提供一个方案,使得新的UI视图可以在主线程之外去创建和配置,这样就可以使得交互变得更加流畅。
+
+## 还是没搞定?
+
+如果你还是很迷惑或者不知如何进展,你可以在[Stack Overflow的react-native标签下](http://stackoverflow.com/tags/react-native)提交一个问题。如果你在这里得不到响应,或者找到了一个核心组件的问题,你可以[提交一个Github issue](https://github.com/facebook/react-native/issues)给我们。
diff --git a/docs/docs/0.41/animated.md b/docs/docs/0.41/animated.md
new file mode 100644
index 0000000..3fa515c
--- /dev/null
+++ b/docs/docs/0.41/animated.md
@@ -0,0 +1,535 @@
+动画是现代用户体验中非常重要的一个部分,`Animated`库就是用来创造流畅、强大、并且易于构建和维护的动画。
+
+最简单的工作流程就是创建一个`Animated.Value`,把它绑定到组件的一个或多个样式属性上。然后可以通过动画驱动它,譬如`Animated.timing`,或者通过`Animated.event`把它关联到一个手势上,譬如拖动或者滑动操作。除了样式,`Animated.value`还可以绑定到props上,并且一样可以被插值。这里有一个简单的例子,一个容器视图会在加载的时候淡入显示:
+
+```javascript
+class FadeInView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // init opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {toValue: 1}, // Configuration
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+ // Binds
+ {this.props.children}
+
+ );
+ }
+ }
+ ```
+
+
+ 注意只有声明为可动画化的组件才能被关联动画。`View`、`Text`,还有`Image`都是可动画化的。如果你想让自定义组件可动画化,可以用`createAnimatedComponent`。这些特殊的组件里面用了一些黑魔法,来把动画数值绑定到属性上,然后在每帧去执行原生更新,来避免每次render和同步过程的开销。他们还处理了在节点卸载时的清理工作以确保使用安全。
+
+ 动画具备很强的可配置性。自定义或者预定义的过渡函数、延迟、时间、衰减比例、刚度等等。取决于动画类型的不同,你还可以配置更多的参数。
+
+ 一个`Animated.Value`可以驱动任意数量的属性,并且每个属性可以配置一个不同的插值函数。插值函数把一个输入的范围映射到输出的范围,通常我们用线性插值,不过你也可以使用其他的过渡函数。默认情况下,当输入超出范围时,它也会对应的进行转换,不过你也可以把输出约束到范围之内。
+
+ 举个例子,你可能希望你的`Animated.Value`从0变化到1时,把组件的位置从150px移动到0px,不透明度从0到1。可以通过以下的方法修改`style`属性来实现:
+
+ ```javascript
+ style={{
+ opacity: this.state.fadeAnim, // Binds directly
+ transform: [{
+ translateY: this.state.fadeAnim.interpolate({
+ inputRange: [0, 1],
+ outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
+ }),
+ }],
+ }}>
+ ```
+
+ 动画还可以被更复杂地组合,通过一些辅助函数例如`sequence`或者`parallel`(它们分别用于先后执行多个动画和同时执行多个动画),而且还可以通过把toValue设置为另一个Animated.Value来产生一个动画序列。
+
+ `Animated.ValueXY`则用来处理一些2D动画,譬如滑动。并且还有一些辅助功能譬如`setOffset`和`getLayout`来帮助实现一些常见的交互效果,譬如拖放操作(Drag and drop)。
+
+ 你可以在`AnimationExample.js`中找到一些更复杂的例子。你还可以看看Gratuitous Animation App,以及[动画指南文档](animations.html)。
+
+注意`Animated`模块被设计为可完全序列化的,这样动画可以脱离JavaScript事件循环,以一种高性能的方式运行。这可能会导致API看起来比较难懂,与一个完全同步的动画系统相比稍微有一些奇怪。`Animated.Value.addListener`可以帮助你解决一些相关限制,不过使用它的时候需要小心,因为将来的版本中它可能会牵扯到性能问题。
+
+### 方法
+
+
+
+
static decay(value: AnimatedValue | AnimatedValueXY, config: DecayAnimationConfig) #
+
+
推动一个值以一个初始的速度和一个衰减系数逐渐变为0。
+
+
+
+
static timing(value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig) #
+
+
推动一个值按照一个过渡曲线而随时间变化。Easing模块定义了一大堆曲线,你也可以使用你自己的函数。
+
+
+
+
static spring(value: AnimatedValue | AnimatedValueXY, config: SpringAnimationConfig) #
+
+
产生一个基于Rebound和Origami实现的Spring动画。它会在toValue值更新的同时跟踪当前的速度状态,以确保动画连贯。可以链式调用。
+
+
+
static add(a: Animated, b: Animated) #
+
static multiply(a: Animated, b: Animated) #
+
+
static delay(time: number) #
+
+
+
+
static sequence(animations: Array<CompositeAnimation>) #
+
+
按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行。
+
+
+
+
static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig) #
+
+
同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。你可以通过stopTogether选项来改变这个效果。
+
+
+
+
static stagger(time: number, animations: Array<CompositeAnimation>) #
+
+
一个动画数组,里面的动画有可能会同时执行(重叠),不过会以指定的延迟来开始。用来制作拖尾效果非常合适。
+
+
+
+
static event(argMapping: Array<Mapping>, config?: EventConfig) #
+
+
接受一个映射的数组,对应的解开每个值,然后调用所有对应的输出的setValue方法。例如:
+
onScroll={this .AnimatedEvent(
+ [{nativeEvent: {contentOffset: {x: this ._scrollX}}}]
+ {listener},
+ )
+ ...
+ onPanResponderMove: this .AnimatedEvent([
+ null ,
+ {dx: this ._panX},
+ ]),
+
+
+
+
+
static createAnimatedComponent(Component: any) #
+
+
使得任何一个React组件支持动画。用它来创建Animated.View等等。
+
+
+
+
+### 属性
+
+
+
+
Value: AnimatedValue #
+
+
表示一个数值的类,用于驱动动画。通常用new Animated.Value(0);来初始化。
+
+
+
+
ValueXY: AnimatedValueXY #
+
+
表示一个2D值的类,用来驱动2D动画,例如拖动操作等。
+
+
+
+
+## class AnimatedValue
+
+用于驱动动画的标准值。一个`Animated.Value`可以用一种同步的方式驱动多个属性,但同时只能被一个行为所驱动。启用一个新的行为(譬如开始一个新的动画,或者运行`setValue`)会停止任何之前的动作。
+
+### 方法
+
+
+
+
constructor(value: number) #
+
+
+
setValue(value: number) #
+
+
直接设置它的值。这个会停止任何正在进行的动画,然后更新所有绑定的属性。
+
+
+
+
setOffset(offset: number) #
+
+
设置一个相对值,不论接下来的值是由setValue、一个动画,还是Animated.event产生的,都会加上这个值。常用来在拖动操作一开始的时候用来记录一个修正值(譬如当前手指位置和View位置)。
+
+
+
+
flattenOffset() #
+
+
把当前的相对值合并到值里,并且将相对值设为0。最终输出的值不会变化。常在拖动操作结束后调用。
+
+
+
+
addListener(callback: ValueListenerCallback) #
+
+
添加一个异步监听函数,这样你就可以监听动画值的变更。这有时候很有用,因为你没办法同步的读取动画的当前值,因为有时候动画会在原生层次运行。
+
+
+
+
removeListener(id: string) #
+
+
+
removeAllListeners() #
+
+
+
stopAnimation(callback?: ?(value: number) => void) #
+
+
停止任何正在运行的动画或跟踪值。callback会被调用,参数是动画结束后的最终值,这个值可能会用于同步更新状态与动画位置。
+
+
+
+
interpolate(config: InterpolationConfigType) #
+
+
在更新属性之前对值进行插值。譬如:把0-1映射到0-10。
+
+
+
+
animate(animation: Animation, callback: EndCallback) #
+
+
一般仅供内部使用。不过有可能一个自定义的动画类会用到此方法。
+
+
+
+
+
track(tracking: Animated) #
+
+
+
+
+## class AnimatedValueXY
+
+用来驱动2D动画的2D值,譬如滑动操作等。API和普通的`Animated.Value`几乎一样,只不过是个复合结构。它实际上包含两个普通的`Animated.Value`。
+
+例子:
+
+```javascript
+class DraggableView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ pan: new Animated.ValueXY(), // inits to zero
+ };
+ this.state.panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: () => true,
+ onPanResponderMove: Animated.event([null, {
+ dx: this.state.pan.x, // x,y are Animated.Value
+ dy: this.state.pan.y,
+ }]),
+ onPanResponderRelease: () => {
+ Animated.spring(
+ this.state.pan, // Auto-multiplexed
+ {toValue: {x: 0, y: 0}} // Back to zero
+ ).start();
+ },
+ });
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+```
+
+### 方法
+
+
+
+
constructor(valueIn?: ?{x: number | AnimatedValue; y: number | AnimatedValue}) #
+
+
+
+
setValue(value: {x: number; y: number}) #
+
+
+
+
setOffset(offset: {x: number; y: number}) #
+
+
+
+
+
stopAnimation(callback?: ?() => number) #
+
+
+
+
addListener(callback: ValueXYListenerCallback) #
+
+
+
+
removeListener(id: string) #
+
+
+
+
getLayout() #
+
+
将一个{x, y}组合转换为{left, top}以用于样式。例如:
+
style={this .state.anim.getLayout()}
+
+
+
+
+
getTranslateTransform() #
+
+
将一个{x, y} 组合转换为一个可用的位移变换(translation transform),例如:
+
style={{
+ transform: this .state.anim.getTranslateTransform()
+ }}
+
+
+
+
+
+ ### 例子
+
+ ```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Animated,
+ Easing,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerButton = require('./UIExplorerButton');
+
+exports.framework = 'React';
+exports.title = 'Animated - Examples';
+exports.description = 'Animated provides a powerful ' +
+ 'and easy-to-use API for building modern, ' +
+ 'interactive user experiences.';
+
+exports.examples = [
+ {
+ title: 'FadeInView',
+ description: 'Uses a simple timing animation to ' +
+ 'bring opacity from 0 to 1 when the component ' +
+ 'mounts.',
+ render: function() {
+ class FadeInView extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {
+ toValue: 1, // Target
+ duration: 2000, // Configuration
+ },
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+ class FadeInExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ show: true,
+ };
+ }
+ render() {
+ return (
+
+ {
+ this.setState((state) => (
+ {show: !state.show}
+ ));
+ }}>
+ Press to {this.state.show ?
+ 'Hide' : 'Show'}
+
+ {this.state.show &&
+
+ FadeInView
+
+ }
+
+ );
+ }
+ }
+ return ;
+ },
+ },
+ {
+ title: 'Transform Bounce',
+ description: 'One `Animated.Value` is driven by a ' +
+ 'spring with custom constants and mapped to an ' +
+ 'ordered set of transforms. Each transform has ' +
+ 'an interpolation to convert the value into the ' +
+ 'right range and units.',
+ render: function() {
+ this.anim = this.anim || new Animated.Value(0);
+ return (
+
+ {
+ Animated.spring(this.anim, {
+ toValue: 0, // Returns to the start
+ velocity: 3, // Velocity makes it move
+ tension: -10, // Slow
+ friction: 1, // Oscillate a lot
+ }).start(); }}>
+ Press to Fling it!
+
+
+ Transforms!
+
+
+ );
+ },
+ },
+ {
+ title: 'Composite Animations with Easing',
+ description: 'Sequence, parallel, delay, and ' +
+ 'stagger with different easing functions.',
+ render: function() {
+ this.anims = this.anims || [1,2,3].map(
+ () => new Animated.Value(0)
+ );
+ return (
+
+ {
+ var timing = Animated.timing;
+ Animated.sequence([ // One after the other
+ timing(this.anims[0], {
+ toValue: 200,
+ easing: Easing.linear,
+ }),
+ Animated.delay(400), // Use with sequence
+ timing(this.anims[0], {
+ toValue: 0,
+ easing: Easing.elastic(2), // Springy
+ }),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(
+ anim, {toValue: 200}
+ )).concat(
+ this.anims.map((anim) => timing(
+ anim, {toValue: 0}
+ ))),
+ ),
+ Animated.delay(400),
+ Animated.parallel([
+ Easing.inOut(Easing.quad), // Symmetric
+ Easing.back(1.5), // Goes backwards first
+ Easing.ease // Default bezier
+ ].map((easing, ii) => (
+ timing(this.anims[ii], {
+ toValue: 320, easing, duration: 3000,
+ })
+ ))),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(anim, {
+ toValue: 0,
+ easing: Easing.bounce, // Like a ball
+ duration: 2000,
+ })),
+ ),
+ ]).start(); }}>
+ Press to Animate
+
+ {['Composite', 'Easing', 'Animations!'].map(
+ (text, ii) => (
+
+ {text}
+
+ )
+ )}
+
+ );
+ },
+ },
+ {
+ title: 'Continuous Interactions',
+ description: 'Gesture events, chaining, 2D ' +
+ 'values, interrupting and transitioning ' +
+ 'animations, etc.',
+ render: () => (
+ Checkout the Gratuitous Animation App!
+ ),
+ }
+];
+
+var styles = StyleSheet.create({
+ content: {
+ backgroundColor: 'deepskyblue',
+ borderWidth: 1,
+ borderColor: 'dodgerblue',
+ padding: 20,
+ margin: 20,
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+});
+ ```
\ No newline at end of file
diff --git a/docs/docs/0.41/animations.md b/docs/docs/0.41/animations.md
new file mode 100644
index 0000000..75cd3c4
--- /dev/null
+++ b/docs/docs/0.41/animations.md
@@ -0,0 +1,414 @@
+流畅、有意义的动画对于移动应用用户体验来说是非常必要的。和React Native的其他部分一样,动画API也还在积极开发中,不过我们已经可以联合使用两个互补的系统:用于全局的布局动画`LayoutAnimation`,和用于创建更精细的交互控制的动画`Animated`。
+
+### Animated
+
+`Animated`库使得开发者可以非常容易地实现各种各样的动画和交互方式,并且具备极高的性能。`Animated`仅关注动画的输入与输出声明,在其中建立一个可配置的变化函数,然后使用简单的`start/stop`方法来控制动画按顺序执行。下面是一个在加载时带有简单的弹跳动画的组件示例:
+
+```javascript
+class Playground extends React.Component {
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ bounceValue: new Animated.Value(0),
+ };
+ }
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ componentDidMount() {
+ this.state.bounceValue.setValue(1.5); // 设置一个较大的初始值
+ Animated.spring( // 可选的基本动画类型: spring, decay, timing
+ this.state.bounceValue, // 将`bounceValue`值动画化
+ {
+ toValue: 0.8, // 将其值以动画的形式改到一个较小值
+ friction: 1, // Bouncier spring
+ }
+ ).start(); // 开始执行动画
+ }
+}
+```
+
+`bounceValue`在构造函数中初始化为`state`的一部分,然后和图片的缩放比例进行绑定。在动画执行的背后,其数值会被不断的计算并用于设置缩放比例。当组件刚刚挂载的时候,缩放比例被设置到1.5。然后紧跟着在`bounceValue`上执行了一个弹跳动画(spring),会逐帧刷新数值,并同步更新所有依赖本数值的绑定(在这个例子里,就是图片的缩放比例)。比起调用`setState`然后重新渲染,这一运行过程要快得多。因为整个配置都是声明式的,我们可以实现更进一步的优化,只要序列化好配置,然后我们可以在一个高优先级的线程执行动画。
+
+#### 核心API
+
+大部分你需要的东西都来自`Animated`模块。它包括两个值类型,`Value`用于单个的值,而`ValueXY`用于向量值;还包括三种动画类型,`spring`,`decay`,还有`timing`,以及三种组件类型,`View`,`Text`和`Image`。你可以使用`Animated.createAnimatedComponent`方法来对其它类型的组件创建动画。
+
+这三种动画类型可以用来创建几乎任何你需要的动画曲线,因为它们每一个都可以被自定义:
+
+* `spring`: 基础的单次弹跳物理模型,符合[Origami设计标准](https://facebook.github.io/origami/)
+ * `friction`: 摩擦力,默认为7.
+ * `tension`: 张力,默认40。
+* `decay`: 以一个初始速度开始并且逐渐减慢停止。
+ * `velocity`: 起始速度,必填参数。
+ * `deceleration`: 速度衰减比例,默认为0.997。
+* `timing`: 从时间范围映射到渐变的值。
+ * `duration`: 动画持续的时间(单位是毫秒),默认为500。
+ * `easing`:一个用于定义曲线的渐变函数。阅读`Easing`模块可以找到许多预定义的函数。iOS默认为`Easing.inOut(Easing.ease)`。
+ * `delay`: 在一段时间之后开始动画(单位是毫秒),默认为0。
+
+动画可以通过调用`start`方法来开始。`start`接受一个回调函数,当动画结束的时候会调用此回调函数。如果动画是因为正常播放完成而结束的,回调函数被调用时的参数为`{finished: true}`,但若动画是在结束之前被调用了`stop`而结束(可能是被一个手势或者其它的动画打断),它会收到参数`{finished: false}`。
+
+#### 组合动画
+
+多个动画可以通过`parallel`(同时执行)、`sequence`(顺序执行)、`stagger`和`delay`来组合使用。它们中的每一个都接受一个要执行的动画数组,并且自动在适当的时候调用start/stop。举个例子:
+
+```javascript
+Animated.sequence([ // 首先执行decay动画,结束后同时执行spring和twirl动画
+ Animated.decay(position, { // 滑行一段距离后停止
+ velocity: {x: gestureState.vx, y: gestureState.vy}, // 根据用户的手势设置速度
+ deceleration: 0.997,
+ }),
+ Animated.parallel([ // 在decay之后并行执行:
+ Animated.spring(position, {
+ toValue: {x: 0, y: 0} // 返回到起始点开始
+ }),
+ Animated.timing(twirl, { // 同时开始旋转
+ toValue: 360,
+ }),
+ ]),
+]).start(); // 执行这一整套动画序列
+```
+
+默认情况下,如果任何一个动画被停止或中断了,组内所有其它的动画也会被停止。Parallel有一个`stopTogether`属性,如果设置为`false`,可以禁用自动停止。
+
+#### 插值(interpolate)
+
+`Animated` API还有一个很强大的部分就是`interpolate`插值函数。它可以接受一个输入区间,然后将其映射到另一个的输出区间。下面是一个一个简单的从0-1区间到0-100区间的映射示例:
+
+```javascript
+value.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 100],
+});
+```
+
+`interpolate`还支持定义多个区间段落,常用来定义静止区间等。举个例子,要让输入在接近-300时取相反值,然后在输入接近-100时到达0,然后在输入接近0时又回到1,接着一直到输入到100的过程中逐步回到0,最后形成一个始终为0的静止区间,对于任何大于100的输入都返回0。具体写法如下:
+
+```javascript
+value.interpolate({
+ inputRange: [-300, -100, 0, 100, 101],
+ outputRange: [300, 0, 1, 0, 0],
+});
+```
+
+它的最终映射结果如下:
+
+输入 | 输出
+------|-------
+ -400| 450
+ -300| 300
+ -200| 150
+ -100| 0
+ -50| 0.5
+ 0| 1
+ 50| 0.5
+ 100| 0
+ 101| 0
+ 200| 0
+
+`interpolate`还支持到字符串的映射,从而可以实现颜色以及带有单位的值的动画变换。例如你可以像下面这样实现一个旋转动画:
+
+ ```javascript
+ value.interpolate({
+ inputRange: [0, 360],
+ outputRange: ['0deg', '360deg']
+ })
+ ```
+
+`interpolation`还支持任意的渐变函数,其中有很多已经在`Easing`类中定义了,包括二次、指数、贝塞尔等曲线以及step、bounce等方法。`interpolation`还支持限制输出区间`outputRange`。你可以通过设置`extrapolate`、`extrapolateLeft`或`extrapolateRight`属性来限制输出区间。默认值是`extend`(允许超出),不过你可以使用`clamp`选项来阻止输出值超过`outputRange`。
+
+#### 跟踪动态值
+
+动画中所设的值还可以通过跟踪别的值得到。你只要把toValue设置成另一个动态值而不是一个普通数字就行了。比如我们可以用弹跳动画来实现聊天头像的闪动,又比如通过`timing`设置`duration:0`来实现快速的跟随。他们还可以使用插值来进行组合:
+
+```javascript
+Animated.spring(follower, {toValue: leader}).start();
+Animated.timing(opacity, {
+ toValue: pan.x.interpolate({
+ inputRange: [0, 300],
+ outputRange: [1, 0],
+ }),
+}).start();
+```
+
+`ValueXY`是一个方便的处理2D交互的办法,譬如旋转或拖拽。它是一个简单的包含了两个`Animated.Value`实例的包装,然后提供了一系列辅助函数,使得`ValueXY`在许多时候可以替代`Value`来使用。比如在上面的代码片段中,`leader`和`follower`可以同时为`valueXY`类型,这样x和y的值都会被跟踪。
+
+#### 输入事件
+
+`Animated.event`是Animated API中与输入有关的部分,允许手势或其它事件直接绑定到动态值上。它通过一个结构化的映射语法来完成,使得复杂事件对象中的值可以被正确的解开。第一层是一个数组,允许同时映射多个值,然后数组的每一个元素是一个嵌套的对象。在下面的例子里,你可以发现`scrollX`被映射到了`event.nativeEvent.contentOffset.x`(`event`通常是回调函数的第一个参数),并且`pan.x`和`pan.y`分别映射到`gestureState.dx`和`gestureState.dy`(`gestureState`是传递给`PanResponder`回调函数的第二个参数)。
+
+```javascript
+onScroll={Animated.event(
+ [{nativeEvent: {contentOffset: {x: scrollX}}}] // scrollX = e.nativeEvent.contentOffset.x
+)}
+onPanResponderMove={Animated.event([
+ null, // 忽略原生事件
+ {dx: pan.x, dy: pan.y} // 从gestureState中解析出dx和dy的值
+]);
+```
+
+#### 响应当前的动画值
+
+你可能会注意到这里没有一个明显的方法来在动画的过程中读取当前的值——这是出于优化的角度考虑,有些值只有在原生代码运行阶段中才知道。如果你需要在JavaScript中响应当前的值,有两种可能的办法:
+
+* `spring.stopAnimation(callback)`会停止动画并且把最终的值作为参数传递给回调函数`callback`——这在处理手势动画的时候非常有用。
+* `spring.addListener(callback)` 会在动画的执行过程中持续异步调用`callback`回调函数,提供一个最近的值作为参数。这在用于触发状态切换的时候非常有用,譬如当用户拖拽一个东西靠近的时候弹出一个新的气泡选项。不过这个状态切换可能并不会十分灵敏,因为它不像许多连续手势操作(如旋转)那样在60fps下运行。
+
+#### 后续工作
+
+如前面所述,我们计划继续优化Animated,以进一步提升性能。我们还想尝试一些声明式的手势响应和触发动画,譬如垂直或者水平的倾斜操作。
+
+上面的API提供了一个强大的工具来简明、健壮、高效地组织各种各种不同的动画。你可以在[UIExplorer/AnimationExample](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/AnimatedGratuitousApp)中看到更多的样例代码。不过还有些时候`Animated`并不能支持你想要的效果,下面的章节包含了一些其它的动画系统。
+
+### LayoutAnimation
+
+`LayoutAnimation`允许你在全局范围内`创建`和`更新`动画,这些动画会在下一次渲染或布局周期运行。它常用来更新flexbox布局,因为它可以无需测量或者计算特定属性就能直接产生动画。尤其是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增加父节点的尺寸又会将位于本行之下的所有行向下推动)时,如果不使用`LayoutAnimation`,可能就需要显式声明组件的坐标,才能使得所有受影响的组件能够同步运行动画。
+
+注意尽管`LayoutAnimation`非常强大且有用,但它对动画本身的控制没有`Animated`或者其它动画库那样方便,所以如果你使用`LayoutAnimation`无法实现一个效果,那可能还是要考虑其他的方案。
+
+另外,如果要在**Android**上使用LayoutAnimation,那么目前还需要在`UIManager`中启用:
+```javascript
+UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
+```
+
+
+
+```javascript
+var App = React.createClass({
+ componentWillMount() {
+ // 创建动画
+ LayoutAnimation.spring();
+ },
+
+ getInitialState() {
+ return { w: 100, h: 100 }
+ },
+
+ _onPress() {
+ // 让视图的尺寸变化以动画形式展现
+ LayoutAnimation.spring();
+ this.setState({w: this.state.w + 15, h: this.state.h + 15})
+ },
+
+ render: function() {
+ return (
+
+
+
+
+ Press me!
+
+
+
+ );
+ }
+});
+```
+[运行这个例子](https://rnplay.org/apps/uaQrGQ)
+
+上面这个例子使用了一个预设值,不过你也可以自己配置你需要的动画。参见[LayoutAnimation.js](https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js)。
+
+### requestAnimationFrame
+
+`requestAnimationFrame`是一个对浏览器标准API的兼容实现,你可能已经熟悉它了。它接受一个函数作为唯一的参数,并且在下一次重绘之前调用此函数。一些基于JavaScript的动画库高度依赖于这一API。通常你不必直接调用它——那些动画库会替你管理好帧的更新。
+
+### react-tween-state(不推荐,用[Animated](#animated)来替代)
+
+[react-tween-state](https://github.com/chenglou/react-tween-state)是一个极小的库,正如它名字(tween:补间)表示的含义:它生成一个节点的状态的中间值,从一个**开始**值,结束于一个**到达**值。这意味着它会生成这两者之间的值,然后在每次`requestAnimationFrame`的时候修改状态。
+
+> 在[Wikipedia](https://en.wikipedia.org/wiki/Inbetweening)上对于补间动画(tweening)的定义:
+>
+> “补间是在两个图像之间生成中间帧的过程,以使得第一个图像能够平滑的变化为第二个图像”。补间帧是指在关键帧之间用于创建过渡假象的图画。”
+
+一个最基础的从一个值运动到另一个值的办法就是线性过渡:只需要将结束值减去开始值,然后除以动画总共需要经历的帧数,再在每一帧加到当前值上,一直到结束值位置。线性过渡有时候看起来怪异且不自然,所以react-tween-state提供了一系列常用的[过渡函数](http://easings.net/),可以用于使你的动画更加自然。
+
+这个库并未随React Native一起发布——要在你的工程中使用它,则需要先在你的工程目录下执行`npm i react-tween-state --save`来安装。
+
+```javascript
+import tweenState from 'react-tween-state';
+import reactMixin from 'react-mixin'; // https://github.com/brigand/react-mixin
+
+class App extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { opacity: 1 };
+ this._animateOpacity = this._animateOpacity.bind(this);
+ }
+
+ _animateOpacity() {
+ this.tweenState('opacity', {
+ easing: tweenState.easingTypes.easeOutQuint,
+ duration: 1000,
+ endValue: this.state.opacity === 0.2 ? 1 : 0.2,
+ });
+ }
+
+ render() {
+ return (
+
+
+ this._box = component}
+ style={{width: 200, height: 200, backgroundColor: 'red',
+ opacity: this.getTweeningValue('opacity')}} />
+
+
+ )
+ }
+}
+
+reactMixin.onClass(App, tweenState.Mixin);
+```
+[运行这个例子](https://rnplay.org/apps/4FUQ-A)
+
+
+
+在上面的例子里我们变化的是透明度,但你可能也猜到了,我们能变化任何数值的值。可以参考它的[说明文档](https://github.com/chenglou/react-tween-state)来了解更多信息。
+
+#### Rebound (不推荐 - 使用[Animated](#animated)来替代)
+
+[Rebound.js](https://github.com/facebook/rebound-js)是一个[安卓版Rebound](https://github.com/facebook/rebound)的JavaScript移植版。它在概念上类似react-tween-state:你有一个起始值,然后定义一个结束值,然后Rebound会生成所有中间的值并用于你的动画。Rebound基于弹性物理模型,你不需要提供一个动画的持续时间,它会自动根据弹性系数、助力、当前值和结束值来计算。我们[在React Native内部应用](https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=rebound)了Rebound,比如`Navigator`和`WarningBox`。
+
+
+
+需要注意的是Rebound动画可以被中断——如果你在按下动画的过程中释放手指,它会从当前状态弹回初始值。
+
+```javascript
+var rebound = require('rebound');
+
+var App = React.createClass({
+ // 首先我们初始化一个spring动画,并添加监听函数,
+ // 这个函数会在spring更新时调用setState
+ componentWillMount() {
+ // 初始化spring
+ this.springSystem = new rebound.SpringSystem();
+ this._scrollSpring = this.springSystem.createSpring();
+ var springConfig = this._scrollSpring.getSpringConfig();
+ springConfig.tension = 230;
+ springConfig.friction = 10;
+
+ this._scrollSpring.addListener({
+ onSpringUpdate: () => {
+ this.setState({scale: this._scrollSpring.getCurrentValue()});
+ },
+ });
+
+ // 将spring的初始值设为1
+ this._scrollSpring.setCurrentValue(1);
+ },
+
+ _onPressIn() {
+ this._scrollSpring.setEndValue(0.5);
+ },
+
+ _onPressOut() {
+ this._scrollSpring.setEndValue(1);
+ },
+
+ render: function() {
+ var imageStyle = {
+ width: 250,
+ height: 200,
+ transform: [{scaleX: this.state.scale}, {scaleY: this.state.scale}],
+ };
+
+ var imageUri = "https://facebook.github.io/react-native/img/ReboundExample.png";
+
+ return (
+
+
+
+
+
+ );
+ }
+});
+```
+
+你还可以为弹跳值启用边界,这样它们不会超出,而是会缓缓接近最终值。在上面的例子里,我们可以添加`this._scrollSpring.setOvershootClampingEnabled(true)`来启用边界。参见下面的gif动画来看一个启用了边界的效果:
+
+ 截图来自
+[react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view)。
+
+你可以在[这里](https://rnplay.org/apps/qHU_5w)看到一个类似的例子。
+
+#### 关于setNativeProps
+
+正如[直接操作](direct-manipulation.html)文档所说,`setNativeProps`方法可以使我们直接修改基于原生视图的组件的属性,而不需要使用`setState`来重新渲染整个组件树。
+
+我们可以把这个用在Rebound样例中来更新缩放比例——如果我们要更新的组件有一个非常深的内嵌结构,并且没有使用`shouldComponentUpdate`来优化,那么使用`setNativeProps`就将大有裨益。
+
+```javascript
+// 回到上面示例的那个组件中,找到componentWillMount方法,
+// 然后将scrollSpring的监听函数替换为如下代码:
+this._scrollSpring.addListener({
+ onSpringUpdate: () => {
+ if (!this._photo) { return }
+ var v = this._scrollSpring.getCurrentValue();
+ var newProps = {style: {transform: [{scaleX: v}, {scaleY: v}]}};
+ this._photo.setNativeProps(newProps);
+ },
+});
+
+// 最后,我们修改render方法,不再通过style来传入transform(避免
+// 重新渲染时产生冲突);然后给图片加上ref引用。
+render: function() {
+ return (
+
+
+ this._photo = component}
+ source={{uri: "https://facebook.github.io/react-native/img/ReboundExample.png"}}
+ style={{width: 250, height: 200}} />
+
+
+ );
+}
+```
+[运行这个例子](https://rnplay.org/apps/fUqjAg)
+
+不过你没办法把`setNativeProps`和react-tween-state结合使用,因为更新的补间值会自动被库设置到state上——Rebound则不同,它通过`onSprintUpdate`函数在每一帧中给我们提供一个更新后的值。
+
+如果你发现你的动画丢帧(低于60帧每秒),可以尝试使用`setNativeProps`或者`shouldComponentUpdate`来优化它们。你还可能需要将部分计算工作放在动画完成之后进行,这时可以使用[InteractionManager](/react-native/docs/interactionmanager.html)。你还可以使用应用内的开发者菜单中的“FPS Monitor”工具来监控应用的帧率。
+
+### 导航器场景切换
+
+正如文档[导航器对比](navigator-comparison.html#content)所说,`Navigator`使用JavaScript实现,而`NavigatoIOS`则是一个对于`UINavigationController`提供的原生功能的包装。所以这些场景切换动画仅仅对`Navigator`有效。为了在Navigator中重新创建`UINavigationController`所提供的动画并且使之可以被自定义,React Native导出了一个[NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js)API。
+
+```javascript
+import { Dimensions } from 'react-native';
+var SCREEN_WIDTH = Dimensions.get('window').width;
+var BaseConfig = Navigator.SceneConfigs.FloatFromRight;
+
+var CustomLeftToRightGesture = Object.assign({}, BaseConfig.gestures.pop, {
+ // 用户中断返回手势时,迅速弹回
+ snapVelocity: 8,
+
+ // 如下设置可以使我们在屏幕的任何地方拖动它
+ edgeHitWidth: SCREEN_WIDTH,
+});
+
+var CustomSceneConfig = Object.assign({}, BaseConfig, {
+ // 如下设置使过场动画看起来很快
+ springTension: 100,
+ springFriction: 1,
+
+ // 使用上面我们自定义的手势
+ gestures: {
+ pop: CustomLeftToRightGesture,
+ }
+});
+```
+[运行这个例子](https://rnplay.org/apps/HPy6UA)
+
+要了解更多有关自定义场景切换的信息,你可以[阅读相应的源码](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js)。
diff --git a/docs/docs/0.41/appregistry.md b/docs/docs/0.41/appregistry.md
new file mode 100644
index 0000000..f4d5dde
--- /dev/null
+++ b/docs/docs/0.41/appregistry.md
@@ -0,0 +1,16 @@
+`AppRegistry`是JS运行所有React Native应用的入口。应用的根组件应当通过`AppRegistry.registerComponent`方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用`AppRegistry.runApplication`来真正运行应用。
+
+要“结束”一个应用并销毁视图的话,请调用`AppRegistry.unmountApplicationComponentAtRootTag`方法,参数为在`runApplication`中使用的标签名。它们必须严格匹配。
+
+`AppRegistry`应当在`require`序列中尽可能早的被require到,以确保JS运行环境在其它模块之前被准备好。
+
+### 方法
+
+
+
static registerConfig(config: Array<AppConfig>) #
+
static registerComponent(appKey: string, getComponentFunc: ComponentProvider) #
+
static registerRunnable(appKey: string, func: Function) #
+
+
static runApplication(appKey: string, appParameters: any) #
+
static unmountApplicationComponentAtRootTag(rootTag: number) #
+
diff --git a/docs/docs/0.41/appstate.md b/docs/docs/0.41/appstate.md
new file mode 100644
index 0000000..a824b94
--- /dev/null
+++ b/docs/docs/0.41/appstate.md
@@ -0,0 +1,157 @@
+`AppState`能告诉你应用当前是在前台还是在后台,并且能在状态变化的时候通知你。
+
+AppState通常在处理推送通知的时候用来决定内容和对应的行为。
+
+### App States
+
+* `active` - 应用正在前台运行
+* `background` - 应用正在后台运行。用户既可能在别的应用中,也可能在桌面。
+* `inactive` - 这是一个过渡状态,不会在正常的React Native应用中出现。
+
+要了解更多信息,可以阅读[Apple的文档](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)。
+
+### 基本用法
+
+要获取当前的状态,你可以使用`AppState.currentState`,这个变量会一直保持更新。不过在启动的过程中,`currentState`可能为null,直到`AppState`从原生代码得到通知为止。
+
+```javascript
+constructor(props) {
+ super(props);
+ this.state = {
+ currentAppState: AppState.currentState,
+ };
+}
+componentDidMount() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+}
+componentWillUnmount() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+}
+_handleAppStateChange = (nextAppState) => {
+ if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
+ console.log('App has come to the foreground!')
+ }
+ this.setState({appState: nextAppState});
+}
+render() {
+ return (
+ Current state is: {this.state.currentAppState}
+ );
+}
+```
+
+上面的这个例子只会显示"Current state is: active",这是因为应用只有在`active`状态下才能被用户看到。并且null状态只会在一开始的一瞬间出现。
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听函数,用于监听应用状态的变化。type参数应填`change` 。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
移除一个监听函数。type参数应填change。
+
+
+
+
+### 属性
+
+
+
+
currentState: TypeCastExpression #
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ AppState,
+ Text,
+ View
+} = ReactNative;
+
+var AppStateSubscription = React.createClass({
+ getInitialState() {
+ return {
+ appState: AppState.currentState,
+ previousAppStates: [],
+ memoryWarnings: 0,
+ };
+ },
+ componentDidMount: function() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+ AppState.addEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ componentWillUnmount: function() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+ AppState.removeEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ _handleMemoryWarning: function() {
+ this.setState({memoryWarnings: this.state.memoryWarnings + 1});
+ },
+ _handleAppStateChange: function(appState) {
+ var previousAppStates = this.state.previousAppStates.slice();
+ previousAppStates.push(this.state.appState);
+ this.setState({
+ appState,
+ previousAppStates,
+ });
+ },
+ render() {
+ if (this.props.showMemoryWarnings) {
+ return (
+
+ {this.state.memoryWarnings}
+
+ );
+ }
+ if (this.props.showCurrentOnly) {
+ return (
+
+ {this.state.appState}
+
+ );
+ }
+ return (
+
+ {JSON.stringify(this.state.previousAppStates)}
+
+ );
+ }
+});
+
+exports.title = 'AppState';
+exports.description = 'app background status';
+exports.examples = [
+ {
+ title: 'AppState.currentState',
+ description: 'Can be null on app initialization',
+ render() { return {AppState.currentState} ; }
+ },
+ {
+ title: 'Subscribed AppState:',
+ description: 'This changes according to the current state, so you can only ever see it rendered as "active"',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Previous states:',
+ render(): ReactElement { return ; }
+ },
+ {
+ platform: 'ios',
+ title: 'Memory Warnings',
+ description: 'In the IOS simulator, hit Shift+Command+M to simulate a memory warning.',
+ render(): ReactElement { return ; }
+ },
+];
+```
diff --git a/docs/docs/0.41/asyncstorage.md b/docs/docs/0.41/asyncstorage.md
new file mode 100644
index 0000000..d1cc11d
--- /dev/null
+++ b/docs/docs/0.41/asyncstorage.md
@@ -0,0 +1,76 @@
+AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统,它对于App来说是全局性的。它用来代替LocalStorage。
+
+我们推荐您在AsyncStorage的基础上做一层抽象封装,而不是直接使用AsyncStorage。
+
+__译注__:推荐由`React Native中文网`封装维护的[`react-native-storage`](https://github.com/sunnylqm/react-native-storage/blob/master/README-CHN.md)模块,提供了较多便利功能。
+
+本模块的JS代码提供了对原生实现的一个封装,以提供一个更清晰的JS API、返回真正的错误对象,以及简单的单项对象操作函数。每个方法都会返回一个`Promise`对象。
+
+### 方法
+
+
+
+
static getItem(key: string, callback?: ?(error: ?Error, result: ?string) => void) #
+
+
读取key字段并将结果作为第二个参数传递给callback。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static setItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
将key字段的值设置成value,并在完成后调用callback函数。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static removeItem(key: string, callback?: ?(error: ?Error) => void) #
+
+
删除一个字段。返回一个Promise对象。
+
+
+
+
static mergeItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
假设已有的值和新的值都是字符串化的JSON,则将两个值合并。返回一个Promise对象。还没有被所有原生实现都支持。
+
+
+
+
static clear(callback?: ?(error: ?Error) => void) #
+
+
删除全部的 AsyncStorage数据,不论来自什么库或调用者。通常不应该调用这个函数——使用removeItem或者multiRemove来清除你自己的key。返回一个Promise对象。
+
+
+
+
static getAllKeys(callback?: ?(error: ?Error, keys: ?Array<string>) => void) #
+
+
获取所有 本应用可以访问到的数据,不论来自什么库或调用者。返回一个Promise对象。
+
+
+
static flushGetRequests() #
+
+
static multiGet(keys: Array<string>, callback?: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void) #
+
+
获取keys所包含的所有字段的值,调用callback回调函数时返回一个key-value数组形式的数组。返回一个Promise对象。
+
multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
+
+
+
+
static multiSet(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
multiSet和multiMerge都接受一个与multiGet输出值一致的key-value数组的数组。返回一个Promise对象。
+
multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
+
+
+
+
static multiRemove(keys: Array<string>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
删除所有键在keys数组中的数据。返回一个Promise对象。
+
+
+
+
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
将多个输入的值和已有的值合并,要求都是字符串化的JSON。返回一个Promise对象。
+
还没有被所有原生实现都支持。
+
+
+
diff --git a/docs/docs/0.41/backandroid.md b/docs/docs/0.41/backandroid.md
new file mode 100644
index 0000000..b7c014a
--- /dev/null
+++ b/docs/docs/0.41/backandroid.md
@@ -0,0 +1,22 @@
+监听硬件的`back`键操作。如果没有任何监听函数,或者监听函数的返回值不是true,则会调用默认的back键功能来退出应用。
+
+例子:
+
+```javascript
+BackAndroid.addEventListener('hardwareBackPress', function() {
+ if (!this.onMainScreen()) {
+ this.goBack();
+ return true;
+ }
+ return false;
+});
+```
+__译注__:以上的`this.onMainScreen()`和`this.goBack()`两个方法都只是伪方法,需要你自己去实现!具体可以参考这篇[博文](http://bbs.reactnative.cn/topic/480)。
+
+### 方法
+
+
+
+
static addEventListener(eventName: BackPressEventName, handler: Function) #
+
static removeEventListener(eventName: BackPressEventName, handler: Function) #
+
diff --git a/docs/docs/0.41/button.md b/docs/docs/0.41/button.md
new file mode 100644
index 0000000..c8e75cc
--- /dev/null
+++ b/docs/docs/0.41/button.md
@@ -0,0 +1,134 @@
+一个简单的跨平台的按钮组件。可以进行一些简单的定制。
+
+
+
+如果这个组件外观并不怎么搭配你的设计,那你可以使用`TouchableOpacity`或是`TouchableNativeFeedback`组件来制作自己所需要的按钮,视频教程[如何制作一个按钮](http://v.youku.com/v_show/id_XMTQ5OTE3MjkzNg==.html?f=26822355&from=y1.7-1.3)讲述了完整的过程。或者你也可以在github.com网站上搜索'react native button'来看看社区其他人的作品。
+
+
+用法示例:
+
+```js
+
+```
+
+### 属性
+
+
accessibilityLabel string #
+
用于给残障人士显示的文本(比如读屏器软件可能会读取这一内容)
+
+
+
文本的颜色(iOS),或是按钮的背景色(Android)
+
+
+
+
+
+
+### 例子
+
+```javascript
+use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ Alert,
+ Button,
+ View,
+} = ReactNative;
+
+const onButtonPress = () => {
+ Alert.alert('Button has been pressed!');
+};
+
+exports.displayName = 'ButtonExample';
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Simple React Native button component.';
+
+exports.examples = [
+ {
+ title: 'Simple Button',
+ description: 'The title and onPress handler are required. It is ' +
+ 'recommended to set accessibilityLabel to help make your app usable by ' +
+ 'everyone.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Adjusted color',
+ description: 'Adjusts the color in a way that looks standard on each ' +
+ 'platform. On iOS, the color prop controls the color of the text. On ' +
+ 'Android, the color adjusts the background color of the button.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Fit to text layout',
+ description: 'This layout strategy lets the title define the width of ' +
+ 'the button',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Disabled Button',
+ description: 'All interactions for the component are disabled.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+];
+```
diff --git a/docs/docs/0.41/cameraroll.md b/docs/docs/0.41/cameraroll.md
new file mode 100644
index 0000000..da08b4d
--- /dev/null
+++ b/docs/docs/0.41/cameraroll.md
@@ -0,0 +1,175 @@
+`CameraRoll`模块提供了访问本地相册的功能。在iOS上使用这个模块之前,你需要先链接`RCTCameraRoll`库,具体做法请参考[链接原生库](linking-libraries-ios.html)文档。
+
+**译注**:本模块只提供了基本的访问图片的功能,并没有提供相册界面。对于多数开发者来说,可能[react-native-image-picker](https://github.com/marcshilling/react-native-image-picker)的功能更为完整易用。
+
+### iOS 10的权限要求
+从iOS10开始,访问相册需要用户授权。你需要在`Info.plist`中添加一条名为`NSCameraUsageDescription`的键,然后在其值中填写向用户请求权限的具体描述。编辑完成后这个键在Xcode中实际会显示为`Privacy - Camera Usage Description`。
+
+### 截图
+
+
+### 方法
+
+
+
+
static saveImageWithTag(tag) #
+
+
保存一个图片到相册。
+
@param {string} tag 在安卓上,本参数是一个本地URI,例如"file:///sdcard/img.png".
+
在iOS设备上可能是以下之一:
+
+ 本地URI
+ 资源库的标签
+ 非以上两种类型,表示图片数据将会存储在内存中(并且在本进程持续的时候一直会占用内存)。
+
+
返回一个Promise,操作成功时返回新的URI。
+
+
+
+
static saveToCameraRoll(tag, type?) #
+
把图片或视频保存到相册中。
+
On Android, the tag must be a local image or video URI, such as "file:///sdcard/img.png".
On iOS, the tag can be any image URI (including local, remote asset-library and base64 data URIs) or a local video file URI (remote or data URIs are not supported for saving video at this time).
+
If the tag has a file extension of .mov or .mp4, it will be inferred as a video. Otherwise it will be treated as a photo. To override the automatic choice, you can pass an optional
+type parameter that must be one of 'photo' or 'video'.
Returns a Promise which will resolve with the new URI.
+
+
+
+
static getPhotos(params: object) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ CameraRoll,
+ Image,
+ Slider,
+ StyleSheet,
+ Switch,
+ Text,
+ View,
+ TouchableOpacity
+} = ReactNative;
+
+const invariant = require('fbjs/lib/invariant');
+
+const CameraRollView = require('./CameraRollView');
+
+const AssetScaledImageExampleView = require('./AssetScaledImageExample');
+
+class CameraRollExample extends React.Component {
+ state = {
+ groupTypes: 'SavedPhotos',
+ sliderValue: 1,
+ bigImages: true,
+ };
+ _cameraRollView: ?CameraRollView;
+ render() {
+ return (
+
+
+ {(this.state.bigImages ? 'Big' : 'Small') + ' Images'}
+
+ {'Group Type: ' + this.state.groupTypes}
+ { this._cameraRollView = ref; }}
+ batchSize={20}
+ groupTypes={this.state.groupTypes}
+ renderImage={this._renderImage}
+ />
+
+ );
+ }
+
+ loadAsset = (asset) => {
+ if (this.props.navigator) {
+ this.props.navigator.push({
+ title: 'Camera Roll Image',
+ component: AssetScaledImageExampleView,
+ backButtonTitle: 'Back',
+ passProps: { asset: asset },
+ });
+ }
+ };
+
+ _renderImage = (asset) => {
+ const imageSize = this.state.bigImages ? 150 : 75;
+ const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
+ const {location} = asset.node;
+ const locationStr = location ? JSON.stringify(location) : 'Unknown location';
+ return (
+
+
+
+
+ {asset.node.image.uri}
+ {locationStr}
+ {asset.node.group_name}
+ {new Date(asset.node.timestamp).toString()}
+
+
+
+ );
+ };
+
+ _onSliderChange = (value) => {
+ const options = CameraRoll.GroupTypesOptions;
+ const index = Math.floor(value * options.length * 0.99);
+ const groupTypes = options[index];
+ if (groupTypes !== this.state.groupTypes) {
+ this.setState({groupTypes: groupTypes});
+ }
+ };
+
+ _onSwitchChange = (value) => {
+ invariant(this._cameraRollView, 'ref should be set');
+ this._cameraRollView.rendererChanged();
+ this.setState({ bigImages: value });
+ };
+}
+
+const styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ flex: 1,
+ },
+ url: {
+ fontSize: 9,
+ marginBottom: 14,
+ },
+ image: {
+ margin: 4,
+ },
+ info: {
+ flex: 1,
+ },
+});
+
+exports.title = 'Camera Roll';
+exports.description = 'Example component that uses CameraRoll to list user\'s photos';
+exports.examples = [
+ {
+ title: 'Photos',
+ render(): React.Element { return ; }
+ }
+];
+```
diff --git a/docs/docs/0.41/clipboard.md b/docs/docs/0.41/clipboard.md
new file mode 100644
index 0000000..94eae4b
--- /dev/null
+++ b/docs/docs/0.41/clipboard.md
@@ -0,0 +1,87 @@
+`Clipboard`组件可以在iOS和Android的剪贴板中读写内容。
+
+### 方法
+
+
+
static getString() #
+
获取剪贴板的文本内容,返回一个Promise你可以用下面的方式来调用。
+
async _getContent( ) {
+ var content = await
+ Clipboard. getString( ) ;
+ }
+
+
+
static setString(content: string) #
+
+
设置剪贴板的文本内容。你可以用下面的方式来调用。
+
_setContent( ) {
+ Clipboard. setString( 'hello world' ) ;
+ }
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Clipboard,
+ View,
+ Text,
+} = ReactNative;
+
+var ClipboardExample = React.createClass({
+ getInitialState() {
+ return {
+ content: 'Content will appear here'
+ };
+ },
+
+ async _setClipboardContent(){
+ Clipboard.setString('Hello World');
+ try {
+ var content = await Clipboard.getString();
+ this.setState({content});
+ } catch (e) {
+ this.setState({content:e.message});
+ }
+ },
+
+ render() {
+ return (
+
+
+ Tap to put "Hello World" in the clipboard
+
+
+ {this.state.content}
+
+
+ );
+ }
+});
+
+exports.title = 'Clipboard';
+exports.description = 'Show Clipboard contents.';
+exports.examples = [
+ {
+ title: 'Clipboard.setString() and getString()',
+ render() {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.41/colors.md b/docs/docs/0.41/colors.md
new file mode 100644
index 0000000..2912ede
--- /dev/null
+++ b/docs/docs/0.41/colors.md
@@ -0,0 +1,166 @@
+以下这些格式的颜色代码都是支持的:
+
+ - `'#f0f'` (#rgb)
+ - `'#f0fc'` (#rgba)
+ - `'#ff00ff'` (#rrggbb)
+ - `'#ff00ff00'` (#rrggbbaa)
+ - `'rgb(255, 255, 255)'`
+ - `'rgba(255, 255, 255, 1.0)'`
+ - `'hsl(360, 100%, 100%)'`
+ - `'hsla(360, 100%, 100%, 1.0)'`
+ - `'transparent'`
+ - `'red'`
+ - `0xff00ff00` (0xrrggbbaa)
+
+对于有称谓的颜色,React Native遵循的是[CSS3的规范](http://www.w3.org/TR/css3-color/#svg-color):
+
+
+ aliceblue (#f0f8ff)
+ antiquewhite (#faebd7)
+ aqua (#00ffff)
+ aquamarine (#7fffd4)
+ azure (#f0ffff)
+ beige (#f5f5dc)
+ bisque (#ffe4c4)
+ black (#000000)
+ blanchedalmond (#ffebcd)
+ blue (#0000ff)
+ blueviolet (#8a2be2)
+ brown (#a52a2a)
+ burlywood (#deb887)
+ cadetblue (#5f9ea0)
+ chartreuse (#7fff00)
+ chocolate (#d2691e)
+ coral (#ff7f50)
+ cornflowerblue (#6495ed)
+ cornsilk (#fff8dc)
+ crimson (#dc143c)
+ cyan (#00ffff)
+ darkblue (#00008b)
+ darkcyan (#008b8b)
+ darkgoldenrod (#b8860b)
+ darkgray (#a9a9a9)
+ darkgreen (#006400)
+ darkgrey (#a9a9a9)
+ darkkhaki (#bdb76b)
+ darkmagenta (#8b008b)
+ darkolivegreen (#556b2f)
+ darkorange (#ff8c00)
+ darkorchid (#9932cc)
+ darkred (#8b0000)
+ darksalmon (#e9967a)
+ darkseagreen (#8fbc8f)
+ darkslateblue (#483d8b)
+ darkslategray (#2f4f4f)
+ darkslategrey (#2f4f4f)
+ darkturquoise (#00ced1)
+ darkviolet (#9400d3)
+ deeppink (#ff1493)
+ deepskyblue (#00bfff)
+ dimgray (#696969)
+ dimgrey (#696969)
+ dodgerblue (#1e90ff)
+ firebrick (#b22222)
+ floralwhite (#fffaf0)
+ forestgreen (#228b22)
+ fuchsia (#ff00ff)
+ gainsboro (#dcdcdc)
+ ghostwhite (#f8f8ff)
+ gold (#ffd700)
+ goldenrod (#daa520)
+ gray (#808080)
+ green (#008000)
+ greenyellow (#adff2f)
+ grey (#808080)
+ honeydew (#f0fff0)
+ hotpink (#ff69b4)
+ indianred (#cd5c5c)
+ indigo (#4b0082)
+ ivory (#fffff0)
+ khaki (#f0e68c)
+ lavender (#e6e6fa)
+ lavenderblush (#fff0f5)
+ lawngreen (#7cfc00)
+ lemonchiffon (#fffacd)
+ lightblue (#add8e6)
+ lightcoral (#f08080)
+ lightcyan (#e0ffff)
+ lightgoldenrodyellow (#fafad2)
+ lightgray (#d3d3d3)
+ lightgreen (#90ee90)
+ lightgrey (#d3d3d3)
+ lightpink (#ffb6c1)
+ lightsalmon (#ffa07a)
+ lightseagreen (#20b2aa)
+ lightskyblue (#87cefa)
+ lightslategray (#778899)
+ lightslategrey (#778899)
+ lightsteelblue (#b0c4de)
+ lightyellow (#ffffe0)
+ lime (#00ff00)
+ limegreen (#32cd32)
+ linen (#faf0e6)
+ magenta (#ff00ff)
+ maroon (#800000)
+ mediumaquamarine (#66cdaa)
+ mediumblue (#0000cd)
+ mediumorchid (#ba55d3)
+ mediumpurple (#9370db)
+ mediumseagreen (#3cb371)
+ mediumslateblue (#7b68ee)
+ mediumspringgreen (#00fa9a)
+ mediumturquoise (#48d1cc)
+ mediumvioletred (#c71585)
+ midnightblue (#191970)
+ mintcream (#f5fffa)
+ mistyrose (#ffe4e1)
+ moccasin (#ffe4b5)
+ navajowhite (#ffdead)
+ navy (#000080)
+ oldlace (#fdf5e6)
+ olive (#808000)
+ olivedrab (#6b8e23)
+ orange (#ffa500)
+ orangered (#ff4500)
+ orchid (#da70d6)
+ palegoldenrod (#eee8aa)
+ palegreen (#98fb98)
+ paleturquoise (#afeeee)
+ palevioletred (#db7093)
+ papayawhip (#ffefd5)
+ peachpuff (#ffdab9)
+ peru (#cd853f)
+ pink (#ffc0cb)
+ plum (#dda0dd)
+ powderblue (#b0e0e6)
+ purple (#800080)
+ rebeccapurple (#663399)
+ red (#ff0000)
+ rosybrown (#bc8f8f)
+ royalblue (#4169e1)
+ saddlebrown (#8b4513)
+ salmon (#fa8072)
+ sandybrown (#f4a460)
+ seagreen (#2e8b57)
+ seashell (#fff5ee)
+ sienna (#a0522d)
+ silver (#c0c0c0)
+ skyblue (#87ceeb)
+ slateblue (#6a5acd)
+ slategray (#708090)
+ slategrey (#708090)
+ snow (#fffafa)
+ springgreen (#00ff7f)
+ steelblue (#4682b4)
+ tan (#d2b48c)
+ teal (#008080)
+ thistle (#d8bfd8)
+ tomato (#ff6347)
+ turquoise (#40e0d0)
+ violet (#ee82ee)
+ wheat (#f5deb3)
+ white (#ffffff)
+ whitesmoke (#f5f5f5)
+ yellow (#ffff00)
+ yellowgreen (#9acd32)
+
diff --git a/docs/docs/0.41/communication-ios.md b/docs/docs/0.41/communication-ios.md
new file mode 100644
index 0000000..a38a4d4
--- /dev/null
+++ b/docs/docs/0.41/communication-ios.md
@@ -0,0 +1,190 @@
+通过[植入原生应用](integration-with-existing-apps.html.html)和[原生UI组件](native-component-ios.html)两篇文档,我们学习了React Native和原生组件的互相整合。在整合的过程中,我们会需要在两个世界间互相通信。有些方法已经在其他的指南中提到了,这篇文章总结了所有可行的技术。
+## 简介
+React Native是从React中得到的灵感,因此基本的信息流是类似的。在React中信息是单向的。我们维护了组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(properties)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
+
+React Native也运用了相同的概念。只要我们完全在框架内构建应用,就可以通过属性和回调函数来调动整个应用。但是,当我们混合React Native和原生组件时,我们需要一些特殊的,跨语言的机制来传递信息。
+
+## 属性
+属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到React Native或者从React Native到原生组件。
+
+### 从原生组件传递属性到React Native
+
+我们使用`RCTRootView`将React Natvie视图封装到原生组件中。`RCTRootView`是一个`UIView`容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。
+
+通过`RCTRootView`的初始化函数你可以将任意属性传递给React Native应用。参数`initialProperties `必须是`NSDictionary`的一个实例。这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。
+```
+NSArray *imageList = @[@"http://foo.com/bar1.png",
+ @"http://foo.com/bar2.png"];
+
+NSDictionary *props = @{@"images" : imageList};
+
+RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"ImageBrowserApp"
+ initialProperties:props];
+```
+
+```
+'use strict';
+import React, { Component } from 'react';
+import {
+ AppRegistry,
+ View,
+ Image,
+} from 'react-native';
+
+class ImageBrowserApp extends Component {
+ renderImage(imgURI) {
+ return (
+
+ );
+ }
+ render() {
+ return (
+
+ {this.props.images.map(this.renderImage)}
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);
+```
+
+`RCTRootView`同样提供了一个可读写的属性`appProperties`。在`appProperties`设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。
+```
+NSArray *imageList = @[@"http://foo.com/bar3.png",
+ @"http://foo.com/bar4.png"];
+rootView.appProperties = @{@"images" : imageList};
+```
+你可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。
+更新属性时并不能做到只更新一部分属性。我们建议你自己封装一个函数来构造属性。
+
+> 注意:目前,最顶层的RN组件(即registerComponent方法中调用的那个)的`componentWillReceiveProps`和`componentWillUpdateProps`方法在属性更新后不会触发。但是,你可以通过`componentWillMount`访问新的属性值。
+
+## 从React Native传递属性到原生组件
+
+这篇[文档](native-component-ios.html#属性)详细讨论了暴露原生组件属性的问题。简而言之,在你自定义的原生组件中通过`RCT_CUSTOM_VIEW_PROPERTY`宏导出属性,就可以直接在React Native中使用,就好像它们是普通的React Native组件一样。
+
+## 属性的限制
+跨语言属性的主要缺点是不支持回调方法,因而无法实现自下而上的数据绑定。设想你有一个小的RN视图,当一个JS动作触发时你想从原生的父视图中移除它。此时你会发现根本做不到,因为信息需要自下而上进行传递。
+
+虽然我们有跨语言回调([参阅这里](native-modules-ios.html#回调函数)),但是这些回调函数并不总能满足需求。最主要的问题是它们并不是被设计来当作属性进行传递。这一机制的本意是允许我们从JS触发一个原生动作,然后用JS处理那个动作的处理结果。
+
+## 其他的跨语言交互(事件和原生模块)
+如上一章所说,使用属性总会有一些限制。有时候属性并不足以满足应用逻辑,因此我们需要更灵活的解决办法。这一章描述了其他的在React Native中可用的通信方法。他们可以用来内部通信(在JS和RN的原生层之间),也可以用作外部通信(在RN和纯原生部分之间)。
+
+React Native允许使用跨语言的函数调用。你可以在JS中调用原生代码,也可以在原生代码中调用JS。在不同端需要用不同的方法来实现相同的目的。在原生代码中我们使用事件机制来调度JS中的处理函数,而在React Native中我们直接使用原生模块导出的方法。
+
+### 从原生代码调用React Natvie函数(事件)
+事件的详细用法在这篇[文章](native-component-ios.html#事件)中进行了讨论。注意使用事件无法确保执行的时间,因为事件的处理函数是在单独的线程中执行。
+
+事件很强大,它可以不需要引用直接修改React Native组件。但是,当你使用时要注意下面这些陷阱:
+
+* 由于事件可以从各种地方产生,它们可能导致混乱的依赖。
+* 事件共享相同的命名空间,因此你可能遇到名字冲突。冲突不会在编写代码时被探测到,因此很难排错。
+* 如果你使用了同一个React Native组件的多个引用,然后想在事件中区分它们,name你很可能需要在事件中同时传递一些标识(你可以使用原生视图中的`reactTag`作为标识)。
+
+在React Native中嵌入原生组件时,通常的做法是用原生组件的RCTViewManager作为视图的代理,通过bridge向JS发送事件。这样可以集中在一处调用相关的事件。
+
+### 从React Native中调用原生方法(原生模块)
+
+原生模块是JS中也可以使用的Objective-C类。一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的。他们可以导出任意的函数和常量给React Native。相关细节可以参阅这篇[文章](native-modules-ios.html#content)。
+
+事实上原生模块的单实例模式限制了嵌入。假设我们有一个React Native组件被嵌入了一个原生视图,并且我们希望更新原生的父视图。使用原生模块机制,我们可以导出一个函数,不仅要接收预设参数,还要接收父视图的标识。这个标识将会用来获得父视图的引用以更新父视图。那样的话,我们需要维持模块中标识到原生模块的映射。
+虽然这个解决办法很复杂,它仍被用在了管理所有React Native视图的`RCTUIManager`类中,
+
+原生模块同样可以暴露已有的原生库给JS,[地理定位库](https://github.com/facebook/react-native/tree/master/Libraries/Geolocation)就是一个现成的例子。
+
+>警告:所有原生模块共享同一个命名空间。创建新模块时注意命名冲突。
+
+## 布局计算流
+
+当集成原生模块和React Natvie时,我们同样需要一个能协同不同的布局系统的办法。这一章节讨论了常见的布局问题,并且提供了解决机制的简单说明。
+
+### 在React Native中嵌入一个原生组件
+这个情况在[这篇文章](native-component-ios.html#样式)中进行了讨论。基本上,由于所有的原生视图都是`UIView`的子集,大多数类型和尺寸属性将和你期望的一样可以使用。
+
+### 在原生中嵌入一个React Native组件
+
+#### 固定大小的React Native内容
+
+最简单的情况是一个对于原生端已知的,固定大小的React Native应用,尤其是一个全屏的React Native视图。如果我们需要一个小一点的根视图,我们可以明确的设置`RCTRootView`的frame。
+比如说,创建一个200像素高,宿主视图那样宽的RN app,我们可以这样做:
+```
+// SomeViewController.m
+
+- (void)viewDidLoad
+{
+ [...]
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:appName
+ initialProperties:props];
+ rootView.frame = CGMakeRect(0, 0, self.view.width, 200);
+ [self.view addSubview:rootView];
+}
+```
+当我们创建了一个固定大小的根视图,则需要在JS中遵守它的边界。换句话说,我们需要确保React Native内容能够在固定的大小中放下。最简单的办法是使用flexbox布局。如果你使用绝对定位,并且React组件在根视图边界外可见,则React Native组件将会和原生视图重叠,导致某些不符合期望的行为。比如说,当你点击根视图边界之外的区域`TouchableHighlight`将不会高亮。
+通过重新设置frame的属性来动态更新根视图的大小是完全可行的。React Native将会关注内容布局的变化。
+
+#### 弹性大小的React Native
+有时候我们需要渲染一些不知道大小的内容。假设尺寸将会在JS中动态指定。我们有两个解决办法。
+
+* 你可以将React Native视图包裹在`ScrollView`中。这样可以保证你的内容总是可以访问,并且不会和原生视图重叠。
+* React Native允许你在JS中决定RN应用的尺寸,并且将它传递给宿主视图`RCTRootView`。然后宿主视图将重新布局子视图,保证UI统一。我们通过`RCTRootView`的弹性模式来达到目的。
+
+`RCTRootView`支持4种不同的弹性模式:
+```
+// RCTRootView.h
+
+typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
+ RCTRootViewSizeFlexibilityNone = 0,
+ RCTRootViewSizeFlexibilityWidth,
+ RCTRootViewSizeFlexibilityHeight,
+ RCTRootViewSizeFlexibilityWidthAndHeight,
+};
+```
+默认值是`RCTRootViewSizeFlexibilityNone`,表示使用固定大小的根视图(仍然可以通过`setFrame`更改)。其他三种模式可以跟踪React Native尺寸的变化。比如说,设置模式为`RCTRootViewSizeFlexibilityHeight`,React Native将会测量内容的高度然后传递回
+`RCTRootView`的代理。代理可以执行任意的行为,包括设置根视图的frame以使内容尺寸相匹配。
+代理仅仅在内容的尺寸发生变化时才进行调用。
+
+>注意:在JS和原生中都设置弹性尺寸可能导致不确定的行为。比如--不要在设置`RCTRootView`为`RCTRootViewSizeFlexibilityWidth`时同时指定最顶层的RN组件宽度可变(使用Flexbox)。
+
+看一个例子。
+```
+// FlexibleSizeExampleView.m
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ [...]
+
+ _rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"FlexibilityExampleApp"
+ initialProperties:@{}];
+
+ _rootView.delegate = self;
+ _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
+ _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0);
+}
+
+#pragma mark - RCTRootViewDelegate
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
+{
+ CGRect newFrame = rootView.frame;
+ newFrame.size = rootView.intrinsicSize;
+
+ rootView.frame = newFrame;
+}
+```
+在例子中我们使用一个`FlexibleSizeExampleView`视图来包含根视图。我们创建了根视图,初始化并且设置了代理。代理将会处理尺寸更新。然后,我们设置根视图的弹性尺寸为`RCTRootViewSizeFlexibilityHeight`,意味着`rootViewDidChangeIntrinsicSize:`方法将会在每次React Native内容高度变化时进行调用。最后,我们设置根视图的宽度和位置。注意我们也设置了高度,但是并没有效果,因为我们已经将高度设置为根据RN内容进行弹性变化了。
+
+你可以在这里查看完整的例子[源代码](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m)。
+
+动态改变根视图的弹性模式是可行的。改变根视图的弹性模式将会导致布局的重新计算,并且在重新量出内容尺寸时会调用`rootViewDidChangeIntrinsicSize`方法。
+
+>注意:React Native布局是通过一个特殊的线程进行计算,而原生UI视图是通过主线程更新。这可能导致短暂的原生端和React Native端的不一致。这是一个已知的问题,我们的团队已经在着手解决不同源的UI同步更新。
+>注意:除非根视图成为其他视图的子视图,否则React Native不会进行任何的布局计算。如果你想在还没有获得React Native视图的尺寸之前先隐藏视图,请将根视图添加为子视图并且在初始化的时候进行隐藏(使用`UIView`的`hidden`属性),然后在代理方法中改变它的可见性。
+
+
+
+
+
diff --git a/docs/docs/0.41/datepickerandroid.md b/docs/docs/0.41/datepickerandroid.md
new file mode 100644
index 0000000..6bf2f5b
--- /dev/null
+++ b/docs/docs/0.41/datepickerandroid.md
@@ -0,0 +1,57 @@
+本组件会打开一个标准的Android日期选择器的对话框。
+
+### 示例
+```js
+try {
+ const {action, year, month, day} = await DatePickerAndroid.open({
+ // 要设置默认值为今天的话,使用`new Date()`即可。
+ // 下面显示的会是2020年5月25日。月份是从0开始算的。
+ date: new Date(2020, 4, 25)
+ });
+ if (action !== DatePickerAndroid.dismissedAction) {
+ // 这里开始可以处理用户选好的年月日三个参数:year, month (0-11), day
+ }
+} catch ({code, message}) {
+ console.warn('Cannot open date picker', message);
+}
+```
+
+### 方法
+
+
+
static open(options: Object) #
+
+
打开一个标准的Android日期选择器的对话框。
+
可选的options对象的key值如下:
+
+ date (Date对象或毫秒时间戳) - 默认显示的日期
+ minDate (Date对象或毫秒时间戳) - 可选的最小日期
+ maxDate (Date对象或毫秒时间戳) - 可选的最大日期
+ mode ((enum('calendar', 'spinner', 'default')) - 设置选择器的模式:
+
+ calendar: Show a date picker in calendar mode.
+ spinner: Show a date picker in spinner mode.
+ default: Show a default native date picker(spinner/calendar) based on android versions.
+
+
+
+ 在用户选好日期后返回一个Promise,回调参数为一个对象,其中包含有action, year,
+ month (0-11),
+ day。如果用户取消了对话框,Promise仍然会执行,返回的action为DatePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必 先检查action的值。
+
+
+
static dateSetAction() #
+
+
+
+
static dismissedAction() #
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/datepickerios.md b/docs/docs/0.41/datepickerios.md
new file mode 100644
index 0000000..7621d1f
--- /dev/null
+++ b/docs/docs/0.41/datepickerios.md
@@ -0,0 +1,217 @@
+使用`DatePickerIOS`来在iOS平台上渲染一个日期/时间选择器。这是一个受约束的(Controlled)组件,所以你必须监听`onDateChange`回调函数并且及时更新`date`属性来使得组件更新,否则用户的修改会立刻被撤销来确保当前显示值和`props.date`一致。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
maximumDate Date #
+
+
可选的最大日期。
+
限制可选的日期/时间范围。
+
+
+
+
minimumDate Date #
+
+
可选的最小日期。
+
限制可选的日期/时间范围。
+
+
+
+
minuteInterval enum(1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30) #
+
+
+
+
mode enum('date', 'time', 'datetime') #
+
+
+
+
onDateChange function #
+
+
当用户修改日期或时间时调用此回调函数。
+
唯一的参数是一个日期对象,表示新的日期和时间。
+
+
+
+
timeZoneOffsetInMinutes number #
+
+
时区差,单位是分钟。
+
默认情况下,选择器会选择设备的默认时区。通过此参数,可以指定一个时区。举个例子,要使用北京时间(东八区),可以传递8 * 60。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ DatePickerIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ View,
+} = ReactNative;
+
+var DatePickerExample = React.createClass({
+ getDefaultProps: function () {
+ return {
+ date: new Date(),
+ timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ date: this.props.date,
+ timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
+ };
+ },
+
+ onDateChange: function(date) {
+ this.setState({date: date});
+ },
+
+ onTimezoneChange: function(event) {
+ var offset = parseInt(event.nativeEvent.text, 10);
+ if (isNaN(offset)) {
+ return;
+ }
+ this.setState({timeZoneOffsetInHours: offset});
+ },
+
+ render: function() {
+ // Ideally, the timezone input would be a picker rather than a
+ // text input, but we don't have any pickers yet :(
+ return (
+
+
+ {
+ this.state.date.toLocaleDateString() +
+ ' ' +
+ this.state.date.toLocaleTimeString()
+ }
+
+
+
+ hours from UTC
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+var WithLabel = React.createClass({
+ render: function() {
+ return (
+
+
+
+ {this.props.label}
+
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var Heading = React.createClass({
+ render: function() {
+ return (
+
+
+ {this.props.label}
+
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Select dates and times using the native UIDatePicker.';
+exports.examples = [
+{
+ title: '',
+ render: function(): ReactElement {
+ return ;
+ },
+}];
+
+var styles = StyleSheet.create({
+ textinput: {
+ height: 26,
+ width: 50,
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ padding: 4,
+ fontSize: 13,
+ },
+ labelContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginVertical: 2,
+ },
+ labelView: {
+ marginRight: 10,
+ paddingVertical: 2,
+ },
+ label: {
+ fontWeight: '500',
+ },
+ headingContainer: {
+ padding: 4,
+ backgroundColor: '#f6f7f8',
+ },
+ heading: {
+ fontWeight: '500',
+ fontSize: 14,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/debugging.md b/docs/docs/0.41/debugging.md
new file mode 100644
index 0000000..1c6cc0a
--- /dev/null
+++ b/docs/docs/0.41/debugging.md
@@ -0,0 +1,140 @@
+## 访问App内的开发菜单
+
+你可以通过摇晃设备或是选择iOS模拟器的"Hardware"菜单中的"Shake Gesture"选项来打开开发菜单。另外,如果是在iOS模拟器中运行,还可以按下**`Command`**`⌘` + **`D`** 快捷键,Android模拟器对应的则是**`Command`**`⌘` + **`M`**(windows上可能是F1或者F2)。
+
+
+
+> 注意:在成品(release/producation builds)中开发者菜单会被关闭。
+
+## 刷新JavaScript
+
+传统的原生应用开发中,每一次修改都需要重新编译,但在RN中你只需要刷新一下JavaScript代码,就能立刻看到变化。具体的操作就是在开发菜单中点击"Reload"选项。也可以在iOS模拟器中按下**`Command`**`⌘` + **`R`** ,Android模拟器上对应的则是按两下**`R`**。(注意,某些RN版本可能在windows中reload无效,请等待官方修复)
+
+> 如果在iOS模拟器中按下**`Command`**`⌘` + **`R`**没啥感觉,则注意检查Hardware菜单中,Keyboard选项下的"Connect Hardware Keyboard"是否被选中。
+
+### 自动刷新
+
+选择开发菜单中的"Enable Live Reload"可以开启自动刷新,这样可以节省你开发中的时间。
+
+更神奇的是,你还可以保持应用的当前运行状态,修改后的JavaScript文件会自动注入进来(就好比行驶中的汽车不用停下就能更换新的轮胎)。要实现这一特性只需开启开发菜单中的[Hot Reloading](https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html)选项。
+
+> 某些情况下hot reload并不能顺利实施。如果碰到任何界面刷新上的问题,请尝试手动完全刷新。
+
+但有些时候你必须要重新编译应用才能使修改生效:
+
+* 增加了新的资源(比如给iOS的`Images.xcassets`或是Andorid的`res/drawable`文件夹添加了图片)
+* 更改了任何的原生代码(objective-c/swift/java)
+
+## 应用内的错误与警告提示(红屏和黄屏)
+
+红屏或黄屏提示都只会在开发版本中显示,正式的离线包中是不会显示的。
+
+### 红屏错误
+
+应用内的报错会以全屏红色显示在应用中(调试模式下),我们称为红屏(red box)报错。你可以使用`console.error()`来手动触发红屏错误。
+
+### 黄屏警告
+
+应用内的警告会以全屏黄色显示在应用中(调试模式下),我们称为黄屏(yellow box)报错。点击警告可以查看详情或是忽略掉。
+和红屏报警类似,你可以使用`console.warn()`来手动触发黄屏警告。
+在默认情况下,开发模式中启用了黄屏警告。可以通过以下代码关闭:
+```js
+console.disableYellowBox = true;
+console.warn('YellowBox is disabled.');
+```
+你也可以通过代码屏蔽指定的警告,像下面这样设置一个数组:
+```js
+console.ignoredYellowBox = ['Warning: ...'];
+```
+数组中的字符串就是要屏蔽的警告的开头的内容。(例如上面的代码会屏蔽掉所有以Warning开头的警告内容)
+
+> 红屏和黄屏在发布版(release/production)中都是自动禁用的。
+
+## 访问控制台日志
+
+在运行RN应用时,可以在终端中运行如下命令来查看控制台的日志:
+
+```
+$ react-native log-ios
+$ react-native log-android
+```
+
+此外,你也可以在iOS模拟器的菜单中选择`Debug → Open System Log...`来查看。如果是Android应用,无论是运行在模拟器或是真机上,都可以通过在终端命令行里运行`adb logcat *:S ReactNative:V ReactNativeJS:V`命令来查看。
+
+## Chrome开发者工具
+
+在开发者菜单中选择"Debug JS Remotely"选项,即可以开始在Chrome中调试JavaScript代码。点击这个选项的同时会自动打开调试页面 .
+
+在Chrome的菜单中选择`Tools → Developer Tools`可以打开开发者工具,也可以通过键盘快捷键来打开(Mac上是**`Command`**`⌘` + **`Option`**`⌥` + **`I`**,Windows上是**`Ctrl`** + **`Shift`** + **`I`**或是F12)。打开[有异常时暂停(Pause On Caught Exceptions)](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511)选项,能够获得更好的开发体验。
+
+__译注__:Chrome中并不能直接看到App的用户界面,而只能提供console的输出,以及在sources项中断点调试js脚本。
+
+> [目前无法正常使用React开发插件](https://github.com/facebook/react-devtools/issues/229)(就是某些教程或截图上提到的Chrome开发工具上多出来的React选项),但这并不影响代码的调试。如果你需要像调试web页面那样查看RN应用的jsx结构,暂时只能使用Nuclide的"React Native Inspector"这一功能来代替。
+
+### 使用Chrome开发者工具来在设备上调试
+
+对于iOS真机来说,需要打开 [`RCTWebSocketExecutor.m`](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m)文件,然后将其中的"localhost"改为你的电脑的IP地址,最后启用开发者菜单中的"Debug JS Remotely"选项。
+
+对于Android 5.0+设备(包括模拟器)来说,将设备通过USB连接到电脑上后,可以使用[`adb`命令行工具](http://developer.android.com/tools/help/adb.html)来设定从设备到电脑的端口转发:
+
+`adb reverse tcp:8081 tcp:8081`
+
+如果设备Android版本在5.0以下,则可以在开发者菜单中选择"Dev Settings - Debug server host for device",然后在其中填入电脑的”IP地址:端口“。
+
+> 如果在Chrome调试时遇到一些问题,那有可能是某些Chrome的插件引起的。试着禁用所有的插件,然后逐个启用,以确定是否某个插件影响到了调试。
+
+### 使用自定义的JavaScript调试器来调试
+
+如果想用其他的JavaScript调试器来代替Chrome,可以设置一个名为`REACT_DEBUGGER`的环境变量,其值为启动自定义调试器的命令。调试的流程依然是从开发者菜单中的"Debug JS Remotely"选项开始。
+
+被指定的调试器需要知道项目所在的目录(可以一次传递多个目录参数,以空格隔开)。例如,如果你设定了`REACT_DEBUGGER="node /某个路径/launchDebugger.js --port 2345 --type ReactNative"`,那么启动调试器的命令就应该是`node /某个路径/launchDebugger.js --port 2345 --type ReactNative /某个路径/你的RN项目目录`。
+
+> 以这种方式执行的调试器最好是一个短进程(short-lived processes),同时最好也不要有超过200k的文字输出。
+
+### 在Android上使用[Stetho](http://facebook.github.io/stetho/)来调试
+
+1. 在```android/app/build.gradle```文件中添加:
+
+ ```gradle
+ compile 'com.facebook.stetho:stetho:1.3.1'
+ compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
+ ```
+
+2. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+
+ ```java
+ import com.facebook.react.modules.network.ReactCookieJarContainer;
+ import com.facebook.stetho.Stetho;
+ import okhttp3.OkHttpClient;
+ import com.facebook.react.modules.network.OkHttpClientProvider;
+ import com.facebook.stetho.okhttp3.StethoInterceptor;
+ import java.util.concurrent.TimeUnit;
+ ```
+
+3. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+ ```java
+ public void onCreate() {
+ super.onCreate();
+ Stetho.initializeWithDefaults(this);
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(0, TimeUnit.MILLISECONDS)
+ .readTimeout(0, TimeUnit.MILLISECONDS)
+ .writeTimeout(0, TimeUnit.MILLISECONDS)
+ .cookieJar(new ReactCookieJarContainer())
+ .addNetworkInterceptor(new StethoInterceptor())
+ .build();
+ OkHttpClientProvider.replaceOkHttpClient(client);
+ }
+ ```
+
+4. 运行```react-native run-android ```
+
+5. 打开一个新的Chrome选项卡,在地址栏中输入```chrome://inspect```并回车。在页面中选择'Inspect device' (标有"Powered by Stetho"字样)。
+
+## 调试原生代码
+
+在和原生代码打交道时(比如编写原生模块),可以直接从Android Studio或是Xcode中启动应用,并利用这些IDE的内置功能来调试(比如设置断点)。这一方面和开发原生应用并无二致。
+
+## 性能监测
+
+你可以在开发者菜单中选择"Pref Monitor"选项以开启一个悬浮层,其中会显示应用的当前帧数。
diff --git a/docs/docs/0.41/dimensions.md b/docs/docs/0.41/dimensions.md
new file mode 100644
index 0000000..b427a50
--- /dev/null
+++ b/docs/docs/0.41/dimensions.md
@@ -0,0 +1,23 @@
+__译注__:本模块用于获取设备屏幕的宽高。
+
+### 方法
+
+
+
+
static set(dims: {[key:string]: any}) #
+
+
这个函数只应该被原生代码调用。.
+
@param {object} dims 一个简单的字符串作为key的对象,包含了需要设置的尺寸信息。
+
+
+
+
static get(dim: string) #
+
+
初始的尺寸信息应该在runApplication之后被执行,所以它可以在任何其他的require被执行之前就可用。不过在稍后可能还会更新。
+
注意:尽管尺寸信息立即就可用,但它可能会在将来被修改(譬如设备的方向改变),所以基于这些常量的渲染逻辑和样式应当每次render之后都调用此函数,而不是将对应的值保存下来。(举例来说,你可能需要使用内联的样式而不是在StyleSheet中保存相应的尺寸)。
+
例子:var {height, width} = Dimensions.get('window');
+
@param {string} dim 想要获取的尺寸信息的字段名。
+
@returns {Object?} 返回的尺寸信息值。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/direct-manipulation.md b/docs/docs/0.41/direct-manipulation.md
new file mode 100644
index 0000000..f0b4b66
--- /dev/null
+++ b/docs/docs/0.41/direct-manipulation.md
@@ -0,0 +1,117 @@
+有时候我们需要直接改动组件并触发局部的刷新,但不使用state或是props。譬如在浏览器中使用React库,有时候会需要直接修改一个DOM节点,而在手机App中操作View时也会碰到同样的情况。在React Native中,`setNativeProps`就是等价于直接操作DOM节点的方法。
+
+> 什么时候使用setNativeProps呢?在(不得不)频繁刷新而又遇到了性能瓶颈的时候。
+>
+> 直接操作组件并不是应该经常使用的工具。一般来说只是用来创建连续的动画,同时避免渲染组件结构和同步太多视图变化所带来的大量开销。`setNativeProps`是一个“简单粗暴”的方法,它直接在底层(DOM、UIView等)而不是React组件中记录state,这样会使代码逻辑难以理清。所以在使用这个方法之前,请尽量先尝试用`setState`和[shouldComponentUpdate](http://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action)方法来解决问题。
+
+## setNativeProps与TouchableOpacity
+
+[TouchableOpacity](https://github.com/facebook/react-native/blob/master/Libraries/Components/Touchable/TouchableOpacity.js)这个组件就在内部使用了`setNativeProps`方法来更新其子组件的透明度:
+
+```javascript
+setOpacityTo: function(value) {
+ // Redacted: animation related code
+ this.refs[CHILD_REF].setNativeProps({
+ opacity: value
+ });
+},
+```
+
+由此我们可以写出下面这样的代码:子组件可以响应点击事件,更改自己的透明度。而子组件自身并不需要处理这件事情,也不需要在实现中做任何修改。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+如果不使用`setNativeProps`这个方法来实现这一需求,那么一种可能的办法是把透明值保存到state中,然后在`onPress`事件触发时更新这个值:
+
+```javascript
+getInitialState() {
+ return { myButtonOpacity: 1, }
+},
+
+render() {
+ return (
+ this.setState({myButtonOpacity: 0.5})}
+ onPressOut={() => this.setState({myButtonOpacity: 1})}>
+
+ Press me!
+
+
+ )
+}
+```
+
+比起之前的例子,这一做法会消耗大量的计算 —— 每一次透明值变更的时候React都要重新渲染组件结构,即便视图的其他属性和子组件并没有变化。一般来说这一开销也不足为虑,但当执行连续的动画以及响应用户手势的时候,只有正确地优化组件才能提高动画的流畅度。
+
+如果你看过[NativeMethodsMixin.js]()中的`setNativeProps`方法的实现,你就会发现它实际是对`RCTUIManager.updateView`的封装 —— 而这正是重渲染所触发的函数调用,具体可以参看[ReactNativeBaseComponent.js中的receiveComponent]().
+
+## 复合组件与setNativeProps
+
+复合组件并不是单纯的由一个原生视图构成,所以你不能对其直接使用`setNativeProps`。比如下面这个例子:
+
+```javascript
+var MyButton = React.createClass({
+ render() {
+ return (
+
+ {this.props.label}
+
+ )
+ },
+});
+
+var App = React.createClass({
+ render() {
+ return (
+
+
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/JXkgmQ)
+
+跑这个例子会马上看到一行报错: `Touchable child
+must either be native or forward setNativeProps to a native component`.
+这是因为`MyButton`并非直接由原生视图构成,而我们只能给原生视图设置透明值。你可以尝试这样去理解:如果你通过`React.createClass`方法自定义了一个组件,直接给它设置样式prop是不会生效的,你得把样式props层层向下传递给子组件,直到子组件是一个能够直接定义样式的原生组件。同理,我们也需要把`setNativeProps`传递给由原生组件封装的子组件。
+
+#### 将setNativeProps传递给子组件
+
+具体要做的就是在我们的自定义组件中再封装一个`setNativeProps`方法,其内容为对合适的子组件调用真正的`setNativeProps`方法,并传递要设置的参数。
+
+```javascript
+var MyButton = React.createClass({
+ setNativeProps(nativeProps) {
+ this._root.setNativeProps(nativeProps);
+ },
+
+ render() {
+ return (
+ this._root = component} {...this.props}>
+ {this.props.label}
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/YJxnEQ)
+
+现在你可以在`TouchableOpacity`中嵌入`MyButton`了!有一点需要特别说明:这里我们使用了[ref回调](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute)语法,而不是传统的字符串型ref引用。
+
+你可能还会注意到我们在向下传递props时使用了`{...this.props}`语法(这一用法的说明请参考[对象的扩展运算符](http://es6.ruanyifeng.com/#docs/object))。这是因为`TouchableOpacity`本身其实也是个复合组件, 它除了要求在子组件上执行`setNativeProps` 以外,还要求子组件对触摸事件进行处理。因此,它会传递多个props,其中包含了[onmoveshouldsetresponder](view.html#onmoveshouldsetresponder) 函数,这个函数需要回调给`TouchableOpacity`组件,以完成触摸事件的处理。与之相对的是`TouchableHighlight`组件,它本身是由原生视图构成,因而只需要我们实现`setNativeProps`。
+
+## 避免和render方法的冲突
+
+如果要更新一个由render方法来维护的属性,则可能会碰到一些出人意料的bug。因为每一次组件重新渲染都可能引起属性变化,这样一来,之前通过`setNativeProps`所设定的值就被完全忽略和覆盖掉了。[这个例子(可能需要科学上网)](https://rnplay.org/apps/bp1DvQ)
+演示了两者冲突时的情形 —— 注意看由于`setState`触发的重新渲染(每250ms)导致的动画卡顿。
+
+## setNativeProps与shouldComponentUpdate
+
+通过[巧妙运用
+`shouldComponentUpdate`方法](https://facebook.github.io/react/docs/advanced-performance.html#avoiding-reconciling-the-dom),可以避免重新渲染那些实际没有变化的子组件所带来的额外开销,此时使用`setState`的性能已经可以与`setNativeProps`相媲美了。
diff --git a/docs/docs/0.41/drawerlayoutandroid.md b/docs/docs/0.41/drawerlayoutandroid.md
new file mode 100644
index 0000000..3c81143
--- /dev/null
+++ b/docs/docs/0.41/drawerlayoutandroid.md
@@ -0,0 +1,108 @@
+封装了平台`DrawerLayout`(仅限安卓平台)的React组件。抽屉(通常用于导航切换)是通过`renderNavigationView`方法渲染的,并且DrawerLayoutAndroid的直接子视图会成为主视图(用于放置你的内容)。导航视图一开始在屏幕上并不可见,不过可以从`drawerPosition`指定的窗口侧面拖拽出来,并且抽屉的宽度可以使用`drawerWidth`属性来指定。
+
+### 截图
+
+
+### 例子
+
+```javascript
+render: function() {
+ var navigationView = (
+
+ I'm in the Drawer!
+
+ );
+ return (
+ navigationView}>
+
+ Hello
+ World!
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
drawerLockMode enum('unlocked', 'locked-closed', 'locked-open')
+ #
+
+
+
设置抽屉的锁定模式。有三种状态:
+
+ unlocked (默认值),意味着此时抽屉可以响应打开和关闭的手势操作。
+ locked-closed,意味着此时抽屉将保持关闭,不可用手势打开。
+ locked-open,意味着此时抽屉将保持打开,不可用手势关闭。
+
+ 无论抽屉处于那种状态,都仍然可以调用
openDrawer/
closeDrawer这两个方法打开和关闭。
+
+
+
+
+
+
drawerPosition enum(DrawerConsts.DrawerPosition.Left, DrawerConsts.DrawerPosition.Right) #
+
+
+
+
drawerWidth number #
+
+
指定抽屉的宽度,也就是从屏幕边缘拖进的视图的宽度。
+
+
+
+
keyboardDismissMode enum('none', "on-drag") #
+
+
指定在拖拽的过程中是否要隐藏软键盘。
+
+ none (默认值),拖拽不会隐藏软键盘。
+ on-drag 当拖拽开始的时候隐藏软键盘。
+
+
+
+
+
onDrawerClose function #
+
+
每当导航视图(抽屉)被关闭之后调用此回调函数。
+
+
+
+
onDrawerOpen function #
+
+
每当导航视图(抽屉)被打开之后调用此回调函数。
+
+
+
+
onDrawerSlide function #
+
+
每当导航视图(抽屉)产生交互的时候调用此回调函数。
+
+
+
+
onDrawerStateChanged function #
+
+
每当抽屉的状态变化时调用此回调函数。抽屉可以有3种状态:
+
+ idle(空闲),表示现在导航条上没有任何正在进行的交互。
+ dragging(拖拽中),表示用户正在与导航条进行交互。
+ settling(停靠中),表示用户刚刚结束与导航条的交互,导航条正在结束打开或者关闭的动画。
+
+
+
+
+
renderNavigationView function #
+
+
此方法用于渲染一个可以从屏幕一边拖入的导航视图。
+
+
+
diff --git a/docs/docs/0.41/easing.md b/docs/docs/0.41/easing.md
new file mode 100644
index 0000000..5a48b93
--- /dev/null
+++ b/docs/docs/0.41/easing.md
@@ -0,0 +1,63 @@
+This class implements common easing functions. The math is pretty obscure, but this cool website has nice visual illustrations of what they represent:
+
+### 方法
+
+
+
+
+
+
+
+
+
+
+
+
+
static elastic(bounciness) #
+
+
A simple elastic interaction, similar to a spring. Default bounciness
+ is 1, which overshoots a little bit once. 0 bounciness doesn't overshoot
+ at all, and bounciness of N > 1 will overshoot about N times.
+
Wolfram Plots:
+
http://tiny.cc/elastic_b_1 (default bounciness = 1)
+ http://tiny.cc/elastic_b_3 (bounciness = 3)
+
+
+
+
static bezier(x1, y1, x2, y2) #
+
+
+
static out(easing) #
+
Runs an easing function backwards.
+
+
static inOut(easing) #
+
Makes any easing function symmetrical.
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/geolocation.md b/docs/docs/0.41/geolocation.md
new file mode 100644
index 0000000..2cbee51
--- /dev/null
+++ b/docs/docs/0.41/geolocation.md
@@ -0,0 +1,111 @@
+定位API遵循[web标准](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation)。
+
+## iOS
+你需要在Info.plist中增加`NSLocationWhenInUseUsageDescription`字段来启用定位功能。如果你使用`react-native init`创建项目,定位会被默认启用。
+
+## Android
+要请求访问地理位置的权限,你需要在`AndroidManifest.xml`文件中加入如下一行:
+
+` `
+
+## 方法
+
+
static getCurrentPosition(geo_success: Function, geo_error?: Function, geo_options?: GeoOptions) #
+
成功时会调用geo_success回调,参数中包含最新的位置信息。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static watchPosition(success: Function, error?: Function, options?: GeoOptions)
+ #
+
持续监听位置,每当位置变化之后都调用success回调。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static clearWatch(watchID: number) #
+
static stopObserving() #
+
+
+
+## 例子
+
+```javascript
+/* eslint no-console: 0 */
+'use strict';
+
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Geolocation';
+exports.description = 'Examples of using the Geolocation API.';
+
+exports.examples = [
+ {
+ title: 'navigator.geolocation',
+ render: function(): ReactElement {
+ return ;
+ },
+ }
+];
+
+var GeolocationExample = React.createClass({
+ watchID: (null: ?number),
+
+ getInitialState: function() {
+ return {
+ initialPosition: 'unknown',
+ lastPosition: 'unknown',
+ };
+ },
+
+ componentDidMount: function() {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ var initialPosition = JSON.stringify(position);
+ this.setState({initialPosition});
+ },
+ (error) => alert(error.message),
+ {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
+ );
+ this.watchID = navigator.geolocation.watchPosition((position) => {
+ var lastPosition = JSON.stringify(position);
+ this.setState({lastPosition});
+ });
+ },
+
+ componentWillUnmount: function() {
+ navigator.geolocation.clearWatch(this.watchID);
+ },
+
+ render: function() {
+ return (
+
+
+ Initial position:
+ {this.state.initialPosition}
+
+
+ Current position:
+ {this.state.lastPosition}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: '500',
+ },
+});
+```
+
diff --git a/docs/docs/0.41/gesture-responder-system.md b/docs/docs/0.41/gesture-responder-system.md
new file mode 100644
index 0000000..7314e0c
--- /dev/null
+++ b/docs/docs/0.41/gesture-responder-system.md
@@ -0,0 +1,62 @@
+移动设备上的手势识别要比在web上复杂得多。用户的一次触摸操作的真实意图是什么,App要经过好几个阶段才能判断。比如App需要判断用户的触摸到底是在滚动页面,还是滑动一个widget,或者只是一个单纯的点击。甚至随着持续时间的不同,这些操作还会转化。此外,还有多点同时触控的情况。
+
+触摸响应系统可以使组件在不关心父组件或子组件的前提下自行处理触摸交互。具体的实现在`ResponderEventPlugin.js`文件中,你可以在源码中读到更多细节和文档。
+
+### 最佳实践
+
+用户之所以会觉得web app和原生app在体验上有巨大的差异,触摸响应是一大关键因素。用户的每一个操作都应该具有下列属性:
+
+- 反馈/高亮 —— 让用户看到他们到底按到了什么东西,以及松开手后会发生什么。
+- 取消功能 —— 当用户正在触摸操作时,应该是可以通过把手指移开来终止操作。
+
+这些特性使得用户在使用App时体验更好,因为它们可以让用户大胆试用,而不必担心点错了什么。
+
+### TouchableHighlight与Touchable系列组件
+
+响应系统用起来可能比较复杂。所以我们提供了一个抽象的`Touchable`实现,用来做“可触控”的组件。这一实现利用了响应系统,使得你可以简单地以声明的方式来配置触控处理。如果要做一个按钮或者网页链接,那么使用`TouchableHighlight`就可以。
+
+
+## 响应者的生命周期
+
+一个View只要实现了正确的协商方法,就可以成为触摸事件的响应者。我们通过两个方法去“询问”一个View是否愿意成为响应者:
+
+ - `View.props.onStartShouldSetResponder: (evt) => true,` - 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
+ - `View.props.onMoveShouldSetResponder: (evt) => true,` - 如果View不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?
+
+如果View返回true,并开始尝试成为响应者,那么会触发下列事件之一:
+
+ - `View.props.onResponderGrant: (evt) => {}` - View现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里。
+ - `View.props.onResponderReject: (evt) => {}` - 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。
+
+如果View已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:
+
+ - `View.props.onResponderMove: (evt) => {}` - 用户正在屏幕上移动手指时(没有停下也没有离开屏幕)。
+ - `View.props.onResponderRelease: (evt) => {}` - 触摸操作结束时触发,比如"touchUp"(手指抬起离开屏幕)。
+ - `View.props.onResponderTerminationRequest: (evt) => true` - 有其他组件请求接替响应者,当前的View是否“放权”?返回true的话则释放响应者权力。
+ - `View.props.onResponderTerminate: (evt) => {}` - 响应者权力已经交出。这可能是由于其他View通过`onResponderTerminationRequest`请求的,也可能是由操作系统强制夺权(比如iOS上的控制中心或是通知中心)。
+
+`evt`是一个合成事件,它包含以下结构:
+
+ - `nativeEvent`
+ + `changedTouches` - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
+ + `identifier` - 触摸点的ID
+ + `locationX` - 触摸点相对于父元素的横坐标
+ + `locationY` - 触摸点相对于父元素的纵坐标
+ + `pageX` - 触摸点相对于根元素的横坐标
+ + `pageY` - 触摸点相对于根元素的纵坐标
+ + `target` - 触摸点所在的元素ID
+ + `timestamp` - 触摸事件的时间戳,可用于移动速度的计算
+ + `touches` - 当前屏幕上的所有触摸点的集合
+
+### 捕获ShouldSet事件处理
+
+`onStartShouldSetResponder`与`onMoveShouldSetResponder`是以冒泡的形式调用的,即嵌套最深的节点最先调用。这意味着当多个View同时在`*ShouldSetResponder`中返回true时,最底层的View将优先“夺权”。在多数情况下这并没有什么问题,因为这样可以确保所有控件和按钮是可用的。
+
+但是有些时候,某个父View会希望能先成为响应者。我们可以利用“捕获期”来解决这一需求。响应系统在从最底层的组件开始冒泡之前,会首先执行一个“捕获期”,在此期间会触发`on*ShouldSetResponderCapture`系列事件。因此,如果某个父View想要在触摸操作开始时阻止子组件成为响应者,那就应该处理`onStartShouldSetResponderCapture`事件并返回true值。
+
+ - `View.props.onStartShouldSetResponderCapture: (evt) => true,`
+ - `View.props.onMoveShouldSetResponderCapture: (evt) => true,`
+
+### PanResponder
+
+要使用更高级的手势功能,请参看[PanResponder](panresponder.html).
diff --git a/docs/docs/0.41/getting-started.md b/docs/docs/0.41/getting-started.md
new file mode 100644
index 0000000..05237b3
--- /dev/null
+++ b/docs/docs/0.41/getting-started.md
@@ -0,0 +1,765 @@
+欢迎使用React Native!这篇文档会帮助你搭建基本的React Native开发环境。如果你已经搭好了环境,那么可以尝试一下[编写Hello World](tutorial.html)。
+
+根据你所使用的操作系统、针对的目标平台不同,具体步骤有所不同。如果想同时开发iOS和Android也没问题,你只需要先选一个平台开始,另一个平台的环境搭建只是稍有不同。
+
+
+
+译注:如果`阅读完本文档`后还碰到很多环境搭建的问题,我们建议你还可以再看看由本站提供的[环境搭建视频教程](http://v.youku.com/v_show/id_XMTQ4OTYyMjg4MA==.html)、[windows环境搭建文字教程](http://bbs.reactnative.cn/topic/10)、以及[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+
+## 暂不支持
+
+苹果公司目前只允许在Mac电脑上开发iOS应用。如果你没有Mac电脑,那么只能考虑先开发Android应用了。
+
+
+
+
+
+
+
+
+## 安装
+
+### 必需的软件
+
+#### Homebrew
+
+[Homebrew](http://brew.sh/), Mac系统的包管理器,用于安装NodeJS和一些其他必需的工具软件。
+
+```
+/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+
+译注:在Max OS X 10.11(El Capitan)版本中,homebrew在安装软件时可能会碰到`/usr/local`目录不可写的权限问题。可以使用下面的命令修复:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+#### Node
+
+使用Homebrew来安装[Node.js](https://nodejs.org/).
+
+> React Native目前需要NodeJS 5.0或更高版本。本文发布时Homebrew默认安装的是最新版本,一般都满足要求。
+
+```
+brew install node
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+
+如果你看到`EACCES: permission denied`这样的权限报错,那么请参照上文的homebrew译注,修复`/usr/local`目录的所有权:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+
+
+#### Xcode
+
+React Native目前需要[Xcode](https://developer.apple.com/xcode/downloads/) 8.0 或更高版本。你可以通过App Store或是到[Apple开发者官网](https://developer.apple.com/xcode/downloads/)上下载。这一步骤会同时安装Xcode IDE和Xcode的命令行工具。
+
+> 虽然一般来说命令行工具都是默认安装了,但你最好还是启动Xcode,并在`Xcode | Preferences | Locations`菜单中检查一下是否装有某个版本的`Command Line Tools`。Xcode的命令行工具中也包含一些必须的工具,比如`git`等。
+
+
+
+#### Android Studio
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 勾选`Performance`和`Android Virtual Device`
+
+
+
+- 安装完成后,在Android Studio的启动欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom System Image`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。具体的做法是把下面的命令加入到`~/.bash_profile`文件中:(__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这个文件有可能并不存在。请在终端下使用`vi ~/.bash_profile`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ~/.bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+
+### 推荐安装的工具
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+```
+brew install watchman
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+
+```
+brew install flow
+```
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。具体做法仍然是在`~/.bash_profile`中添加:
+
+```
+export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
+```
+
+### 其他可选的安装项
+
+#### Git
+
+Git版本控制。如果你已经安装过[Xcode](https://developer.apple.com/xcode/),则Git也已经一并安装了。如若没有,则使用下列命令安装:
+
+```
+brew install git
+```
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下⌘+M来打开开发者菜单。
+
+
+
+
+## 安装
+
+### 必需的软件
+
+
+
+#### Chocolatey
+
+[Chocolatey](https://chocolatey.org)是一个Windows上的包管理器,类似于linux上的`yum`和
+`apt-get`。 你可以在其[官方网站](https://chocolatey.org)上查看具体的使用说明。一般的安装步骤应该是下面这样:
+
+```
+@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
+```
+
+> 一般来说,使用Chocolatey来安装软件的时候,需要以管理员的身份来运行命令提示符窗口。译注:chocolatey的网站可能在国内访问困难,导致上述安装命令无法正常完成。请使用稳定的翻墙工具。
+> 如果你实在装不上这个工具,也不要紧。下面所需的python2和nodejs你可以分别单独去对应的官方网站下载安装即可。
+
+#### Python 2
+
+打开命令提示符窗口,使用Chocolatey来安装Python 2.
+
+> 注意目前不支持Python 3版本。
+
+```
+choco install python2
+```
+
+
+
+#### Node
+
+
+
+打开终端窗口,输入下面的命令来安装NodeJS:
+
+```
+sudo apt-get install -y build-essential
+curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -
+sudo apt-get install -y nodejs
+sudo ln -s /usr/bin/nodejs /usr/bin/node
+```
+
+
+
+
+打开命令提示符窗口,使用Chocolatey来安装NodeJS。注意,目前已知Node 7.1版本在windows上无法正常工作,请避开这个版本!
+
+```
+choco install nodejs.install
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+> 如果你遇到`EACCES: permission denied`权限错误,可以尝试运行下面的命令(限linux系统):
+> `sudo npm install -g yarn react-native-cli`.
+
+#### Android Studio
+
+[Android Studio](http://developer.android.com/sdk/index.html) 2.0 or higher.
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+> 或是使用包管理器来安装(比如`choco install jdk8`或是
+> `apt-get install default-jdk`)
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 选择`Android Virtual Device`
+
+
+
+
+
+- 确定所有安装都勾选了,尤其是`Android SDK`和`Android Device Emulator`。
+
+- 在初步安装完成后,选择`Custom`安装项:
+
+
+
+- 检查已安装的组件,尤其是模拟器和HAXM加速驱动。
+
+
+
+
+
+- 安装完成后,在Android Studio的欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom System Image`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+
+
+
+
+
+
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。
+
+
+
+具体的做法是把下面的命令加入到`~/.bashrc`、`~/.bash_profile`文件中。如果你使用的是其他的shell,则选择对应的配置文件:
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ./bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> `新建`
+
+> 具体的路径可能和下图不一致,请自行确认。
+
+
+
+> 你需要关闭现有的命令符提示窗口然后重新打开,这样新的环境变量才能生效。
+
+
+
+### 推荐安装的工具
+
+
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+> 安装watchman还可以避免node的一个与文件监视有关的bug。
+
+在终端中输入以下命令来编译并安装watchman:
+
+```
+git clone https://github.com/facebook/watchman.git
+cd watchman
+git checkout v4.5.0 # 这是本文发布时的最新版本
+./autogen.sh
+./configure
+make
+sudo make install
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+在终端中输入以下命令来安装flow:
+
+```
+npm install -g flow-bin
+```
+
+
+
+
+#### Gradle Daemon
+
+开启[Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)可以极大地提升java代码的增量编译速度。
+
+
+
+
+```
+touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties
+```
+
+
+
+
+```
+(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo org.gradle.daemon=true >> "%USERPROFILE%/.gradle/gradle.properties")
+```
+
+
+
+
+#### Android模拟器加速器
+
+在安装Android Studio时你可能会看到下面这样的提示:
+
+
+
+如果你的系统支持KVM,那就应该安装[Intel的Android模拟器加速器](https://software.intel.com/en-us/android/articles/speeding-up-the-android-emulator-on-intel-architecture#_Toc358213272)。
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。
+
+
+
+在`~/.bashrc`或是`~/.bash_profile`文件中添加:
+
+```
+# 你的具体路径可能有所不同,请自行确认。
+PATH="~/Android/Sdk/tools:~/Android/Sdk/platform-tools:${PATH}"
+export PATH
+```
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> 选中`PATH` -> 双击进行编辑
+
+> 注意你的具体路径可能和下图不同
+
+
+
+
+
+### 可选的安装项
+
+#### Git
+
+
+
+[使用包管理器](https://git-scm.com/download/linux)来安装Git
+(例如`sudo apt-get install git-all`).
+
+
+
+你可以使用Chocolatey来安装`git`:
+
+```
+choco install git
+```
+
+另外你也可以直接去下载[Git for Windows](https://git-for-windows.github.io/)。
+在安装过程中注意勾选"Run Git from Windows Command Prompt",这样才会把`git`命令添加到`PATH`环境变量中。
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下F1来打开开发者菜单。
+
+
+
+#### Visual Studio Emulator for Android
+
+[Visual Studio Emulator for Android](https://www.visualstudio.com/zh-cn/features/msft-android-emulator-vs.aspx#中国 (简体中文))是利用了Hyper-V技术进行硬件加速的免费android模拟器。也是Android Studio自带的原装模拟器之外的一个很好的选择。而且你并不需要安装Visual Studio。
+在用于React Native开发前,需要先在注册表中进行一些修改:
+
+1. 打开运行命令(按下Windows+R键)
+2. 输入`regedit.exe`然后回车
+3. 在注册表编辑器中找到`HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools`条目
+4. 右键点击`Android SDK Tools`,选择`新建 > 字符串值`
+5. 名称设为`Path`
+6. 双击`Path`,将其值设为你的Android SDK的路径。(例如`C:\Program Files\Android\sdk`)
+
+
+
+
+## 测试安装
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-ios
+```
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹
+然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line),或是双击`ios/AwesomeProject.xcodeproj`文件然后在Xcode中点击`Run`按钮。
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line)。
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+
+
+- 使用你喜欢的编辑器打开`index.ios.js`并随便改上几行。
+- 在iOS Emulator中按下`⌘-R`就可以刷新APP并看到你的最新修改!
+
+
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 测试安装
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+__Windows用户请注意,请不要在命令行默认的System32目录中init项目!会有各种权限限制导致不能运行!__
+
+
+### 手动运行Packager
+
+有个常见的问题是在你运行`react-native run-android`命令后,Packager可能不会自动运行。此时你可以手动启动它:
+
+```
+cd AwesomeProject
+react-native start
+```
+
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 接下来
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-ios.html#content)。
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+## 接下来
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
diff --git a/docs/docs/0.41/handling-text-input.md b/docs/docs/0.41/handling-text-input.md
new file mode 100644
index 0000000..52bb4eb
--- /dev/null
+++ b/docs/docs/0.41/handling-text-input.md
@@ -0,0 +1,39 @@
+[`TextInput`](textinput.html#content)是一个允许用户输入文本的基础组件。它有一个名为`onChangeText`的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为`onSubmitEditing`的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。
+
+假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。我们假设这另一种文字来自某个吃货星球,只有一个单词: 🍕。所以"Hello there Bob"将会被翻译为"🍕🍕🍕"。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, TextInput, View } from 'react-native';
+
+class PizzaTranslator extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+
+ render() {
+ return (
+
+ this.setState({text})}
+ />
+
+ {this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
+
+
+ );
+ }
+}
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('PizzaTranslator', () => PizzaTranslator);
+```
+
+在上面的例子里,我们把`text`保存到state中,因为它会随着时间变化。
+
+文本输入方面还有很多其他的东西要处理。比如你可能想要在用户输入的时候进行验证,在[React的表单组件中的受限组件](http://reactjs.cn/react/docs/forms.html)一节中有一些详细的示例(注意react中的onChange对应的是rn中的onChangeText)。此外你还需要看看[TextInput的文档](textinput.html)。
+
+TextInput可能是天然具有“动态状态”的最简单的组件了。下面我们来看看另一类控制布局的组件,先从[ScrollView开始学习](using-a-scrollview.html)。
diff --git a/docs/docs/0.41/handling-touches.md b/docs/docs/0.41/handling-touches.md
new file mode 100644
index 0000000..3808eae
--- /dev/null
+++ b/docs/docs/0.41/handling-touches.md
@@ -0,0 +1,57 @@
+移动应用上的用户交互基本靠“摸”。当然,“摸”也是有各种姿势的:在一个按钮上点击,在一个列表上滑动,或是在一个地图上缩放。
+
+React Native提供了可以处理常见触摸手势(例如点击或滑动)的组件, 以及可用于识别更复杂的手势的完整的[手势响应系统](gesturerespondersystem.html)。
+
+## 可点击的组件
+
+在需要捕捉用户点击操作时,可以使用"Touchable"开头的一系列组件。这些组件通过`onPress`属性接受一个点击事件的处理函数。当一个点击操作开始并且终止于本组件时(即在本组件上按下手指并且抬起手指时也没有移开到组件外),此函数会被调用。
+
+示例:
+
+```javascript
+class MyButton extends Component {
+ _onPressButton() {
+ console.log("You tapped the button!");
+ }
+
+ render() {
+ return (
+
+ Button
+
+ );
+ }
+}
+```
+
+可点击的组件需要给用户提供视觉反馈,例如是哪个组件正在响应用户的操作,以及当用户抬起手指后会发生什么。用户也应该可以通过把手指移到一边来取消点击操作。
+
+具体使用哪种组件,取决于你希望给用户什么样的视觉反馈:
+
+- 一般来说,你可以使用[**TouchableHighlight**](touchablehighlight.html)来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。
+
+- 在Android上还可以使用[**TouchableNativeFeedback**](touchablenativefeedback.html),它会在用户手指按下时形成类似墨水涟漪的视觉效果。
+
+- [**TouchableOpacity**](touchableopacity.html)会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
+
+- 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用[**TouchableWithoutFeedback**](touchablewithoutfeedback.html)。
+
+### 长按
+
+某些场景中你可能需要检测用户是否进行了长按操作。可以在上面列出的任意组件中使用`onLongPress`属性来实现。
+
+## 在列表中上下滑动和在视图上左右滑动
+
+可滚动的列表是移动应用中一个常见的模式。用户会在列表中或快或慢的各种滑动。[ScrollView](using-a-scrollView.html)组件可以满足这一需求。
+
+ScrollView可以在垂直或水平方向滚动,还可以配置`pagingEnabled`属性来让用户整屏整屏的滑动。此外,水平方向的滑动还可以使用Android上的[ViewPagerAndroid](viewpagerandroid.html) 组件。
+
+[ListView](using-a-listview.html)则是一种特殊的ScrollView,用于显示比较长的垂直列表。它还可以显示分区块的头部和尾部,类似iOS上的`UITableView`控件。
+
+### 双指缩放
+
+如果在ScrollView中只放置一个组件,则可以用来实现缩放操作。设置`maximumZoomScale`和`minimumZoomScale`属性即可以使用户能够缩放其中的内容。
+
+## 处理其他的手势
+
+如果你想实现视图的拖拽,或是实现自定义的手势,那么请参阅[PanResponder](panresponder.html) API或是[手势识别系统](gesture-responder-system.html)的文档。
diff --git a/docs/docs/0.41/headless-js-android.md b/docs/docs/0.41/headless-js-android.md
new file mode 100644
index 0000000..0cc71fd
--- /dev/null
+++ b/docs/docs/0.41/headless-js-android.md
@@ -0,0 +1,49 @@
+Headless JS是一种使用js在后台执行任务的方法。它可以用来在后台同步数据、处理推送通知或是播放音乐等等。
+
+## JS端的API
+
+首先我们要通过`AppRegistry`来注册一个async函数,这个函数我们称之为“任务”。注册方式类似在index.js中注册RN应用:
+
+```js
+AppRegistry.registerHeadlessTask('SomeTaskName', () => require('SomeTaskName'));
+```
+
+然后创建require对应的`SomeTaskName.js`文件:
+
+```js
+module.exports = async (taskData) => {
+ // 要做的事情
+}
+```
+
+你可以在任务中处理任何事情(网络请求、定时器等等),但唯独**不要涉及用户界面**!在任务完成后(例如在promise中调用resolve),RN会进入一个“暂停”模式,直到有新任务需要执行或者是应用回到前台。
+
+## Java端的API
+
+没错,我们还需要一些原生代码,但是请放心并不麻烦。你需要像下面这样继承`HeadlessJsTaskService`,然后覆盖`getTaskConfig`方法的实现:
+
+```java
+public class MyTaskService extends HeadlessJsTaskService {
+
+ @Override
+ protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ return new HeadlessJsTaskConfig(
+ "SomeTaskName",
+ Arguments.fromBundle(extras),
+ 5000);
+ }
+ return null;
+ }
+}
+```
+
+好了,现在当你[启动服务时][0](例如一个周期性的任务或是响应一些系统事件/广播),JS任务就会开始执行。
+
+## 注意事项
+
+* 默认情况下,如果应用正在前台运行时尝试执行任务,那么应用会崩溃。这是为了防止开发者在任务中处理太多逻辑而拖慢用户界面。
+* 如果你是通过`BroadcastReceiver`来启动的服务,那么谨记在从`onReceive()`返回之前要调用`HeadlessJsTaskService.acquireWakelockNow()`。
+
+[0]: https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)
\ No newline at end of file
diff --git a/docs/docs/0.41/height-and-width.md b/docs/docs/0.41/height-and-width.md
new file mode 100644
index 0000000..6431b24
--- /dev/null
+++ b/docs/docs/0.41/height-and-width.md
@@ -0,0 +1,56 @@
+组件的高度和宽度决定了其在屏幕上显示的尺寸。
+
+#### 指定宽高
+
+最简单的给组件设定尺寸的方式就是在样式中指定固定的`width`和`height`。React Native中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FixedDimensionsBasics extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+};
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
+```
+这样给组件设置尺寸也是一种常见的模式,比如要求在不同尺寸的屏幕上都显示成一样的大小。
+
+#### 弹性(Flex)宽高
+
+在组件样式中使用`flex`可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用`flex:1`来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了`flex:1`,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的`flex`值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间`flex`值的比)。
+
+> 组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的`width`和`height`,也没有设定`flex`,则父容器的尺寸为零。其子组件如果使用了`flex`,也是无法显示的。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDimensionsBasics extends Component {
+ render() {
+ return (
+ // 试试去掉父View中的`flex: 1`。
+ // 则父View不再具有尺寸,因此子组件也无法再撑开。
+ // 然后再用`height: 300`来代替父View的`flex: 1`试试看?
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
+```
+
+当你熟练掌握了如何控制组件的尺寸后,下一步可以[学习如何在屏幕上排列组件了](layout-with-flexbox.html)。
diff --git a/docs/docs/0.41/image.md b/docs/docs/0.41/image.md
new file mode 100644
index 0000000..41e501d
--- /dev/null
+++ b/docs/docs/0.41/image.md
@@ -0,0 +1,956 @@
+一个用于显示多种不同类型图片的React组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。详细用法参阅[图片文档](images.html)。
+
+用法样例:
+
+```javascript
+renderImages() {
+ return (
+
+
+
+
+ );
+}
+```
+
+### 截图
+
+
+### 在Android上支持GIF和WebP格式图片
+
+默认情况下Android是不支持GIF和WebP格式的。你需要在`android/app/build.gradle`文件中根据需要手动添加以下模块:
+
+```
+dependencies {
+ // 如果你需要支持Android4.0(API level 14)之前的版本
+ compile 'com.facebook.fresco:animated-base-support:0.11.0'
+
+ // 如果你需要支持GIF动图
+ compile 'com.facebook.fresco:animated-gif:0.11.0'
+
+ // 如果你需要支持WebP格式,包括WebP动图
+ compile 'com.facebook.fresco:animated-webp:0.11.0'
+ compile 'com.facebook.fresco:webpsupport:0.11.0'
+
+ // 如果只需要支持WebP格式而不需要动图
+ compile 'com.facebook.fresco:webpsupport:0.11.0'
+}
+```
+
+如果你在使用GIF的同时还使用了ProGuard,那么需要在`proguard-rules.pro`中添加如下规则 :
+
+```
+-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl {
+ public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory, com.facebook.imagepipeline.core.ExecutorSupplier);
+}
+```
+
+### 属性
+
+
+
+
onLayout function #
+
+
当元素挂载或者布局改变的时候调用,参数为:{nativeEvent: {layout: {x, y, width, height}}}.
+
+
+
+
+
onLoadEnd function #
+
+
加载结束后,不论成功还是失败,调用此回调函数。
+
+
+
+
onLoadStart function #
+
+
+
+
resizeMode enum('cover', 'contain', 'stretch', 'repeat', 'center') #
+
+
决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。
+
+ cover: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全覆盖甚至超出容器,容器中不留任何空白。
+ contain: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全被包裹在容器中,容器中可能留有空白
+ stretch: 拉伸图片且不维持宽高比,直到宽高都刚好填满容器。
+ repeat: 重复平铺图片直到填满容器。图片会维持原始尺寸。仅iOS可用。
+ center: 居中不拉伸。
+
+
+
+
+
source {uri: string}, number #
+
+
uri是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+
+
+
style style #
+
+
+
+
+
+
backfaceVisibility ReactPropTypes.oneOf(['visible', 'hidden'])
+
+
+
resizeMode Object.keys(ImageResizeMode)
+
+
+
backgroundColor color
+
+
+
borderBottomLeftRadius ReactPropTypes.number
+
+
+
borderBottomRightRadius ReactPropTypes.number
+
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius ReactPropTypes.number
+
+
+
borderTopRightRadius ReactPropTypes.number
+
+
+
borderWidth number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
+
opacity number
+
+
+
android overlayColor ReactPropTypes.string
+
+
+
+
+
+
+
testID string #
+
+
一个唯一的资源标识符,用来在自动测试脚本中标识这个元素。
+
+
+
android resizeMethod
+ enum('auto', 'resize', 'scale') #
+
当图片实际尺寸和容器样式尺寸不一致时,决定以怎样的策略来调整图片的尺寸。默认值为auto。
+
+ auto:使用启发式算法来在resize和scale中自动决定。
+
+ resize: 在图片解码之前,使用软件算法对其在内存中的数据进行修改。当图片尺寸比容器尺寸大得多时,应该优先使用此选项。
+ scale:对图片进行缩放。和resize相比,
+ scale速度更快(一般有硬件加速),而且图片质量更优。在图片尺寸比容器尺寸小或者只是稍大一点时,应该优先使用此选项。
+
+
关于resize和scale的详细说明请参考http://frescolib.org/docs/resizing-rotating.html .
+
+
+
+
ios accessibilityLabel string #
+
+
当用户与图片交互时,读屏器(无障碍功能)会朗读的文字。
+
+
+
+
ios accessible bool #
+
+
当此属性为真的时候,表示这个图片是一个启用了无障碍功能的元素。
+
+
+
+
ios blurRadius number #
+
+
+
blurRadius(模糊半径):为图片添加一个指定半径的模糊滤镜。
+
+
+
+
ios capInsets {top: number, left: number, bottom: number, right: number} #
+
+
当图片被缩放的时候,capInsets指定的角上的尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用(译注:这就是常说的九宫格或者.9图。了解更多信息,可以参见苹果官方文档
+
+
+
ios defaultSource
+ {uri: string, width: number, height: number, scale: number}, number #
+
在读取图片时默认显示的加载提示图片
+
+ uri - 是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+ width, height - 如果你知道图片的尺寸,那么可以在这里指定。这一尺寸会被用作<Image/>组件的默认尺寸。
+
+ scale - 图片的缩放系数。默认是1.0,意味着每一个图片像素都对应一个设备独立像素(DIP)。
+
+ number - 本地图片引用语法require('./image.jpg')所返回的内部资源id。
+
+
+
+
+
ios onError function #
+
+
当加载错误的时候调用此回调函数,参数为{nativeEvent: {error}}
+
+
+
ios onPartialLoad
+ function #
+
如果图片本身支持逐步加载,则逐步加载的过程中会调用此方法。“逐步加载”的具体定义与具体的标准和实现有关。
+
+
+
ios onProgress function #
+
+
在加载过程中不断调用,参数为{nativeEvent: {loaded, total}}
+
+
+
+
+### 方法
+
+
+
static getSize(uri: string, success: (width: number, height: number) => void, failure: (error: any) => void)
+ #
+
在显示图片前获取图片的宽高(以像素为单位)。如果图片地址不正确或下载失败,此方法也会失败。
+
要获取图片的尺寸,首先需要加载或下载图片(同时会被缓存起来)。这意味着理论上你可以用这个方法来预加载图片,虽然此方法并没有针对这一用法进行优化,而且将来可能会换一些实现方案使得并不需要完整下载图片即可获取尺寸。所以更好的预加载方案是使用下面那个专门的预加载方法。
+
+
static prefetch(url: string) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActivityIndicator,
+ Image,
+ Platform,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
+
+var ImageCapInsetsExample = require('./ImageCapInsetsExample');
+const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
+var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
+
+var NetworkImageCallbackExample = React.createClass({
+ getInitialState: function() {
+ return {
+ events: [],
+ startLoadPrefetched: false,
+ mountTime: new Date(),
+ };
+ },
+
+ componentWillMount() {
+ this.setState({mountTime: new Date()});
+ },
+
+ render: function() {
+ var { mountTime } = this.state;
+
+ return (
+
+ this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => {
+ this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`);
+ this.setState({startLoadPrefetched: true}, () => {
+ prefetchTask.then(() => {
+ this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
+ }, error => {
+ this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
+ });
+ });
+ }}
+ />
+ {this.state.startLoadPrefetched ?
+ this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
+ />
+ : null}
+
+ {this.state.events.join('\n')}
+
+
+ );
+ },
+
+ _loadEventFired(event) {
+ this.setState((state) => {
+ return state.events = [...state.events, event];
+ });
+ }
+});
+
+var NetworkImageExample = React.createClass({
+ getInitialState: function() {
+ return {
+ error: false,
+ loading: false,
+ progress: 0
+ };
+ },
+ render: function() {
+ var loader = this.state.loading ?
+
+ {this.state.progress}%
+
+ : null;
+ return this.state.error ?
+ {this.state.error} :
+ this.setState({loading: true})}
+ onError={(e) => this.setState({error: e.nativeEvent.error, loading: false})}
+ onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})}
+ onLoad={() => this.setState({loading: false, error: false})}>
+ {loader}
+ ;
+ }
+});
+
+var ImageSizeExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 0,
+ height: 0,
+ };
+ },
+ componentDidMount: function() {
+ Image.getSize(this.props.source.uri, (width, height) => {
+ this.setState({width, height});
+ });
+ },
+ render: function() {
+ return (
+
+
+
+ Actual dimensions:{'\n'}
+ Width: {this.state.width}, Height: {this.state.height}
+
+
+ );
+ },
+});
+
+var MultipleSourcesExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 30,
+ height: 30,
+ };
+ },
+ render: function() {
+ return (
+
+
+
+ Decrease image size
+
+
+ Increase image size
+
+
+ Container image size: {this.state.width}x{this.state.height}
+
+
+
+
+ );
+ },
+ increaseImageSize: function() {
+ if (this.state.width >= 100) {
+ return;
+ }
+ this.setState({
+ width: this.state.width + 10,
+ height: this.state.height + 10,
+ });
+ },
+ decreaseImageSize: function() {
+ if (this.state.width <= 10) {
+ return;
+ }
+ this.setState({
+ width: this.state.width - 10,
+ height: this.state.height - 10,
+ });
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Base component for displaying different types of images.';
+
+exports.examples = [
+ {
+ title: 'Plain Network Image',
+ description: 'If the `source` prop `uri` property is prefixed with ' +
+ '"http", then it will be downloaded from the network.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Plain Static Image',
+ description: 'Static assets should be placed in the source code tree, and ' +
+ 'required in the same way as JavaScript modules.',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Image Loading Events',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Error Handler',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Download Progress',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'defaultSource',
+ description: 'Show a placeholder image when a network image is loading',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Border Color',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Width',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Radius',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Background Color',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Opacity',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Nesting',
+ render: function() {
+ return (
+
+
+ React
+
+
+ );
+ },
+ },
+ {
+ title: 'Tint Color',
+ description: 'The `tintColor` style prop changes all the non-alpha ' +
+ 'pixels to the tint color.',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ It also works with downloaded images:
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Resize Mode',
+ description: 'The `resizeMode` style prop controls how the image is ' +
+ 'rendered within the frame.',
+ render: function() {
+ return (
+
+ {[smallImage, fullImage].map((image, index) => {
+ return (
+
+
+
+
+ Contain
+
+
+
+
+
+ Cover
+
+
+
+
+
+
+
+ Stretch
+
+
+
+ { Platform.OS === 'ios' ?
+
+
+ Repeat
+
+
+
+ : null }
+ { Platform.OS === 'android' ?
+
+
+ Center
+
+
+
+ : null }
+
+
+ );
+ })}
+
+ );
+ },
+ },
+ {
+ title: 'Animated GIF',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Base64 image',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Cap Insets',
+ description:
+ 'When the image is resized, the corners of the size specified ' +
+ 'by capInsets will stay a fixed size, but the center content and ' +
+ 'borders of the image will be stretched. This is useful for creating ' +
+ 'resizable rounded buttons, shadows, and other resizable assets.',
+ render: function() {
+ return ;
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Size',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'MultipleSourcesExample',
+ description:
+ 'The `source` prop allows passing in an array of uris, so that native to choose which image ' +
+ 'to diplay based on the size of the of the target image',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'Legacy local image',
+ description:
+ 'Images shipped with the native bundle, but not managed ' +
+ 'by the JS packager',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Bundled images',
+ description:
+ 'Images shipped in a separate native bundle',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ platform: 'ios',
+ },
+];
+
+var fullImage = {uri: 'https://facebook.github.io/react/img/logo_og.png'};
+var smallImage = {uri: 'https://facebook.github.io/react/img/logo_small_2x.png'};
+
+var styles = StyleSheet.create({
+ base: {
+ width: 38,
+ height: 38,
+ },
+ progress: {
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ width: 100
+ },
+ leftMargin: {
+ marginLeft: 10,
+ },
+ background: {
+ backgroundColor: '#222222'
+ },
+ sectionText: {
+ marginVertical: 6,
+ },
+ nestedText: {
+ marginLeft: 12,
+ marginTop: 20,
+ backgroundColor: 'transparent',
+ color: 'white'
+ },
+ resizeMode: {
+ width: 90,
+ height: 60,
+ borderWidth: 0.5,
+ borderColor: 'black'
+ },
+ resizeModeText: {
+ fontSize: 11,
+ marginBottom: 3,
+ },
+ icon: {
+ width: 15,
+ height: 15,
+ },
+ horizontal: {
+ flexDirection: 'row',
+ },
+ gif: {
+ flex: 1,
+ height: 200,
+ },
+ base64: {
+ flex: 1,
+ height: 50,
+ resizeMode: 'contain',
+ },
+ touchableText: {
+ fontWeight: '500',
+ color: 'blue',
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/imageeditor.md b/docs/docs/0.41/imageeditor.md
new file mode 100644
index 0000000..b77155e
--- /dev/null
+++ b/docs/docs/0.41/imageeditor.md
@@ -0,0 +1,10 @@
+### 方法
+
+
+
static cropImage(uri, cropData, success, failure)
+ #
+
根据指定的URI参数剪裁对应的图片。如果URI指向一个远程图片,则首先会自动下载该图片。如果图片无法下载或读取,则调用failure回调函数。
+
如果剪裁成功完成,则剪裁好的图片会被存放在ImageStore 中,同时success回调函数中返回的URI参数会指向ImageStore中的此图片。请记得在完成处理逻辑后删除ImageStore中的图片。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/imagepickerios.md b/docs/docs/0.41/imagepickerios.md
new file mode 100644
index 0000000..06a8484
--- /dev/null
+++ b/docs/docs/0.41/imagepickerios.md
@@ -0,0 +1,28 @@
+### 方法
+
+
+
+
static canRecordVideos(callback)
+ #
+
+
+
+
static canUseCamera(callback)
+ #
+
+
+
+
static openCameraDialog(config, successCallback, cancelCallback)
+ #
+
+
+
+
static openSelectDialog(config, successCallback, cancelCallback)
+ #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/images.md b/docs/docs/0.41/images.md
new file mode 100644
index 0000000..9289385
--- /dev/null
+++ b/docs/docs/0.41/images.md
@@ -0,0 +1,136 @@
+## 静态图片资源
+
+从0.14版本开始,React Native提供了一个统一的方式来管理iOS和Android应用中的图片。要往App中添加一个静态图片,只需把图片文件放在代码文件夹中某处,然后像下面这样去引用它:
+
+```javascript
+
+```
+
+图片文件的查找会和JS模块的查找方式一样。在上面的这个例子里,是哪个组件引用了这个图片,Packager就会去这个组件所在的文件夹下查找`my-icon.png`。并且,如果你有`my-icon.ios.png`和`my-icon.android.png`,Packager就会根据平台而选择不同的文件。
+
+你还可以使用`@2x`,`@3x`这样的文件名后缀,来为不同的屏幕精度提供图片。比如下面这样的代码结构:
+
+```
+.
+├── button.js
+└── img
+ ├── check@2x.png
+ └── check@3x.png
+```
+
+并且`button.js`里有这样的代码:
+
+```javascript
+
+```
+
+Packager会打包所有的图片并且依据屏幕精度提供对应的资源。譬如说,iPhone 5s会使用`check@2x.png`,而Nexus 5上则会使用`check@3x.png`。如果没有图片恰好满足屏幕分辨率,则会自动选中最接近的一个图片。
+
+_注意_:如果你添加图片的时候packager正在运行,可能需要重启packager以便能正确引入新添加的图片。
+
+这样会带来如下的一些好处:
+
+1. iOS和Android一致的文件系统。
+2. 图片和JS代码处在相同的文件夹,这样组件就可以包含自己所用的图片而不用单独去设置。
+3. 不需要全局命名。你不用再担心图片名字的冲突问题了。
+4. 只有实际被用到(即被require)的图片才会被打包到你的app。
+5. 现在在开发期间,增加和修改图片不需要重新编译了,只要和修改js代码一样刷新你的模拟器就可以了。
+6. 与访问网络图片相比,Packager可以得知图片大小了,不需要在代码里再声明一遍尺寸。
+7. 现在通过npm来分发组件或库可以包含图片了。
+
+注意:为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串。
+
+```javascript
+// 正确
+
+
+// 错误
+var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
+
+
+// 正确
+var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png');
+
+```
+
+**本特性从0.14开始生效**。请注意:新的资源系统依靠修改打包脚本来实现,`react-native init`创建的新工程已经包含了这些修改:[Xcode](https://github.com/facebook/react-native/pull/3523)和[Gradle](https://github.com/facebook/react-native/commit/9dc036d2b99e6233297c55a3490bfc308e34e75f)。如果你的工程是在0.13或者更早版本创建的,你可能需要自行添加对应的代码来支持新的图片资源系统。请参考文档[升级版本](/docs/upgrading.html)文档中的升级操作说明。
+
+## 使用混合App的图片资源
+
+如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(通过Xcode的asset类目或者Android的drawable文件夹打包):
+
+```javascript
+
+```
+
+注意:这一做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸。
+
+
+## 网络图片
+
+很多要在App中显示的图片并不能在编译的时候获得,又或者有时候需要动态载入来减少打包后的二进制文件的大小。这些时候,与静态资源不同的是,`你需要手动指定图片的尺寸`。
+
+```javascript
+// 正确
+
+
+// 错误
+
+```
+
+## 本地文件系统中的图片
+
+参考[相册(CameraRoll)](cameraroll.html)这个例子来看如何使用在`Images.xcassets`以外的本地资源。
+
+### 最合适的相册图片
+
+iOS会为同一张图片在相册中保存多个不同尺寸的副本。为了性能考虑,从这些副本中挑出最合适的尺寸显得尤为重要。对于一处200x200大小的缩略图,显然不应该选择最高质量的3264x2448大小的图片。如果恰好有匹配的尺寸,那么React Native会自动为你选好。如果没有,则会选择最接近的尺寸进行缩放,但也至少缩放到比所需尺寸大出50%,以使图片看起来仍然足够清晰。这一切过程都是自动完成的,所以你不用操心自己去完成这些繁琐且易错的代码。
+
+## 为什么不在所有情况下都自动指定尺寸呢?
+
+`在浏览器中`,如果你不给图片指定尺寸,那么浏览器会首先渲染一个0x0大小的元素占位,然后下载图片,在下载完成后再基于正确的尺寸来渲染图片。这样做的最大问题是UI会在图片加载的过程中上下跳动,使得用户体验非常糟糕。
+
+`在React Native`中我们有意避免了这一行为。如此一来开发者就需要做更多工作来提前知晓远程图片的尺寸(或宽高比),但我们相信这样可以带来更好的用户体验。然而,从已经打包好的应用资源文件中读取图片(使用`require('image!x')`语法)则`无需指定尺寸`,因为它们的尺寸在加载时就可以立刻知道。
+
+比如这样一个引用`require('image!logo')`的实际输出结果可能是:
+
+```javascript
+{"__packager_asset":true,"isStatic":true,"path":"/Users/react/HelloWorld/iOS/Images.xcassets/react.imageset/logo.png","uri":"logo","width":591,"height":573}
+```
+
+## 资源属性是一个对象(object)
+
+在React Native中,另一个值得一提的变动是我们把`src`属性改为了`source`属性,而且并不接受字符串,正确的值是一个带有`uri`属性的对象。
+
+```javascript
+
+```
+
+深层次的考虑是,这样可以使我们在对象中添加一些元数据(metadata)。假设你在使用`require('./my-icon.png')`,那么我们就会在其中添加真实文件路径以及尺寸等信息(这只是举个例子,未来的版本中require的具体行为可能会变化)。此外这也是考虑了未来的扩展性,比如我们可能会加入精灵图(sprites)的支持:在输出`{uri: ...}`的基础上,我们可以进一步输出裁切信息`{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}`,这样理论上就可以在现有的代码中无缝支持精灵图的切分。
+
+对于开发者来说,则可以在其中标注一些有用的属性,例如图片的尺寸,这样可以使图片自己去计算将要显示的尺寸(而不必在样式中写死)。请在这一数据结构中自由发挥,存储你可能需要的任何图片相关的信息。
+
+## 通过嵌套来实现背景图片
+
+开发者们常面对的一种需求就是类似web中的背景图(`background-image`)。要实现这一用例,只需简单地创建一个``组件,然后把需要背景图的子组件嵌入其中即可。
+
+```javascript
+return (
+
+ Inside
+
+);
+```
+## iOS边框圆角的注意事项
+
+请注意下列边框圆角样式目前在iOS的图片组件上还不支持:
+
+* `borderTopLeftRadius`
+* `borderTopRightRadius`
+* `borderBottomLeftRadius`
+* `borderBottomRightRadius`
+
+## 在主线程外解码图片
+
+图片解码有可能会需要超过一帧的时间。在web上这是页面掉帧的一大因素,因为解码是在主线程中完成的。然而在React Native中,图片解码则是在另一线程中完成的。在实际开发中,一般对图片还没下载完成时的场景都做了处理(添加loading等),而图片解码时显示的占位符只占用几帧时间,并不需要你改动代码去额外处理。
diff --git a/docs/docs/0.41/imagestore.md b/docs/docs/0.41/imagestore.md
new file mode 100644
index 0000000..75b2759
--- /dev/null
+++ b/docs/docs/0.41/imagestore.md
@@ -0,0 +1,33 @@
+### 属性
+
+
+
+
static hasImageForTag(uri, callback) #
+
检查ImageStore中是否包含了指定URI的图片数据。目前仅限iOS。
+
+
+
static removeImageForTag(uri) #
+
从ImageStore中删除指定图片。存储在ImageStore中的图标必须手动删除,否则在应用退出之前将会一直占用内存。调用此删除方法并不需要先调用hasImageForTag()方法来检查,此方法会自动处理异常情况。目前仅限iOS。
+
+
+
static addImageFromBase64(base64ImageData, success, failure)
+ #
+
+
+
在ImageStore中以base64编码格式存储一幅图片,并返回一个URI以便访问或显示此图片。图片数据仅仅保存在内存中,在使用完毕后请调用removeImageForTag()方法来手动删除。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。目前仅限iOS。
+
+
+
static getBase64ForTag(uri, success, failure)
+ #
+
+
将ImageStore中的指定URI图片以base64编码格式的数据返回。如果找不到指定的URI,则会调用failure回调函数。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。如果只是为了显示图片,可以直接把URI传递给<Image/>组件,并不需要额外取base64数据。
+
+
+
diff --git a/docs/docs/0.41/img/AddToBuildPhases.png b/docs/docs/0.41/img/AddToBuildPhases.png
new file mode 100644
index 0000000..7b83937
Binary files /dev/null and b/docs/docs/0.41/img/AddToBuildPhases.png differ
diff --git a/docs/docs/0.41/img/AddToLibraries.png b/docs/docs/0.41/img/AddToLibraries.png
new file mode 100644
index 0000000..652cdfd
Binary files /dev/null and b/docs/docs/0.41/img/AddToLibraries.png differ
diff --git a/docs/docs/0.41/img/AddToSearchPaths.png b/docs/docs/0.41/img/AddToSearchPaths.png
new file mode 100644
index 0000000..ccbe819
Binary files /dev/null and b/docs/docs/0.41/img/AddToSearchPaths.png differ
diff --git a/docs/docs/0.41/img/AndroidSDK1.png b/docs/docs/0.41/img/AndroidSDK1.png
new file mode 100644
index 0000000..9b9add7
Binary files /dev/null and b/docs/docs/0.41/img/AndroidSDK1.png differ
diff --git a/docs/docs/0.41/img/AndroidSDK2.png b/docs/docs/0.41/img/AndroidSDK2.png
new file mode 100644
index 0000000..663b8cc
Binary files /dev/null and b/docs/docs/0.41/img/AndroidSDK2.png differ
diff --git a/docs/docs/0.41/img/AnimationExperimentalOpacity.gif b/docs/docs/0.41/img/AnimationExperimentalOpacity.gif
new file mode 100644
index 0000000..cdc7902
Binary files /dev/null and b/docs/docs/0.41/img/AnimationExperimentalOpacity.gif differ
diff --git a/docs/docs/0.41/img/AnimationExperimentalScaleXY.gif b/docs/docs/0.41/img/AnimationExperimentalScaleXY.gif
new file mode 100644
index 0000000..850cfd1
Binary files /dev/null and b/docs/docs/0.41/img/AnimationExperimentalScaleXY.gif differ
diff --git a/docs/docs/0.41/img/CreateAVD.png b/docs/docs/0.41/img/CreateAVD.png
new file mode 100644
index 0000000..5a3d494
Binary files /dev/null and b/docs/docs/0.41/img/CreateAVD.png differ
diff --git a/docs/docs/0.41/img/DeveloperMenu.png b/docs/docs/0.41/img/DeveloperMenu.png
new file mode 100644
index 0000000..bb29544
Binary files /dev/null and b/docs/docs/0.41/img/DeveloperMenu.png differ
diff --git a/docs/docs/0.41/img/EmbeddedAppAndroid.png b/docs/docs/0.41/img/EmbeddedAppAndroid.png
new file mode 100644
index 0000000..126ba2d
Binary files /dev/null and b/docs/docs/0.41/img/EmbeddedAppAndroid.png differ
diff --git a/docs/docs/0.41/img/EmbeddedAppContainerViewExample.png b/docs/docs/0.41/img/EmbeddedAppContainerViewExample.png
new file mode 100644
index 0000000..6130dfb
Binary files /dev/null and b/docs/docs/0.41/img/EmbeddedAppContainerViewExample.png differ
diff --git a/docs/docs/0.41/img/EmbeddedAppExample.png b/docs/docs/0.41/img/EmbeddedAppExample.png
new file mode 100644
index 0000000..fefd306
Binary files /dev/null and b/docs/docs/0.41/img/EmbeddedAppExample.png differ
diff --git a/docs/docs/0.41/img/LayoutAnimationExample.gif b/docs/docs/0.41/img/LayoutAnimationExample.gif
new file mode 100644
index 0000000..68fcfce
Binary files /dev/null and b/docs/docs/0.41/img/LayoutAnimationExample.gif differ
diff --git a/docs/docs/0.41/img/NavigationStack-Navigator.gif b/docs/docs/0.41/img/NavigationStack-Navigator.gif
new file mode 100644
index 0000000..c1f8313
Binary files /dev/null and b/docs/docs/0.41/img/NavigationStack-Navigator.gif differ
diff --git a/docs/docs/0.41/img/NavigationStack-NavigatorIOS.gif b/docs/docs/0.41/img/NavigationStack-NavigatorIOS.gif
new file mode 100644
index 0000000..c1d56a1
Binary files /dev/null and b/docs/docs/0.41/img/NavigationStack-NavigatorIOS.gif differ
diff --git a/docs/docs/0.41/img/Rebound.gif b/docs/docs/0.41/img/Rebound.gif
new file mode 100644
index 0000000..0371663
Binary files /dev/null and b/docs/docs/0.41/img/Rebound.gif differ
diff --git a/docs/docs/0.41/img/ReboundExample.png b/docs/docs/0.41/img/ReboundExample.png
new file mode 100644
index 0000000..db33e5f
Binary files /dev/null and b/docs/docs/0.41/img/ReboundExample.png differ
diff --git a/docs/docs/0.41/img/ReboundImage.gif b/docs/docs/0.41/img/ReboundImage.gif
new file mode 100644
index 0000000..9c1da74
Binary files /dev/null and b/docs/docs/0.41/img/ReboundImage.gif differ
diff --git a/docs/docs/0.41/img/StaticImageAssets.png b/docs/docs/0.41/img/StaticImageAssets.png
new file mode 100644
index 0000000..e79acdc
Binary files /dev/null and b/docs/docs/0.41/img/StaticImageAssets.png differ
diff --git a/docs/docs/0.41/img/SystraceBadCreateUI.png b/docs/docs/0.41/img/SystraceBadCreateUI.png
new file mode 100644
index 0000000..813b101
Binary files /dev/null and b/docs/docs/0.41/img/SystraceBadCreateUI.png differ
diff --git a/docs/docs/0.41/img/SystraceBadJS.png b/docs/docs/0.41/img/SystraceBadJS.png
new file mode 100644
index 0000000..c67c840
Binary files /dev/null and b/docs/docs/0.41/img/SystraceBadJS.png differ
diff --git a/docs/docs/0.41/img/SystraceBadJS2.png b/docs/docs/0.41/img/SystraceBadJS2.png
new file mode 100644
index 0000000..de972c6
Binary files /dev/null and b/docs/docs/0.41/img/SystraceBadJS2.png differ
diff --git a/docs/docs/0.41/img/SystraceBadUI.png b/docs/docs/0.41/img/SystraceBadUI.png
new file mode 100644
index 0000000..ebd9faf
Binary files /dev/null and b/docs/docs/0.41/img/SystraceBadUI.png differ
diff --git a/docs/docs/0.41/img/SystraceExample.png b/docs/docs/0.41/img/SystraceExample.png
new file mode 100644
index 0000000..521ee16
Binary files /dev/null and b/docs/docs/0.41/img/SystraceExample.png differ
diff --git a/docs/docs/0.41/img/SystraceHighlightVSync.png b/docs/docs/0.41/img/SystraceHighlightVSync.png
new file mode 100644
index 0000000..dc7595a
Binary files /dev/null and b/docs/docs/0.41/img/SystraceHighlightVSync.png differ
diff --git a/docs/docs/0.41/img/SystraceJSThreadExample.png b/docs/docs/0.41/img/SystraceJSThreadExample.png
new file mode 100644
index 0000000..736af7d
Binary files /dev/null and b/docs/docs/0.41/img/SystraceJSThreadExample.png differ
diff --git a/docs/docs/0.41/img/SystraceNativeModulesThreadExample.png b/docs/docs/0.41/img/SystraceNativeModulesThreadExample.png
new file mode 100644
index 0000000..7e919f2
Binary files /dev/null and b/docs/docs/0.41/img/SystraceNativeModulesThreadExample.png differ
diff --git a/docs/docs/0.41/img/SystraceRenderThreadExample.png b/docs/docs/0.41/img/SystraceRenderThreadExample.png
new file mode 100644
index 0000000..2fa05bd
Binary files /dev/null and b/docs/docs/0.41/img/SystraceRenderThreadExample.png differ
diff --git a/docs/docs/0.41/img/SystraceUIThreadExample.png b/docs/docs/0.41/img/SystraceUIThreadExample.png
new file mode 100644
index 0000000..4883e85
Binary files /dev/null and b/docs/docs/0.41/img/SystraceUIThreadExample.png differ
diff --git a/docs/docs/0.41/img/SystraceWellBehaved.png b/docs/docs/0.41/img/SystraceWellBehaved.png
new file mode 100644
index 0000000..9540873
Binary files /dev/null and b/docs/docs/0.41/img/SystraceWellBehaved.png differ
diff --git a/docs/docs/0.41/img/TutorialFinal.png b/docs/docs/0.41/img/TutorialFinal.png
new file mode 100644
index 0000000..2f05b13
Binary files /dev/null and b/docs/docs/0.41/img/TutorialFinal.png differ
diff --git a/docs/docs/0.41/img/TutorialFinal2.png b/docs/docs/0.41/img/TutorialFinal2.png
new file mode 100644
index 0000000..75ec47c
Binary files /dev/null and b/docs/docs/0.41/img/TutorialFinal2.png differ
diff --git a/docs/docs/0.41/img/TutorialMock.png b/docs/docs/0.41/img/TutorialMock.png
new file mode 100644
index 0000000..6a267d0
Binary files /dev/null and b/docs/docs/0.41/img/TutorialMock.png differ
diff --git a/docs/docs/0.41/img/TutorialMock2.png b/docs/docs/0.41/img/TutorialMock2.png
new file mode 100644
index 0000000..94c7f65
Binary files /dev/null and b/docs/docs/0.41/img/TutorialMock2.png differ
diff --git a/docs/docs/0.41/img/TutorialSingleFetched.png b/docs/docs/0.41/img/TutorialSingleFetched.png
new file mode 100644
index 0000000..914cb88
Binary files /dev/null and b/docs/docs/0.41/img/TutorialSingleFetched.png differ
diff --git a/docs/docs/0.41/img/TutorialSingleFetched2.png b/docs/docs/0.41/img/TutorialSingleFetched2.png
new file mode 100644
index 0000000..c7dfd69
Binary files /dev/null and b/docs/docs/0.41/img/TutorialSingleFetched2.png differ
diff --git a/docs/docs/0.41/img/TutorialStyledMock.png b/docs/docs/0.41/img/TutorialStyledMock.png
new file mode 100644
index 0000000..48fb1c5
Binary files /dev/null and b/docs/docs/0.41/img/TutorialStyledMock.png differ
diff --git a/docs/docs/0.41/img/TutorialStyledMock2.png b/docs/docs/0.41/img/TutorialStyledMock2.png
new file mode 100644
index 0000000..16e99c2
Binary files /dev/null and b/docs/docs/0.41/img/TutorialStyledMock2.png differ
diff --git a/docs/docs/0.41/img/TweenState.gif b/docs/docs/0.41/img/TweenState.gif
new file mode 100644
index 0000000..84f34d2
Binary files /dev/null and b/docs/docs/0.41/img/TweenState.gif differ
diff --git a/docs/docs/0.41/img/Upgrading1.png b/docs/docs/0.41/img/Upgrading1.png
new file mode 100644
index 0000000..b60a852
Binary files /dev/null and b/docs/docs/0.41/img/Upgrading1.png differ
diff --git a/docs/docs/0.41/img/Upgrading2.png b/docs/docs/0.41/img/Upgrading2.png
new file mode 100644
index 0000000..c9a109d
Binary files /dev/null and b/docs/docs/0.41/img/Upgrading2.png differ
diff --git a/docs/docs/0.41/img/Upgrading3.png b/docs/docs/0.41/img/Upgrading3.png
new file mode 100644
index 0000000..3150aab
Binary files /dev/null and b/docs/docs/0.41/img/Upgrading3.png differ
diff --git a/docs/docs/0.41/img/alertIOS.png b/docs/docs/0.41/img/alertIOS.png
new file mode 100644
index 0000000..b35a2a4
Binary files /dev/null and b/docs/docs/0.41/img/alertIOS.png differ
diff --git a/docs/docs/0.41/img/api/actionsheetios1.png b/docs/docs/0.41/img/api/actionsheetios1.png
new file mode 100644
index 0000000..9f7f489
Binary files /dev/null and b/docs/docs/0.41/img/api/actionsheetios1.png differ
diff --git a/docs/docs/0.41/img/api/actionsheetios2.png b/docs/docs/0.41/img/api/actionsheetios2.png
new file mode 100644
index 0000000..4cf739f
Binary files /dev/null and b/docs/docs/0.41/img/api/actionsheetios2.png differ
diff --git a/docs/docs/0.41/img/api/alertios1.png b/docs/docs/0.41/img/api/alertios1.png
new file mode 100644
index 0000000..0406823
Binary files /dev/null and b/docs/docs/0.41/img/api/alertios1.png differ
diff --git a/docs/docs/0.41/img/api/alertios2.png b/docs/docs/0.41/img/api/alertios2.png
new file mode 100644
index 0000000..6c3964b
Binary files /dev/null and b/docs/docs/0.41/img/api/alertios2.png differ
diff --git a/docs/docs/0.41/img/api/cameraroll.png b/docs/docs/0.41/img/api/cameraroll.png
new file mode 100644
index 0000000..129b98b
Binary files /dev/null and b/docs/docs/0.41/img/api/cameraroll.png differ
diff --git a/docs/docs/0.41/img/api/statusbarios.png b/docs/docs/0.41/img/api/statusbarios.png
new file mode 100644
index 0000000..15e1ee7
Binary files /dev/null and b/docs/docs/0.41/img/api/statusbarios.png differ
diff --git a/docs/docs/0.41/img/api/toastandroid.png b/docs/docs/0.41/img/api/toastandroid.png
new file mode 100644
index 0000000..a4ec2a2
Binary files /dev/null and b/docs/docs/0.41/img/api/toastandroid.png differ
diff --git a/docs/docs/0.41/img/chrome_breakpoint.png b/docs/docs/0.41/img/chrome_breakpoint.png
new file mode 100644
index 0000000..d37c953
Binary files /dev/null and b/docs/docs/0.41/img/chrome_breakpoint.png differ
diff --git a/docs/docs/0.41/img/components/activityindicatorios.png b/docs/docs/0.41/img/components/activityindicatorios.png
new file mode 100644
index 0000000..57567ca
Binary files /dev/null and b/docs/docs/0.41/img/components/activityindicatorios.png differ
diff --git a/docs/docs/0.41/img/components/buttonExample.png b/docs/docs/0.41/img/components/buttonExample.png
new file mode 100644
index 0000000..40ce923
Binary files /dev/null and b/docs/docs/0.41/img/components/buttonExample.png differ
diff --git a/docs/docs/0.41/img/components/datepickerios.png b/docs/docs/0.41/img/components/datepickerios.png
new file mode 100644
index 0000000..bf34f1c
Binary files /dev/null and b/docs/docs/0.41/img/components/datepickerios.png differ
diff --git a/docs/docs/0.41/img/components/drawerlayoutandroid.png b/docs/docs/0.41/img/components/drawerlayoutandroid.png
new file mode 100644
index 0000000..f4911dd
Binary files /dev/null and b/docs/docs/0.41/img/components/drawerlayoutandroid.png differ
diff --git a/docs/docs/0.41/img/components/image.png b/docs/docs/0.41/img/components/image.png
new file mode 100644
index 0000000..1a2158d
Binary files /dev/null and b/docs/docs/0.41/img/components/image.png differ
diff --git a/docs/docs/0.41/img/components/listview1.png b/docs/docs/0.41/img/components/listview1.png
new file mode 100644
index 0000000..36a072e
Binary files /dev/null and b/docs/docs/0.41/img/components/listview1.png differ
diff --git a/docs/docs/0.41/img/components/listview2.png b/docs/docs/0.41/img/components/listview2.png
new file mode 100644
index 0000000..aceb4b5
Binary files /dev/null and b/docs/docs/0.41/img/components/listview2.png differ
diff --git a/docs/docs/0.41/img/components/listview3.png b/docs/docs/0.41/img/components/listview3.png
new file mode 100644
index 0000000..4b777a6
Binary files /dev/null and b/docs/docs/0.41/img/components/listview3.png differ
diff --git a/docs/docs/0.41/img/components/mapview.png b/docs/docs/0.41/img/components/mapview.png
new file mode 100644
index 0000000..12277f1
Binary files /dev/null and b/docs/docs/0.41/img/components/mapview.png differ
diff --git a/docs/docs/0.41/img/components/modal.png b/docs/docs/0.41/img/components/modal.png
new file mode 100644
index 0000000..9ff9dd0
Binary files /dev/null and b/docs/docs/0.41/img/components/modal.png differ
diff --git a/docs/docs/0.41/img/components/navigator1.png b/docs/docs/0.41/img/components/navigator1.png
new file mode 100644
index 0000000..1baadd9
Binary files /dev/null and b/docs/docs/0.41/img/components/navigator1.png differ
diff --git a/docs/docs/0.41/img/components/navigator2.png b/docs/docs/0.41/img/components/navigator2.png
new file mode 100644
index 0000000..4e86cb5
Binary files /dev/null and b/docs/docs/0.41/img/components/navigator2.png differ
diff --git a/docs/docs/0.41/img/components/navigatorios1.png b/docs/docs/0.41/img/components/navigatorios1.png
new file mode 100644
index 0000000..f7a8630
Binary files /dev/null and b/docs/docs/0.41/img/components/navigatorios1.png differ
diff --git a/docs/docs/0.41/img/components/navigatorios2.png b/docs/docs/0.41/img/components/navigatorios2.png
new file mode 100644
index 0000000..c4484c6
Binary files /dev/null and b/docs/docs/0.41/img/components/navigatorios2.png differ
diff --git a/docs/docs/0.41/img/components/pickerios.png b/docs/docs/0.41/img/components/pickerios.png
new file mode 100644
index 0000000..0a285dd
Binary files /dev/null and b/docs/docs/0.41/img/components/pickerios.png differ
diff --git a/docs/docs/0.41/img/components/progressbarandroid.png b/docs/docs/0.41/img/components/progressbarandroid.png
new file mode 100644
index 0000000..ce6be4c
Binary files /dev/null and b/docs/docs/0.41/img/components/progressbarandroid.png differ
diff --git a/docs/docs/0.41/img/components/progressviewios.png b/docs/docs/0.41/img/components/progressviewios.png
new file mode 100644
index 0000000..b37bf1e
Binary files /dev/null and b/docs/docs/0.41/img/components/progressviewios.png differ
diff --git a/docs/docs/0.41/img/components/scrollview.png b/docs/docs/0.41/img/components/scrollview.png
new file mode 100644
index 0000000..399b8e8
Binary files /dev/null and b/docs/docs/0.41/img/components/scrollview.png differ
diff --git a/docs/docs/0.41/img/components/segmentedcontrolios.png b/docs/docs/0.41/img/components/segmentedcontrolios.png
new file mode 100644
index 0000000..3cf27d6
Binary files /dev/null and b/docs/docs/0.41/img/components/segmentedcontrolios.png differ
diff --git a/docs/docs/0.41/img/components/sliderios.png b/docs/docs/0.41/img/components/sliderios.png
new file mode 100644
index 0000000..aba2736
Binary files /dev/null and b/docs/docs/0.41/img/components/sliderios.png differ
diff --git a/docs/docs/0.41/img/components/switchandroid.png b/docs/docs/0.41/img/components/switchandroid.png
new file mode 100644
index 0000000..c6e5342
Binary files /dev/null and b/docs/docs/0.41/img/components/switchandroid.png differ
diff --git a/docs/docs/0.41/img/components/switchios.png b/docs/docs/0.41/img/components/switchios.png
new file mode 100644
index 0000000..6dcf042
Binary files /dev/null and b/docs/docs/0.41/img/components/switchios.png differ
diff --git a/docs/docs/0.41/img/components/tabbarios.png b/docs/docs/0.41/img/components/tabbarios.png
new file mode 100644
index 0000000..1f203e8
Binary files /dev/null and b/docs/docs/0.41/img/components/tabbarios.png differ
diff --git a/docs/docs/0.41/img/components/text.png b/docs/docs/0.41/img/components/text.png
new file mode 100644
index 0000000..031593e
Binary files /dev/null and b/docs/docs/0.41/img/components/text.png differ
diff --git a/docs/docs/0.41/img/components/textinput.png b/docs/docs/0.41/img/components/textinput.png
new file mode 100644
index 0000000..57b579e
Binary files /dev/null and b/docs/docs/0.41/img/components/textinput.png differ
diff --git a/docs/docs/0.41/img/components/toolbarandroid.png b/docs/docs/0.41/img/components/toolbarandroid.png
new file mode 100644
index 0000000..6805c5a
Binary files /dev/null and b/docs/docs/0.41/img/components/toolbarandroid.png differ
diff --git a/docs/docs/0.41/img/components/touchable.png b/docs/docs/0.41/img/components/touchable.png
new file mode 100644
index 0000000..b4083e9
Binary files /dev/null and b/docs/docs/0.41/img/components/touchable.png differ
diff --git a/docs/docs/0.41/img/components/view.png b/docs/docs/0.41/img/components/view.png
new file mode 100644
index 0000000..d917353
Binary files /dev/null and b/docs/docs/0.41/img/components/view.png differ
diff --git a/docs/docs/0.41/img/components/viewpager.png b/docs/docs/0.41/img/components/viewpager.png
new file mode 100644
index 0000000..99ce67f
Binary files /dev/null and b/docs/docs/0.41/img/components/viewpager.png differ
diff --git a/docs/docs/0.41/img/components/webview.png b/docs/docs/0.41/img/components/webview.png
new file mode 100644
index 0000000..2315a19
Binary files /dev/null and b/docs/docs/0.41/img/components/webview.png differ
diff --git a/docs/docs/0.41/img/react-native-add-react-native-integration-example-high-scores.png b/docs/docs/0.41/img/react-native-add-react-native-integration-example-high-scores.png
new file mode 100644
index 0000000..6d07707
Binary files /dev/null and b/docs/docs/0.41/img/react-native-add-react-native-integration-example-high-scores.png differ
diff --git a/docs/docs/0.41/img/react-native-add-react-native-integration-example-home-screen.png b/docs/docs/0.41/img/react-native-add-react-native-integration-example-home-screen.png
new file mode 100644
index 0000000..2b1b8b2
Binary files /dev/null and b/docs/docs/0.41/img/react-native-add-react-native-integration-example-home-screen.png differ
diff --git a/docs/docs/0.41/img/react-native-add-react-native-integration-link.png b/docs/docs/0.41/img/react-native-add-react-native-integration-link.png
new file mode 100644
index 0000000..3d89eaf
Binary files /dev/null and b/docs/docs/0.41/img/react-native-add-react-native-integration-link.png differ
diff --git a/docs/docs/0.41/img/react-native-add-react-native-integration-wire-up.png b/docs/docs/0.41/img/react-native-add-react-native-integration-wire-up.png
new file mode 100644
index 0000000..43d2add
Binary files /dev/null and b/docs/docs/0.41/img/react-native-add-react-native-integration-wire-up.png differ
diff --git a/docs/docs/0.41/img/react-native-android-sdk-environment-variable-windows.png b/docs/docs/0.41/img/react-native-android-sdk-environment-variable-windows.png
new file mode 100644
index 0000000..6b3d981
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-sdk-environment-variable-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-additional-installs-linux.png b/docs/docs/0.41/img/react-native-android-studio-additional-installs-linux.png
new file mode 100644
index 0000000..3a0eda5
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-additional-installs-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-additional-installs.png b/docs/docs/0.41/img/react-native-android-studio-additional-installs.png
new file mode 100644
index 0000000..de32a09
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-additional-installs.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-linux.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-linux.png
new file mode 100644
index 0000000..10391c7
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-windows.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-windows.png
new file mode 100644
index 0000000..600ef3a
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools.png
new file mode 100644
index 0000000..a1d80be
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-build-tools.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-linux.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-linux.png
new file mode 100644
index 0000000..8c43a49
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-windows.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-windows.png
new file mode 100644
index 0000000..a5cf175
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms.png b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms.png
new file mode 100644
index 0000000..34407b1
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-android-sdk-platforms.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-avd-linux.png b/docs/docs/0.41/img/react-native-android-studio-avd-linux.png
new file mode 100644
index 0000000..de5f254
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-avd-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-avd-windows.png b/docs/docs/0.41/img/react-native-android-studio-avd-windows.png
new file mode 100644
index 0000000..ddc8f47
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-avd-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-avd.png b/docs/docs/0.41/img/react-native-android-studio-avd.png
new file mode 100644
index 0000000..74c053b
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-avd.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-configure-sdk-linux.png b/docs/docs/0.41/img/react-native-android-studio-configure-sdk-linux.png
new file mode 100644
index 0000000..8bb9d5f
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-configure-sdk-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-configure-sdk-windows.png b/docs/docs/0.41/img/react-native-android-studio-configure-sdk-windows.png
new file mode 100644
index 0000000..1adf5cb
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-configure-sdk-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-configure-sdk.png b/docs/docs/0.41/img/react-native-android-studio-configure-sdk.png
new file mode 100644
index 0000000..acfe1f3
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-configure-sdk.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-custom-install-linux.png b/docs/docs/0.41/img/react-native-android-studio-custom-install-linux.png
new file mode 100644
index 0000000..4410948
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-custom-install-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-custom-install-windows.png b/docs/docs/0.41/img/react-native-android-studio-custom-install-windows.png
new file mode 100644
index 0000000..7ed385a
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-custom-install-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-custom-install.png b/docs/docs/0.41/img/react-native-android-studio-custom-install.png
new file mode 100644
index 0000000..01ab7b2
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-custom-install.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-kvm-linux.png b/docs/docs/0.41/img/react-native-android-studio-kvm-linux.png
new file mode 100644
index 0000000..dab0810
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-kvm-linux.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-no-virtual-device-windows.png b/docs/docs/0.41/img/react-native-android-studio-no-virtual-device-windows.png
new file mode 100644
index 0000000..933a583
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-no-virtual-device-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-studio-verify-installs-windows.png b/docs/docs/0.41/img/react-native-android-studio-verify-installs-windows.png
new file mode 100644
index 0000000..8f0cf1b
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-studio-verify-installs-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-android-tools-environment-variable-windows.png b/docs/docs/0.41/img/react-native-android-tools-environment-variable-windows.png
new file mode 100644
index 0000000..5ddeb61
Binary files /dev/null and b/docs/docs/0.41/img/react-native-android-tools-environment-variable-windows.png differ
diff --git a/docs/docs/0.41/img/react-native-congratulations.png b/docs/docs/0.41/img/react-native-congratulations.png
new file mode 100644
index 0000000..92f520e
Binary files /dev/null and b/docs/docs/0.41/img/react-native-congratulations.png differ
diff --git a/docs/docs/0.41/img/react-native-existing-app-integration-ios-before.png b/docs/docs/0.41/img/react-native-existing-app-integration-ios-before.png
new file mode 100644
index 0000000..445dd79
Binary files /dev/null and b/docs/docs/0.41/img/react-native-existing-app-integration-ios-before.png differ
diff --git a/docs/docs/0.41/img/react-native-sorry-not-supported.png b/docs/docs/0.41/img/react-native-sorry-not-supported.png
new file mode 100644
index 0000000..8848f4c
Binary files /dev/null and b/docs/docs/0.41/img/react-native-sorry-not-supported.png differ
diff --git a/docs/docs/0.41/img/segmentedcontrolios.jpg b/docs/docs/0.41/img/segmentedcontrolios.jpg
new file mode 100644
index 0000000..5a01172
Binary files /dev/null and b/docs/docs/0.41/img/segmentedcontrolios.jpg differ
diff --git a/docs/docs/0.41/indexes.json b/docs/docs/0.41/indexes.json
new file mode 100644
index 0000000..83a7cf9
--- /dev/null
+++ b/docs/docs/0.41/indexes.json
@@ -0,0 +1,503 @@
+{
+ "contains": [
+ {
+ "group": "入门基础",
+ "contains": [
+ {
+ "subject": "搭建开发环境",
+ "mdlink": "getting-started"
+ },
+ {
+ "subject": "编写Hello World",
+ "mdlink": "tutorial"
+ },
+ {
+ "subject": "Props(属性)",
+ "mdlink": "props"
+ },
+ {
+ "subject": "State(状态)",
+ "mdlink": "state"
+ },
+ {
+ "subject": "样式",
+ "mdlink": "style"
+ },
+ {
+ "subject": "高度与宽度",
+ "mdlink": "height-and-width"
+ },
+ {
+ "subject": "使用Flexbox布局",
+ "mdlink": "layout-with-flexbox"
+ },
+ {
+ "subject": "处理文本输入",
+ "mdlink": "handling-text-input"
+ },
+ {
+ "subject": "如何使用ScrollView",
+ "mdlink": "using-a-scrollview"
+ },
+ {
+ "subject": "如何使用ListView",
+ "mdlink": "using-a-listview"
+ },
+ {
+ "subject": "网络",
+ "mdlink": "network"
+ },
+ {
+ "subject": "使用导航器跳转页面",
+ "mdlink": "using-navigators"
+ },
+ {
+ "subject": "其他参考资源",
+ "mdlink": "more-resources"
+ }
+ ]
+ },
+ {
+ "group": "进阶指南",
+ "contains": [
+ {
+ "subject": "嵌入到现有原生应用",
+ "mdlink": "integration-with-existing-apps"
+ },
+ {
+ "subject": "颜色",
+ "mdlink": "colors"
+ },
+ {
+ "subject": "图片",
+ "mdlink": "images"
+ },
+ {
+ "subject": "处理触摸事件",
+ "mdlink": "handling-touches"
+ },
+ {
+ "subject": "动画",
+ "mdlink": "animations"
+ },
+ {
+ "subject": "无障碍功能",
+ "mdlink": "accessibility"
+ },
+ {
+ "subject": "定时器",
+ "mdlink": "timers"
+ },
+ {
+ "subject": "直接操作",
+ "mdlink": "direct-manipulation"
+ },
+ {
+ "subject": "调试",
+ "mdlink": "debugging"
+ },
+ {
+ "subject": "自动化测试",
+ "mdlink": "testing"
+ },
+ {
+ "subject": "JavaScript环境",
+ "mdlink": "javascript-environment"
+ },
+ {
+ "subject": "导航器对比",
+ "mdlink": "navigation"
+ },
+ {
+ "subject": "性能",
+ "mdlink": "performance"
+ },
+ {
+ "subject": "升级",
+ "mdlink": "upgrading"
+ },
+ {
+ "subject": "特定平台代码",
+ "mdlink": "platform-specific-code"
+ },
+ {
+ "subject": "手势响应系统",
+ "mdlink": "gesture-responder-system"
+ }
+ ]
+ },
+ {
+ "group": "社区资源",
+ "contains": [
+ {
+ "subject": "中文视频教程",
+ "external": "/videos.html"
+ },
+ {
+ "subject": "js.coach第三方组件库",
+ "external": "https://js.coach/react-native"
+ },
+ {
+ "subject": "中文论坛组件分享区",
+ "external": "http://bbs.reactnative.cn/category/5"
+ },
+ {
+ "subject": "中文论坛问题求助区",
+ "external": "http://bbs.reactnative.cn/category/4"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(iOS)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-ios"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-ios"
+ },
+ {
+ "subject": "链接原生库",
+ "mdlink": "linking-libraries-ios"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-ios"
+ },
+ {
+ "subject": "在模拟器上运行",
+ "mdlink": "running-on-simulator-ios"
+ },
+ {
+ "subject": "在原生和React Native间通信",
+ "mdlink": "communication-ios"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(Android)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-android"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-android"
+ },
+ {
+ "subject": "Headless JS(后台任务)",
+ "mdlink": "headless-js-android"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-android"
+ },
+ {
+ "subject": "打包APK",
+ "mdlink": "signed-apk-android"
+ },
+ {
+ "subject": "调试Android UI性能",
+ "mdlink": "android-ui-performance"
+ },
+ {
+ "subject": "从源代码编译React Native",
+ "mdlink": "android-building-from-source"
+ }
+ ]
+ },
+ {
+ "group": "组件",
+ "contains": [
+ {
+ "subject": "ActivityIndicator",
+ "mdlink": "activityindicator"
+ },
+ {
+ "subject": "Button",
+ "mdlink": "button"
+ },
+ {
+ "subject": "DatePickerIOS",
+ "mdlink": "datepickerios"
+ },
+ {
+ "subject": "DrawerLayoutAndroid",
+ "mdlink": "drawerlayoutandroid"
+ },
+ {
+ "subject": "Image",
+ "mdlink": "image"
+ },
+ {
+ "subject": "KeyboardAvoidingView",
+ "mdlink": "keyboardavoidingview"
+ },
+ {
+ "subject": "ListView",
+ "mdlink": "listview"
+ },
+ {
+ "subject": "ListView.DataSource",
+ "mdlink": "listviewdatasource"
+ },
+ {
+ "subject": "MapView",
+ "mdlink": "mapview"
+ },
+ {
+ "subject": "Modal",
+ "mdlink": "modal"
+ },
+ {
+ "subject": "Navigator",
+ "mdlink": "navigator"
+ },
+ {
+ "subject": "NavigatorIOS",
+ "mdlink": "navigatorios"
+ },
+ {
+ "subject": "Picker",
+ "mdlink": "picker"
+ },
+ {
+ "subject": "PickerIOS",
+ "mdlink": "pickerios"
+ },
+ {
+ "subject": "ProgressBarAndroid",
+ "mdlink": "progressbarandroid"
+ },
+ {
+ "subject": "ProgressViewIOS",
+ "mdlink": "progressviewios"
+ },
+ {
+ "subject": "RefreshControl",
+ "mdlink": "refreshcontrol"
+ },
+ {
+ "subject": "ScrollView",
+ "mdlink": "scrollview"
+ },
+ {
+ "subject": "SegmentedControlIOS",
+ "mdlink": "segmentedcontrolios"
+ },
+ {
+ "subject": "Slider",
+ "mdlink": "slider"
+ },
+ {
+ "subject": "StatusBar",
+ "mdlink": "statusbar"
+ },
+ {
+ "subject": "Switch",
+ "mdlink": "switch"
+ },
+ {
+ "subject": "TabBarIOS",
+ "mdlink": "tabbarios"
+ },
+ {
+ "subject": "TabBarIOS.Item",
+ "mdlink": "tabbarios-item"
+ },
+ {
+ "subject": "Text",
+ "mdlink": "text"
+ },
+ {
+ "subject": "TextInput",
+ "mdlink": "textinput"
+ },
+ {
+ "subject": "ToolbarAndroid",
+ "mdlink": "toolbarandroid"
+ },
+ {
+ "subject": "TouchableHighlight",
+ "mdlink": "touchablehighlight"
+ },
+ {
+ "subject": "TouchableNativeFeedback",
+ "mdlink": "touchablenativefeedback"
+ },
+ {
+ "subject": "TouchableOpacity",
+ "mdlink": "touchableopacity"
+ },
+ {
+ "subject": "TouchableWithoutFeedback",
+ "mdlink": "touchablewithoutfeedback"
+ },
+ {
+ "subject": "View",
+ "mdlink": "view"
+ },
+ {
+ "subject": "ViewPagerAndroid",
+ "mdlink": "viewpagerandroid"
+ },
+ {
+ "subject": "WebView",
+ "mdlink": "webview"
+ }
+ ]
+ },
+ {
+ "group": "API",
+ "contains": [
+ {
+ "subject": "ActionSheetIOS",
+ "mdlink": "actionsheetios"
+ },
+ {
+ "subject": "AdSupportIOS",
+ "mdlink": "adsupportios"
+ },
+ {
+ "subject": "Alert",
+ "mdlink": "alert"
+ },
+ {
+ "subject": "AlertIOS",
+ "mdlink": "alertios"
+ },
+ {
+ "subject": "Animated",
+ "mdlink": "animated"
+ },
+ {
+ "subject": "AppRegistry",
+ "mdlink": "appregistry"
+ },
+ {
+ "subject": "AppState",
+ "mdlink": "appstate"
+ },
+ {
+ "subject": "AsyncStorage",
+ "mdlink": "asyncstorage"
+ },
+ {
+ "subject": "BackAndroid",
+ "mdlink": "backandroid"
+ },
+ {
+ "subject": "CameraRoll",
+ "mdlink": "cameraroll"
+ },
+ {
+ "subject": "Clipboard",
+ "mdlink": "clipboard"
+ },
+ {
+ "subject": "DatePickerAndroid",
+ "mdlink": "datepickerandroid"
+ },
+ {
+ "subject": "Dimensions",
+ "mdlink": "dimensions"
+ },
+ {
+ "subject": "Easing",
+ "mdlink": "easing"
+ },
+ {
+ "subject": "Geolocation",
+ "mdlink": "geolocation"
+ },
+ {
+ "subject": "ImageEditor",
+ "mdlink": "imageeditor"
+ },
+ {
+ "subject": "ImagePickerIOS",
+ "mdlink": "imagepickerios"
+ },
+ {
+ "subject": "ImageStore",
+ "mdlink": "imagestore"
+ },
+ {
+ "subject": "InteractionManager",
+ "mdlink": "interactionmanager"
+ },
+ {
+ "subject": "Keyboard",
+ "mdlink": "keyboard"
+ },
+ {
+ "subject": "LayoutAnimation",
+ "mdlink": "layoutanimation"
+ },
+ {
+ "subject": "Linking",
+ "mdlink": "linking"
+ },
+ {
+ "subject": "NativeMethodsMixin",
+ "mdlink": "nativemethodsmixin"
+ },
+ {
+ "subject": "NetInfo",
+ "mdlink": "netinfo"
+ },
+ {
+ "subject": "PanResponder",
+ "mdlink": "panresponder"
+ },
+ {
+ "subject": "PermissionsAndroid",
+ "mdlink": "permissionsandroid"
+ },
+ {
+ "subject": "PixelRatio",
+ "mdlink": "pixelratio"
+ },
+ {
+ "subject": "PushNotificationIOS",
+ "mdlink": "pushnotificationios"
+ },
+ {
+ "subject": "Share",
+ "mdlink": "share"
+ },
+ {
+ "subject": "StyleSheet",
+ "mdlink": "stylesheet"
+ },
+ {
+ "subject": "Systrace",
+ "mdlink": "systrace"
+ },
+ {
+ "subject": "TimePickerAndroid",
+ "mdlink": "timepickerandroid"
+ },
+ {
+ "subject": "ToastAndroid",
+ "mdlink": "toastandroid"
+ },
+ {
+ "subject": "Vibration",
+ "mdlink": "vibration"
+ },
+ {
+ "subject": "布局样式属性",
+ "mdlink": "layout-props"
+ },
+ {
+ "subject": "阴影样式属性",
+ "mdlink": "shadow-props"
+ }
+ ]
+ }
+ ]
+}
diff --git a/docs/docs/0.41/integration-with-existing-apps.md b/docs/docs/0.41/integration-with-existing-apps.md
new file mode 100644
index 0000000..c166942
--- /dev/null
+++ b/docs/docs/0.41/integration-with-existing-apps.md
@@ -0,0 +1,850 @@
+
+
+
+## 核心概念
+
+如果你正准备从头开始制作一个新的应用,那么React Native会是个非常好的选择。但如果你只想给现有的原生应用中添加一两个视图或是业务流程,React Native也同样不在话下。只需简单几步,你就可以给原有应用加上新的基于React Native的特性、画面和视图等。
+
+
+
+
+把React Native组件植入到iOS应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 创建一个`Podfile`,在其中以`subspec`的形式填写所有你要植入的React Native的组件。
+3. 创建js文件,编写React Native组件的js代码。
+4. 添加一个事件处理函数,用于创建一个`RCTRootView`。这个`RCTRootView`正是用来承载你的React Native组件的,而且它必须对应你在`index.ios.js`中使用`AppRegistry`注册的模块名字。
+5. 启动React Native的Packager服务,运行应用。
+6. 根据需要添加更多React Native的组件。
+7. [调试](debugging.html)。
+8. 准备[部署发布](running-on-device-ios.html) (比如可以利用`react-native-xcode.sh`脚本)。
+9. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+把React Native组件植入到Android应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 在Android项目根目录中使用npm来安装`react-native` ,这样同时会创建一个`node_modules/`的目录。
+3. 创建js文件,编写React Native组件的js代码。
+4. 在`build.gradle`文件中添加`com.facebook.react:react-native:+`,以及一个指向`node_nodules/`目录中的`react-native`预编译库的`maven`路径。
+5. 创建一个React Native专属的`Activity`,在其中再创建`ReactRootView`。
+6. 启动React Native的Packager服务,运行应用。
+7. 根据需要添加更多React Native的组件。
+8. 在真机上[运行](running-on-device-android.html)、[调试](debugging.html)。
+9. [打包](signed-apk-android.html)。
+10. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+## 开发环境准备
+
+
+
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在安卓平台上所需的一切依赖软件(比如`npm`)。
+
+
+
+
+### 基础环境
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在iOS平台上所需的一切依赖软件(比如`npm`)。
+
+### CocoaPods
+
+[CocoaPods](http://cocoapods.org)是针对iOS和Mac开发的包管理工具。我们用它来把React Native框架的代码下载下来并添加到你当前的项目中。
+
+```bash
+$ sudo gem install cocoapods
+```
+
+> 从技术上来讲,我们完全可以跳过CocoaPods,但是这样一来我们就需要手工来完成很多配置项。CocoaPods可以帮我们完成这些繁琐的工作。
+
+
+## 示例App
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/iOS-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。 下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/swift-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+
+
+## 依赖包
+
+React Native的植入过程同时需要React和React Native两个node依赖包。
+
+### `package.json`
+
+我们把具体的依赖包记录在`package.json`文件中。如果项目根目录中没有这个文件,那就自己创建一个。
+
+> 对于一个典型的React Native项目来说,一般`package.json`和`index.ios.js`等文件会放在项目的根目录下。而iOS相关的原生代码会放在一个名为`ios/`的子目录中,这里也同时放着你的Xcode项目文件(`.xcodeproj`)。
+
+下面是一个最简单的`package.json`的内容示例。
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+```bash
+{
+ "name": "swift-2048",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+### 安装依赖包
+
+使用npm(node包管理器,Node package manager)来安装React和React Native模块。这些模块会被安装到项目根目录下的`node_modules/`目录中。
+在包含有package.json文件的目录(一般也就是项目根目录)中运行下列命令来安装:
+
+```bash
+$ npm install
+```
+
+## React Native框架
+
+React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的`Podfile`中指定我们所需要使用的组件。
+
+### Subspecs
+
+在你开始把React Native植入到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是`subspec`要做的工作。在创建`Podfile`文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个`subspec`。
+
+可用的`subspec`都列在[`node_modules/react-native/React.podspec`](https://github.com/facebook/react-native/blob/master/React.podspec)中,基本都是按其功能命名的。一般来说你首先需要添加`Core`,这一`subspec`包含了必须的`AppRegistry`、`StyleSheet`、`View`以及其他的一些React Native核心库。如果你想使用React Native的`Text`库(即``组件),那就需要添加`RCTText`的`subspec`。同理,`Image`需要加入`RCTImage`,等等。
+
+#### Podfile
+
+在React和React Native模块成功安装到`node_modules`目录之后,你就可以开始创建`Podfile`以便选择所需的组件安装到应用中。
+
+创建`Podfile`的最简单的方式就是在iOS原生代码所在的目录中使用CocoaPods的`init`命令:
+
+```bash
+## 在iOS原生代码所在的目录中(也就是`.xcodeproj`文件所在的目录)执行:
+$ pod init
+```
+
+`Podfile`会创建在执行命令的目录中。你需要调整其内容以满足你的植入需求。调整后的`Podfile`的内容看起来类似下面这样:
+
+
+
+```
+# target的名字一般与你的项目名字相同
+target 'NumberTileGame' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+
+end
+```
+
+
+
+```
+source 'https://github.com/CocoaPods/Specs.git'
+
+# 对于Swift应用来说下面两句是必须的
+platform :ios, '8.0'
+use_frameworks!
+
+# target的名字一般与你的项目名字相同
+target 'swift-2048' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+
+end
+```
+
+
+
+#### Pod安装
+
+创建好了`Podfile`后,就可以开始安装React Native的pod包了。
+
+```bash
+$ pod install
+```
+
+然后你应该可以看到类似下面的输出(译注:同样由于众所周知的网络原因,pod install的过程在国内非常不顺利,请自行配备稳定的翻墙工具,或是尝试一些[镜像源](https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&ch=2&tn=98010089_dg&wd=cocoapods%20%E9%95%9C%E5%83%8F&oq=cocoapods%E9%95%9C%E5%83%8F&rsv_pq=8fe4602600052d40&rsv_t=5d9fNEvNrqwcBS3rvMCKw0Cc%2FoW6XdW%2Bm4zks2nF3BxZ6cyWtJx1g%2F39Id6cUzeRTLM&rqlang=cn&rsv_enter=0&inputT=809&rsv_sug3=9&rsv_sug1=7&rsv_sug7=100&prefixsug=cocoapods%20%E9%95%9C%E5%83%8F&rsp=0&rsv_sug4=1010)):
+
+```bash
+Analyzing dependencies
+Fetching podspec for `React` from `../node_modules/react-native`
+Downloading dependencies
+Installing React (0.26.0)
+Generating Pods project
+Integrating client project
+Sending stats
+Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.
+```
+
+
+
+> 如果你看到类似"*The `swift-2048 [Debug]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig`. This can lead to problems with the CocoaPods installation*"的警告,请查看Xcode的`Build Settings`中的`Framework Search Paths`选项,确保其中的`Debug`和`Release`都只包含`$(inherited)`。
+
+
+
+## 代码集成
+
+现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正植入到应用中了。在我们的2048示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的React Native页面。
+
+### React Native组件
+
+我们首先要写的是"High Score"(得分排行榜)的JavaScript端的代码。
+
+#### 创建一个`index.ios.js`文件
+
+首先创建一个空的`index.ios.js`文件。一般来说我们把它放置在项目根目录下。
+
+> `index.ios.js`是React Native应用在iOS上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行`require/import`导入语句。本教程中为了简单示范,把全部的代码都写到了`index.ios.js`里(当然实际开发中我们并不推荐这样做)。
+
+```bash
+# 在项目根目录执行以下命令创建文件:
+$ touch index.ios.js
+```
+
+#### 添加你自己的React Native代码
+
+在`index.ios.js`中添加你自己的组件。这里我们只是简单的添加一个``组件,然后用一个带有样式的``组件把它包起来。
+
+```js
+'use strict';
+
+import React from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class RNHighScores extends React.Component {
+ render() {
+ var contents = this.props["scores"].map(
+ score => {score.name}:{score.value}{"\n"}
+ );
+ return (
+
+
+ 2048 High Scores!
+
+
+ {contents}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#FFFFFF',
+ },
+ highScoresTitle: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ scores: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+});
+
+// 整体js模块的名称
+AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
+```
+
+> `RNHighScores`是整体js模块(即你所有的js代码)的名称。你在iOS原生代码中添加React Native视图时会用到这个名称。
+
+## The Magic: `RCTRootView`
+
+现在我们已经在`index.ios.js`中创建了React Native组件,下一步就是把这个组件添加给一个新的或已有的`ViewController`。 The easiest path to take is to optionally create an event path to your component and then add that component to an existing `ViewController`.
+
+We will tie our React Native component with a new native view in the `ViewController` that will actually host it called `RCTRootView` .
+
+### Create an Event Path
+
+You can add a new link on the main game menu to go to the "High Score" React Native page.
+
+
+
+#### 事件处理
+
+We will now add an event handler from the menu link. A method will be added to the main `ViewController` of your application. This is where `RCTRootView` comes into play.
+
+When you build a React Native application, you use the React Native packager to create an `index.ios.bundle` that will be served by the React Native server. Inside `index.ios.bundle` will be our `RNHighScore` module. So, we need to point our `RCTRootView` to the location of the `index.ios.bundle` resource (via `NSURL`) and tie it to the module.
+
+We will, for debugging purposes, log that the event handler was invoked. Then, we will create a string with the location of our React Native code that exists inside the `index.ios.bundle`. Finally, we will create the main `RCTRootView`. Notice how we provide `RNHighScores` as the `moduleName` that we created [above](#the-react-native-component) when writing the code for our React Native component.
+
+
+
+首先导入`RCTRootView`的头文件。
+
+```
+#import "RCTRootView.h"
+```
+
+> 这里的`initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+- (IBAction)highScoreButtonPressed:(id)sender {
+ NSLog(@"High Score Button Pressed");
+ NSURL *jsCodeLocation = [NSURL
+ URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
+ RCTRootView *rootView =
+ [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
+ moduleName : @"RNHighScores"
+ initialProperties :
+ @{
+ @"scores" : @[
+ @{
+ @"name" : @"Alex",
+ @"value": @"42"
+ },
+ @{
+ @"name" : @"Joel",
+ @"value": @"10"
+ }
+ ]
+ }
+ launchOptions : nil];
+ UIViewController *vc = [[UIViewController alloc] init];
+ vc.view = rootView;
+ [self presentViewController:vc animated:YES completion:nil];
+}
+```
+
+> Note that `RCTRootView initWithURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `[RCTRootView alloc] initWithURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+首先`import`导入`React`库。
+
+```
+import React
+```
+
+> The `initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+@IBAction func highScoreButtonTapped(sender : UIButton) {
+ NSLog("Hello")
+ let jsCodeLocation = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")
+ let mockData:NSDictionary = ["scores":
+ [
+ ["name":"Alex", "value":"42"],
+ ["name":"Joel", "value":"10"]
+ ]
+ ]
+
+ let rootView = RCTRootView(
+ bundleURL: jsCodeLocation,
+ moduleName: "RNHighScores",
+ initialProperties: mockData as [NSObject : AnyObject],
+ launchOptions: nil
+ )
+ let vc = UIViewController()
+ vc.view = rootView
+ self.present(vc, animated: true, completion: nil)
+}
+```
+
+> 注意`RCTRootView bundleURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `RCTRootView bundleURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `let mainBundle = NSBundle(URLForResource: "main" withExtension:"jsbundle")`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+#### Wire Up
+
+Wire up the new link in the main menu to the newly added event handler method.
+
+
+
+> One of the easier ways to do this is to open the view in the storyboard and right click on the new link. Select something such as the `Touch Up Inside` event, drag that to the storyboard and then select the created method from the list provided.
+
+## 测试植入结果
+
+You have now done all the basic steps to integrate React Native with your current application. Now we will start the React Native packager to build the `index.ios.bundle` packager and the server running on `localhost` to serve it.
+
+### App Transport Security
+
+Apple has blocked implicit cleartext HTTP resource loading. So we need to add the following our project's `Info.plist` (or equivalent) file.
+
+```xml
+NSAppTransportSecurity
+
+ NSExceptionDomains
+
+ localhost
+
+ NSTemporaryExceptionAllowsInsecureHTTPLoads
+
+
+
+
+```
+
+### 运行Packager
+
+```bash
+# From the root of your project, where the `node_modules` directory is located.
+$ npm start
+```
+
+### 运行应用
+
+如果你使用的是Xcode,那么照常编译和运行应用即可。如果你没有使用Xcode(但是你仍然必须安装Xcode),则可以在命令行中使用以下命令来运行应用:
+
+```bash
+# 在项目的根目录中执行:
+$ react-native run-ios
+```
+
+In our sample application, you should see the link to the "High Scores" and then when you click on that you will see the rendering of your React Native component.
+
+Here is the *native* application home screen:
+
+
+
+Here is the *React Native* high score screen:
+
+
+
+> If you are getting module resolution issues when running your application please see [this GitHub issue](https://github.com/facebook/react-native/issues/4968) for information and possible resolution. [This comment](https://github.com/facebook/react-native/issues/4968#issuecomment-220941717) seemed to be the latest possible resolution.
+
+### 看一下完整的代码变更
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/iOS-2048/commit/9ae70c7cdd53eb59f5f7c7daab382b0300ed3585)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/swift-2048/commit/13272a31ee6dd46dc68b1dcf4eaf16c1a10f5229)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+## 在应用中添加JS代码
+
+在项目的根目录中运行:
+
+ $ npm init
+ $ npm install --save react react-native
+ $ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
+
+`npm init`创建了一个空的node模块(其实就是创建了一个package.json描述文件),而`npm install`则创建了node_modules目录并把react和react-native下载到了其中。至于第三步curl命令,其实质是`下载`.flowconfig配置文件,这个文件用于约束js代码的写法。这一步非必需,可跳过。下面我们打开新创建的`package.json`文件,然后在其`scripts`字段中加入:
+
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+
+现在你的`package.json`内容应该类似这样:
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+接下来在项目根目录中创建`index.android.js`文件,然后将下面的代码复制粘贴进来:
+
+```js
+'use strict';
+
+import React from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class HelloWorld extends React.Component {
+ render() {
+ return (
+
+ Hello, World
+
+ )
+ }
+}
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ hello: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+});
+
+AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
+```
+
+## 准备工作
+
+在你的app中 `build.gradle` 文件中添加 React Native 依赖:
+
+```
+ dependencies {
+ ...
+ compile "com.facebook.react:react-native:+" // From node_modules.
+ }
+```
+
+> 你想要指定构建时的 React Native 版本,请用 `npm` 已下载的本地 React Native 的版本号替换 `+` 。
+
+在项目的 `build.gradle` 文件中为 React Native 添加一个 maven 依赖的入口,必须写在 "allprojects" 代码块中:
+
+```
+allprojects {
+ repositories {
+ ...
+ maven {
+ // All of React Native (JS, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+ }
+ ...
+}
+```
+
+> 确保依赖路径的正确!以免在 Android Studio 运行Gradle同步构建时抛出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 异常。
+
+接着,在 `AndroidManifest.xml` 清单文件中声明网络权限:
+
+
+
+如果需要访问 `DevSettingsActivity` 界面,也需要在 `AndroidManifest.xml` 中声明:
+
+
+
+
+This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.
+
+## 添加原生代码
+
+想要通过原生代码调用 React Native ,就像这样,我们需要在一个 `Activity` 中创建一个 `ReactRootView` 对象,将它关联一个 React application 并设为界面的主视图。
+
+> 如果你想在安卓5.0以下的系统上运行,请用 `com.android.support:appcompat` 包中的 `AppCompatActivity` 代替 `Activity` 。
+
+
+```java
+public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
+ private ReactRootView mReactRootView;
+ private ReactInstanceManager mReactInstanceManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mReactRootView = new ReactRootView(this);
+ mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ .setBundleAssetName("index.android.bundle")
+ .setJSMainModuleName("index.android")
+ .addPackage(new MainReactPackage())
+ .setUseDeveloperSupport(BuildConfig.DEBUG)
+ .setInitialLifecycleState(LifecycleState.RESUMED)
+ .build();
+
+ // 注意这里的HelloWorld必须对应“index.android.js”中的
+ // “AppRegistry.registerComponent()”的第一个参数
+ mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
+
+ setContentView(mReactRootView);
+ }
+
+ @Override
+ public void invokeDefaultOnBackPressed() {
+ super.onBackPressed();
+ }
+}
+```
+
+> 如果你的项目名字不是叫“HelloWorld”,则需要将“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一个参数替换为对应的名字。
+
+如果你使用的是 Android Studio , 请用 `Alt + Enter` 为 MyReactActivity 类导包。当你使用了不止一个 `...facebook...` 包时,请谨慎选择要导入的类。
+
+我们需要把 `MyReactActivity` 的主题设定为 `Theme.AppCompat.Light.NoActionBar` ,因为里面有许多组件都使用了这一主题。
+
+ ```xml
+
+
+ ```
+
+> A `ReactInstanceManager` can be shared amongst multiple activities and/or fragments. You will want to make your own `ReactFragment` or `ReactActivity` and have a singleton *holder* that holds a `ReactInstanceManager`. When you need the `ReactInstanceManager` (e.g., to hook up the `ReactInstanceManager` to the lifecycle of those Activities or Fragments) use the one provided by the singleton.
+
+Next, we need to pass some activity lifecycle callbacks down to the `ReactInstanceManager`:
+
+```java
+@Override
+protected void onPause() {
+ super.onPause();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostPause(this);
+ }
+}
+
+@Override
+protected void onResume() {
+ super.onResume();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostResume(this, this);
+ }
+}
+
+@Override
+protected void onDestroy() {
+ super.onDestroy();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostDestroy();
+ }
+}
+```
+
+We also need to pass back button events to React Native:
+
+```java
+@Override
+ public void onBackPressed() {
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+}
+```
+
+This allows JavaScript to control what happens when the user presses the hardware back button (e.g. to implement navigation). When JavaScript doesn't handle a back press, your `invokeDefaultOnBackPressed` method will be called. By default this simply finishes your `Activity`.
+
+Finally, we need to hook up the dev menu. By default, this is activated by (rage) shaking the device, but this is not very useful in emulators. So we make it show when you press the hardware menu button (use `Ctrl + M` if you're using Android Studio emulator):
+
+```java
+@Override
+public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
+ mReactInstanceManager.showDevOptionsDialog();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+}
+```
+
+现在activity已就绪,可以运行一些JavaScript代码了。
+
+### 配置权限以便开发中的红屏错误能正确显示
+
+If your app is targeting the Android `API level 23` or greater, make sure you have the `overlay` permission enabled for the development build. You can check it with `Settings.canDrawOverlays(this);`. This is required in dev builds because react native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23, the user needs to approve it. This can be acheived by adding the following code to the Activity file in the onCreate() method. OVERLAY_PERMISSION_REQ_CODE is a field of the class which would be responsible for passing the result back to the Activity.
+
+```java
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:" + getPackageName()));
+ startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
+ }
+}
+```
+
+Finally, the `onActivityResult()` method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX.
+
+```java
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ // SYSTEM_ALERT_WINDOW permission not granted...
+ }
+ }
+ }
+}
+```
+
+
+## 运行你的应用
+
+运行应用首先需要启动开发服务器(Packager)。你只需在项目根目录中执行以下命令即可:
+
+ $ npm start
+
+Now build and run your Android app as normal (`./gradlew installDebug` from command-line; in Android Studio just create debug build as usual).
+
+> If you are using Android Studio for your builds and not the Gradle Wrapper directly, make sure you install [watchman](https://facebook.github.io/watchman/) before running `npm start`. It will prevent the packager from crashing due to conflicts between Android Studio and the React Native packager.
+
+Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display:
+
+
+
+## 在Android Studio中打包
+
+你也可以使用Android Studio来打包!You can use Android Studio to create your release builds too! It’s as easy as creating release builds of your previously-existing native Android app. There’s just one additional step, which you’ll have to do before every release build. You need to execute the following to create a React Native bundle, which’ll be included with your native Android app:
+
+ $ react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/
+
+Don’t forget to replace the paths with correct ones and create the assets folder if it doesn’t exist!
+
+Now just create a release build of your native app from within Android Studio as usual and you should be good to go!
+
+
+
diff --git a/docs/docs/0.41/interactionmanager.md b/docs/docs/0.41/interactionmanager.md
new file mode 100644
index 0000000..16555fb
--- /dev/null
+++ b/docs/docs/0.41/interactionmanager.md
@@ -0,0 +1,58 @@
+Interactionmanager可以将一些耗时较长的工作安排到所有互动或动画完成之后再进行。这样可以保证JavaScript动画的流畅运行。
+
+应用这样可以安排一个任务在交互和动画完成之后执行:
+
+```javascript
+InteractionManager.runAfterInteractions(() => {
+ // ...耗时较长的同步的任务...
+});
+```
+
+把这个和其他的延迟计划函数对比:
+
+- requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
+- setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
+- runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
+
+触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将`runAfterInteractions()`的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
+
+InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
+
+```javascript
+var handle = InteractionManager.createInteractionHandle();
+// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
+// 在动画完成之后
+InteractionManager.clearInteractionHandle(handle);
+// 在所有句柄都清除之后,现在开始依序执行队列中的任务
+```
+`runAfterInteractions`接受一个普通的回调函数,或是一个`PromiseTask`对象,该对象需要带有名为`gen`的方法,并返回一个`Promise`。如果提供的参数是一个`PromiseTask`, 那么即便它是异步的它也会阻塞任务队列,直到它(以及它所有的依赖任务,哪怕这些依赖任务也是异步的)执行完毕后,才会执行下一个任务。
+
+默认情况下,排队的任务会在一次setImmediate方法中依序批量执行。如果你调用了setDeadLine方法并设定了一个正整数值,则任务只会在设定的时间到达后开始执行。在此之前,任务会通过setTimeout来挂起并阻塞其他任务执行,这样可以给诸如触摸交互一类的事件留出时间,使应用可以更快地响应用户。
+
+### 方法
+
+
+
+
static runAfterInteractions(callback: Function) #
+
安排一个函数在所有的交互和动画完成之后运行。返回一个可取消的promise。
+
+
+
static createInteractionHandle() #
+
+
+
+
static clearInteractionHandle(handle: Handle) #
+
+
+
+
static setDeadline(deadline: number) #
+
如果设定了一个正整数值,则会使用setTimeout来挂起所有尚未执行的任务。在eventLoopRunningTime到达设定时间后,才开始使用一个setImmediate方法来批量执行所有任务。
+
+
+
+### 属性
+
+
+
+
addListener: CallExpression #
+
diff --git a/docs/docs/0.41/javascript-environment.md b/docs/docs/0.41/javascript-environment.md
new file mode 100644
index 0000000..d95513d
--- /dev/null
+++ b/docs/docs/0.41/javascript-environment.md
@@ -0,0 +1,75 @@
+在使用React Native时,你的JavaScript代码将会运行在两个不同的环境上:
+
+* 在iOS、Android的模拟器或是真机上,React Native使用的是[JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore),也就是Safari所使用的JavaScript引擎。但是在iOS上JavaScriptCore并没有使用即时编译技术(JIT),因为在iOS中应用无权拥有可写可执行的内存页(因而无法动态生成代码)。
+* 在使用Chrome调试时,所有的JavaScript代码都运行在Chrome中,并且通过WebSocket与原生代码通信。此时的运行环境是[V8引擎](https://code.google.com/p/v8/)。
+
+虽然两个环境非常类似,但开发者还是可能碰到一些不一致的地方。未来我们很可能会尝试一些其他的JS引擎,所以请尽量避免使用依赖于特定运行环境的代码。
+
+## JavaScript语法转换器
+
+语法转换器可以使编写代码的过程更加享受,因为开发者可以借助转换器直接使用新的JavaScirpt语法标准,而无需等待JS解释器的支持。
+
+React Native从0.5.0版本开始已经内置[Babel转换器](https://babeljs.io)。你可以查看[Babel的文档](https://babeljs.io/docs/plugins/#transform-plugins)来了解有关它可以转换的语法的详情。
+
+这里可以看到目前React Native默认开启的[语法转换特性](https://github.com/facebook/react-native/blob/master/babel-preset/configs/main.js#L16)。
+注:若想学习相关语法,译者推荐阮一峰老师的[《ECMAScript 6入门》](http://es6.ruanyifeng.com/)以及论坛的[讨论帖](http://bbs.reactnative.cn/topic/15)。
+
+ES5
+
+* 保留关键字: `promise.catch(function() { });`
+
+ES6
+
+* [箭头函数Arrow functions](http://babeljs.io/docs/learn-es2015/#arrows): ` this.setState({pressed: true})}`
+* [块级作用域Block scoping](https://babeljs.io/docs/learn-es2015/#let-const): `let greeting = 'hi';`
+* [数组的扩展运算Call spread](http://babeljs.io/docs/learn-es2015/#default-rest-spread): `Math.max(...array);`
+* [类Classes](http://babeljs.io/docs/learn-es2015/#classes): `class C extends React.Component { render() { return ; } }`
+* [常量Constants](https://babeljs.io/docs/learn-es2015/#let-const): `const answer = 42;`
+* [解构Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring): `var {isActive, style} = this.props;`
+* [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of): `for (var num of [1, 2, 3]) {}`
+* [模块Modules](http://babeljs.io/docs/learn-es2015/#modules): `import React, { Component } from 'react';`
+* [动态属性键Computed Properties](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var key = 'abc'; var obj = {[key]: 10};`
+* 对象方法的简写Object Consise Method: `var obj = { method() { return 10; } };`
+* [对象属性的简写Object Short Notation](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var name = 'vjeux'; var obj = { name };`
+* [参数的扩展运算Rest Params](https://github.com/sebmarkbage/ecmascript-rest-spread): `function(type, ...args) { }`
+* [字符串模板Template Literals](http://babeljs.io/docs/learn-es2015/#template-strings): ``var who = 'world'; var str = `Hello ${who}`;``
+
+ES7
+
+* [对象的扩展运算Object Spread](https://github.com/sebmarkbage/ecmascript-rest-spread): `var extended = { ...obj, a: 10 };`
+* [参数列表末尾允许放置逗号Function Trailing Comma](https://github.com/jeffmo/es-trailing-function-commas): `function f(a, b, c,) { }`
+* [Async函数](https://github.com/tc39/ecmascript-asyncawait): `async function doStuffAsync() { const foo = await doOtherStuffAsync(); }`;
+
+其他特性
+
+* [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): ` `
+* [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
+
+## 接口兼容(Polyfills)
+
+许多标准功能也都在支持的JavaScript运行环境上做了兼容支持。
+
+浏览器
+
+* [console.{log, warn, error, info, trace, table}](https://developer.chrome.com/devtools/docs/console-api)
+* [CommonJS require](https://nodejs.org/docs/latest/api/modules.html)
+* [XMLHttpRequest, fetch](/react-native/docs/network.html#content)
+* [{set, clear}{Timeout, Interval, Immediate}, {request, cancel}AnimationFrame](/react-native/docs/timers.html#content)
+* [navigator.geolocation](/react-native/docs/geolocation.html#content)
+
+ES6
+
+* [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+* String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)}
+* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
+* Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)}
+
+ES7
+
+* Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)}
+
+其他特性
+
+* `__DEV__`
+
+
diff --git a/docs/docs/0.41/keyboard.md b/docs/docs/0.41/keyboard.md
new file mode 100644
index 0000000..a53f0bf
--- /dev/null
+++ b/docs/docs/0.41/keyboard.md
@@ -0,0 +1,73 @@
+`Keyboard`组件可以用来控制键盘相关的事件。
+
+### 用法
+`Keyboard`组件可以监听原生键盘事件以做出相应回应,比如收回键盘。
+
+```js
+import React, { Component } from 'react';
+import { Keyboard, TextInput } from 'react-native';
+
+class Example extends Component {
+ componentWillMount () {
+ this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
+ this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
+ }
+
+ componentWillUnmount () {
+ this.keyboardDidShowListener.remove();
+ this.keyboardDidHideListener.remove();
+ }
+
+ _keyboardDidShow () {
+ alert('Keyboard Shown');
+ }
+
+ _keyboardDidHide () {
+ alert('Keyboard Hidden');
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+```
+### 方法
+
+
+
static addListener(nativeEvent, jsFunction) #
+
addListener用于注册一个JavaScript函数来监听处理原生键盘通知事件。
+
此方法会返回监听函数的引用。
+
@param {string} nativeEvent nativeEvent参数用来指明要监听的事件,具体有以下几种:
+ - keyboardWillShow
+ - keyboardDidShow
+ - keyboardWillHide
+ - keyboardDidHide
+ - keyboardWillChangeFrame
+ - keyboardDidChangeFrame
+
@param {function} jsFunction 事件触发时调用的js函数。
+
+
static removeAllListeners(eventType) #
+
移除某个类型事件的所有监听函数.
+
@param {string} eventType 要移除的原生事件类型
+
+
static removeSubscription(subscription) #
+
+
@param {EmitterSubscription} subscription 要移除的监听函数
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/keyboardavoidingview.md b/docs/docs/0.41/keyboardavoidingview.md
new file mode 100644
index 0000000..9b98529
--- /dev/null
+++ b/docs/docs/0.41/keyboardavoidingview.md
@@ -0,0 +1,150 @@
+本组件用于解决一个常见的尴尬问题:手机上弹出的键盘常常会挡住当前的视图。本组件可以自动根据键盘的位置,调整自身的position或底部的padding,以避免被遮挡。
+
+### 属性
+
+
+
+
behavior PropTypes.oneOf(['height', 'position', 'padding'])
+ #
+
+
+
+
contentContainerStyle
+ View#style
+ #
+
+
如果设定behavior值为'position',则会生成一个View作为内容容器。此属性用于指定此内容容器的样式。
+
+
+
keyboardVerticalOffset
+ PropTypes.number.isRequired
+ #
+
+
有时候应用离屏幕顶部还有一些距离(比如状态栏等等),利用此属性来补偿修正这段距离。
+
+
+
+### 方法
+
+
+
relativeKeyboardHeight(keyboardFrame): #
+
+
+
+
onKeyboardChange(event) #
+
+
+
+
onLayout(event)
+ #
+
+
+
+
+### 例子
+
+```js
+'use strict';
+
+const React = require('React');
+const ReactNative = require('react-native');
+const {
+ KeyboardAvoidingView,
+ Modal,
+ SegmentedControlIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+const UIExplorerBlock = require('./UIExplorerBlock');
+const UIExplorerPage = require('./UIExplorerPage');
+
+class KeyboardAvoidingViewExample extends React.Component {
+ static title = '';
+ static description = 'Base component for views that automatically adjust their height or position to move out of the way of the keyboard.';
+
+ state = {
+ behavior: 'padding',
+ modalOpen: false,
+ };
+
+ onSegmentChange = (segment: String) => {
+ this.setState({behavior: segment.toLowerCase()});
+ };
+
+ renderExample = () => {
+ return (
+
+
+
+
+
+
+ this.setState({modalOpen: false})}
+ style={styles.closeButton}>
+ Close
+
+
+
+ this.setState({modalOpen: true})}>
+ Open Example
+
+
+ );
+ };
+
+ render() {
+ return (
+
+
+ {this.renderExample()}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ outerContainer: {
+ flex: 1,
+ },
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ paddingHorizontal: 20,
+ paddingTop: 20,
+ },
+ textInput: {
+ borderRadius: 5,
+ borderWidth: 1,
+ height: 44,
+ paddingHorizontal: 10,
+ },
+ segment: {
+ marginBottom: 10,
+ },
+ closeButton: {
+ position: 'absolute',
+ top: 30,
+ left: 10,
+ }
+});
+
+module.exports = KeyboardAvoidingViewExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/known-issues.md b/docs/docs/0.41/known-issues.md
new file mode 100644
index 0000000..2fe0cd0
--- /dev/null
+++ b/docs/docs/0.41/known-issues.md
@@ -0,0 +1,78 @@
+### Chrome开发工具中的"React"选项无法使用
+目前[无法使用](https://github.com/facebook/react-devtools/issues/229)开发工具中的"React"选项来查看App的组件。这是由于脚本在开发工具插件中的运行方式改变了;它们现在在Web Worker内部运行,插件并不知道,因此无法很好的和React Native进行通讯。
+即便如此,你仍然可以使用开发工具的Console和Sources选项,而且可以使用断点来调试JavaScript。为了能够使用Console功能,你必须确认在开发工具下拉菜单中选择入口文件为 ⚙debuggerWorker.js,(默认选择为<top frame>)。
+
+
+### 缺失的Android模块和视图
+
+虽然React Native的Android版本的开发工作晚于iOS版本,但目前大多数视图都在Android上实现了,除了下面几个例外:
+
+#### 视图
+
+- Maps —— 我们推荐使用Leland Richardson的[react-native-maps](https://github.com/lelandrichardson/react-native-maps),它比我们内部实现的map功能更完善。
+
+
+#### 模块
+- Android推送通知 (请使用第三方模块,比如[react-native-jpush](https://github.com/reactnativecn/react-native-jpush))
+
+
+### 某些属性仅仅支持单个平台
+
+有些属性只能在单个平台上使用,这是由于这些特性仅有单个平台支持或者是尚未在其他平台上实现。所有这些都在JS文档中被`@platform`标注,并且左侧有一个小标记。
+
+### 平台一致性
+以下是一些本该(或将要)设计得更通用的API或组件:
+
+- ``和``功能类似。我们或许希望统一成``。
+
+- `ActivityIndicator`可以跨平台地渲染一个原生的加载(loading)指示器(目前在iOS上使用`ActivityIndicatorIOS`,而在Android上使用`ProgressBarAndroid`)
+
+- `ProgressBar`可以跨平台渲染一个水平的进度条(目前只在iOS上支持,使用`ProgressViewIOS `)
+
+
+### 使用第三方的原生模块
+
+[JS.coach](https://js.coach/react-native)上有很多非常优秀的第三方模块。
+在你的项目中集成这些模块应该并不困难,这里有一个[实际应用的例子](https://github.com/apptailor/react-native-google-signin)。
+
+### overflow样式在Android默认为hidden而且无法更改
+
+这是Android本身的渲染机制所致。我们没有实现这一特性,因为这是个大工程,而且我们还有很多其他重要的任务。
+Android的`overflow:hidden`还有另外一个问题:如果父容器有`borderRadius`圆角边框样式,那么即便开启了`overflow:hidden`也仍然无法把子视图超出圆角边框的部分裁切掉。这个问题只存在于Android上,iOS并没有这个问题(子视图的内容不会超出父容器的圆角边框)。你可以在[这里](https://rnplay.org/apps/BlGjdQ)看到问题的演示,以及在[这里](https://github.com/facebook/react-native/issues/3198)查看这个问题的报告以及后续进展。
+
+### 视图阴影
+
+`shadow`开头的[样式](view.html#style)现在可以在iOS上应用,而Android上对应的属性(props)是`elevation`。设置`elevation`属性就等价于使用原生的[`elevation API`](https://developer.android.com/training/material/shadows-clipping.html#Elevation),因而也有同样的限制(比如最明显的就是需要Android 5.0以上版本)。此外还会影响到层叠视图在空间z轴上的顺序。
+
+### Android M(6.0)的权限
+
+当前版本的React Native还不支持Android M的[权限模型](http://developer.android.com/training/permissions/requesting.html)。
+
+### Android纯布局(Layout-only)节点
+
+Android版本的React Native有一个优化的特性:有些视图,只起布局作用而没有对应的原生视图,那么只有它们的布局属性会被传递给子视图。这个优化对于深层次的视图的稳定性很重要因此默认开启。要关闭这个特性,请设置`collapsable`为false:
+
+```
+
+ ...
+
+```
+
+### PNG图片的内存问题
+React Native Android 依靠[Fresco](https://github.com/facebook/fresco)载入和显示图片。目前我们关闭了下采样(downsampling)(这一特性还不稳定),因此有可能载入较大的PNG图片时会出现内存问题。
+
+### react-native init时卡住
+
+尝试运行`react-native init`时加上`--verbose`参数,点这里[#2797](https://github.com/facebook/react-native/issues/2797)查看一般可能的原因。
+译注:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请将npm仓库源替换为国内镜像:
+
+```
+npm config set registry https://registry.npm.taobao.org
+npm config set disturl https://npm.taobao.org/dist
+```
+另,执行init时切记不要在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题,请使用chown修复)。
+又,react-native.cn中文网提供了完整的[绿色纯净新项目包](http://bbs.reactnative.cn/topic/11)。完整打包全部iOS和Android的第三方依赖,只要环境配置正确,无需科学上网漫长等待,解压后即可直接运行。
+
+### 文本框的边界(border)
+
+文本框默认的边界在视图的底部。这个边界有一个内衬(padding),这个padding由系统提供的背景图片所设定,并且无法改变。解决这个问题有两个方案,一是可以不指定高度,这样系统会自动处理,在恰当的位置显示边界;或者干脆通过设定[underlineColorAndroid](textinput.html#underlinecolorandroid)为透明来隐藏边界。
diff --git a/docs/docs/0.41/layout-props.md b/docs/docs/0.41/layout-props.md
new file mode 100644
index 0000000..4998bc6
--- /dev/null
+++ b/docs/docs/0.41/layout-props.md
@@ -0,0 +1,236 @@
+
+
alignItems enum('flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
alignSelf enum('auto', 'flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
borderBottomWidth number #
+
+
+
+
borderLeftWidth number #
+
+
+
borderRightWidth number #
+
+
+
+
borderTopWidth number #
+
+
+
borderWidth number
+ #
+
+
+
+
flex number
+ #
+
在React Native中flex的表现和CSS有些区别。
+ flex在RN中只能为整数值,其具体表现请参考yoga引擎库的文档,其网址是https://github.com/facebook/yoga
+
当flex取正整数值时, is a positive number, it makes the component flexible
+ and it will be sized proportional to its flex value. So a
+ component with flex set to 2 will take twice the space as a
+ component with flex set to 1.
+
When flex is 0, the component is sized according to width
+ and height and it is inflexible.
+
When flex is -1, the component is normally sized according
+ width and height. However, if there's not enough space,
+ the component will shrink to its minWidth and minHeight.
+
flexGrow, flexShrink, and flexBasis work the same as in CSS.
+
+
+
flexDirection enum('row', 'row-reverse', 'column', 'column-reverse') #
+
+
flexDirection controls which directions children of a container go.
+ row goes left to right, column goes top to bottom, and you may
+ be able to guess what the other two do. It works like flex-direction
+ in CSS, except the default is column.访问https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction 来进一步了解。
+
+
+
+
flexWrap enum('wrap', 'nowrap')
+ #
+
+
+
+
justifyContent enum('flex-start', 'flex-end', 'center', 'space-between', 'space-around') #
+
+
+
+
+
marginBottom number #
+
+
+
marginHorizontal number #
+
+
Setting marginHorizontal has the same effect as setting
+ both marginLeft and marginRight.
+
+
marginLeft number
+ #
+
+
+
marginRight number
+ #
+
+
+
+
marginVertical number #
+
Setting marginVertical has the same effect as setting both
+ marginTop and marginBottom.
+
+
+
+
+
+
overflow enum('visible', 'hidden', 'scroll')
+ #
+
overflow controls how a children are measured and displayed.
+ overflow: hidden causes views to be clipped while overflow: scroll
+ causes views to be measured independently of their parents main axis.It works likeoverflow` in
+ CSS (default: visible).访问https://developer.mozilla.org/en/docs/Web/CSS/overflow 来进一步了解。
+
+
+
paddingBottom number #
+
+
+
paddingHorizontal number #
+
+
Setting paddingHorizontal is like setting both of
+ paddingLeft and paddingRight.
+
+
paddingLeft number
+ #
+
+
+
paddingRight number #
+
+
+
paddingTop number
+ #
+
+
+
paddingVertical number #
+
Setting paddingVertical is like setting both of
+ paddingTop and paddingBottom.
+
+
position enum('absolute', 'relative')
+ #
+
position in React Native is similar to regular CSS, but
+ everything is set to relative by default, so absolute
+ positioning is always just relative to the parent.
+
If you want to position a child using specific numbers of logical
+ pixels relative to its parent, set the child to have absolute
+ position.
+
If you want to position a child relative to something
+ that is not its parent, just don't use styles for that. Use the
+ component tree.
+
访问https://facebook.github.io/yoga/docs/absolute-position/ 来进一步了解position在React Native和CSS中的差异。
+
+
+
+
+
zIndex number #
+
zIndex controls which components display on top of others.
+ Normally, you don't use zIndex. Components render according to
+ their order in the document tree, so later components draw over
+ earlier ones. zIndex may be useful if you have animations or custom
+ modal interfaces where you don't want this behavior.
+
It works like the CSS z-index property - components with a larger
+ zIndex will render on top. Think of the z-direction like it's
+ pointing from the phone into your eyeball.访问https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
+来进一步了解。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/layout-with-flexbox.md b/docs/docs/0.41/layout-with-flexbox.md
new file mode 100644
index 0000000..9b1130f
--- /dev/null
+++ b/docs/docs/0.41/layout-with-flexbox.md
@@ -0,0 +1,97 @@
+我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
+
+一般来说,使用`flexDirection`、`alignItems`和 `justifyContent`三个样式属性就已经能满足大多数布局需求。译注:这里有一份[简易布局图解](http://weibo.com/1712131295/CoRnElNkZ?ref=collection&type=comment),可以给你一个大概的印象。
+
+> React Native中的Flexbox的工作原理和web上的CSS基本一致,当然也存在少许差异。首先是默认值不同:`flexDirection`的默认值是`column`而不是`row`,而`flex`也只能指定一个数字值。
+
+#### Flex Direction
+
+在组件的`style`中指定`flexDirection`可以决定布局的**主轴**。子元素是应该沿着**水平轴(`row`)**方向排列,还是沿着**竖直轴(`column`)**方向排列呢?默认值是**竖直轴(`column`)**方向。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDirectionBasics extends Component {
+ render() {
+ return (
+ // 尝试把`flexDirection`改为`column`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
+```
+
+#### Justify Content
+
+在组件的style中指定`justifyContent`可以决定其子元素沿着**主轴**的**排列方式**。子元素是应该靠近主轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`、`space-around`以及`space-between`。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class JustifyContentBasics extends Component {
+ render() {
+ return (
+ // 尝试把`justifyContent`改为`center`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
+```
+
+#### Align Items
+
+在组件的style中指定`alignItems`可以决定其子元素沿着**次轴**(与主轴垂直的轴,比如若主轴方向为`row`,则次轴方向为`column`)的**排列方式**。子元素是应该靠近次轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`以及`stretch`。
+
+> 注意:要使`stretch`选项生效的话,子元素在次轴方向上不能有固定的尺寸。以下面的代码为例:只有将子元素样式中的`width: 50`去掉之后,`alignItems: 'stretch'`才能生效。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class AlignItemsBasics extends Component {
+ render() {
+ return (
+ // 尝试把`alignItems`改为`flex-start`看看
+ // 尝试把`justifyContent`改为`flex-end`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
+```
+
+#### 深入学习
+
+以上我们已经介绍了一些基础知识,但要运用好布局,我们还需要很多其他的样式。对于布局有影响的完整样式列表记录在[这篇文档中](layout-props.html)。
+
+现在我们已经差不多可以开始真正的开发工作了。哦,忘了还有个常用的知识点:[如何使用TextInput组件来处理用户输入](handling-text-input.html)。
diff --git a/docs/docs/0.41/layoutanimation.md b/docs/docs/0.41/layoutanimation.md
new file mode 100644
index 0000000..e309eb6
--- /dev/null
+++ b/docs/docs/0.41/layoutanimation.md
@@ -0,0 +1,49 @@
+当布局变化时,自动将视图运动到它们新的位置上。
+
+
+一个常用的调用此API的办法是调用`LayoutAnimation.configureNext`,然后调用`setState`。
+
+
+注意:目前如果要在**Android**上使用LayoutAnimation,那么还需要在`UIManager`中明确启用:
+```javascript
+UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
+```
+
+
+### 方法
+
+
+
+
static configureNext(config: Config, onAnimationDidEnd?: Function) #
+
+
计划下一次布局要发生的动画。
+
@param config 表示动画相应的属性
+
+ duration 动画持续时间,单位是毫秒
+ create, 配置创建新视图时的动画。(参阅 Anim 类型)
+ update, 配置被更新的视图的动画。(参阅 Anim 类型)
+
+
@param onAnimationDidEnd 当动画结束的时候被调用。只在iOS设备上支持。
+
@param onError 当动画产生错误的时候被调用。只在iOS设备上支持。
+
+
+
+
static create(duration: number, type, creationProp) #
+
+
用来创建configureNext所需的config参数的辅助函数。
+
+
+
+
+### 属性
+
+
+
+
Properties: CallExpression #
+
configChecker: CallExpression #
+
Presets: ObjectExpression #
+
easeInEaseOut: CallExpression #
+
+
+
+
diff --git a/docs/docs/0.41/linking-libraries-ios.md b/docs/docs/0.41/linking-libraries-ios.md
new file mode 100644
index 0000000..ac7a243
--- /dev/null
+++ b/docs/docs/0.41/linking-libraries-ios.md
@@ -0,0 +1,62 @@
+并不是所有的APP都需要使用全部的原生功能,包含支持全部特性的代码会增大应用的体积。但我们仍然希望能让你简单地根据自己的需求添加需要的特性。
+
+在这种思想下,我们把许多特性都发布成为互不相关的静态库。
+
+大部分的库只需要拖进两个文件就可以使用了,偶尔你还需要几步额外的工作,但不会再有更多的事情要做了。
+
+_我们随着React Native发布的所有库都在仓库中的`Libraries`文件夹下。其中有一些是纯Javascript代码,你只需要去`require`它们就可以使用了。另外有一些库基于一些原生代码实现,你必须把这些文件添加到你的应用,否则应用会在你使用这些库的时候产生报错。_
+
+## 添加包含原生代码的库需要几个步骤:
+
+### 自动链接
+
+#### 第一步
+安装一个带原生依赖的库:
+
+```bash
+$ npm install 某个带有原生依赖的库 --save
+```
+
+**注意:** 这一步中`--save`或`--save-dev`参数是非常重要的。React Native需要根据`package.json`文件中的`dependencies`和`devDependencies`记录来链接库。
+
+#### 第二步
+
+链接原生依赖:
+
+```bash
+$ react-native link
+```
+
+完成了!现在所有的原生依赖都成功地链接到你的iOS/Android项目了。
+
+### 手动链接
+
+#### 第一步
+
+如果该库包含原生代码,那么在它的文件夹下一定有一个`.xcodeproj`文件。
+把这个文件拖到你的XCode工程下(通常拖到XCode的`Libraries`分组里)
+
+
+
+#### 第二步
+
+点击你的主工程文件,选择`Build Phases`,然后把刚才所添加进去的`.xcodeproj`下的`Products`文件夹中的静态库文件(.a文件),拖到`Link Binary With Libraries`组内。
+
+
+
+#### 第三步
+
+不是所有的库都需要进行这个步骤,你需要考虑的问题在于:
+
+_我需要在编译的期间了解库的内容吗?_
+
+这个问题的意思是,你是需要在原生代码中使用这个库,还是只需要通过JavaScript访问?如果你只需要通过JavaScript访问这个库,你就可以跳过这步了。
+
+这一步骤对于我们随React Native发布的大部分库来说都不是必要的,但有两个例外是`PushNotificationIOS`和`LinkingIOS`。
+
+以`PushNotificationIOS`为例,你需要在`AppDelegate`每收到一条推送通知之后,调用库中的一个方法。
+
+这种情况下我们需要能够访问到库的头文件。为了能够顺利打包,你需要打开你的工程文件,选择`Build Settings`,然后搜索`Header Search Paths`,然后添加库所在的目录(如果它还有像`React`这样的子目录需要包含,注意要选中`recursive`选项)
+
+
+
diff --git a/docs/docs/0.41/linking.md b/docs/docs/0.41/linking.md
new file mode 100644
index 0000000..b8b25a4
--- /dev/null
+++ b/docs/docs/0.41/linking.md
@@ -0,0 +1,123 @@
+`Linking`提供了一个通用的接口来与传入和传出的App链接进行交互。
+
+### 基本用法
+
+#### 处理链接
+
+如果你的应用被其注册过的外部url调起,则可以在任何组件内这样获取和处理它:
+
+```javascript
+componentDidMount() {
+ var url = Linking.getInitialURL().then(url) => {
+ if (url) {
+ console.log('Initial url is: ' + url);
+ }
+ }).catch(err => console.error('An error occurred', err));
+}
+```
+注:要了解更多如何在Android上支持深度链接的说明,请参阅[Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters)。
+
+如果要在现有的MainActivity中监听传入的intent,那么需要在`AndroidManifest.xml`中将MainActivity的`launchMode`设置为`singleTask`。相关解释可参考[``](http://developer.android.com/guide/topics/manifest/activity-element.html)文档。
+
+```xml
+
+```
+
+对于iOS来说,如果要在App启动后也监听传入的App链接,那么首先需要在项目中链接`RCTLinking`,具体步骤请参考[使用链接库](linking-libraries-ios.html)这篇文档,然后需要在`AppDelegate.m`中增加以下代码:
+
+```objective-c
+#import
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+ {
+ return [RCTLinkingManager application:application openURL:url
+ sourceApplication:sourceApplication annotation:annotation];
+ }
+
+// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+ {
+ return [RCTLinkingManager application:application
+ continueUserActivity:userActivity
+ restorationHandler:restorationHandler];
+ }
+```
+
+然后你的React组件就可以监听`Linking`的相关事件:
+
+```javascript
+componentDidMount() {
+ Linking.addEventListener('url', this._handleOpenURL);
+},
+componentWillUnmount() {
+ Linking.removeEventListener('url', this._handleOpenURL);
+},
+_handleOpenURL(event) {
+ console.log(event.url);
+}
+```
+
+
+#### 打开外部链接
+
+要启动一个链接相对应的应用(打开浏览器、邮箱或者其它的应用),只需调用:
+
+```javascript
+Linking.openURL(url).catch(err => console.error('An error occurred', err));
+```
+如果想在打开链接前先检查是否安装了对应的应用,则调用以下方法:
+
+```javascript
+Linking.canOpenURL(url).then(supported => {
+ if (!supported) {
+ console.log('Can\'t handle url: ' + url);
+ } else {
+ return Linking.openURL(url);
+ }
+}).catch(err => console.error('An error occurred', err));
+```
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听Linking变化的事件。type参数应填`url`,并提供一个处理函数。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
删除一个事件处理函数。type参数应填`url`。
+
+
+
+
static openURL(url: string) #
+
+
尝试使用设备上已经安装的应用打开指定的url。
+
你还可以使用其他类型的URL,比如一个地理位置(形如"geo:37.484847,-122.148386"或是一个通讯录名片,只要是可以通过{@code Intent.ACTION_VIEW}打开的即可。
+
注:如果系统不知道如何处理给定的URL,则此方法会调用失败。如果你传入的URL不是一个http链接,则最好先通过{@code canOpenURL}方法检查一下。
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
+
+
+
static canOpenURL(url: string, callback: Function) #
+
+
判断设备上是否有已经安装的应用可以处理指定的URL。回调函数的参数只有一个:bool supported
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
注:对于iOS 9以上版本,你还需要在Info.plist中添加LSApplicationQueriesSchemes字段。
+
+
+
+
static getInitialURL() #
+
+
+
diff --git a/docs/docs/0.41/listview.md b/docs/docs/0.41/listview.md
new file mode 100644
index 0000000..0476e75
--- /dev/null
+++ b/docs/docs/0.41/listview.md
@@ -0,0 +1,309 @@
+ListView - 一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个`ListView.DataSource`数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个`ListView`组件,并且定义它的`renderRow`回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)。
+
+最简单的例子:
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows(['row 1', 'row 2']),
+ };
+}
+render() {
+ return (
+ {rowData} }
+ />
+ );
+}
+```
+
+ListView还支持一些高级特性,譬如给每段/组(section)数据添加一个带有粘性的头部(类似iPhone的通讯录,其首字母会在滑动过程中吸附在屏幕上方);在列表头部和尾部增加单独的内容;在到达列表尾部的时候调用回调函数(`onEndReached`),还有在视野内可见的数据变化时调用回调函数(`onChangeVisibleRows`),以及一些性能方面的优化。
+
+有一些性能优化使得ListView可以滚动的更加平滑,尤其是在动态加载可能很大(或者概念上无限长的)数据集的时候:
+
+* 只更新变化的行 - 提供给数据源的rowHasChanged函数可以告诉ListView它是否需要重绘一行数据(即:数据是否发生了变化)参见ListViewDataSource
+* 限制频率的行渲染 - 默认情况下,每次消息循环只有一行会被渲染(可以用`pageSize`属性配置)。这把较大的工作分散成小的碎片,以降低因为渲染而导致丢帧的可能性。
+
+### 截图
+
+
+
+
+
+
+### 属性
+
+
+
+
+
+
译注:这意味着ListView可以使用所有ScrollView的属性。
+
+
+
+
dataSource ListViewDataSource #
+
+
+
+
initialListSize number #
+
+
指定在组件刚挂载的时候渲染多少行数据。用这个属性来确保首屏显示合适数量的数据,而不是花费太多帧逐步显示出来。
+
+
+
+
onChangeVisibleRows function #
+
+
(visibleRows, changedRows) => void
+
当可见的行的集合变化的时候调用此回调函数。visibleRows 以 { sectionID: { rowID: true }}的格式包含了所有可见行,而changedRows 以{ sectionID: { rowID: true | false }}的格式包含了所有刚刚改变了可见性的行,其中如果值为true表示一个行变得可见,而为false表示行刚刚离开可视区域而变得不可见。
+
+
+
+
onEndReached function #
+
+
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。
+
+
+
+
onEndReachedThreshold number #
+
+
调用onEndReached之前的临界值,单位是像素。
+
+
+
+
+
removeClippedSubviews bool #
+
+
用于提升大列表的滚动性能。需要给行容器添加样式overflow:'hidden'。(Android已默认添加此样式)。此属性默认开启。
+
+
+
+
renderFooter function #
+
+
() => renderable
+
页头与页脚会在每次渲染过程中都重新渲染(如果提供了这些属性)。如果它们重绘的性能开销很大,把他们包装到一个StaticContainer或者其它恰当的结构中。页脚会永远在列表的最底部,而页头会在最顶部。
+
+
+
+
renderHeader function #
+
+
+
renderRow function #
+
+
(rowData, sectionID, rowID, highlightRow) => renderable
+
从数据源(Data source)中接受一条数据,以及它和它所在section的ID。返回一个可渲染的组件来为这行数据进行渲染。默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。
+
如果某一行正在被高亮(通过调用highlightRow函数),ListView会得到相应的通知。当一行被高亮时,其两侧的分割线会被隐藏。行的高亮状态可以通过调用highlightRow(null)来重置。
+
+
+
+
renderScrollComponent function #
+
+
(props) => renderable
+
指定一个函数,在其中返回一个可以滚动的组件。ListView将会在该组件内部进行渲染。默认情况下会返回一个包含指定属性的ScrollView。
+
+
+
+
renderSectionHeader function #
+
+
(sectionData, sectionID) => renderable
+
如果提供了此函数,会为每个小节(section)渲染一个粘性的标题。
+
粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。
+
+
+
+
renderSeparator function #
+
+
(sectionID, rowID, adjacentRowHighlighted) => renderable
+
如果提供了此属性,一个可渲染的组件会被渲染在每一行下面,除了小节标题的前面的最后一行。在其上方的小节ID和行ID,以及邻近的行是否被高亮会作为参数传递进来。
+
+
+
+
scrollRenderAheadDistance number #
+
+
当一个行接近屏幕范围多少像素之内的时候,就开始渲染这一行。
+
+
+
+
ios stickyHeaderIndices [number] #
+
+
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。举个例子,传递stickyHeaderIndices={[0]}会让第一个成员固定在滚动视图顶端。这个属性不能和horizontal={true}一起使用。
+
+
+
+
+### 方法
+
+
+
+
scrollTo(...args)
+ #
+
+
+
scrollToEnd(options?) #
+
+
滚动到视图底部(水平方向的视图则滚动到最右边)。
加上动画参数 scrollToEnd({animated: true})则启用平滑滚动动画,或是调用
+scrollToEnd({animated: false})来立即跳转。如果不使用参数,则animated选项默认启用。
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ ListView,
+ TouchableHighlight,
+ StyleSheet,
+ RecyclerViewBackedScrollView,
+ Text,
+ View,
+} = ReactNative;
+
+var UIExplorerPage = require('./UIExplorerPage');
+
+var ListViewSimpleExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Performant, scrollable list of data.'
+ },
+
+ getInitialState: function() {
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ return {
+ dataSource: ds.cloneWithRows(this._genRows({})),
+ };
+ },
+
+ _pressData: ({}: {[key: number]: boolean}),
+
+ componentWillMount: function() {
+ this._pressData = {};
+ },
+
+ render: function() {
+ return (
+ '}
+ noSpacer={true}
+ noScroll={true}>
+ }
+ renderSeparator={this._renderSeperator}
+ />
+
+ );
+ },
+
+ _renderRow: function(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
+ var rowHash = Math.abs(hashCode(rowData));
+ var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
+ return (
+ {
+ this._pressRow(rowID);
+ highlightRow(sectionID, rowID);
+ }}>
+
+
+
+
+ {rowData + ' - ' + LOREM_IPSUM.substr(0, rowHash % 301 + 10)}
+
+
+
+
+ );
+ },
+
+ _genRows: function(pressData: {[key: number]: boolean}): Array {
+ var dataBlob = [];
+ for (var ii = 0; ii < 100; ii++) {
+ var pressedText = pressData[ii] ? ' (pressed)' : '';
+ dataBlob.push('Row ' + ii + pressedText);
+ }
+ return dataBlob;
+ },
+
+ _pressRow: function(rowID: number) {
+ this._pressData[rowID] = !this._pressData[rowID];
+ this.setState({dataSource: this.state.dataSource.cloneWithRows(
+ this._genRows(this._pressData)
+ )});
+ },
+
+ _renderSeperator: function(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
+ return (
+
+ );
+ }
+});
+
+var THUMB_URLS = [
+ require('./Thumbnails/like.png'),
+ require('./Thumbnails/dislike.png'),
+ require('./Thumbnails/call.png'),
+ require('./Thumbnails/fist.png'),
+ require('./Thumbnails/bandaged.png'),
+ require('./Thumbnails/flowers.png'),
+ require('./Thumbnails/heart.png'),
+ require('./Thumbnails/liking.png'),
+ require('./Thumbnails/party.png'),
+ require('./Thumbnails/poke.png'),
+ require('./Thumbnails/superlike.png'),
+ require('./Thumbnails/victory.png'),
+ ];
+var LOREM_IPSUM = 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';
+
+/* eslint no-bitwise: 0 */
+var hashCode = function(str) {
+ var hash = 15;
+ for (var ii = str.length - 1; ii >= 0; ii--) {
+ hash = ((hash << 5) - hash) + str.charCodeAt(ii);
+ }
+ return hash;
+};
+
+var styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ padding: 10,
+ backgroundColor: '#F6F6F6',
+ },
+ thumb: {
+ width: 64,
+ height: 64,
+ },
+ text: {
+ flex: 1,
+ },
+});
+
+module.exports = ListViewSimpleExample;
+```
diff --git a/docs/docs/0.41/listviewdatasource.md b/docs/docs/0.41/listviewdatasource.md
new file mode 100644
index 0000000..7aa981e
--- /dev/null
+++ b/docs/docs/0.41/listviewdatasource.md
@@ -0,0 +1,106 @@
+`ListViewDataSource`为`ListView`组件提供高性能的数据处理和访问。我们需要调用方法从原始输入数据中抽取数据来创建`ListViewDataSource`对象,并用其进行数据变更的比较。原始输入数据可以是简单的字符串数组,也可以是复杂嵌套的对象——分不同区(section)各自包含若干行(row)数据。
+
+要更新datasource中的数据,请(每次都重新)调用`cloneWithRows`方法(如果用到了section,则对应`cloneWithRowsAndSections`方法)。数据源中的数据本身是不可修改的,所以请勿直接尝试修改。clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。
+
+在下面这个例子中,一个组件在分块接受数据,这些数据由`_onDataArrived`方法处理——将新数据拼接(concat)到旧数据尾部,同时使用clone方法更新DataSource。我们使用concat方法来修改`this._data`以创建新数组,注意不能使用push方法拼接数组。实现`_rowHasChanged`方法需要透彻了解行数据的结构,以便提供高效的比对策略。
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ ds,
+ };
+ this._data = [];
+}
+
+_onDataArrived = (newData) => {
+ this._data = this._data.concat(newData);
+ this.setState({
+ ds: this.state.ds.cloneWithRows(this._data)
+ });
+};
+```
+
+
+### 方法
+
+
constructor(params)
+ #
+
你可以在构造函数中针对section标题和行数据提供自定义的提取方法和hasChanged比对方法。如果不提供,则会使用默认的defaultGetRowData和defaultGetSectionHeaderData方法来提取行数据和section标题。
+
默认的提取函数可以处理下列形式的数据:
+
{ sectionID_1: { rowID_1: rowData1, ... }, ... }
+
或者:
+
{ sectionID_1: [ rowData1, rowData2, ... ], ... }
+
或者:
+
[ [ rowData1, rowData2, ... ], ... ]
+
构造函数可以接受下列四种参数(都是可选):
+
+ getRowData(dataBlob, sectionID, rowID);
+ getSectionHeaderData(dataBlob, sectionID);
+ rowHasChanged(prevRowData, nextRowData);
+ sectionHeaderHasChanged(prevSectionData, nextSectionData);
+
+
+
+
cloneWithRows(dataBlob, rowIdentities) #
+
+
根据指定的dataBlob和
+ rowIdentities为ListViewDataSource复制填充数据。dataBlob即原始数据。需要在初始化时定义抽取函数(否则使用默认的抽取函数)。
+
rowIdentities是一个二维数组,包含了行数据对应的id标识符,例如[['a1', 'a2'], ['b1', 'b2', 'b3'], ...]。如果没有指定此数组,则默认取行数据的key。
+
注:此方法实际并没有 复制数据。它只是重新创建一个datasource,然后将你指定的dataBlob传递给构造函数中指定的提取函数,因而会抛弃先前的数据。如果你希望保留先前的数据,则必须先自行进行新老数据的合并处理,然后再将合并后的结果作为dataBlob传递给此方法调用。
+
+
cloneWithRowsAndSections(dataBlob, sectionIdentities, rowIdentities) #
+
+
此方法作用基本等同cloneWithRows,区别在于可以额外指定sectionIdentities 。如果你不需要section,则直接使用cloneWithRows即可。
+
sectionIdentities同理是包含了section标识符的数组。例如['s1', 's2', ...]。如果没有指定此数组,则默认取section的key。
+
注:此方法会返回新的对象!
+
+
+
getRowAndSectionCount() #
+
rowShouldUpdate(sectionIndex, rowIndex) #
+
+
+
+
getRowData(sectionIndex, rowIndex)
+ #
+
返回渲染行所需的数据(指定如何从原始dataBlob中提取数据)。
+
+
getRowIDForFlatIndex(index) #
+
给定索引值,求其对应rowID。如果查找不到则返回null。
+
+
getSectionIDForFlatIndex(index) #
+
给定索引值,求其对应sectionID。如果查找不到则返回null。
+
+
getSectionLengths() #
+
+
+
+
sectionHeaderShouldUpdate(sectionIndex) #
+
+
返回值用于说明section标题是否需要重新渲染。
+
+
getSectionHeaderData(sectionIndex) #
+
+
+
+
diff --git a/docs/docs/0.41/mapview.md b/docs/docs/0.41/mapview.md
new file mode 100644
index 0000000..75ad320
--- /dev/null
+++ b/docs/docs/0.41/mapview.md
@@ -0,0 +1,567 @@
+官方建议使用[react-native-maps](https://github.com/airbnb/react-native-maps)代替此地图组件。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
ios annotations [{latitude: number, longitude: number, animateDrop: bool, title: string, subtitle: string, hasLeftCallout: bool, hasRightCallout: bool, onLeftCalloutPress: function, onRightCalloutPress: function, id: string}] #
+
+
+
+
ios legalLabelInsets {top: number, left: number, bottom: number, right: number} #
+
+
地图上标签的合法范围。默认在地图底部左侧。参见EdgeInsetsPropType.js了解更多信息。
+
+
+
+
ios mapType enum('standard', 'satellite', 'hybrid') #
+
+
要显示的地图类型。
+
+ standard: 标准道路地图(默认)。
+ satellite: 卫星视图。
+ hybrid: 卫星视图并附带道路和感兴趣的点标记。
+
+
+
+
+
ios maxDelta number #
+
+
+
+
ios minDelta number #
+
+
+
+
ios overlays [{coordinates: [{latitude: number, longitude: number}], lineWidth: number, strokeColor: ColorPropType, fillColor: ColorPropType, id: string}] #
+
+
+
onAnnotationPress function #
+
+
当用户点击地图上的标注之后会调用此回调函数一次。
+
+
+
+
onRegionChange function #
+
+
+
+
onRegionChangeComplete function #
+
+
当用户停止拖拽地图之后,调用此回调函数一次。
+
+
+
+
pitchEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的抬起角度会使地图平面倾斜。当此属性设为false,镜头的抬起角度会忽略,地图永远都显示为俯视角度。
+
+
+
+
region {latitude: number, longitude: number, latitudeDelta: number, longitudeDelta: number} #
+
+
地图显示的区域。
+
区域使用中心的坐标和要显示的范围来定义。
+
+
+
+
rotateEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的朝向角度会用于基于中心点旋转地图平面。当此属性设置为false时,朝向角度会被忽略,并且地图永远都显示为顶部方向为正北方。
+
+
+
+
scrollEnabled bool #
+
+
如果此属性设为false,用户不能改变地图所显示的区域。默认值为true。
+
+
+
+
showsUserLocation bool #
+
+
如果此属性为true,应用会请求用户当前的位置并且聚焦到该位置。默认值是false。
+
注意 :你需要在Info.plist中增加NSLocationWhenInUseUsageDescription字段。否则它会没有任何提示而直接失败 !
+
+
+
+
+
zoomEnabled bool #
+
+
如果此属性为false,用户则不能旋转/缩放地图。默认值为true。
+
+
+
+
+
ios showsCompass bool #
+
+
如果此属性为false,地图上不会显示指南针。默认值为true。
+
+
+
+
ios showsPointsOfInterest bool #
+
+
如果此属性为false,感兴趣的点不会在地图上显示。默认为true。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var { PropTypes } = React;
+var {
+ Image,
+ MapView,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ View,
+} = ReactNative;
+
+var regionText = {
+ latitude: '0',
+ longitude: '0',
+ latitudeDelta: '0',
+ longitudeDelta: '0',
+};
+
+var MapRegionInput = React.createClass({
+
+ propTypes: {
+ region: PropTypes.shape({
+ latitude: PropTypes.number.isRequired,
+ longitude: PropTypes.number.isRequired,
+ latitudeDelta: PropTypes.number,
+ longitudeDelta: PropTypes.number,
+ }),
+ onChange: PropTypes.func.isRequired,
+ },
+
+ getInitialState() {
+ return {
+ region: {
+ latitude: 0,
+ longitude: 0,
+ }
+ };
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ this.setState({
+ region: nextProps.region || this.getInitialState().region
+ });
+ },
+
+ render: function() {
+ var region = this.state.region || this.getInitialState().region;
+ return (
+
+
+
+ {'Latitude'}
+
+
+
+
+
+ {'Longitude'}
+
+
+
+
+
+ {'Latitude delta'}
+
+
+
+
+
+ {'Longitude delta'}
+
+
+
+
+
+ {'Change'}
+
+
+
+ );
+ },
+
+ _onChangeLatitude: function(e) {
+ regionText.latitude = e.nativeEvent.text;
+ },
+
+ _onChangeLongitude: function(e) {
+ regionText.longitude = e.nativeEvent.text;
+ },
+
+ _onChangeLatitudeDelta: function(e) {
+ regionText.latitudeDelta = e.nativeEvent.text;
+ },
+
+ _onChangeLongitudeDelta: function(e) {
+ regionText.longitudeDelta = e.nativeEvent.text;
+ },
+
+ _change: function() {
+ this.setState({
+ region: {
+ latitude: parseFloat(regionText.latitude),
+ longitude: parseFloat(regionText.longitude),
+ latitudeDelta: parseFloat(regionText.latitudeDelta),
+ longitudeDelta: parseFloat(regionText.longitudeDelta),
+ },
+ });
+ this.props.onChange(this.state.region);
+ },
+
+});
+
+var MapViewExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ mapRegion: undefined,
+ mapRegionInput: undefined,
+ annotations: [],
+ };
+ },
+
+ render() {
+ return (
+
+
+
+
+ );
+ },
+
+ _getAnnotations(region) {
+ return [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ title: 'You Are Here',
+ }];
+ },
+
+ _onRegionChange(region) {
+ this.setState({
+ mapRegionInput: region,
+ });
+ },
+
+ _onRegionChangeComplete(region) {
+ if (this.state.isFirstLoad) {
+ this.setState({
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ isFirstLoad: false,
+ });
+ }
+ },
+
+ _onRegionInputChanged(region) {
+ this.setState({
+ mapRegion: region,
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ });
+ },
+
+});
+
+var AnnotationExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ this.setState({
+ isFirstLoad: false,
+ annotations: [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ ...this.props.annotation,
+ }],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var DraggableAnnotationExample = React.createClass({
+
+ createAnnotation(longitude, latitude) {
+ return {
+ longitude,
+ latitude,
+ draggable: true,
+ onDragStateChange: (event) => {
+ if (event.state === 'idle') {
+ this.setState({
+ annotations: [this.createAnnotation(event.longitude, event.latitude)],
+ });
+ }
+ console.log('Drag state: ' + event.state);
+ },
+ };
+ },
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ //When the MapView loads for the first time, we can create the annotation at the
+ //region that was loaded.
+ this.setState({
+ isFirstLoad: false,
+ annotations: [this.createAnnotation(region.longitude, region.latitude)],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var styles = StyleSheet.create({
+ map: {
+ height: 150,
+ margin: 10,
+ borderWidth: 1,
+ borderColor: '#000000',
+ },
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ textInput: {
+ width: 150,
+ height: 20,
+ borderWidth: 0.5,
+ borderColor: '#aaaaaa',
+ fontSize: 13,
+ padding: 4,
+ },
+ changeButton: {
+ alignSelf: 'center',
+ marginTop: 5,
+ padding: 3,
+ borderWidth: 0.5,
+ borderColor: '#777777',
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Base component to display maps';
+exports.examples = [
+ {
+ title: 'Map',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'showsUserLocation + followUserLocation',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Callout example',
+ render() {
+ return {
+ alert('You Are Here');
+ }}>
+
+
+ ),
+ }}/>;
+ }
+ },
+ {
+ title: 'Annotation focus example',
+ render() {
+ return {
+ alert('Annotation gets focus');
+ },
+ onBlur: () => {
+ alert('Annotation lost focus');
+ }
+ }}/>;
+ }
+ },
+ {
+ title: 'Draggable pin',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin color',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin image',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin view',
+ render() {
+ return
+
+ Thumbs Up!
+
+
+ ,
+ }}/>;
+ }
+ },
+ {
+ title: 'Custom overlay',
+ render() {
+ return ;
+ }
+ },
+];
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/modal.md b/docs/docs/0.41/modal.md
new file mode 100644
index 0000000..d99b00a
--- /dev/null
+++ b/docs/docs/0.41/modal.md
@@ -0,0 +1,298 @@
+Modal组件可以用来覆盖包含React Native根视图的原生视图(如UIViewController,Activity)。
+
+在嵌入React Native的混合应用中可以使用Modal。Modal可以使你应用中RN编写的那部分内容覆盖在原生视图上显示。
+
+```js
+import React, { Component } from 'react';
+import { Modal, Text, TouchableHighlight, View } from 'react-native';
+
+class ModalExample extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {modalVisible: false};
+ }
+
+ setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ }
+
+ render() {
+ return (
+
+ {alert("Modal has been closed.")}}
+ >
+
+
+ Hello World!
+
+ {
+ this.setModalVisible(!this.state.modalVisible)
+ }}>
+ Hide Modal
+
+
+
+
+
+
+ {
+ this.setModalVisible(true)
+ }}>
+ Show Modal
+
+
+
+ );
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
animationType PropTypes.oneOf(['none', 'slide', 'fade']) #
+
+
The animationType prop controls how the modal animates.
+
+ slide slides in from the bottom
+ fade fades into view
+ none appears without an animation
+
+
+
+
onRequestClose Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func #
+
+
The onRequestClose prop allows passing a function that will be called once the modal has been dismissed.
+
On the Android platform, this is a required function.
+
+
+
onShow function #
+
+
The onShow prop allows passing a function that will be called once the modal has been shown.
+
+
+
transparent bool
+ #
+
+
The transparent prop determines whether your modal will fill the entire view. Setting this to true will render the modal over a transparent background.
+
+
+
visible bool #
+
The visible prop determines whether your modal is visible.
+
+
+
ios onOrientationChange PropTypes.func
+ #
+
+
The onOrientationChange callback is called when the orientation changes while the modal is being displayed.
+ The orientation provided is only 'portrait' or 'landscape'. This callback is also called on initial render, regardless of the current orientation.
+
+
+
+
ios supportedOrientations PropTypes.arrayOf(PropTypes.oneOf(['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right']))
+ #
+
+
+
The supportedOrientations prop allows the modal to be rotated to any of the specified orientations. On iOS, the modal is still restricted by what's specified in your app's Info.plist's UISupportedInterfaceOrientations field.
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Modal,
+ StyleSheet,
+ Switch,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Component for presenting modal views.';
+
+var Button = React.createClass({
+ getInitialState() {
+ return {
+ active: false,
+ };
+ },
+
+ _onHighlight() {
+ this.setState({active: true});
+ },
+
+ _onUnhighlight() {
+ this.setState({active: false});
+ },
+
+ render() {
+ var colorStyle = {
+ color: this.state.active ? '#fff' : '#000',
+ };
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var ModalExample = React.createClass({
+ getInitialState() {
+ return {
+ animationType: 'none',
+ modalVisible: false,
+ transparent: false,
+ };
+ },
+
+ _setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ },
+
+ _setAnimationType(type) {
+ this.setState({animationType: type});
+ },
+
+ _toggleTransparent() {
+ this.setState({transparent: !this.state.transparent});
+ },
+
+ render() {
+ var modalBackgroundStyle = {
+ backgroundColor: this.state.transparent ? 'rgba(0, 0, 0, 0.5)' : '#f5fcff',
+ };
+ var innerContainerTransparentStyle = this.state.transparent
+ ? {backgroundColor: '#fff', padding: 20}
+ : null;
+ var activeButtonStyle = {
+ backgroundColor: '#ddd'
+ };
+
+ return (
+
+ {this._setModalVisible(false)}}
+ >
+
+
+ This modal was presented {this.state.animationType === 'none' ? 'without' : 'with'} animation.
+
+ Close
+
+
+
+
+
+ Animation Type
+
+ none
+
+
+ slide
+
+
+ fade
+
+
+
+
+ Transparent
+
+
+
+
+ Present
+
+
+ );
+ },
+});
+
+exports.examples = [
+ {
+ title: 'Modal Presentation',
+ description: 'Modals can be presented with or without animation',
+ render: () => ,
+ },
+];
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ padding: 20,
+ },
+ innerContainer: {
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+ row: {
+ alignItems: 'center',
+ flex: 1,
+ flexDirection: 'row',
+ marginBottom: 20,
+ },
+ rowTitle: {
+ flex: 1,
+ fontWeight: 'bold',
+ },
+ button: {
+ borderRadius: 5,
+ flex: 1,
+ height: 44,
+ alignSelf: 'stretch',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ },
+ buttonText: {
+ fontSize: 18,
+ margin: 5,
+ textAlign: 'center',
+ },
+ modalButton: {
+ marginTop: 10,
+ },
+});
+```
diff --git a/docs/docs/0.41/more-resources.md b/docs/docs/0.41/more-resources.md
new file mode 100644
index 0000000..6735969
--- /dev/null
+++ b/docs/docs/0.41/more-resources.md
@@ -0,0 +1,43 @@
+如果你耐心的读完并理解了本网站上的所有文档,那么你应该已经可以编写一个像样的React Native应用了。但是React Native并不全是某一家公司的作品——它汇聚了成千上万开源社区开发者的智慧结晶。如果你想深入研究React Native,那么建议不要错过下面这些参考资源。
+
+## 常用的第三方库
+
+如果你正在使用React Native,那你应该已经对[React](https://facebook.github.io/react/)有一定的了解了。React是基础中的基础所以我其实不太好意思提这个——但是,如果不幸你属于“但是”,那么请一定先了解下React,它也非常适合编写现代化的网站。
+
+开发实践中的一个常见问题就是如何管理应用的“状态(state)”。这方面目前最流行的库非[Redux](http://redux.js.org/)莫属了。不要被Redux中经常出现的类似"reducer"这样的概念术语给吓住了——它其实是个很简单的库,网上也有很多优秀的[视频教程(英文)](https://egghead.io/courses/getting-started-with-redux) 。。
+
+如果你在寻找具有某个特定功能的第三方库,那么可以看看别人[精心整理的资源列表](https://github.com/jondot/awesome-react-native)。这里还有个类似的[中文资源列表](https://github.com/reactnativecn/react-native-guide)。
+
+## 示例应用
+
+在[React Native Playground](https://rnplay.org/apps/picks)网站上有很多示例的代码。这个网站有个很酷的特性:它直接对接了真实设备,可以实时在网页上显示运行效果。当然,对于国内用户来说,可能访问很困难。
+
+另外就是Facebook的F8开发大会有一个对应的app,这个app现在已经[开源](https://github.com/fbsamples/f8app),其开发者还详细地撰写了[相关教程](http://f8-app.liaohuqiu.net/#content)。如果你想学习一个更实际更有深度的例子,那你应该看看这个。
+
+## 开发工具
+
+[Nuclide](https://nuclide.io/)是Facebook内部所使用的React Native开发工具。它最大的特点是自带调试功能,并且非常好地支持flow语法规则。(译注:然而我们还是推荐webstorm或是sublime text)。
+
+[Ignite](https://github.com/infinitered/ignite)是一套整合了Redux以及一些常见UI组件的脚手架。它带有一个命令行可以生成app、组件或是容器。如果你喜欢它的选择搭配,那么不妨一试。
+
+[CodePush](https://microsoft.github.io/code-push/)是由微软提供的热更新服务。热更新可以使你绕过AppStore的审核机制,直接修改已经上架的应用。对于国内用户,我们也推荐由本网站提供的[Pushy](http://update.reactnative.cn)热更新服务,相比CodePush来说,提供了全中文的文档和技术支持,服务器部署在国内速度更快,还提供了全自动的差量更新方式,大幅节约更新流量,欢迎朋友们试用和反馈意见!
+
+[Exponent](http://docs.getexponent.com/versions/v6.0.0/index.html)是一套开发环境,还带有一个已上架的空应用容器。这样你可以在没有原生开发平台(Xcode或是Android Studio)的情况下直接编写React Native应用(当然这样你只能写js部分代码而没法写原生代码)。
+
+[Deco](https://www.decosoftware.com/)是一个专为React Native设计的集成开发环境。它可以自动创建新项目、搜索开源组件并插入到项目中。你还可以实时地可视化地调整应用的界面。不过目前还只支持mac。
+
+## React Native的交流社区
+
+以下这些都是英文的交流区,我也就不翻译了……
+
+The [React Native Community](https://www.facebook.com/groups/react.native.community) Facebook group has thousands of developers, and it's pretty active. Come there to show off your project, or ask how other people solved similar problems.
+
+[Reactiflux](https://discord.gg/0ZcbPKXt5bZjGY5n) is a Discord chat where a lot of React-related discussion happens, including React Native. Discord is just like Slack except it works better for open source projects with a zillion contributors. Check out the #react-native channel.
+
+The [React Twitter account](https://twitter.com/reactjs) covers both React and React Native. Following that account is a pretty good way to find out what's happening in the world of React.
+
+There are a lot of [React Native Meetups](http://www.meetup.com/topics/react-native/) that happen around the world. Often there is React Native content in React meetups as well.
+
+Sometimes we have React conferences. We posted the [videos from React.js Conf 2016](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY), and we'll probably have more conferences in the future, too. Stay tuned.
+
+欢迎朋友们在下方评论区分享中文教程和资源。
\ No newline at end of file
diff --git a/docs/docs/0.41/native-component-android.md b/docs/docs/0.41/native-component-android.md
new file mode 100644
index 0000000..714423f
--- /dev/null
+++ b/docs/docs/0.41/native-component-android.md
@@ -0,0 +1,172 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对Android编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`ImageView`组件的具体实现。
+
+## ImageView样例
+
+在这个例子里,我们来看看为了让JavaScript中可以使用ImageView,需要做哪些准备工作。
+
+原生视图需要被一个`ViewManager`的派生类(或者更常见的,`SimpleViewManage`的派生类)创建和管理。一个`SimpleViewManager`可以用于这个场景,是因为它能够包含更多公共的属性,譬如背景颜色、透明度、Flexbox布局等等。
+
+这些子类本质上都是单例——React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`NativeViewHierarchyManager`,NativeViewHierarchyManager则会反过来委托它们在需要的时候去设置和更新视图的属性。`ViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+1. 创建一个ViewManager的子类。
+2. 实现`createViewInstance`方法。
+3. 导出视图的属性设置器:使用`@ReactProp`(或`@ReactPropGroup`)注解。
+4. 把这个视图管理类注册到应用程序包的`createViewManagers`里。
+5. 实现JavaScript模块。
+
+## 1. 创建`ViewManager`的子类
+
+在这个例子里我们创建一个视图管理类`ReactImageManager`,它继承自`SimpleViewManager`。`ReactImageView`是这个视图管理类所管理的对象类型,这应当是一个自定义的原生视图。`getName`方法返回的名字会用于在JavaScript端引用这个原生视图类型。
+
+```java
+...
+
+public class ReactImageManager extends SimpleViewManager {
+
+ public static final String REACT_CLASS = "RCTImageView";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+```
+
+## 2. 实现方法`createViewInstance`
+
+视图在`createViewInstance`中创建,且应当把自己初始化为默认的状态。所有属性的设置都通过后续的`updateView`来进行。
+
+```java
+ @Override
+ public ReactImageView createViewInstance(ThemedReactContext context) {
+ return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext);
+ }
+```
+
+## 3. 通过`@ReactProp`(或`@ReactPropGroup`)注解来导出属性的设置方法。
+
+要导出给JavaScript使用的属性,需要申明带有`@ReactProp`(或`@ReactPropGroup`)注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为`void`,而且访问控制必须被声明为`public`。JavaScript所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:`boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`。
+
+`@ReactProp`注解必须包含一个字符串类型的参数`name`。这个参数指定了对应属性在JavaScript端的名字。
+
+除了`name`,`@ReactProp`注解还接受这些可选的参数:`defaultBoolean`, `defaultInt`, `defaultFloat`。这些参数必须是对应的基础类型的值(也就是`boolean`, `int`, `float`),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。注意这个"默认"值只对基本类型生效,对于其他的类型而言,当对应的属性删除时,`null`会作为默认值提供给方法。
+
+使用`@ReactPropGroup`来注解的设置方法和`@ReactProp`不同。请参见`@ReactPropGroup`注解类源代码中的文档来获取更多详情。
+
+**重要!** 在ReactJS里,修改一个属性会引发一次对设置方法的调用。有一种修改情况是,移除掉之前设置的属性。在这种情况下设置方法也一样会被调用,并且“默认”值会被作为参数提供(对于基础类型来说可以通过`defaultBoolean`、`defaultFloat`等`@ReactProp`的属性提供,而对于复杂类型来说参数则会设置为`null`)
+
+```java
+ @ReactProp(name = "src")
+ public void setSrc(ReactImageView view, @Nullable String src) {
+ view.setSource(src);
+ }
+
+ @ReactProp(name = "borderRadius", defaultFloat = 0f)
+ public void setBorderRadius(ReactImageView view, float borderRadius) {
+ view.setBorderRadius(borderRadius);
+ }
+
+ @ReactProp(name = ViewProps.RESIZE_MODE)
+ public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
+ view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
+ }
+```
+
+## 4. 注册`ViewManager`
+
+在Java中的最后一步就是把视图控制器注册到应用中。这和[原生模块](NativeModulesAndroid.md)的注册方法类似,唯一的区别是我们把它放到`createViewManagers`方法的返回值里。
+
+```java
+ @Override
+ public List createViewManagers(
+ ReactApplicationContext reactContext) {
+ return Arrays.asList(
+ new ReactImageManager()
+ );
+ }
+```
+
+## 5. 实现对应的JavaScript模块
+
+整个过程的最后一步就是创建JavaScript模块并且定义Java和JavaScript之间的接口层。大部分过程都由React底层的Java和JavaScript代码来完成,你所需要做的就是通过`propTypes`来描述属性的类型。
+
+```js
+// ImageView.js
+
+import { PropTypes } from 'react';
+import { requireNativeComponent, View } from 'react-native';
+
+var iface = {
+ name: 'ImageView',
+ propTypes: {
+ src: PropTypes.string,
+ borderRadius: PropTypes.number,
+ resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
+ ...View.propTypes // 包含默认的View的属性
+ },
+};
+
+module.exports = requireNativeComponent('RCTImageView', iface);
+```
+
+`requireNativeComponent`通常接受两个参数,第一个参数是原生视图的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的`name`,用来在调试信息中显示;组件接口还必须声明`propTypes`字段,用来对应到原生视图上。这个`propTypes`还可以用来检查用户使用View的方式是否正确。
+
+注意,如果你还需要一个JavaScript组件来做一些除了指定`name`和`propTypes`以外的事情,譬如事件处理,你可以把原生组件用一个普通React组件封装。在这种情况下,`requireNativeComponent`的第二个参数变为用于封装的组件。这个在后文的`MyCustomView`例子里面用到。
+
+_译注_:和原生模块不同,原生视图的前缀RCT不会被自动去掉。
+
+# 事件
+
+现在我们已经知道了怎么导出一个原生视图组件,并且我们可以在JS里很方便的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动?当一个原生事件发生的时候,它应该也能触发JavaScript端视图上的事件,这两个视图会依据getId()而关联在一起。
+
+```java
+class MyCustomView extends View {
+ ...
+ public void onReceiveNativeEvent() {
+ WritableMap event = Arguments.createMap();
+ event.putString("message", "MyMessage");
+ ReactContext reactContext = (ReactContext)getContext();
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
+ getId(),
+ "topChange",
+ event);
+ }
+}
+```
+
+这个事件名`topChange`在JavaScript端映射到`onChange`回调属性上(这个映射关系在`UIManagerModuleConstants.java`文件里)。这个回调会被原生事件执行,然后我们通常会在封装组件里构造一个类似的API:
+
+```js
+// MyCustomView.js
+
+class MyCustomView extends React.Component {
+ constructor() {
+ this._onChange = this._onChange.bind(this);
+ }
+ _onChange(event: Event) {
+ if (!this.props.onChangeMessage) {
+ return;
+ }
+ this.props.onChangeMessage(event.nativeEvent.message);
+ }
+ render() {
+ return ;
+ }
+}
+MyCustomView.propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onChangeMessage: React.PropTypes.func,
+ ...
+};
+
+var RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`, MyCustomView, {
+ nativeOnly: {onChange: true}
+});
+```
+
+注意上面用到了`nativeOnly`。有时候有一些特殊的属性,想从原生组件中导出,但是又不希望它们成为对应React封装组件的属性。举个例子,`Switch`组件可能在原生组件上有一个`onChange`事件,然后在封装类中导出`onValueChange`回调属性。这个属性在调用的时候会带上Switch的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上`nativeOnly`选项。
diff --git a/docs/docs/0.41/native-component-ios.md b/docs/docs/0.41/native-component-ios.md
new file mode 100644
index 0000000..811b8e2
--- /dev/null
+++ b/docs/docs/0.41/native-component-ios.md
@@ -0,0 +1,362 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对iOS编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`MapView`组件的具体实现。
+
+## iOS MapView样例
+
+假设我们要把地图组件植入到我们的App中——我们用到的是[`MKMapView`](https://developer.apple.com/library/prerelease/mac/documentation/MapKit/Reference/MKMapView_Class/index.html),而现在只需要让它可以被Javascript重用。
+
+原生视图都需要被一个`RCTViewManager`的子类来创建和管理。这些管理器在功能上有些类似“视图控制器”,但它们本质上都是单例 - React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`RCTUIManager`,`RCTUIManager`则会反过来委托它们在需要的时候去设置和更新视图的属性。`RCTViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+- 首先创建一个子类
+- 添加`RCT_EXPORT_MODULE()`标记宏
+- 实现`-(UIView *)view`方法
+
+```objective-c
+// RNTMapManager.m
+#import
+
+#import
+
+@interface RNTMapManager : RCTViewManager
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+- (UIView *)view
+{
+ return [[MKMapView alloc] init];
+}
+
+@end
+```
+
+接下来你需要一些Javascript代码来让这个视图变成一个可用的React组件:
+
+```javascript
+// MapView.js
+
+var { requireNativeComponent } = require('react-native');
+
+// requireNativeComponent 自动把这个组件提供给 "RNTMapManager"
+module.exports = requireNativeComponent('RNTMap', null);
+```
+
+现在我们就已经实现了一个完整功能的地图组件了,诸如捏放和其它的手势都已经完整支持。但是现在我们还不能真正的从Javascript端控制它。(╯﹏╰)
+
+## 属性
+
+我们能让这个组件变得更强大的第一件事情就是要能够封装一些原生属性供Javascript使用。举例来说,我们希望能够禁用手指捏放操作,然后指定一个初始的地图可见区域。禁用捏放操作只需要一个布尔值类型的属性就行了,所以我们添加这么一行:
+
+```objective-c
+// RNTMapManager.m
+RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
+```
+
+注意我们现在把类型声明为`BOOL`类型——React Native用`RCTConvert`来在JavaScript和原生代码之间完成类型转换。如果转换无法完成,会产生一个“红屏”的报错提示,这样你就能立即知道代码中出现了问题。如果一切进展顺利,上面这个宏就已经包含了导出属性的全部实现。
+
+现在要想禁用捏放操作,我们只需要在JS里设置对应的属性:
+
+```javascript
+// MyApp.js
+
+```
+
+但这样并不能很好的说明这个组件的用法——用户要想知道我们的组件有哪些属性可以用,以及可以取什么样的值,他不得不一路翻到Objective-C的代码。要解决这个问题,我们可以创建一个封装组件,并且通过`PropTypes`来说明这个组件的接口。
+
+```javascript
+// MapView.js
+import React, { Component, PropTypes } from 'react';
+import { requireNativeComponent } from 'react-native';
+
+var RNTMap = requireNativeComponent('RNTMap', MapView);
+
+export default class MapView extends Component {
+ static propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: PropTypes.bool,
+ };
+ render() {
+ return ;
+ }
+}
+```
+
+_译注_:使用了封装组件之后,你还需要注意到module.exports导出的不再是requireNativeComponent的返回值,而是所创建的包装组件。
+
+现在我们有了一个封装好的组件,还有了一些注释文档,用户使用起来也更方便了。注意我们现在把`requireNativeComponent`的第二个参数从null变成了用于封装的组件`MapView`。这使得React Native的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。
+
+现在,让我们添加一个更复杂些的`region`属性。我们首先添加原生代码:
+
+```objective-c
+// RNTMapManager.m
+RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RNTMap)
+{
+ [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
+}
+```
+
+这段代码比刚才的一个简单的`BOOL`要复杂的多了。现在我们多了一个需要做类型转换的`MKCoordinateRegion`类型,还添加了一部分自定义的代码,这样当我们在JS里改变地图的可视区域的时候,视角会平滑地移动过去。在我们提供的函数体内,`json`代表了JS中传递的尚未解析的原始值。函数里还有一个`view`变量,使得我们可以访问到对应的视图实例。最后,还有一个`defaultView`对象,这样当JS给我们发送null的时候,可以把视图的这个属性重置回默认值。
+
+你可以为视图编写任何你所需要的转换函数——下面就是`MKCoordinateRegion`的转换实现,它通过两个RCTConvert的扩展来完成:
+
+```objective-c
+@implementation RCTConvert(CoreLocation)
+
+RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue);
+RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue);
+
++ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json
+{
+ json = [self NSDictionary:json];
+ return (CLLocationCoordinate2D){
+ [self CLLocationDegrees:json[@"latitude"]],
+ [self CLLocationDegrees:json[@"longitude"]]
+ };
+}
+
+@end
+
+@implementation RCTConvert(MapKit)
+
++ (MKCoordinateSpan)MKCoordinateSpan:(id)json
+{
+ json = [self NSDictionary:json];
+ return (MKCoordinateSpan){
+ [self CLLocationDegrees:json[@"latitudeDelta"]],
+ [self CLLocationDegrees:json[@"longitudeDelta"]]
+ };
+}
+
++ (MKCoordinateRegion)MKCoordinateRegion:(id)json
+{
+ return (MKCoordinateRegion){
+ [self CLLocationCoordinate2D:json],
+ [self MKCoordinateSpan:json]
+ };
+}
+```
+
+这些转换函数被设计为可以安全的处理任何JS扔过来的JSON:当有任何缺少的键或者其它问题发生的时候,显示一个“红屏”的错误提示。
+
+为了完成`region`属性的支持,我们还需要在`propTypes`里添加相应的说明(否则我们会立刻收到一个错误提示),然后就可以像使用其他属性一样使用了:
+
+```javascript
+// MapView.js
+
+MapView.propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: React.PropTypes.bool,
+
+ /**
+ * 地图要显示的区域。
+ *
+ * 区域由中心点坐标和区域范围坐标来定义。
+ *
+ */
+ region: React.PropTypes.shape({
+ /**
+ * 地图中心点的坐标。
+ */
+ latitude: React.PropTypes.number.isRequired,
+ longitude: React.PropTypes.number.isRequired,
+
+ /**
+ * 最小/最大经、纬度间的距离。
+ */
+ latitudeDelta: React.PropTypes.number.isRequired,
+ longitudeDelta: React.PropTypes.number.isRequired,
+ }),
+};
+
+// MyApp.js
+
+ render() {
+ var region = {
+ latitude: 37.48,
+ longitude: -122.16,
+ latitudeDelta: 0.1,
+ longitudeDelta: 0.1,
+ };
+ return ;
+ }
+
+```
+
+现在你可以看到region属性的整个结构已经加上了文档说明——将来可能我们会自动生成一些类似的代码,但目前还没有这样的手段。
+
+有时候你的原生组件有一些特殊的属性希望导出,但并不希望它成为公开的接口。举个例子,`Switch`组件可能会有一个`onChange`属性用来传递原始的原生事件,然后导出一个`onValueChange`属性,这个属性在调用的时候会带上`Switch`的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上额外的`nativeOnly`参数,像这样:
+
+```javascript
+var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
+ nativeOnly: { onChange: true }
+});
+```
+
+## 事件
+
+现在我们已经有了一个原生地图组件,并且从JS可以很容易的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动来改变可视区域?关键的步骤是在`RNTMapManager`中声明一个事件处理函数的属性(onChange),来委托我们提供的所有视图,然后把事件传递给JavaScript。最终的代码看起来类似这样(比起完整的实现有所简化):
+
+```objective-c
+// RNTMap.h
+
+#import
+
+#import
+
+@interface RNTMap: MKMapView
+
+@property (nonatomic, copy) RCTBubblingEventBlock onChange;
+
+@end
+```
+
+```objective-c
+// RNTMap.m
+
+#import "RNTMap.h"
+
+@implementation RNTMap
+
+@end
+```
+
+```objective-c
+#import "RNTMapManager.h"
+
+#import
+
+#import "RNTMap.h"
+#import
+
+@interface RNTMapManager()
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
+
+- (UIView *)view
+{
+ RNTMap *map = [RNTMap new];
+ map.delegate = self;
+ return map;
+}
+
+#pragma mark MKMapViewDelegate
+
+- (void)mapView:(RNTMap *)mapView regionDidChangeAnimated:(BOOL)animated
+{
+ if (!mapView.onChange) {
+ return;
+ }
+
+ MKCoordinateRegion region = mapView.region;
+ mapView.onChange(@{
+ @"region": @{
+ @"latitude": @(region.center.latitude),
+ @"longitude": @(region.center.longitude),
+ @"latitudeDelta": @(region.span.latitudeDelta),
+ @"longitudeDelta": @(region.span.longitudeDelta),
+ }
+ });
+}
+```
+
+如你所见,我们刚才通过继承`MKMapView`添加了事件处理函数,然后我们将`onChange`暴露出来,委托`RNTMapManager`代理其创建的所有视图。最后在委托方法`-mapView:regionDidChangeAnimated:`中,根据对应的视图调用事件处理函数并传递区域数据。调用`onChange`事件会触发JavaScript端的同名回调函数。这个回调会被原生事件执行,然后我们通常都会在封装组件里做一些处理,来使得API更简明:
+
+
+```javascript
+// MapView.js
+
+class MapView extends React.Component {
+ constructor() {
+ this._onChange = this._onChange.bind(this);
+ }
+ _onChange(event: Event) {
+ if (!this.props.onRegionChange) {
+ return;
+ }
+ this.props.onRegionChange(event.nativeEvent.region);
+ }
+ render() {
+ return ;
+ }
+}
+MapView.propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onRegionChange: React.PropTypes.func,
+ ...
+};
+```
+
+## 样式
+
+因为我们所有的视图都是`UIView`的子类,大部分的样式属性应该直接就可以生效。但有一部分组件会希望使用自己定义的默认样式,例如`UIDatePicker`希望自己的大小是固定的。这个默认属性对于布局算法的正常工作来说很重要,但我们也希望在使用这个组件的时候可以覆盖这些默认的样式。`DatePickerIOS`实现这个功能的办法是通过封装一个拥有弹性样式的额外视图,然后在内层的视图上应用一个固定样式(通过原生传递来的常数生成):
+
+```javascript
+// DatePickerIOS.ios.js
+
+var RCTDatePickerIOSConsts = require('react-native').UIManager.RCTDatePicker.Constants;
+...
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ rkDatePickerIOS: {
+ height: RCTDatePickerIOSConsts.ComponentHeight,
+ width: RCTDatePickerIOSConsts.ComponentWidth,
+ },
+});
+```
+
+常量`RCTDatePickerIOSConsts`在原生代码中导出,从一个组件的实际布局上获取到:
+
+```objective-c
+// RCTDatePickerManager.m
+
+- (NSDictionary *)constantsToExport
+{
+ UIDatePicker *dp = [[UIDatePicker alloc] init];
+ [dp layoutIfNeeded];
+
+ return @{
+ @"ComponentHeight": @(CGRectGetHeight(dp.frame)),
+ @"ComponentWidth": @(CGRectGetWidth(dp.frame)),
+ @"DatePickerModes": @{
+ @"time": @(UIDatePickerModeTime),
+ @"date": @(UIDatePickerModeDate),
+ @"datetime": @(UIDatePickerModeDateAndTime),
+ }
+ };
+}
+```
+
+本向导覆盖了包装原生组件所需了解的许多方面,不过你可能还有很多知识需要了解,譬如特殊的方式来插入和布局子视图。如果你想更深入了解,可以阅读`RNTMapManager`和其它的组件的[源代码](https://github.com/facebook/react-native/blob/master/React/Views)。
+
diff --git a/docs/docs/0.41/native-modules-android.md b/docs/docs/0.41/native-modules-android.md
new file mode 100644
index 0000000..7f1c9b0
--- /dev/null
+++ b/docs/docs/0.41/native-modules-android.md
@@ -0,0 +1,431 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块包装;或者你需要复用一些Java代码,而不是用Javascript重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+## Toast模块
+
+本向导会用[Toast](http://developer.android.com/reference/android/widget/Toast.html)作为例子。假设我们希望可以从Javascript发起一个Toast消息(Android中的一种会在屏幕下方弹出、保持一段时间的消息通知)
+
+我们首先来创建一个原生模块。一个原生模块是一个继承了`ReactContextBaseJavaModule`的Java类,它可以实现一些JavaScript所需的功能。我们这里的目标是可以在JavaScript里写`ToastAndroid.show('Awesome', ToastAndroid.SHORT);`,来调起一个Toast通知。
+
+```java
+package com.facebook.react.modules.toast;
+
+import android.widget.Toast;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+import java.util.Map;
+
+public class ToastModule extends ReactContextBaseJavaModule {
+
+ private static final String DURATION_SHORT_KEY = "SHORT";
+ private static final String DURATION_LONG_KEY = "LONG";
+
+ public ToastModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+}
+```
+
+`ReactContextBaseJavaModule`要求派生类实现`getName`方法。这个函数用于返回一个字符串名字,这个名字在JavaScript端标记这个模块。这里我们把这个模块叫做`ToastAndroid`,这样就可以在JavaScript中通过`React.NativeModules.ToastAndroid`访问到这个模块。**译注:RN已经内置了一个名为ToastAndroid的模块,所以如果你在练习时完全照抄,那么运行时会报错名字冲突!所以请在这里选择另外一个名字!**
+
+```java
+ @Override
+ public String getName() {
+ return "ToastAndroid";
+ }
+```
+
+_译注_:模块名前的RCT前缀会被自动移除。所以如果返回的字符串为"RCTToastAndroid",在JavaScript端依然通过`React.NativeModules.ToastAndroid`访问到这个模块。
+
+一个可选的方法`getContants`返回了需要导出给JavaScript使用的常量。它并不一定需要实现,但在定义一些可以被JavaScript同步访问到的预定义的值时非常有用。
+
+```java
+ @Override
+ public Map getConstants() {
+ final Map constants = new HashMap<>();
+ constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
+ constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
+ return constants;
+ }
+```
+
+要导出一个方法给JavaScript使用,Java方法需要使用注解`@ReactMethod`。方法的返回类型必须为`void`。React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件(参见下文的描述)。
+
+```java
+ @ReactMethod
+ public void show(String message, int duration) {
+ Toast.makeText(getReactApplicationContext(), message, duration).show();
+ }
+```
+
+### 参数类型
+
+下面的参数类型在`@ReactMethod`注明的方法中,会被直接映射到它们对应的JavaScript类型。
+
+```
+Boolean -> Bool
+Integer -> Number
+Double -> Number
+Float -> Number
+String -> String
+Callback -> function
+ReadableMap -> Object
+ReadableArray -> Array
+```
+参阅[ReadableMap](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java)和[ReadableArray](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java)。
+
+### 注册模块
+
+在Java这边要做的最后一件事就是注册这个模块。我们需要在应用的Package类的`createNativeModules`方法中添加这个模块。如果模块没有被注册,它也无法在JavaScript中被访问到。
+
+```java
+package com.facebook.react.modules.toast;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AnExampleReactPackage implements ReactPackage {
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createNativeModules(
+ ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new ToastModule(reactContext));
+
+ return modules;
+ }
+```
+
+这个package需要在`MainApplication.java`文件的`getPackages`方法中提供。这个文件位于你的react-native应用文件夹的android目录中。具体路径是: `android/app/src/main/java/com/your-app-name/MainApplication.java`.
+
+```java
+protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new AnExampleReactPackage()); // <-- 添加这一行,类名替换成你的Package类的名字.
+}
+```
+
+为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从`NativeModules`中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。
+
+```javascript
+'use strict';
+
+/**
+ * This exposes the native ToastAndroid module as a JS module. This has a function 'show'
+ * which takes the following parameters:
+ *
+ * 1. String message: A string with the text to toast
+ * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or ToastAndroid.LONG
+ */
+import { NativeModules } from 'react-native';
+
+// 下一句中的ToastAndroid即对应上文
+// public String getName()中返回的字符串
+// 练习时请务必选择另外的名字!
+
+export default NativeModules.ToastAndroid;
+```
+
+现在,在别处的JavaScript代码中可以这样调用你的方法:
+
+```javascript
+import ToastAndroid from './ToastAndroid';
+ToastAndroid.show('Awesome', ToastAndroid.SHORT);
+```
+
+## 更多特性
+
+### 回调函数
+
+原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
+
+```java
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Callback errorCallback,
+ Callback successCallback) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+ float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+ float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+ float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+ float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+ successCallback.invoke(relativeX, relativeY, width, height);
+ } catch (IllegalViewOperationException e) {
+ errorCallback.invoke(e.getMessage());
+ }
+ }
+
+...
+```
+
+这个函数可以在JavaScript里这样使用:
+
+```js
+UIManager.measureLayout(
+ 100,
+ 100,
+ (msg) => {
+ console.log(msg);
+ },
+ (x, y, width, height) => {
+ console.log(x + ':' + y + ':' + width + ':' + height);
+ }
+);
+```
+
+原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。
+
+请务必注意callback并非在对应的原生函数返回后立即被执行——注意跨语言通讯是异步的,这个执行过程会通过消息循环来进行。
+
+## Promises
+
+__译注__:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。
+
+原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的`async/await`语法则效果更佳。如果桥接原生方法的最后一个参数是一个`Promise`,则对应的JS方法就会返回一个Promise对象。
+
+我们把上面的代码用promise来代替回调进行重构:
+
+```java
+import com.facebook.react.bridge.Promise;
+
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Promise promise) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+
+ WritableMap map = Arguments.createMap();
+
+ map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0]));
+ map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1]));
+ map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2]));
+ map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3]));
+
+ promise.resolve(map);
+ } catch (IllegalViewOperationException e) {
+ promise.reject(e.getMessage());
+ }
+ }
+
+...
+```
+
+现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了`async`的异步函数内使用`await`关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
+
+```js
+async function measureLayout() {
+ try {
+ var {
+ relativeX,
+ relativeY,
+ width,
+ height,
+ } = await UIManager.measureLayout(100, 100);
+
+ console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+measureLayout();
+```
+
+### 多线程
+
+原生模块不应对自己被调用时所处的线程做任何假设,当前的状况有可能会在将来的版本中改变。如果一个过程要阻塞执行一段时间,这个工作应当分配到一个内部管理的工作线程,然后从那边可以调用任意的回调函数。_译注_:我们通常用AsyncTask来完成这项工作。
+
+### 发送事件到JavaScript
+
+原生模块可以在没有被调用的情况下往JavaScript发送事件通知。最简单的办法就是通过`RCTDeviceEventEmitter`,这可以通过`ReactContext`来获得对应的引用,像这样:
+
+```java
+...
+private void sendEvent(ReactContext reactContext,
+ String eventName,
+ @Nullable WritableMap params) {
+ reactContext
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit(eventName, params);
+}
+...
+WritableMap params = Arguments.createMap();
+...
+sendEvent(reactContext, "keyboardWillShow", params);
+```
+
+JavaScript模块可以通过使用`DeviceEventEmitter`模块来监听事件:
+
+```js
+import { DeviceEventEmitter } from 'react-native';
+...
+componentWillMount: function() {
+ DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) {
+ // handle event.
+ });
+}
+...
+```
+
+### 从`startActivityForResult`中获取结果
+
+如果你使用`startActivityForResult`调起了一个activity并想从其中获取返回结果,那么你需要监听`onActivityResult`事件。具体的做法是继承`BaseActivityEventListener`或是实现`ActivityEventListener`。我们推荐前一种做法,因为它相对来说不太会受到API变更的影响。然后你需要在模块的构造函数中注册这一监听事件。
+
+```java
+reactContext.addActivityEventListener(mActivityResultListener);
+```
+
+现在你可以通过重写下面的方法来实现对`onActivityResult`的监听:
+
+```java
+@Override
+public void onActivityResult(
+ final Activity activity,
+ final int requestCode,
+ final int resultCode,
+ final Intent intent) {
+ // 在这里实现你自己的逻辑
+}
+```
+
+下面我们写一个简单的图片选择器来实践一下。这个图片选择器会把`pickImage`方法暴露给JavaScript,而这个方法在调用时就会把图片的路径返回到JS端。
+
+```java
+public class ImagePickerModule extends ReactContextBaseJavaModule {
+
+ private static final int IMAGE_PICKER_REQUEST = 467081;
+ private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
+ private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
+ private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
+ private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";
+
+ private Promise mPickerPromise;
+
+ private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
+
+ @Override
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
+ if (requestCode == IMAGE_PICKER_REQUEST) {
+ if (mPickerPromise != null) {
+ if (resultCode == Activity.RESULT_CANCELED) {
+ mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
+ } else if (resultCode == Activity.RESULT_OK) {
+ Uri uri = intent.getData();
+
+ if (uri == null) {
+ mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
+ } else {
+ mPickerPromise.resolve(uri.toString());
+ }
+ }
+
+ mPickerPromise = null;
+ }
+ }
+ }
+ };
+
+ public ImagePickerModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+
+ // Add the listener for `onActivityResult`
+ reactContext.addActivityEventListener(mActivityEventListener);
+ }
+
+ @Override
+ public String getName() {
+ return "ImagePickerModule";
+ }
+
+ @ReactMethod
+ public void pickImage(final Promise promise) {
+ Activity currentActivity = getCurrentActivity();
+
+ if (currentActivity == null) {
+ promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
+ return;
+ }
+
+ // Store the promise to resolve/reject when picker returns data
+ mPickerPromise = promise;
+
+ try {
+ final Intent galleryIntent = new Intent(Intent.ACTION_PICK);
+
+ galleryIntent.setType("image/*");
+
+ final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");
+
+ currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST);
+ } catch (Exception e) {
+ mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
+ mPickerPromise = null;
+ }
+ }
+}
+```
+
+### 监听生命周期事件
+
+监听activity的生命周期事件(比如`onResume`, `onPause`等等)和我们在前面实现 `ActivityEventListener`的做法类似。模块必须实现`LifecycleEventListener`,然后需要在构造函数中注册一个监听函数:
+
+```java
+reactContext.addLifecycleEventListener(this);
+```
+
+现在你可以通过实现下列方法来监听activity的生命周期事件了:
+
+```java
+@Override
+public void onHostResume() {
+ // Activity `onResume`
+}
+
+@Override
+public void onHostPause() {
+ // Activity `onPause`
+}
+
+@Override
+public void onHostDestroy() {
+ // Activity `onDestroy`
+}
+```
diff --git a/docs/docs/0.41/native-modules-ios.md b/docs/docs/0.41/native-modules-ios.md
new file mode 100644
index 0000000..0ffa289
--- /dev/null
+++ b/docs/docs/0.41/native-modules-ios.md
@@ -0,0 +1,453 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块封装;或者你需要复用Objective-C、Swift或C++代码,而不是用JavaScript重新实现一遍;又或者你需要实现某些高性能、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+本文是关于如何封装原生模块的高级向导,我们假设您已经具备Objective-C或者Swift,以及iOS核心库(Foundation、UIKit)的相关知识。
+
+## iOS 日历模块演示
+
+本向导将会用[iOS日历API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html)作为示例。我们的目标就是在Javascript中可以访问到iOS的日历功能。
+
+在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
+
+```objective-c
+// CalendarManager.h
+#import
+#import
+
+@interface CalendarManager : NSObject
+@end
+```
+
+为了实现`RCTBridgeModule`协议,你的类需要包含`RCT_EXPORT_MODULE()`宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。
+
+```objective-c
+// CalendarManager.m
+@implementation CalendarManager
+
+RCT_EXPORT_MODULE();
+
+@end
+```
+
+你必须明确的声明要给Javascript导出的方法,否则React Native不会导出任何方法。声明通过`RCT_EXPORT_METHOD()`宏来实现:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
+{
+ RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
+}
+```
+
+现在从Javascript里可以这样调用这个方法:
+
+```javascript
+import { NativeModules } from 'react-native';
+var CalendarManager = NativeModules.CalendarManager;
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
+```
+
+> **注意**: Javascript方法名
+>
+> 导出到Javascript的方法名是Objective-C的方法名的第一个部分。React Native还定义了一个`RCT_REMAP_METHOD()`宏,它可以指定Javascript方法名。当许多方法的第一部分相同的时候用它来避免在Javascript端的名字冲突。
+
+桥接到Javascript的方法返回值类型必须是`void`。React Native的桥接操作是异步的,所以要返回结果给Javascript,你必须通过回调或者触发事件来进行。(参见本文档后面的部分)
+
+## 参数类型
+
+`RCT_EXPORT_METHOD` 支持所有标准JSON类型,包括:
+
+- string (`NSString`)
+- number (`NSInteger`, `float`, `double`, `CGFloat`, `NSNumber`)
+- boolean (`BOOL`, `NSNumber`)
+- array (`NSArray`) 包含本列表中任意类型
+- object (`NSDictionary`) 包含string类型的键和本列表中任意类型的值
+- function (`RCTResponseSenderBlock`)
+
+除此以外,任何`RCTConvert`类支持的的类型也都可以使用(参见[`RCTConvert`](https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h)了解更多信息)。`RCTConvert`还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。
+
+在我们的`CalendarManager`例子里,我们需要把事件的时间交给原生方法。我们不能在桥接通道里传递Date对象,所以需要把日期转化成字符串或数字来传递。我们可以这么实现原生函数:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)secondsSinceUnixEpoch)
+{
+ NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
+}
+```
+
+或者这样:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString)
+{
+ NSDate *date = [RCTConvert NSDate:ISO8601DateString];
+}
+```
+
+不过我们可以依靠自动类型转换的特性,跳过手动的类型转换,而直接这么写:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSDate *)date)
+{
+ // Date is ready to use!
+}
+```
+
+在Javascript既可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.getTime()); // 把日期以unix时间戳形式传递
+```
+
+也可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.toISOString()); // 把日期以ISO-8601的字符串形式传递
+```
+
+两个值都会被转换为正确的`NSDate`类型。但如果提供一个不合法的值,譬如一个`Array`,则会产生一个“红屏”报错信息。
+
+随着`CalendarManager.addEvent`方法变得越来越复杂,参数的个数越来越多,其中有一些可能是可选的参数。在这种情况下我们应该考虑修改我们的API,用一个dictionary来存放所有的事件参数,像这样:
+
+```objective-c
+#import
+
+RCT_EXPORT_METHOD(addEvent:(NSString *)name details:(NSDictionary *)details)
+{
+ NSString *location = [RCTConvert NSString:details[@"location"]];
+ NSDate *time = [RCTConvert NSDate:details[@"time"]];
+ ...
+}
+```
+
+然后在JS里这样调用:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', {
+ location: '4 Privet Drive, Surrey',
+ time: date.toTime(),
+ description: '...'
+})
+```
+
+> **注意**: 关于数组和映射
+>
+> Objective-C并没有提供确保这些结构体内部值的类型的方式。你的原生模块可能希望收到一个字符串数组,但如果JavaScript在调用的时候提供了一个混合number和string的数组,你会收到一个`NSArray`,里面既有`NSNumber`也有`NSString`。对于数组来说,`RCTConvert`提供了一些类型化的集合,譬如`NSStringArray`或者`UIColorArray`,你可以用在你的函数声明中。对于映射而言,开发者有责任自己调用`RCTConvert`的辅助方法来检测和转换值的类型。
+
+## 回调函数
+
+> **警告**
+>
+> 本章节内容目前还处在实验阶段,因为我们还并没有太多的实践经验来处理回调函数。
+
+原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
+
+```objective-c
+RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback)
+{
+ NSArray *events = ...
+ callback(@[[NSNull null], events]);
+}
+```
+
+`RCTResponseSenderBlock`只接受一个参数——传递给JavaScript回调函数的参数数组。在上面这个例子里我们用Node.js的常用习惯:第一个参数是一个错误对象(没有发生错误的时候为null),而剩下的部分是函数的返回值。
+
+```javascript
+CalendarManager.findEvents((error, events) => {
+ if (error) {
+ console.error(error);
+ } else {
+ this.setState({events: events});
+ }
+})
+```
+
+原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。这在封装那些通过“委托函数”来获得返回值的iOS API时最为常见。[`RCTAlertManager`](https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m)中就属于这种情况。
+
+如果你想传递一个更接近`Error`类型的对象给Javascript,可以用[`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h)提供的`RCTMakeError`函数。现在它仅仅是发送了一个和Error结构一样的dictionary给Javascript,但我们考虑在将来版本里让它产生一个真正的`Error`对象。
+
+> **注意**
+>
+> 如果你传递了回调函数,那么在原生端就必须执行它(如果传递了两个,比如onSuccess和onFail,那么执行其中一个即可),否则会导致内存泄漏。
+
+## Promises
+
+__译注__:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。
+
+原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的`async/await`语法则效果更佳。如果桥接原生方法的最后两个参数是`RCTPromiseResolveBlock`和`RCTPromiseRejectBlock`,则对应的JS方法就会返回一个Promise对象。
+
+我们把上面的代码用promise来代替回调进行重构:
+
+```objective-c
+RCT_REMAP_METHOD(findEvents,
+ resolver:(RCTPromiseResolveBlock)resolve
+ rejecter:(RCTPromiseRejectBlock)reject)
+{
+ NSArray *events = ...
+ if (events) {
+ resolve(events);
+ } else {
+ reject(error);
+ }
+}
+```
+
+现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了`async`的异步函数内使用`await`关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
+
+```js
+async function updateEvents() {
+ try {
+ var events = await CalendarManager.findEvents();
+
+ this.setState({ events });
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+updateEvents();
+```
+
+## 多线程
+
+原生模块不应对自己被调用时所处的线程做任何假设。React Native在一个独立的串行GCD队列中调用原生模块的方法,但这属于实现的细节,并且可能会在将来的版本中改变。通过实现方法`- (dispatch_queue_t)methodQueue`,原生模块可以指定自己想在哪个队列中被执行。具体来说,如果模块需要调用一些必须在主线程才能使用的API,那应当这样指定:
+
+```objective-c
+- (dispatch_queue_t)methodQueue
+{
+ return dispatch_get_main_queue();
+}
+```
+
+类似的,如果一个操作需要花费很长时间,原生模块不应该阻塞住,而是应当声明一个用于执行操作的独立队列。举个例子,`RCTAsyncLocalStorage`模块创建了自己的一个queue,这样它在做一些较慢的磁盘操作的时候就不会阻塞住React本身的消息队列:
+
+```objective-c
+- (dispatch_queue_t)methodQueue
+{
+ return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
+}
+```
+
+指定的`methodQueue`会被你模块里的所有方法共享。如果你的方法中“只有一个”是耗时较长的(或者是由于某种原因必须在不同的队列中运行的),你可以在函数体内用`dispatch_async`方法来在另一个队列执行,而不影响其他方法:
+
+```objective-c
+RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
+{
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ // 在这里执行长时间的操作
+ ...
+ // 你可以在任何线程/队列中执行回调函数
+ callback(@[...]);
+ });
+}
+```
+
+> **注意**: 在模块之间共享分发队列
+>
+> `methodQueue`方法会在模块被初始化的时候被执行一次,然后会被React Native的桥接机制保存下来,所以你不需要自己保存队列的引用,除非你希望在模块的其它地方使用它。但是,如果你希望在若干个模块中共享同一个队列,则需要自己保存并返回相同的队列实例;仅仅是返回相同名字的队列是不行的。
+
+## 依赖注入
+bridge会自动注册实现了`RCTBridgeModule`协议的模块,但是你可能也希望能够初始化自定义的模块实例(这样可以注入依赖)。
+
+要实现这个功能,你需要实现`RTCBridgeDelegate`协议,初始化`RTCBridge`,并且在初始化方法里指定代理。然后用初始化好的`RTCBridge`实例初始化一个`RTCRootView`。
+
+```objective-c
+id moduleInitialiser = [[classThatImplementsRTCBridgeDelegate alloc] init];
+
+RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];
+
+RCTRootView *rootView = [[RCTRootView alloc]
+ initWithBridge:bridge
+ moduleName:kModuleName
+ initialProperties:nil];
+```
+
+## 导出常量
+
+原生模块可以导出一些常量,这些常量在JavaScript端随时都可以访问。用这种方法来传递一些静态数据,可以避免通过bridge进行一次来回交互。
+
+```objective-c
+- (NSDictionary *)constantsToExport
+{
+ return @{ @"firstDayOfTheWeek": @"Monday" };
+}
+```
+
+Javascript端可以随时同步地访问这个数据:
+
+```javascript
+console.log(CalendarManager.firstDayOfTheWeek);
+```
+
+但是注意这个常量仅仅在初始化的时候导出了一次,所以即使你在运行期间改变`constantToExport`返回的值,也不会影响到JavaScript环境下所得到的结果。
+
+### 枚举常量
+
+用`NS_ENUM`定义的枚举类型必须要先扩展对应的RCTConvert方法才可以作为函数参数传递。
+
+假设我们要导出如下的`NS_ENUM`定义:
+
+```objc
+typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
+ UIStatusBarAnimationNone,
+ UIStatusBarAnimationFade,
+ UIStatusBarAnimationSlide,
+};
+```
+
+你需要这样来扩展RCTConvert类:
+
+```objc
+@implementation RCTConvert (StatusBarAnimation)
+ RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone),
+ @"statusBarAnimationFade" : @(UIStatusBarAnimationFade),
+ @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)}),
+ UIStatusBarAnimationNone, integerValue)
+@end
+```
+
+接着你可以这样定义方法并且导出enum值作为常量:
+
+```objc
+- (NSDictionary *)constantsToExport
+{
+ return @{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone),
+ @"statusBarAnimationFade" : @(UIStatusBarAnimationFade),
+ @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide) }
+};
+
+RCT_EXPORT_METHOD(updateStatusBarAnimation:(UIStatusBarAnimation)animation
+ completion:(RCTResponseSenderBlock)callback)
+```
+
+你的枚举现在会用上面提供的选择器进行转换(上面的例子中是`integerValue`),然后再传递给你导出的函数。
+
+## 给Javascript发送事件
+
+即使没有被JavaScript调用,原生模块也可以给JavaScript发送事件通知。最好的方法是继承`RCTEventEmitter`,实现`suppportEvents`方法并调用`self sendEventWithName:`。
+
+```objective-c
+// CalendarManager.h
+#import
+#import
+
+@interface CalendarManager : RCTEventEmitter
+
+@end
+```
+```objective-c
+// CalendarManager.m
+#import "CalendarManager.h"
+
+@implementation CalendarManager
+
+RCT_EXPORT_MODULE();
+
+- (NSArray *)supportedEvents
+{
+ return @[@"EventReminder"];
+}
+
+- (void)calendarEventReminderReceived:(NSNotification *)notification
+{
+ NSString *eventName = notification.userInfo[@"name"];
+ [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
+}
+
+@end
+```
+JavaScript代码可以创建一个包含你的模块的`NativeEventEmitter`实例来订阅这些事件。
+
+```javascript
+import { NativeEventEmitter, NativeModules } from 'react-native';
+const { CalendarManager } = NativeModules;
+
+const calendarManagerEmitter = new NativeEventEmitter(CalendarManager);
+
+const subscription = calendarManagerEmitter.addListener(
+ 'EventReminder',
+ (reminder) => console.log(reminder.name)
+);
+...
+// 别忘了取消订阅,通常在componentWillUnmount生命周期方法中实现。
+subscription.remove();
+```
+更多给JavaScript发送事件的例子请看[`RCTLocationObserver`](https://github.com/facebook/react-native/blob/master/Libraries/Geolocation/RCTLocationObserver.m)。
+
+
+## 优化无监听处理的事件
+
+如果你发送了一个事件却没有任何监听处理,则会因此收到一个资源警告。要优化因此带来的额外开销,你可以在你的`RCTEventEmitter`子类中覆盖`startObserving`和`stopObserving`方法。
+
+```objective-c
+@implementation CalendarManager
+{
+ bool hasListeners;
+}
+
+// 在添加第一个监听函数时触发
+-(void)startObserving {
+ hasListeners = YES;
+ // Set up any upstream listeners or background tasks as necessary
+}
+
+// Will be called when this module's last listener is removed, or on dealloc.
+-(void)stopObserving {
+ hasListeners = NO;
+ // Remove upstream listeners, stop unnecessary background tasks
+}
+
+- (void)calendarEventReminderReceived:(NSNotification *)notification
+{
+ NSString *eventName = notification.userInfo[@"name"];
+ if (hasListeners) { // Only send events if anyone is listening
+ [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
+ }
+}
+```
+
+## 从Swift导出
+
+Swift不支持宏,所以从Swift向React Native导出类和函数需要多做一些设置,但是大致与Objective-C是相同的。
+
+假设我们已经有了一个一样的`CalendarManager`,不过是用Swift实现的类:
+
+```swift
+// CalendarManager.swift
+
+@objc(CalendarManager)
+class CalendarManager: NSObject {
+
+ @objc func addEvent(name: String, location: String, date: NSNumber) -> Void {
+ // Date is ready to use!
+ }
+
+}
+```
+
+> **注意**: 你必须使用@objc标记来确保类和函数对Objective-C公开。
+
+接着,创建一个私有的实现文件,并将必要的信息注册到React Native中。
+
+```objc
+// CalendarManagerBridge.m
+#import
+
+@interface RCT_EXTERN_MODULE(CalendarManager, NSObject)
+
+RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)
+
+@end
+```
+
+请注意,一旦你[在IOS中混用2种语言](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html), 那就还需要一个额外的桥接头文件,称作“bridging header”,用来导出Objective-C文件给Swift。如果你是通过Xcode菜单中的`File>New File`来创建的Swift文件,Xcode会自动为你创建这个头文件。在这个头文件中,你需要引入`RCTBridgeModule.h`。
+
+```objc
+// CalendarManager-Bridging-Header.h
+#import
+```
+
+同样的,你也可以使用`RCT_EXTERN_REMAP_MODULE`和`RCT_EXTERN_REMAP_METHOD`来改变导出模块和方法的JavaScript调用名称。
+了解更多信息,请参阅[`RCTBridgeModule`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridgeModule.h).
+
+
diff --git a/docs/docs/0.41/nativemethodsmixin.md b/docs/docs/0.41/nativemethodsmixin.md
new file mode 100644
index 0000000..f9fab4f
--- /dev/null
+++ b/docs/docs/0.41/nativemethodsmixin.md
@@ -0,0 +1,48 @@
+`NativeMethodsMixin`提供了一些用于直接访问底层原生组件的方法。这在你需要聚焦(focus)一个视图或者计算它在屏幕上显示的尺寸之类的情况下可能会需要。
+
+这些方法在大部分React Native提供的默认的组件中都可以使用。注意,它们不能在一些复合组件(并非直接由原生视图构成)中使用,这可能包括你自己在应用中定义的绝大部分组件。想了解更多信息,可以参阅[直接操作](direct-manipulation.html)。
+
+### 方法
+
+
+
+
static measure(callback: MeasureOnSuccessCallback) #
+
+
计算指定视图在屏幕上显示的位置和尺寸,通过一个异步回调返回计算的结果。如果成功,回调函数会被调用,并带有以下参数::
+
+ x
+ y
+ width
+ height
+ pageX
+ pageY
+
+
注意这些信息直到原生渲染完成之前都不能使用。如果你希望尽快获取视图的位置和尺寸信息,考虑使用onLayout属性 来替代。
+
+
+
+
static measureLayout(relativeToNativeNode: number, onSuccess: MeasureLayoutOnSuccessCallback, onFail: () => void) #
+
+
与measure() 函数类似,不过计算的是相对指定祖先节点relativeToNativeNode的位置和尺寸。这意味着返回的x, y是相对于指定祖先视图的。
+
要找到一个组件的原生节点的ID,一般做法是调用React.findNodeHandle(component)。
+
+
+
+
static setNativeProps(nativeProps: Object) #
+
+
这个函数直接发送属性到原生代码。这些属性不会参与后续的对比过程——这意味着如果你不在下一次render中包含这些属性,这些属性还会保持有效(参见直接操作 )。
+
+
+
+
static focus() #
+
+
请求聚焦指定的输入框或者视图。具体的效果要取决于平台和视图的类型。
+
+
+
+
static blur() #
+
+
移除指定的输入框或者视图的焦点。这是focus()的相反操作。。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/navigation.md b/docs/docs/0.41/navigation.md
new file mode 100644
index 0000000..1cba7e8
--- /dev/null
+++ b/docs/docs/0.41/navigation.md
@@ -0,0 +1,333 @@
+本文档总结对比了React Native中现有的几个导航组件。如果你刚开始接触,那么直接选择`Navigator`就好。如果你只针对iOS平台开发,并且想和系统原生外观一致,那么可以选择`NavigatorIOS`。如果你想更好地管理导航栈,那么应该尝试一下`NavigationExperimental`。
+
+## Navigator
+
+`Navigator`使用纯JavaScript实现了一个导航栈,因此可以跨平台工作,同时也便于定制。这也是我们在[使用导航器跳转页面](using-navigators.html)的教程中示例用的组件。
+
+
+
+`Navigator`可以在`renderScene`方法中根据当前路由渲染不同的组件。默认情况下新的场景会从屏幕右侧滑进来,但你也可以通过`configureScene`方法来管理这一行为。你还可以通过`navigationBar`属性来配置一个跨场景的导航栏。(译注:但我们不推荐使用跨场景的navigationBar,它的代码逻辑维护起来很困难!建议自己在场景中用`View`实现自定义的导航栏。)
+
+点击这里阅读[Navigator的API文档](navigator.html)。
+
+## NavigatorIOS
+
+如果你只针对iOS平台开发,那么可以考虑使用[NavigatorIOS](navigatorios.html)。它是基于 [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/)封装的,所以看起来很像。
+
+
+
+```javascript
+
+```
+
+用法类似`Navigator`,`NavigatorIOS`也使用路由对象来描述场景,但有一些重要区别。其中要渲染的组件在路由对象的`component`字段中指定,要给目标组件传递的参数则写在`passProps`中。被渲染的component都会自动接受到一个名为`navigator`的属性,你可以直接调用此对象(this.props.navigator)的`push`和`pop`方法。
+
+由于`NavigatorIOS`使用的是原生的UIKit导航,所以它会自动渲染一个带有返回按钮和标题的导航栏。
+
+```javascript
+import React, { Component, PropTypes } from 'react';
+import { NavigatorIOS, Text, TouchableHighlight, View } from 'react-native';
+
+export default class NavigatorIOSApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ navigator: PropTypes.object.isRequired,
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this._onForward = this._onForward.bind(this);
+ }
+
+ _onForward() {
+ this.props.navigator.push({
+ title: 'Scene ' + nextIndex,
+ });
+ }
+
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ )
+ }
+}
+```
+
+点击这里阅读[Navigator的API文档](navigatorios.html)。
+
+> 你还可以看看[react-navigation](https://reactnavigation.org/),这是一个尚处在实验阶段的官方组件,旨在于提供原生的跨平台的导航组件。
+
+## NavigationExperimental
+
+`Navigator`和`NavigatorIOS`都是有状态的组件。如果你在app中多处使用这些组件,那么维护工作就会变得非常麻烦。`NavigationExperimental`以不同的方式实现了导航,它可以使用任何视图来作为导航视图,同时还用到了规约函数(reducer)自顶向下地管理状态。正如名字中的`Experimental`所示,这一组件的整体实现具有一定的实验性,但我们仍然建议你尝试一下用它去更好地管理应用的导航。
+
+```javascript
+
+```
+
+引入`NavigationExperimental`的步骤和React Native中的其他组件一样。在引入此组件之后,还可以进一步解构其中一些有用的子组件,比如这里我们会从中解构`NavigationCardStack`和 `NavigationStateUtils`这两个子组件。
+
+```javascript
+import React, { Component } from 'react';
+import { NavigationExperimental } from 'react-native';
+
+const {
+ CardStack: NavigationCardStack,
+ StateUtils: NavigationStateUtils,
+} = NavigationExperimental;
+```
+
+正如上文所说,`NavigationExperimental`的实现机制与`Navigator`和`NavigatorIOS`有所不同。用它来构筑导航栈还需要一些额外的步骤,但这些步骤并不是无用功。
+
+### 第一步:定义初始状态和根容器
+
+首先创建一个新组件,我们会把它作为根容器,并在这里定义初始状态。导航栈会定义在`navigationState`字段中,其中也包含了初始的路由定义:
+
+```javascript
+class BleedingEdgeApplication extends Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ // 定义初始的导航状态
+ navigationState: {
+ index: 0, // 现在是第一页(索引从0开始)
+ routes: [{key: 'My Initial Scene'}], // 初始仅设定一个路由
+ },
+ };
+
+ // 我们稍后再补充此函数的实现细节
+ this._onNavigationChange = this._onNavigationChange.bind(this);
+ }
+
+ _onNavigationChange(type) {
+ // 我们稍后再补充此函数的实现细节
+ }
+
+ render() {
+ return (
+ 这是一段占位的文字。稍后我们会在这里渲染导航。
+ );
+ }
+}
+```
+
+现在我们定义了一个有状态的组件,然而暂时并无太多卵用。我们的初始状态包含了一个路由对象,以及当前页面的索引值。但是这看起来跟Navigator的初始路由定义好像没什么区别嘛!回忆一下navigator对象提供了哪些操作?——对的,push和pop,看起来也非常直观。但是前面我们说过了,现在我们会在根容器上使用规约函数来管理状态。下面注意仔细看好了。
+
+### 第二步:规约导航状态
+
+NavigationExperimental内置了一些有用的规约函数(reducer),都放在NavigationStateUtils中。我们现在要用的两个就是push和pop了。它们接受一个navigationState对象参数,然后返回新的navigationState对象。
+
+据此我们可以这样来编写`_onNavigationChange`函数,在其中判断"push"和"pop"的行为,并分别规约对应的状态。
+
+```javascript
+_onNavigationChange(type) {
+ // 从state中解构出navigationState
+ let {navigationState} = this.state;
+
+ switch (type) {
+ case 'push':
+ // push一个新路由,在这里就是一个带有key属性的对象。
+ // 我个人喜欢随机数的key(但是说正经的,key必须要确保唯一性)
+ const route = {key: 'Route-' + Date.now()};
+
+ // 调用NavigationStateUtils提供的push规约函数
+ navigationState = NavigationStateUtils.push(navigationState, route);
+ break;
+
+ case 'pop':
+ // 使用pop函数来弹出当前路由
+ navigationState = NavigationStateUtils.pop(navigationState);
+ break;
+ }
+
+ // 如果没有实际变化,则NavigationStateUtils会返回同样的`navigationState`
+ // 我们只会更新确实发生变化的状态
+ if (this.state.navigationState !== navigationState) {
+ // 请记住更新状态必须通过setState()方法!
+ this.setState({navigationState});
+ // 如果你还不了解ES6中的新语法,那么简单讲解一下上面那一句
+ // 如果key和value的字面一样,那么可以简写成一个,等同于下面的写法:
+ // this.setState({navigationState: navigationState});
+ }
+}
+```
+
+Cool.我们已经触碰到了NavigationExperimental的精髓之所在。这里我们只处理了两种行为,实际开发中行为可能更复杂,比如可能会考虑后退(back)行为,又或者是tab间的切换过渡行为等等。
+
+我们现在还没写初始场景和实际的导航器,不过别急,我们一步一步来。
+
+### 第三步:定义场景
+
+为方便起见我们先定义一个Row(行)组件。其中显示了一些文字,并带有点击事件。
+
+```javascript
+class TappableRow extends Component {
+ render() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+}
+```
+
+现在来定义实际的场景。其中用到了一个ScrollView来显示一个垂直列表,第一行显示当前路由对象的key字段值,后两行用来点击后调用导航器的push和pop方法。
+
+```javascript
+class MyVeryComplexScene extends Component {
+ render() {
+ return (
+
+
+ Route: {this.props.route.key}
+
+
+
+
+ );
+ }
+}
+```
+
+### 第四步:创建导航栈
+
+我们之前已经定义了状态和管理状态的规约函数,现在可以创建导航器组件了。在写导航器的同时,我们可以使用当前路由的属性来配置场景并渲染它了。
+
+```javascript
+class MyVerySimpleNavigator extends Component {
+
+ // 在这里绑定一些导航用的方法
+ constructor(props, context) {
+ super(props, context);
+
+ this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
+ this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');
+
+ this._renderScene = this._renderScene.bind(this);
+ }
+
+ // Now we finally get to use the `NavigationCardStack` to render the scenes.
+ render() {
+ return (
+
+ );
+ }
+
+ // 根据路由来渲染场景
+ // `sceneProps`的具体结构定义在`NavigationTypeDefinition`的`NavigationSceneRendererProps`中
+ // 这里你可以根据路由的不同来返回不同的场景组件,我们这里为了简要说明,始终只返回这一个场景组件
+ _renderScene(sceneProps) {
+ return (
+
+ );
+ }
+}
+```
+
+差不多了!我已经可以闻到终点线的味道啦。现在把我们新做的导航器放到根容器中:
+
+```javascript
+class BleedingEdgeApplication extends Component {
+
+ // 为了简化说明,这里省略了constructor和其他的方法
+
+ render() {
+ return (
+
+ );
+ }
+}
+```
+
+完工了!赞美NavigationExperimental吧!
+
+#### 等一下——好像少了什么?
+
+(啊没错,我们忘了引入组件和样式。)
+
+```javascript
+import { NavigationExperimental, PixelRatio, ScrollView, StyleSheet, Text, TouchableHighlight } from 'react-native';
+
+const styles = StyleSheet.create({
+ navigator: {
+ flex: 1,
+ },
+ scrollView: {
+ marginTop: 64
+ },
+ row: {
+ padding: 15,
+ backgroundColor: 'white',
+ borderBottomWidth: 1 / PixelRatio.get(),
+ borderBottomColor: '#CDCDCD',
+ },
+ rowText: {
+ fontSize: 17,
+ },
+ buttonText: {
+ fontSize: 17,
+ fontWeight: '500',
+ },
+});
+```
+
+### 小作业
+
+你现在是导航器的专家了!参考下我们写的[NavigationExperimental的例子](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/js/NavigationExperimental),学习如何实现其他类型的导航结构,比如多个tab对应多个导航栈的情况。
+
diff --git a/docs/docs/next/navigator-comparison.md b/docs/docs/0.41/navigator-comparison.md
similarity index 100%
rename from docs/docs/next/navigator-comparison.md
rename to docs/docs/0.41/navigator-comparison.md
diff --git a/docs/docs/0.41/navigator.md b/docs/docs/0.41/navigator.md
new file mode 100644
index 0000000..672829c
--- /dev/null
+++ b/docs/docs/0.41/navigator.md
@@ -0,0 +1,127 @@
+使用导航器可以让你在应用的不同场景(页面)间进行切换。导航器通过路由对象来分辨不同的场景。利用`renderScene`方法,导航栏可以根据指定的路由来渲染场景。
+
+可以通过`configureScene`属性获取指定路由对象的配置信息,从而改变场景的动画或者手势。查看`Navigator.SceneConfigs`来获取默认的动画和更多的场景配置选项。
+
+__译注__:本文档的说明较为简略,使用上有一定的难度。论坛中有一篇更为详细的[教程](http://bbs.reactnative.cn/topic/20),推荐阅读。
+
+### 截图
+
+
+
+
+### 基本用法
+```javascript
+
+ {
+ var nextIndex = route.index + 1;
+ navigator.push({
+ name: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+```
+
+### 导航方法
+如果你得到了一个navigator对象的引用(__译注__:再次推荐仔细阅读此[教程](http://bbs.reactnative.cn/topic/20),理解如何在renderScene方法中传递navigator对象,否则直接调用会报undefined错误),则可以调用许多方法来进行导航:
+
+* getCurrentRoutes() - 获取当前栈里的路由,也就是push进来,没有pop掉的那些。
+* jumpBack() - 跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。
+* jumpForward() - 上一个方法不是调到之前的路由了么,用这个跳回来就好了。
+* jumpTo(route) - 跳转到已有的场景并且不卸载。
+* push(route) - 跳转到新的场景,并且将场景入栈,你可以稍后跳转过去
+* pop() - 跳转回去并且卸载掉当前场景
+* replace(route) - 用一个新的路由替换掉当前场景
+* replaceAtIndex(route, index) - 替换掉指定序列的路由场景
+* replacePrevious(route) - 替换掉之前的场景
+* resetTo(route) - 跳转到新的场景,并且重置整个路由栈
+* immediatelyResetRouteStack(routeStack) - 用新的路由数组来重置路由栈
+* popToRoute(route) - pop到路由指定的场景,在整个路由栈中,处于指定场景之后的场景将会被卸载。
+* popToTop() - pop到栈中的第一个场景,卸载掉所有的其他场景。
+
+### 属性
+
+
+
+
configureScene function #
+
+
可选的函数,用来配置场景动画和手势。会带有两个参数调用,一个是当前的路由,一个是当前的路由栈。然后它应当返回一个场景配置对象
+
(route, routeStack) => Navigator.SceneConfigs.FloatFromRight
+
+
+ Navigator.SceneConfigs.PushFromRight (默认)
+ Navigator.SceneConfigs.FloatFromRight
+ Navigator.SceneConfigs.FloatFromLeft
+ Navigator.SceneConfigs.FloatFromBottom
+ Navigator.SceneConfigs.FloatFromBottomAndroid
+ Navigator.SceneConfigs.FadeAndroid
+ Navigator.SceneConfigs.HorizontalSwipeJump
+ Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
+ Navigator.SceneConfigs.VerticalUpSwipeJump
+ Navigator.SceneConfigs.VerticalDownSwipeJump
+
+
+
+
+
initialRoute object #
+
+
定义启动时加载的路由。路由是导航栏用来识别渲染场景的一个对象。initialRoute必须是initialRouteStack中的一个路由。initialRoute默认为initialRouteStack中最后一项。
+
+
+
+
initialRouteStack [object] #
+
+
提供一个路由集合用来初始化。如果没有设置初始路由的话则必须设置该属性。如果没有提供该属性,它将被默认设置成一个只含有initialRoute的数组。
+
+
+
+
navigationBar node #
+
+
可选参数,提供一个在场景切换的时候保持的导航栏。
+
+
+
+
navigator object #
+
+
可选参数,提供从父导航器获得的导航器对象。
+
+
+
+
onDidFocus function #
+
+
每当导航切换完成或初始化之后,调用此回调,参数为新场景的路由。
+
+
+
+
onWillFocus function #
+
+
+
+
renderScene function #
+
+
必要参数。用来渲染指定路由的场景。调用的参数是路由和导航器。
+
(route, navigator) =>
+ <MySceneComponent title ={route.title} navigator ={navigator} />
+
+
+
+
+
diff --git a/docs/docs/0.41/navigatorios.md b/docs/docs/0.41/navigatorios.md
new file mode 100644
index 0000000..cc888be
--- /dev/null
+++ b/docs/docs/0.41/navigatorios.md
@@ -0,0 +1,650 @@
+`NavigatorIOS` is a wrapper around `UINavigationController`, enabling you to implement a navigation stack. It works exactly the same as it would on a native app using `UINavigationController`, providing the same animations and behavior from UIKIt.
+
+As the name implies, it is only available on iOS. Take a look at Navigator for a similar solution for your cross-platform needs, or check out [react-native-navigation](https://github.com/wix/react-native-navigation), a component that aims to provide native navigation on both iOS and Android.
+
+To set up the navigator, provide the `initialRoute` prop with a route object. A route object is used to describe each scene that your app navigates to. `initialRoute` represents the first route in your navigator.
+
+```js
+import React, { Component, PropTypes } from 'react';
+import { NavigatorIOS, Text } from 'react-native';
+
+export default class NavigatorIOSApp extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ navigator: PropTypes.object.isRequired,
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this._onForward = this._onForward.bind(this);
+ this._onBack = this._onBack.bind(this);
+ }
+
+ _onForward() {
+ this.props.navigator.push({
+ title: 'Scene ' + nextIndex,
+ });
+ }
+
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ )
+ }
+}
+```
+
+In this code, the navigator renders the component specified in `initialRoute`, which in this case is `MyScene`. This component will receive a `route` prop and a `navigator` prop representing the navigator. The navigator's navigation bar will render the title for the current scene, "My Initial Scene".
+
+You can optionally pass in a `passProps` property to your `initialRoute`. `NavigatorIOS` passes this in as props to the rendered component:
+
+```js
+initialRoute={{
+ component: MyScene,
+ title: 'My Initial Scene',
+ passProps: { myProp: 'foo' }
+}}
+```
+
+You can then access the props passed in via `{this.props.myProp}`.
+
+### 处理导航
+
+To trigger navigation functionality such as pushing or popping a view, you have access to a navigator object. The object is passed in as a prop to any component that is rendered by NavigatorIOS. You can then call the relevant methods to perform the navigation action you need:
+
+```js
+class MyView extends Component {
+ _handleBackPress() {
+ this.props.navigator.pop();
+ }
+
+ _handleNextPress(nextRoute) {
+ this.props.navigator.push(nextRoute);
+ }
+
+ render() {
+ const nextRoute = {
+ component: MyView,
+ title: 'Bar That',
+ passProps: { myProp: 'bar' }
+ };
+ return(
+ this._handleNextPress(nextRoute)}>
+
+ See you on the other nav {this.props.myProp}!
+
+
+ );
+ }
+}
+You can also trigger navigator functionality from the NavigatorIOS component:
+
+class NavvyIOS extends Component {
+ _handleNavigationRequest() {
+ this.refs.nav.push({
+ component: MyView,
+ title: 'Genius',
+ passProps: { myProp: 'genius' },
+ });
+ }
+
+ render() {
+ return (
+ this._handleNavigationRequest(),
+ }}
+ style={{flex: 1}}
+ />
+ );
+ }
+}
+```
+
+The code above adds a `_handleNavigationRequest` private method that is invoked from the `NavigatorIOS` component when the right navigation bar item is pressed. To get access to the navigator functionality, a reference to it is saved in the `ref` prop and later referenced to push a new scene into the navigation stack.
+
+### 导航栏的配置
+
+Props passed to `NavigatorIOS` will set the default configuration for the navigation bar. Props passed as properties to a route object will set the configuration for that route's navigation bar, overriding any props passed to the `NavigatorIOS `component.
+
+```js
+_handleNavigationRequest() {
+ this.refs.nav.push({
+ //...
+ passProps: { myProp: 'genius' },
+ barTintColor: '#996699',
+ });
+}
+
+render() {
+ return (
+
+ );
+}
+```
+
+In the example above the navigation bar color is changed when the new route is pushed.
+
+### 截图
+
+
+
+
+### 属性
+
+
+
+
barTintColor string #
+
+
+
+
initialRoute {component: function, title: string, passProps: object, backButtonIcon: Image.propTypes.source, backButtonTitle: string, leftButtonIcon: Image.propTypes.source, leftButtonTitle: string, onLeftButtonPress: function, rightButtonIcon: Image.propTypes.source, rightButtonTitle: string, onRightButtonPress: function, wrapperStyle: [object Object]} #
+
+
NavigatorIOS使用"路由"对象来包含要渲染的子视图、它们的属性、以及导航条配置。"push"和任何其它的导航函数的参数都是这样的路由对象。
+
+
+
+
+
+
导航器中的组件的默认属性。一个常见的用途是设置所有页面的背景颜色。
+
+
+
+
navigationBarHidden bool #
+
+
+
+
shadowHidden bool #
+
+
+
+
+
titleTextColor string #
+
+
+
+
+
interactivePopGestureEnabled bool #
+
+
决定是否启用滑动返回手势。不指定此属性时,手势会根据navigationBar的显隐情况决定是否启用(显示时启用手势,隐藏时禁用手势)。指定此属性后,手势与navigationBar的显隐情况无关。
+
+
+
+
+### 方法
+
+
+
push(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Navigate forward to a new route
+
+
popN(n: number) #
+
Go back N pages at once. When N=1, behavior matches pop()
+
+
+
replaceAtIndex(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}, index: number) #
+
Replace a route in the navigation stack.
+
index specifies the route in the stack that should be replaced.
+ If it's negative, it counts from the back.
+
+
replace(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replace the route for the current page and immediately
+ load the view for the new route.
+
+
replacePrevious(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replace the route/view for the previous page.
+
+
+
popToRoute(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Go back to the item for a particular route object
+
+
replacePreviousAndPop(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replaces the previous route/view and transitions back to it.
+
+
resetTo(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replaces the top item and popToTop
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const ViewExample = require('./ViewExample');
+
+const createExamplePage = require('./createExamplePage');
+const nativeImageSource = require('nativeImageSource');
+const {
+ AlertIOS,
+ NavigatorIOS,
+ ScrollView,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+class EmptyPage extends React.Component {
+ render() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+}
+
+class NavigatorIOSExamplePage extends React.Component {
+ render() {
+ var recurseTitle = 'Recurse Navigation';
+ if (!this.props.depth || this.props.depth === 1) {
+ recurseTitle += ' - more examples here';
+ }
+ return (
+
+
+
+ {this._renderRow(recurseTitle, () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: NavigatorIOSExamplePage,
+ backButtonTitle: 'Custom Back',
+ passProps: {depth: this.props.depth ? this.props.depth + 1 : 1},
+ });
+ })}
+ {this._renderRow('Push View Example', () => {
+ this.props.navigator.push({
+ title: 'Very Long Custom View Example Title',
+ component: createExamplePage(null, ViewExample),
+ });
+ })}
+ {this._renderRow('Custom title image Example', () => {
+ this.props.navigator.push({
+ title: 'Custom title image Example',
+ titleImage: require('./relay.png'),
+ component: createExamplePage(null, ViewExample),
+ });
+ })}
+ {this._renderRow('Custom Right Button', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ rightButtonTitle: 'Cancel',
+ onRightButtonPress: () => this.props.navigator.pop(),
+ passProps: {
+ text: 'This page has a right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Right System Button', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ rightButtonSystemIcon: 'bookmarks',
+ onRightButtonPress: () => this.props.navigator.pop(),
+ passProps: {
+ text: 'This page has a right system button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Left & Right Icons', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ leftButtonTitle: 'Custom Left',
+ onLeftButtonPress: () => this.props.navigator.pop(),
+ rightButtonIcon: nativeImageSource({
+ ios: 'NavBarButtonPlus',
+ width: 17,
+ height: 17
+ }),
+ onRightButtonPress: () => {
+ AlertIOS.alert(
+ 'Bar Button Action',
+ 'Recognized a tap on the bar button icon',
+ [
+ {
+ text: 'OK',
+ onPress: () => console.log('Tapped OK'),
+ },
+ ]
+ );
+ },
+ passProps: {
+ text: 'This page has an icon for the right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Left & Right System Icons', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ leftButtonSystemIcon: 'cancel',
+ onLeftButtonPress: () => this.props.navigator.pop(),
+ rightButtonSystemIcon: 'search',
+ onRightButtonPress: () => {
+ AlertIOS.alert(
+ 'Bar Button Action',
+ 'Recognized a tap on the bar button icon',
+ [
+ {
+ text: 'OK',
+ onPress: () => console.log('Tapped OK'),
+ },
+ ]
+ );
+ },
+ passProps: {
+ text: 'This page has an icon for the right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Pop', () => {
+ this.props.navigator.pop();
+ })}
+ {this._renderRow('Pop to top', () => {
+ this.props.navigator.popToTop();
+ })}
+ {this._renderReplace()}
+ {this._renderReplacePrevious()}
+ {this._renderReplacePreviousAndPop()}
+ {this._renderRow('Exit NavigatorIOS Example', this.props.onExampleExit)}
+
+
+
+ );
+ }
+
+ _renderReplace = () => {
+ if (!this.props.depth) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace here', () => {
+ var prevRoute = this.props.route;
+ this.props.navigator.replace({
+ title: 'New Navigation',
+ component: EmptyPage,
+ rightButtonTitle: 'Undo',
+ onRightButtonPress: () => this.props.navigator.replace(prevRoute),
+ passProps: {
+ text: 'The component is replaced, but there is currently no ' +
+ 'way to change the right button or title of the current route',
+ }
+ });
+ });
+ };
+
+ _renderReplacePrevious = () => {
+ if (!this.props.depth || this.props.depth < 2) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace previous', () => {
+ this.props.navigator.replacePrevious({
+ title: 'Replaced',
+ component: EmptyPage,
+ passProps: {
+ text: 'This is a replaced "previous" page',
+ },
+ wrapperStyle: styles.customWrapperStyle,
+ });
+ });
+ };
+
+ _renderReplacePreviousAndPop = () => {
+ if (!this.props.depth || this.props.depth < 2) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace previous and pop', () => {
+ this.props.navigator.replacePreviousAndPop({
+ title: 'Replaced and Popped',
+ component: EmptyPage,
+ passProps: {
+ text: 'This is a replaced "previous" page',
+ },
+ wrapperStyle: styles.customWrapperStyle,
+ });
+ });
+ };
+
+ _renderRow = (title: string, onPress: Function) => {
+ return (
+
+
+
+
+ {title}
+
+
+
+
+
+ );
+ };
+}
+
+class NavigatorIOSExample extends React.Component {
+ static title = '';
+ static description = 'iOS navigation capabilities';
+ static external = true;
+
+ render() {
+ const {onExampleExit} = this.props;
+ return (
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ customWrapperStyle: {
+ backgroundColor: '#bbdddd',
+ },
+ emptyPage: {
+ flex: 1,
+ paddingTop: 64,
+ },
+ emptyPageText: {
+ margin: 10,
+ },
+ list: {
+ backgroundColor: '#eeeeee',
+ marginTop: 10,
+ },
+ group: {
+ backgroundColor: 'white',
+ },
+ groupSpace: {
+ height: 15,
+ },
+ line: {
+ backgroundColor: '#bbbbbb',
+ height: StyleSheet.hairlineWidth,
+ },
+ row: {
+ backgroundColor: 'white',
+ justifyContent: 'center',
+ paddingHorizontal: 15,
+ paddingVertical: 15,
+ },
+ separator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: '#bbbbbb',
+ marginLeft: 15,
+ },
+ rowNote: {
+ fontSize: 17,
+ },
+ rowText: {
+ fontSize: 17,
+ fontWeight: '500',
+ },
+});
+
+module.exports = NavigatorIOSExample;
+```
diff --git a/docs/docs/0.41/navigators.md b/docs/docs/0.41/navigators.md
new file mode 100644
index 0000000..eb389f8
--- /dev/null
+++ b/docs/docs/0.41/navigators.md
@@ -0,0 +1,167 @@
+---
+id: navigators
+title: Using Navigators
+layout: docs
+category: The Basics
+permalink: docs/using-navigators.html
+next: more-resources
+---
+
+Mobile apps rarely consist of just one screen. As soon as you add a second screen to your app, you will have to take into consideration how the user will navigate from one screen to the other.
+
+You can use navigators to transition between multiple screens. These transitions can be typical side-to-side animations down a master/detail stack, or vertical modal popups.
+
+## Navigator
+
+React Native has several built-in navigation components, but for your first app you will probably want to use `Navigator`. It provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize.
+
+
+
+### Working with Scenes
+
+At this point you should feel comfortable rendering all sorts of components in your app, be it a simple `View` with `Text` inside, or a `ScrollView` with a list of `Image`s. Together, these components make up a scene (another word for screen) in your app.
+
+A scene is nothing other than a React component that is typically rendered full screen. This is in contrast to a `Text`, an `Image`, or even a custom `SpinningBeachball` component that is meant to be rendered as part of a screen. You may have already used one without realizing it - the ["HelloWorldApp"](docs/tutorial.html), the ["FlexDirectionBasics"](docs/flexbox.html), and the ["ListViewBasics"](docs/using-a-listview.html) components covered earlier in the tutorial are all examples of scenes.
+
+For simplicity's sake, let's define a simple scene that displays a bit of text. We will come back to this scene later as we add navigation to our app. Create a new file called "MyScene.js" with the following contents:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+export default class MyScene extends Component {
+ getDefaultProps() {
+ return {
+ title: 'MyScene'
+ };
+ }
+
+ render() {
+ return (
+
+ Hi! My name is {this.props.title}.
+
+ )
+ }
+}
+```
+
+Notice the `export default` in front of the component declaration. This will _export_ the component, and in turn allow other components to _import_ it later on, like so:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+import MyScene from './MyScene';
+
+class YoDawgApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp);
+```
+
+We now have a simple app that renders your scene and nothing else. In this case, `MyScene` is a simple example of a [reusable React component](https://facebook.github.io/react/docs/reusable-components.html).
+
+### Using Navigator
+
+Enough about scenes, let's start navigating. We will start by rendering a `Navigator`, and then let the `Navigator` render the scene for you by passing in your own render function to its `renderScene` prop.
+
+```javascript
+render() {
+ return (
+ {
+
+ }}
+ />
+ );
+}
+```
+
+Something you will encounter a lot when dealing with navigation is the concept of routes. A route is an object that contains information about a scene. It is used to provide all the context that the navigator's `renderScene` function needs to render a scene. It can have any number of keys to help distinguish your scene, and I happened to pick a single `title` key for the above example.
+
+#### Pushing scenes onto the stack
+
+In order to transition to a new scene, you will need to learn about `push` and `pop`. These two methods are provided by the `navigator` object that is passed to your `renderScene` function above. They can be used, as you may have realized, to push and pop routes into your navigation stack.
+
+```javascript
+navigator.push({
+ title: 'Next Scene',
+ index: 1,
+});
+
+navigator.pop();
+```
+
+A more complete example that demonstrates the pushing and popping of routes could therefore look something like this:
+
+```javascript
+import React, { Component, PropTypes } from 'react';
+import { Navigator, Text, TouchableHighlight, View } from 'react-native';
+
+export default class SimpleNavigationApp extends Component {
+ render() {
+ return (
+
+ {
+ const nextIndex = route.index + 1;
+ navigator.push({
+ title: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+
+ // Function to call to go back to the previous scene
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+ )
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ onForward: PropTypes.func.isRequired,
+ onBack: PropTypes.func.isRequired,
+ }
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ Tap me to go back
+
+
+ )
+ }
+}
+```
+
+In this example, the `MyScene` component is passed the title of the current route via the `title` prop. It displays two tappable components that call the `onForward` and `onBack` functions passed through its props, which in turn will call `navigator.push()` and `navigator.pop()` as needed.
+
+Check out the [Navigator API reference](docs/navigator.html) for more `Navigator` code samples, or read through the [Navigation guide](docs/navigation.html) for other examples of what you can do with navigators.
+
+## High Five!
+
+If you've gotten here by reading linearly through the tutorial, then you are a pretty impressive human being. Congratulations. Next, you might want to check out [all the cool stuff the community does with React Native](/react-native/docs/more-resources.html).
diff --git a/docs/docs/0.41/netinfo.md b/docs/docs/0.41/netinfo.md
new file mode 100644
index 0000000..e286111
--- /dev/null
+++ b/docs/docs/0.41/netinfo.md
@@ -0,0 +1,286 @@
+NetInfo模块可以获知设备联网或离线的状态信息。
+
+```javascript
+NetInfo.fetch().done((reach) => {
+ console.log('Initial: ' + reach);
+});
+function handleFirstConnectivityChange(reach) {
+ console.log('First change: ' + reach);
+ NetInfo.removeEventListener(
+ 'change',
+ handleFirstConnectivityChange
+ );
+}
+NetInfo.addEventListener(
+ 'change',
+ handleFirstConnectivityChange
+);
+```
+
+### IOS
+以异步的方式判断设备是否联网,以及是否使用了移动数据网络。
+
+- `none` - 设备处于离线状态。
+- `wifi` - 设备处于联网状态且通过wifi链接,或者是一个iOS的模拟器。
+- `cell` - 设备是通过Edge、3G、WiMax或是LTE网络联网的。
+- `unknown` - 发生错误,网络状况不可知
+
+### Android
+请求网络信息需要先在应用的`AndroidManifest.xml`文件中添加如下权限字段:
+```
+
+```
+Android的联网类型:
+- `NONE` - 设备处于离线状态
+- `BLUETOOTH` - 蓝牙数据连接
+- `DUMMY` - 模拟数据连接
+- `ETHERNET` - 以太网数据连接
+- `MOBILE` - 移动网络数据连接
+- `MOBILE_DUN` - 拨号移动网络数据连接
+- `MOBILE_HIPRI` - 高优先级移动网络数据连接
+- `MOBILE_MMS` - 彩信移动网络数据连接
+- `MOBILE_SUPL` - 安全用户面定位(SUPL)数据连接
+- `VPN` - 虚拟网络连接。需要Android5.0以上
+- `WIFI` - WIFI数据连接
+- `WIMAX` - WiMAX数据连接
+- `UNKNOWN` - 未知数据连接
+
+其他的连接状态已被Android API隐藏,但可以在需要时使用。
+
+### isConnectionExpensive
+此方法仅Android可用。用于判断当前活动的连接是否计费。如果当前连接是通过移动数据网络,或者通过基于移动数据网络所创建的wifi热点,都有可能被判定为计费的数据连接。
+
+```javascript
+NetInfo.isConnectionExpensive((isConnectionExpensive) => {
+ console.log('Connection is ' + (isConnectionExpensive ? 'Expensive' : 'Not Expensive'));
+});
+```
+
+### isConnected
+此方法所有平台皆可使用。以异步方式获取一个布尔值,用于判断当前设备是否联网。
+
+```javascript
+NetInfo.isConnected.fetch().done((isConnected) => {
+ console.log('First, is ' + (isConnected ? 'online' : 'offline'));
+});
+function handleFirstConnectivityChange(isConnected) {
+ console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
+ NetInfo.isConnected.removeEventListener(
+ 'change',
+ handleFirstConnectivityChange
+ );
+}
+NetInfo.isConnected.addEventListener(
+ 'change',
+ handleFirstConnectivityChange
+);
+```
+
+
+### 方法
+
+
+
+
static addEventListener(eventName, handler) #
+
在网络状况/类型发生变化时调用此监听函数。回调的参数为上面列出的网络状况/类型。
+
+
+
+
static removeEventListener(eventName, handler) #
+
+
+
static fetch() #
+
返回一个promise,用于获取当前的网络状况/类型。
+
+
+
static isConnectionExpensive() #
+
+
+
+### 属性
+
+
+
isConnected: ObjectExpression
+ #
+
此属性为一个对象,也可调用上面列出的方法。但其监听函数接受的参数为一个布尔值,仅仅能表明当前网络是否联通。如果你只关心设备是否连上网了(不关心网络类型),那么使用此属性即可。
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ NetInfo,
+ Text,
+ View,
+ TouchableWithoutFeedback,
+} = ReactNative;
+
+const ConnectionInfoSubscription = React.createClass({
+ getInitialState() {
+ return {
+ connectionInfoHistory: [],
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.addEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.removeEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ _handleConnectionInfoChange: function(connectionInfo) {
+ const connectionInfoHistory = this.state.connectionInfoHistory.slice();
+ connectionInfoHistory.push(connectionInfo);
+ this.setState({
+ connectionInfoHistory,
+ });
+ },
+ render() {
+ return (
+
+ {JSON.stringify(this.state.connectionInfoHistory)}
+
+ );
+ }
+});
+
+const ConnectionInfoCurrent = React.createClass({
+ getInitialState() {
+ return {
+ connectionInfo: null,
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.addEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ NetInfo.fetch().done(
+ (connectionInfo) => { this.setState({connectionInfo}); }
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.removeEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ _handleConnectionInfoChange: function(connectionInfo) {
+ this.setState({
+ connectionInfo,
+ });
+ },
+ render() {
+ return (
+
+ {this.state.connectionInfo}
+
+ );
+ }
+});
+
+const IsConnected = React.createClass({
+ getInitialState() {
+ return {
+ isConnected: null,
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.isConnected.addEventListener(
+ 'change',
+ this._handleConnectivityChange
+ );
+ NetInfo.isConnected.fetch().done(
+ (isConnected) => { this.setState({isConnected}); }
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.isConnected.removeEventListener(
+ 'change',
+ this._handleConnectivityChange
+ );
+ },
+ _handleConnectivityChange: function(isConnected) {
+ this.setState({
+ isConnected,
+ });
+ },
+ render() {
+ return (
+
+ {this.state.isConnected ? 'Online' : 'Offline'}
+
+ );
+ }
+});
+
+const IsConnectionExpensive = React.createClass({
+ getInitialState() {
+ return {
+ isConnectionExpensive: (null : ?boolean),
+ };
+ },
+ _checkIfExpensive() {
+ NetInfo.isConnectionExpensive().then(
+ isConnectionExpensive => { this.setState({isConnectionExpensive}); }
+ );
+ },
+ render() {
+ return (
+
+
+
+ Click to see if connection is expensive:
+ {this.state.isConnectionExpensive === true ? 'Expensive' :
+ this.state.isConnectionExpensive === false ? 'Not expensive'
+ : 'Unknown'}
+
+
+
+
+ );
+ }
+});
+
+exports.title = 'NetInfo';
+exports.description = 'Monitor network status';
+exports.examples = [
+ {
+ title: 'NetInfo.isConnected',
+ description: 'Asynchronously load and observe connectivity',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'NetInfo.update',
+ description: 'Asynchronously load and observe connectionInfo',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'NetInfo.updateHistory',
+ description: 'Observed updates to connectionInfo',
+ render(): ReactElement { return ; }
+ },
+ {
+ platform: 'android',
+ title: 'NetInfo.isConnectionExpensive (Android)',
+ description: 'Asynchronously check isConnectionExpensive',
+ render(): ReactElement { return ; }
+ },
+];
+```
diff --git a/docs/docs/0.41/network.md b/docs/docs/0.41/network.md
new file mode 100644
index 0000000..5b7e159
--- /dev/null
+++ b/docs/docs/0.41/network.md
@@ -0,0 +1,138 @@
+很多移动应用都需要从远程地址中获取数据或资源。你可能需要给某个REST API发起POST请求以提交用户数据,又或者可能仅仅需要从某个服务器上获取一些静态内容——以下就是你会用到的东西。新手可以对照这个[简短的视频教程](http://v.youku.com/v_show/id_XMTUyNTEwMTA5Ng==.html)加深理解。
+
+## 使用Fetch
+
+React Native提供了和web标准一致的[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API),用于满足开发者访问网络的需求。如果你之前使用过`XMLHttpRequest`(即俗称的ajax)或是其他的网络API,那么Fetch用起来将会相当容易上手。这篇文档只会列出Fetch的基本用法,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索`fetch api`关键字以了解更多信息。
+
+#### 发起网络请求
+
+要从任意地址获取内容的话,只需简单地将网址作为参数传递给fetch方法即可(fetch这个词本身也就是`获取`的意思):
+
+```js
+fetch('https://mywebsite.com/mydata.json')
+```
+
+Fetch还有可选的第二个参数,可以用来定制HTTP请求一些参数。你可以指定header参数,或是指定使用POST方法,又或是提交数据等等:
+
+```js
+fetch('https://mywebsite.com/endpoint/', {
+ method: 'POST',
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ firstParam: 'yourValue',
+ secondParam: 'yourOtherValue',
+ })
+})
+```
+
+译注:如果你的服务器无法识别上面POST的数据格式,那么可以尝试传统的form格式,示例如下:
+
+```js
+fetch('https://mywebsite.com/endpoint/', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: 'key1=value1&key2=value2'
+})
+```
+
+可以参考[Fetch请求文档](https://developer.mozilla.org/en-US/docs/Web/API/Request)来查看所有可用的参数。
+
+#### 处理服务器的响应数据
+
+上面的例子演示了如何发起请求。很多情况下,你还需要处理服务器回复的数据。
+
+网络请求天然是一种异步操作(译注:同样的还有[asyncstorage](asyncstorage.html),请不要再问怎样把异步变成同步!无论在语法层面怎么折腾,它们的异步本质是无法变更的。异步的意思是你应该趁这个时间去做点别的事情,比如显示loading,而不是让界面卡住傻等)。Fetch 方法会返回一个[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise),这种模式可以简化异步风格的代码(译注:同样的,如果你不了解promise,建议使用搜索引擎补课):
+
+ ```js
+ getMoviesFromApiAsync() {
+ return fetch('http://facebook.github.io/react-native/movies.json')
+ .then((response) => response.json())
+ .then((responseJson) => {
+ return responseJson.movies;
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+ }
+ ```
+
+你也可以在React Native应用中使用ES7标准中的`async`/`await` 语法:
+
+ ```js
+ // 注意这个方法前面有async关键字
+ async getMoviesFromApi() {
+ try {
+ // 注意这里的await语句,其所在的函数必须有async关键字声明
+ let response = await fetch('http://facebook.github.io/react-native/movies.json');
+ let responseJson = await response.json();
+ return responseJson.movies;
+ } catch(error) {
+ console.error(error);
+ }
+ }
+ ```
+
+别忘了catch住`fetch`可能抛出的异常,否则出错时你可能看不到任何提示。
+
+> 默认情况下,iOS会阻止所有非HTTPS的请求。如果你请求的接口是http协议,那么首先需要添加一个App Transport Securty的例外,详细可参考[这篇帖子](https://segmentfault.com/a/1190000002933776)。
+
+
+### 使用其他的网络库
+
+React Native中已经内置了[XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)(也就是俗称的ajax)。一些基于XMLHttpRequest封装的第三方库也可以使用,例如[frisbee](https://github.com/niftylettuce/frisbee)或是[axios](https://github.com/mzabriskie/axios)等。但注意不能使用jQuery,因为jQuery中还使用了很多浏览器中才有而RN中没有的东西(所以也不是所有web中的ajax库都可以直接使用)。
+
+```js
+var request = new XMLHttpRequest();
+request.onreadystatechange = (e) => {
+ if (request.readyState !== 4) {
+ return;
+ }
+
+ if (request.status === 200) {
+ console.log('success', request.responseText);
+ } else {
+ console.warn('error');
+ }
+};
+
+request.open('GET', 'https://mywebsite.com/endpoint/');
+request.send();
+```
+
+> 需要注意的是,安全机制与网页环境有所不同:在应用中你可以访问任何网站,没有[跨域](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)的限制。
+
+## WebSocket支持
+
+React Native还支持[WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket),这种协议可以在单个TCP连接上提供全双工的通信信道。
+
+```js
+var ws = new WebSocket('ws://host.com/path');
+
+ws.onopen = () => {
+ // 打开一个连接
+
+ ws.send('something'); // 发送一个消息
+};
+
+ws.onmessage = (e) => {
+ // 接收到了一个消息
+ console.log(e.data);
+};
+
+ws.onerror = (e) => {
+ // 发生了一个错误
+ console.log(e.message);
+};
+
+ws.onclose = (e) => {
+ // 连接被关闭了
+ console.log(e.code, e.reason);
+};
+```
+
+现在你的应用已经可以从各种渠道获取数据了,那么接下来面临的问题多半就是如何在不同的页面间组织和串联内容了。要管理页面的跳转,你需要学习使用[导航器](using-navigators.html)。
diff --git a/docs/docs/0.41/panresponder.md b/docs/docs/0.41/panresponder.md
new file mode 100644
index 0000000..f4afb4d
--- /dev/null
+++ b/docs/docs/0.41/panresponder.md
@@ -0,0 +1,236 @@
+`PanResponder`类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
+
+它提供了一个对[触摸响应系统](gesture-responder-system.html)响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的`gestureState`对象。
+
+```javascript
+onPanResponderMove: (event, gestureState) => {}
+```
+
+原生事件是指由以下字段组成的合成触摸事件:
+
+- `nativeEvent`
+ + `changedTouches` - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
+ + `identifier` - 触摸点的ID
+ + `locationX` - 触摸点相对于父元素的横坐标
+ + `locationY` - 触摸点相对于父元素的纵坐标
+ + `pageX` - 触摸点相对于根元素的横坐标
+ + `pageY` - 触摸点相对于根元素的纵坐标
+ + `target` - 触摸点所在的元素ID
+ + `timestamp` - 触摸事件的时间戳,可用于移动速度的计算
+ + `touches` - 当前屏幕上的所有触摸点的集合
+
+一个`gestureState`对象有如下的字段:
+
+* `stateID` - 触摸状态的ID。在屏幕上有至少一个触摸点的情况下,这个ID会一直有效。
+* `moveX` - 最近一次移动时的屏幕横坐标
+* `moveY` - 最近一次移动时的屏幕纵坐标
+* `x0` - 当响应器产生时的屏幕坐标
+* `y0` - 当响应器产生时的屏幕坐标
+* `dx` - 从触摸操作开始时的累计横向路程
+* `dy` - 从触摸操作开始时的累计纵向路程
+* `vx` - 当前的横向移动速度
+* `vy` - 当前的纵向移动速度
+* `numberActiveTouches` - 当前在屏幕上的有效触摸点的数量
+
+### 基本用法
+
+```javascript
+ componentWillMount: function() {
+ this._panResponder = PanResponder.create({
+ // 要求成为响应者:
+ onStartShouldSetPanResponder: (evt, gestureState) => true,
+ onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
+ onMoveShouldSetPanResponder: (evt, gestureState) => true,
+ onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
+
+ onPanResponderGrant: (evt, gestureState) => {
+ // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
+
+ // gestureState.{x,y}0 现在会被设置为0
+ },
+ onPanResponderMove: (evt, gestureState) => {
+ // 最近一次的移动距离为gestureState.move{X,Y}
+
+ // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
+ },
+ onPanResponderTerminationRequest: (evt, gestureState) => true,
+ onPanResponderRelease: (evt, gestureState) => {
+ // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
+ // 一般来说这意味着一个手势操作已经成功完成。
+ },
+ onPanResponderTerminate: (evt, gestureState) => {
+ // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
+ },
+ onShouldBlockNativeResponder: (evt, gestureState) => {
+ // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
+ // 默认返回true。目前暂时只支持android。
+ return true;
+ },
+ });
+ },
+
+ render: function() {
+ return (
+
+ );
+ },
+```
+
+### 可运行的例子
+
+要想看看可以直接使用的例子,请参阅[UIExplorer中的PanResponder](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/PanResponderExample.js)
+
+### 方法
+
+
+
+
static create(config: object) #
+
+
@param {object} 配置所有响应器回调的加强版本,不仅仅包括原本的ResponderSyntheticEvent,还包括PanResponder手势状态的回调。你只要简单的把onResponder*回调中的Responder替换为PanResponder。举例来说,这个config对象可能看起来像这样:
+
+ onMoveShouldSetPanResponder: (e, gestureState) => {...}
+ onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
+ onStartShouldSetPanResponder: (e, gestureState) => {...}
+ onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
+ onPanResponderReject: (e, gestureState) => {...}
+ onPanResponderGrant: (e, gestureState) => {...}
+ onPanResponderStart: (e, gestureState) => {...}
+ onPanResponderEnd: (e, gestureState) => {...}
+ onPanResponderRelease: (e, gestureState) => {...}
+ onPanResponderMove: (e, gestureState) => {...}
+ onPanResponderTerminate: (e, gestureState) => {...}
+ onPanResponderTerminationRequest: (e, gestureState) => {...}
+
+ onShouldBlockNativeResponder: (e, gestureState) => {...}
+ 通常来说,对那些有对应捕获事件的事件来说,我们在捕获阶段更新gestureState一次,然后在冒泡阶段直接使用即可。
+ 注意onStartShould* 回调。他们只会在此节点冒泡/捕获的开始/结束事件中提供已经更新过的gestureState。一旦这个节点成为了事件的响应者,则所有的开始/结束事件都会被手势正确处理,并且gestureState也会被正确更新。(numberActiveTouches)有可能没有包含所有的触摸点,除非你就是触摸事件的响应者。
+
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ PanResponder,
+ StyleSheet,
+ View,
+ processColor,
+} = ReactNative;
+
+var CIRCLE_SIZE = 80;
+
+var PanResponderExample = React.createClass({
+
+ statics: {
+ title: 'PanResponder Sample',
+ description: 'Shows the use of PanResponder to provide basic gesture handling.',
+ },
+
+ _panResponder: {},
+ _previousLeft: 0,
+ _previousTop: 0,
+ _circleStyles: {},
+ circle: (null : ?{ setNativeProps(props: Object): void }),
+
+ componentWillMount: function() {
+ this._panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
+ onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
+ onPanResponderGrant: this._handlePanResponderGrant,
+ onPanResponderMove: this._handlePanResponderMove,
+ onPanResponderRelease: this._handlePanResponderEnd,
+ onPanResponderTerminate: this._handlePanResponderEnd,
+ });
+ this._previousLeft = 20;
+ this._previousTop = 84;
+ this._circleStyles = {
+ style: {
+ left: this._previousLeft,
+ top: this._previousTop,
+ backgroundColor: 'green',
+ }
+ };
+ },
+
+ componentDidMount: function() {
+ this._updateNativeStyles();
+ },
+
+ render: function() {
+ return (
+
+ {
+ this.circle = circle;
+ }}
+ style={styles.circle}
+ {...this._panResponder.panHandlers}
+ />
+
+ );
+ },
+
+ _highlight: function() {
+ this._circleStyles.style.backgroundColor = 'blue';
+ this._updateNativeStyles();
+ },
+
+ _unHighlight: function() {
+ this._circleStyles.style.backgroundColor = 'green';
+ this._updateNativeStyles();
+ },
+
+ _updateNativeStyles: function() {
+ this.circle && this.circle.setNativeProps(this._circleStyles);
+ },
+
+ _handleStartShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
+ // Should we become active when the user presses down on the circle?
+ return true;
+ },
+
+ _handleMoveShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
+ // Should we become active when the user moves a touch over the circle?
+ return true;
+ },
+
+ _handlePanResponderGrant: function(e: Object, gestureState: Object) {
+ this._highlight();
+ },
+ _handlePanResponderMove: function(e: Object, gestureState: Object) {
+ this._circleStyles.style.left = this._previousLeft + gestureState.dx;
+ this._circleStyles.style.top = this._previousTop + gestureState.dy;
+ this._updateNativeStyles();
+ },
+ _handlePanResponderEnd: function(e: Object, gestureState: Object) {
+ this._unHighlight();
+ this._previousLeft += gestureState.dx;
+ this._previousTop += gestureState.dy;
+ },
+});
+
+var styles = StyleSheet.create({
+ circle: {
+ width: CIRCLE_SIZE,
+ height: CIRCLE_SIZE,
+ borderRadius: CIRCLE_SIZE / 2,
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ },
+ container: {
+ flex: 1,
+ paddingTop: 64,
+ },
+});
+
+module.exports = PanResponderExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/performance.md b/docs/docs/0.41/performance.md
new file mode 100644
index 0000000..cdb88cc
--- /dev/null
+++ b/docs/docs/0.41/performance.md
@@ -0,0 +1,173 @@
+使用React Native替代基于WebView的框架来开发App的一个强有力的理由,就是为了使App可以达到每秒60帧(足够流畅),并且能有类似原生App的外观和手感。因此我们也尽可能地优化React Native去实现这一目标,使开发者能集中精力处理App的业务逻辑,而不用费心考虑性能。但是,总还是有一些地方有所欠缺,以及在某些场合React Native还不能够替你决定如何进行优化(用原生代码写也无法避免),因此人工的干预依然是必要的。
+本文的目的是教给你一些基本的知识,来帮你排查性能方面的问题,以及探讨这些问题产生的原因和推荐的解决方法。
+
+## 关于“帧”你所需要知道的
+
+老一辈人常常把电影称为“移动的画”,是因为视频中逼真的动态效果其实是一种幻觉,这种幻觉是由一组静态的图片以一个稳定的速度快速变化所产生的。我们把这组图片中的每一张图片叫做一帧,而每秒钟显示的帧数直接的影响了视频(或者说用户界面)的流畅度和真实感。iOS设备提供了每秒60的帧率,这就留给了开发者和UI系统大约16.67ms来完成生成一张静态图片(帧)所需要的所有工作。如果在这分派的16.67ms之内没有能够完成这些工作,就会引发‘丢帧’的后果,使界面表现的不够流畅。
+
+下面要讲的事情可能更为复杂:请先调出你应用的开发菜单,打开`Show FPS Monitor`. 你会注意到有两个不同的帧率.
+
+### JavaScript 帧率
+
+对大多数React Native应用来说,业务逻辑是运行在JavaScript线程上的。这是React应用所在的线程,也是发生API调用,以及处理触摸事件等操作的线程。更新数据到原生支持的视图是批量进行的,并且在事件循环每进行一次的时候被发送到原生端,这一步通常会在一帧时间结束之前处理完(如果一切顺利的话)。如果JavaScript线程有一帧没有及时响应,就被认为发生了一次丢帧。 例如,你在一个复杂应用的根组件上调用了`this.setState`,从而导致一次开销很大的子组件树的重绘,可想而知,这可能会花费200ms也就是整整12帧的丢失。此时,任何由JavaScript控制的动画都会卡住。只要卡顿超过100ms,用户就会明显的感觉到。
+
+这种情况经常发生在Navigator的切换过程中:当你push一个新的路由时,JavaScript需要绘制新场景所需的所有组件,以发送正确的命令给原生端去创建视图。由于切换是由JavaScript线程所控制,因此经常会占用若干帧的时间,引起一些卡顿。有的时候,组件会在`componentDidMount`函数中做一些额外的事情,这甚至可能会导致页面切换过程中多达一秒的卡顿。
+
+另一个例子是触摸事件的响应:如果你正在JavaScript线程处理一个跨越多个帧的工作,你可能会注意到TouchableOpacity的响应被延迟了。这是因为JavaScript线程太忙了,不能够处理主线程发送过来的原始触摸事件。结果TouchableOpacity就不能及时响应这些事件并命令主线程的页面去调整透明度了。
+
+### 主线程 (也即UI线程) 帧率
+
+很多人会注意到,`NavigatorIOS`的性能要比Navigator好的多。原因就是它的切换动画是完全在主线程上执行的,因此不会被JavaScript线程上的掉帧所影响。([阅读关于为何你仍然需要使用Navigator](using-navigators.html))
+
+同样,当JavaScript线程卡住的时候,你仍然可以欢快的上下滚动ScrollView,因为ScrollView运行在主线程之上(尽管滚动事件会被分发到JS线程,但是接收这些事件对于滚动这个动作来说并不必要)。
+
+## 性能问题的常见原因
+
+### console.log语句
+
+在运行打好了离线包的应用时,控制台打印语句可能会极大地拖累JavaScript线程。注意有些第三方调试库也可能包含控制台打印语句,比如[redux-logger](https://github.com/evgenyrodionov/redux-logger),所以在发布应用前请务必仔细检查,确保全部移除。
+
+
+> 这里有个小技巧可以在发布时屏蔽掉所有的`console.*`调用。React Native中有一个全局变量`__DEV__`用于指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的console实现。
+
+```js
+if (!__DEV__) {
+ global.console = {
+ info: () => {},
+ log: () => {},
+ warn: () => {},
+ error: () => {},
+ };
+}
+```
+
+这样在打包发布时,所有的控制台语句就会被自动替换为空函数,而在调试时它们仍然会被正常调用。
+
+### 开发模式 (dev=true)
+
+JavaScript线程的性能在开发模式下是很糟糕的。这是不可避免的,因为有许多工作需要在运行的时候去做,譬如使你获得良好的警告和错误信息,又比如验证属性类型(propTypes)以及产生各种其他的警告。
+
+### 缓慢的导航器(Navigator)切换
+
+如之前说,`Navigator`的动画是由JavaScript线程所控制的。想象一下“从右边推入”这个场景的切换:每一帧中,新的场景从右向左移动,从屏幕右边缘开始(不妨认为是320单位宽的的x轴偏移),最终移动到x轴偏移为0的屏幕位置。切换过程中的每一帧,JavaScript线程都需要发送一个新的x轴偏移量给主线程。如果JavaScript线程卡住了,它就无法处理这项事情,因而这一帧就无法更新,动画就被卡住了。
+
+长远的解决方法,其中一部分是要允许基于JavaScript的动画从主线程分离。同样是上面的例子,我们可以在切换动画开始的时候计算出一个列表,其中包含所有的新的场景需要的x轴偏移量,然后一次发送到主线程以某种优化的方式执行。由于JavaScript线程已经从更新x轴偏移量给主线程这个职责中解脱了出来,因此JavaScript线程中的掉帧就不是什么大问题了 —— 用户将基本上不会意识到这个问题,因为用户的注意力会被流畅的切换动作所吸引。
+
+不幸的是,这个方案还没有被实现。所以当前的解决方案是,在动画的进行过程中,利用InteractionManager来选择性的渲染新场景所需的最小限度的内容。
+
+`InteractionManager.runAfterInteractions`的参数中包含一个回调,这个回调会在navigator切换动画结束的时候被触发(每个来自于`Animated`接口的动画都会通知InteractionManager,不过这个就超出了本文的讨论)。
+
+你的场景组件看上去应该是这样的:
+
+```javascript
+class ExpensiveScene extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {renderPlaceholderOnly: true};
+ }
+
+ componentDidMount() {
+ InteractionManager.runAfterInteractions(() => {
+ this.setState({renderPlaceholderOnly: false});
+ });
+ }
+
+ render() {
+ if (this.state.renderPlaceholderOnly) {
+ return this._renderPlaceholderView();
+ }
+
+ return (
+
+ Your full view goes here
+
+ );
+ }
+
+
+ _renderPlaceholderView() {
+ return (
+
+ Loading...
+
+ );
+ }
+};
+```
+
+你不必被限制在仅仅是做一些loading指示的渲染,你也可以绘制部分的页面内容 —— 例如,当你加载Facebook应用的时候,你会看见一个灰色方形的消息流的占位符,是将来用来显示文字的地方。如果你正在场景中绘制地图,那么最好在场景切换完成之前,显示一个灰色的占位页面或者是一个转动的动画,因为切换过程的确会导致主线程的掉帧。
+
+### ListView初始化渲染太慢以及列表过长时滚动性能太差
+这是一个频繁出现的问题。因为iOS配备了UITableView,通过重用底层的UIViews实现了非常高性能的体验(相比之下ListView的性能没有那么好)。用React Native实现相同效果的工作仍正在进行中,但是在此之前,我们有一些可用的方法来稍加改进性能以满足我们的需求。
+
+#### initialListSize
+
+这个属性定义了在首次渲染中绘制的行数。如果我们关注于快速的显示出页面,可以设置`initialListSize`为1,然后我们会发现其他行在接下来的帧中被快速绘制到屏幕上。而每帧所显示的行数由`pageSize`所决定。
+
+#### pageSize
+
+在初始渲染也就是`initialListSize`被使用之后,ListView将利用`pageSize`来决定每一帧所渲染的行数。默认值为1 —— 但是如果你的页面很小,而且渲染的开销不大的话,你会希望这个值更大一些。稍加调整,你会发现它所起到的作用。
+
+#### scrollRenderAheadDistance
+
+“在将要进入屏幕区域之前的某个位置,开始绘制一行,距离按像素计算。”
+
+如果我们有一个2000个元素的列表,并且立刻全部渲染出来的话,无论是内存还是计算资源都会显得很匮乏。还很可能导致非常可怕的阻塞。因此`scrollRenderAheadDistance`允许我们来指定一个超过视野范围之外所需要渲染的行数。
+
+#### removeClippedSubviews
+
+“当这一选项设置为true的时候,超出屏幕的子视图(同时`overflow`值为`hidden`)会从它们原生的父视图中移除。这个属性可以在列表很长的时候提高滚动的性能。默认为false。(0.14版本后默认为true)”
+
+这是一个应用在长列表上极其重要的优化。Android上,`overflow`值总是`hidden`的,所以你不必担心没有设置它。而在iOS上,你需要确保在行容器上设置了`overflow: hidden`。
+
+### 我的组件渲染太慢,我不需要立即显示全部
+
+这在初次浏览ListView时很常见,适当的使用它是获得稳定性能的关键。就像之前所提到的,它可以提供一些手段在不同帧中来分开渲染页面,稍加改进就可以满足你的需求。此外要记住的是,ListView也可以横向滚动。
+
+### 在重绘一个几乎没有什么变化的页面时,JS帧率严重降低
+
+如果你正在使用一个ListView,你必须提供一个`rowHasChanged`函数,它通过快速的算出某一行是否需要重绘,来减少很多不必要的工作。如果你使用了不可变的数据结构,这项工作就只需检查其引用是否相等。
+
+同样的,你可以实现`shouldComponentUpdate`函数来指明在什么样的确切条件下,你希望这个组件得到重绘。如果你编写的是纯粹的组件(返回值完全由props和state所决定),你可以利用`PureRenderMixin`来为你做这个工作。再强调一次,不可变的数据结构在提速方面非常有用 —— 当你不得不对一个长列表对象做一个深度的比较,它会使重绘你的整个组件更加快速,而且代码量更少。
+
+### 由于在JavaScript线程中同时做很多事情,导致JS线程掉帧
+
+“导航切换极慢”是该问题的常见表现。在其他情形下,这种问题也可能会出现。使用`InteractionManager`是一个好的方法,但是如果在动画中,为了用户体验的开销而延迟其他工作并不太能接受,那么你可以考虑一下使用`LayoutAnimation`。
+
+`Animated`的接口一般会在JavaScript线程中计算出所需要的每一个关键帧,而`LayoutAnimation`则利用了`Core Animation`,使动画不会被JS线程和主线程的掉帧所影响。
+
+举一个需要使用这项功能的例子:比如需要给一个模态框做动画(从下往上划动,并在半透明遮罩中淡入),而这个模态框正在初始化,并且可能响应着几个网络请求,渲染着页面的内容,并且还在更新着打开这个模态框的父页面。了解更多有关如何使用LayoutAnimation的信息,请查看[动画指南](/docs/animations.html)。
+
+注意:
+
+ - `LayoutAnimation`只工作在“一次性”的动画上("静态"动画) -- 如果动画可能会被中途取消,你还是需要使用`Animated`。
+
+### 在屏幕上移动视图(滚动,切换,旋转)时,UI线程掉帧
+
+当具有透明背景的文本位于一张图片上时,或者在每帧重绘视图时需要用到透明合成的任何其他情况下,这种现象尤为明显。设置`shouldRasterizeIOS`或者`renderToHardwareTextureAndroid`属性可以显著改善这一现象。
+注意不要过度使用该特性,否则你的内存使用量将会飞涨。在使用时,要评估你的性能和内存使用情况。如果你没有需要移动这个视图的需求,请关闭这一属性。
+
+### 使用动画改变图片的尺寸时,UI线程掉帧
+
+在iOS上,每次调整Image组件的宽度或者高度,都需要重新裁剪和缩放原始图片。这个操作开销会非常大,尤其是大的图片。比起直接修改尺寸,更好的方案是使用`transform: [{scale}]`的样式属性来改变尺寸。比如当你点击一个图片,要将它放大到全屏的时候,就可以使用这个属性。
+
+### Touchable系列组件不能很好的响应
+
+有些时候,如果我们有一项操作与点击事件所带来的透明度改变或者高亮效果发生在同一帧中,那么有可能在`onPress`函数结束之前我们都看不到这些效果。比如在`onPress`执行了一个`setState`的操作,这个操作需要大量计算工作并且导致了掉帧。对此的一个解决方案是将`onPress`处理函数中的操作封装到`requestAnimationFrame`中:
+
+
+```javascript
+handleOnPress() {
+ // 谨记在使用requestAnimationFrame、setTimeout以及setInterval时
+ // 要使用TimerMixin(其作用是在组件unmount时,清除所有定时器)
+ this.requestAnimationFrame(() => {
+ this.doExpensiveAction();
+ });
+}
+```
+
+## 分析
+
+你可以利用内置的分析器来同时获取JavaScript线程和主线程中代码执行情况的详细信息。
+
+对于iOS来说,Instruments是一个宝贵的工具库,Android的话,你可以使用systrace,参见[调试Android UI性能](/docs/android-ui-performance.html#content)。
diff --git a/docs/docs/0.41/permissionsandroid.md b/docs/docs/0.41/permissionsandroid.md
new file mode 100644
index 0000000..b002c58
--- /dev/null
+++ b/docs/docs/0.41/permissionsandroid.md
@@ -0,0 +1,61 @@
+`PermissionsAndroid`可以访问Android M(也就是6.0)开始提供的权限模型。有一些权限写在`AndroidManifest.xml`就可以在安装时自动获得。但有一些“危险”的权限则需要弹出提示框供用户选择。本API即用于后一种情形。
+
+在低于Android 6.0的设备上,权限只要写在`AndroidManifest.xml`里就会自动获得,此情形下`check`和`request` 方法将始终返回true。
+
+如果用户之前拒绝过你的某项权限请求,那么系统会建议你显示一个为什么需要这个权限的“详细解释”(rationale参数)。如果用户之前拒绝过,那么当你再次申请的时候,弹出的就可能不是原先的申请信息,而是`rationale`参数里提供的进一步解释。
+
+### 例子
+
+```js
+async function requestCameraPermission() {
+ try {
+ const granted = await AndroidPermissions.request(
+ AndroidPermissions.PERMISSIONS.CAMERA,
+ {
+ 'title': '申请摄像头权限',
+ 'message': '一个很牛逼的应用想借用你的摄像头,' +
+ '然后你就可以拍出酷炫的皂片啦。'
+ }
+ )
+ if (granted === PermissionsAndroid.RESULTS.GRANTED) {
+ console.log("现在你获得摄像头权限了")
+ } else {
+ console.log("用户并不屌你")
+ }
+ } catch (err) {
+ console.warn(err)
+ }
+}
+```
+### 方法
+
+
+
+
+ constructor
+ ()
+ #
+
+
+
+
check(permission)
+ #
+
+
返回一个promise,最终值为用户是否授权过的布尔值。
+
+
+
request(permission, rationale?)
+ #
+
+
+
+
+
requestMultiple(permissions)
+ #
+
在一个弹出框中向用户请求多个权限。返回值为一个object,key为各权限名称,对应值为用户授权与否。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/picker.md b/docs/docs/0.41/picker.md
new file mode 100644
index 0000000..d8d6f07
--- /dev/null
+++ b/docs/docs/0.41/picker.md
@@ -0,0 +1,56 @@
+本组件可以在iOS和Android上渲染原生的选择器(Picker)。用例:
+```js
+ this.setState({language: lang})}>
+
+
+
+```
+
+### 属性
+
+
+
+
onValueChange function #
+
某一项被选中时执行此回调。调用时带有如下参数:
+
+ itemValue: 被选中项的value属性
+ itemPosition: 被选中项在picker中的索引位置
+
+
+
+
+
style pickerStyleType
+ #
+
+
android enabled
+ bool #
+
+
+
android mode
+ enum('dialog', 'dropdown') #
+
在Android上,可以指定在用户点击选择器时,以怎样的形式呈现选项:
+
+ dialog(对话框形式): 显示一个模态对话框。默认选项。
+ dropdown(下拉框形式): 以选择器所在位置为锚点展开一个下拉框。
+
+
+
+
android prompt
+ string #
+
设置选择器的提示字符串。在Android的对话框模式中用作对话框的标题。
+
+
ios itemStyle
+ itemStylePropType #
+
+
+
diff --git a/docs/docs/0.41/pickerios.md b/docs/docs/0.41/pickerios.md
new file mode 100644
index 0000000..8af8904
--- /dev/null
+++ b/docs/docs/0.41/pickerios.md
@@ -0,0 +1,154 @@
+### 截图
+
+
+### 属性
+
+
+
itemStyle itemStylePropType #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ PickerIOS,
+ Text,
+ View,
+} = ReactNative;
+
+var PickerItemIOS = PickerIOS.Item;
+
+var CAR_MAKES_AND_MODELS = {
+ amc: {
+ name: 'AMC',
+ models: ['AMX', 'Concord', 'Eagle', 'Gremlin', 'Matador', 'Pacer'],
+ },
+ alfa: {
+ name: 'Alfa-Romeo',
+ models: ['159', '4C', 'Alfasud', 'Brera', 'GTV6', 'Giulia', 'MiTo', 'Spider'],
+ },
+ aston: {
+ name: 'Aston Martin',
+ models: ['DB5', 'DB9', 'DBS', 'Rapide', 'Vanquish', 'Vantage'],
+ },
+ audi: {
+ name: 'Audi',
+ models: ['90', '4000', '5000', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'Q5', 'Q7'],
+ },
+ austin: {
+ name: 'Austin',
+ models: ['America', 'Maestro', 'Maxi', 'Mini', 'Montego', 'Princess'],
+ },
+ borgward: {
+ name: 'Borgward',
+ models: ['Hansa', 'Isabella', 'P100'],
+ },
+ buick: {
+ name: 'Buick',
+ models: ['Electra', 'LaCrosse', 'LeSabre', 'Park Avenue', 'Regal',
+ 'Roadmaster', 'Skylark'],
+ },
+ cadillac: {
+ name: 'Cadillac',
+ models: ['Catera', 'Cimarron', 'Eldorado', 'Fleetwood', 'Sedan de Ville'],
+ },
+ chevrolet: {
+ name: 'Chevrolet',
+ models: ['Astro', 'Aveo', 'Bel Air', 'Captiva', 'Cavalier', 'Chevelle',
+ 'Corvair', 'Corvette', 'Cruze', 'Nova', 'SS', 'Vega', 'Volt'],
+ },
+};
+
+var PickerExample = React.createClass({
+ getInitialState: function() {
+ return {
+ carMake: 'cadillac',
+ modelIndex: 3,
+ };
+ },
+
+ render: function() {
+ var make = CAR_MAKES_AND_MODELS[this.state.carMake];
+ var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
+ return (
+
+ Please choose a make for your car:
+ this.setState({carMake, modelIndex: 0})}>
+ {Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
+
+ ))}
+
+ Please choose a model of {make.name}:
+ this.setState({modelIndex})}>
+ {CAR_MAKES_AND_MODELS[this.state.carMake].models.map((modelName, modelIndex) => (
+
+ ))}
+
+ You selected: {selectionString}
+
+ );
+ },
+});
+
+var PickerStyleExample = React.createClass({
+ getInitialState: function() {
+ return {
+ carMake: 'cadillac',
+ modelIndex: 0,
+ };
+ },
+
+ render: function() {
+ var make = CAR_MAKES_AND_MODELS[this.state.carMake];
+ var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
+ return (
+ this.setState({carMake, modelIndex: 0})}>
+ {Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
+
+ ))}
+
+ );
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Render lists of selectable options with UIPickerView.';
+exports.examples = [
+{
+ title: '',
+ render: function(): ReactElement {
+ return ;
+ },
+},
+{
+ title: ' with custom styling',
+ render: function(): ReactElement {
+ return ;
+ },
+}];
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/pixelratio.md b/docs/docs/0.41/pixelratio.md
new file mode 100644
index 0000000..485755c
--- /dev/null
+++ b/docs/docs/0.41/pixelratio.md
@@ -0,0 +1,67 @@
+PixelRatio类提供了访问设备的像素密度的方法。
+
+使用PixelRatio有如下几种常用情形:
+
+### 根据像素密度获取指定大小的图片
+
+如果应用运行在一个高像素密度的设备上,显示的图片也应当分辨率更高。一个取得缩略图的好规则就是将显示尺寸乘以像素密度比:
+
+```javascript
+var image = getImage({
+ width: PixelRatio.getPixelSizeForLayoutSize(200),
+ height: PixelRatio.getPixelSizeForLayoutSize(100),
+});
+
+```
+__译注__: 这段代码的意思是,如果你要在屏幕上摆放一个宽200高100的图片,那么首先要准备多个分辨率尺寸的图。`PixelRatio.getPixelSizeForLayoutSize(200)`方法会根据当前设备的pixelratio返回对应值,比如当前设备的pixelratio为2,则返回 200 * 2 = 400,最后生成的参数为{ width: 400, height: 200 },然后开发者自己实现getImage方法,根据这一参数,返回最符合此尺寸的图片地址。
+
+### 方法
+
+
+
+
static get() #
+
+
返回设备的像素密度,例如:
+
+ PixelRatio.get() === 1mdpi Android 设备 (160 dpi)
+ PixelRatio.get() === 1.5hdpi Android 设备 (240 dpi)
+ PixelRatio.get() === 2iPhone 4, 4S iPhone 5, 5c, 5s iPhone 6 xhdpi Android 设备 (320 dpi)
+ PixelRatio.get() === 3iPhone 6 plus xxhdpi Android 设备 (480 dpi)
+ PixelRatio.get() === 3.5
+
+
+
+
+
static getFontScale() #
+
+
返回字体大小缩放比例。这个比例可以用于计算绝对的字体大小,所以很多深度依赖字体大小的组件需要用此函数的结果进行计算。
+
如果没有设置字体大小,它会直接返回设备的像素密度。
+
目前这个函数仅仅在Android设备上实现了,它会体现用户选项里的“设置 > 显示 > 字体大小”。在iOS设备上它会直接返回默认的像素密度。
+
+
+
+
static getPixelSizeForLayoutSize(layoutSize: number) #
+
+
将一个布局尺寸(dp)转换为像素尺寸(px)。
+
一定会返回一个整数数值。
+
+
+
+
static startDetecting() #
+
+
+
+
+### 描述
+
+## 像素网格对齐
+
+在iOS设备上,你可以给元素指定任意精度的坐标和尺寸,例如29.674825。不过最终的物理屏幕上只会显示固定的坐标数。譬如iPhone4的分辨率是640x960,而iPhone6是750*1334。iOS会试图尽可能忠实地显示你指定的坐标,所以它采用了一种把一个像素分散到多个像素里的做法来欺骗眼睛。但这个作用的负面影响是显示出来的元素看起来会有一些模糊。
+
+在实践中,我们发现开发者们并不想要这个特性,反而需要去做一些额外的工作来确保坐标与像素坐标对齐,来避免元素显得模糊。在React Native中,我们会自动对齐坐标到像素坐标。
+
+我们做这个对齐的时候必须十分小心。如果你同时使用已经对齐的值和没有对齐的值,就会很容易产生一些因为近似导致的累积错误。即使这样的累积错误只发生一次,后果也可能会很严重,因为很可能会导致一个像素宽的边框最终突然消失或者显示为两倍的宽度。
+
+在React Native中,所有JS中的东西,包括布局引擎,都使用任意精度的数值。我们只在主线程最后设置原生组件的位置和坐标的时候才去做对齐工作。而且,对齐是相对于屏幕进行的,而非相对于父元素进行,进一步避免近似误差的累积。
diff --git a/docs/docs/0.41/platform-specific-code.md b/docs/docs/0.41/platform-specific-code.md
new file mode 100644
index 0000000..7414dad
--- /dev/null
+++ b/docs/docs/0.41/platform-specific-code.md
@@ -0,0 +1,93 @@
+在制作跨平台的App时,多半会碰到针对不同平台编写不同代码的需求。最直接的方案就是把组件放置到不同的文件夹下:
+
+```sh
+/common/components/
+/android/components/
+/ios/components/
+```
+
+另一个选择是根据平台不同在组件的文件命名上加以区分,如下:
+
+```sh
+BigButtonIOS.js
+BigButtonAndroid.js
+```
+
+但除此以外React Native还提供了另外两种简单区分平台的方案:
+
+## 特定平台扩展名
+React Native会检测某个文件是否具有`.ios.`或是`.android.`的扩展名,然后根据当前运行的平台加载正确对应的文件。
+
+假设你的项目中有如下两个文件:
+
+```sh
+BigButton.ios.js
+BigButton.android.js
+```
+
+这样命名组件后你就可以在其他组件中直接引用,而无需关心当前运行的平台是哪个。
+
+```javascript
+import BigButton from './components/BigButton';
+```
+
+React Native会根据运行平台的不同引入正确对应的组件。
+
+还有个实用的方法是Platform.select(),它可以以Platform.OS为key,从传入的对象中返回对应平台的值,见下面的示例:
+
+```javascript
+import { Platform, StyleSheet } from 'react-native';
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ ...Platform.select({
+ ios: {
+ backgroundColor: 'red',
+ },
+ android: {
+ backgroundColor: 'blue',
+ },
+ }),
+ },
+});
+```
+
+上面的代码会根据平台的不同返回不同的container样式——iOS上背景色为红色,而android为蓝色。
+
+这一方法可以接受任何合法类型的参数,因此你也可以直接用它针对不同平台返回不同的组件,像下面这样:
+
+
+```javascript
+var Component = Platform.select({
+ ios: () => require('ComponentIOS'),
+ android: () => require('ComponentAndroid'),
+})();
+
+ ;
+```
+
+
+## 平台模块
+React Native提供了一个检测当前运行平台的模块。如果组件只有一小部分代码需要依据平台定制,那么这个模块就可以派上用场。
+
+```javascript
+import { Platform, StyleSheet } from 'react-native';
+
+var styles = StyleSheet.create({
+ height: (Platform.OS === 'ios') ? 200 : 100,
+});
+```
+
+`Platform.OS`在iOS上会返回`ios`,而在Android设备或模拟器上则会返回`android`。
+
+### 检测Android版本
+在Android上,平台模块还可以用来检测当前所运行的Android平台的版本:
+
+```javascript
+import { Platform } from 'react-native';
+
+if(Platform.Version === 21){
+ console.log('Running on Lollipop!');
+}
+```
diff --git a/docs/docs/0.41/progressbarandroid.md b/docs/docs/0.41/progressbarandroid.md
new file mode 100644
index 0000000..e434d7c
--- /dev/null
+++ b/docs/docs/0.41/progressbarandroid.md
@@ -0,0 +1,165 @@
+封装了Android平台上的`ProgressBar`的React组件。这个组件可以用来表示应用正在加载或者有些事情正在进行中。
+
+例子:
+
+```javascript
+render: function() {
+ var progressBar =
+
+
+ ;
+
+ return (
+
+ );
+},
+```
+### 截图
+
+
+### 属性
+
+
+
+
+
+
indeterminate indeterminateType #
+
+
决定进度条是否要显示一个不确定的进度。注意这个在styleAttr是Horizontal的时候必须是false。
+
+
+
+
+
styleAttr STYLE_ATTRIBUTES #
+
+
进度条的样式。可取值有:
+
+ Horizontal
+ Small
+ Large
+ Inverse
+ SmallInverse
+ LargeInverse
+
+
+
+
+
+
+### 样例
+
+```javascript
+'use strict';
+
+var ProgressBar = require('ProgressBarAndroid');
+var React = require('React');
+var UIExplorerBlock = require('UIExplorerBlock');
+var UIExplorerPage = require('UIExplorerPage');
+
+var TimerMixin = require('react-timer-mixin');
+
+var MovingBar = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState: function() {
+ return {
+ progress: 0
+ };
+ },
+
+ componentDidMount: function() {
+ this.setInterval(
+ () => {
+ var progress = (this.state.progress + 0.02) % 1;
+ this.setState({progress: progress});
+ }, 50
+ );
+ },
+
+ render: function() {
+ return ;
+ },
+});
+
+var ProgressBarAndroidExample = React.createClass({
+
+ statics: {
+ title: '',
+ description: 'Visual indicator of progress of some operation. ' +
+ 'Shows either a cyclic animation or a horizontal bar.',
+ },
+
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+module.exports = ProgressBarAndroidExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/progressviewios.md b/docs/docs/0.41/progressviewios.md
new file mode 100644
index 0000000..4c571ba
--- /dev/null
+++ b/docs/docs/0.41/progressviewios.md
@@ -0,0 +1,123 @@
+使用`ProgressViewIOS`来在iOS上渲染一个UIProgressView。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
progressImage Image.propTypes.source #
+
+
+
+
progressTintColor string #
+
+
+
+
progressViewStyle enum('default', 'bar') #
+
+
+
+
trackImage Image.propTypes.source #
+
+
一个可拉伸的图片,用于显示进度条后面的轨道。
+
+
+
+
trackTintColor string #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ProgressViewIOS,
+ StyleSheet,
+ View,
+} = ReactNative;
+var TimerMixin = require('react-timer-mixin');
+
+var ProgressViewExample = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState() {
+ return {
+ progress: 0,
+ };
+ },
+
+ componentDidMount() {
+ this.updateProgress();
+ },
+
+ updateProgress() {
+ var progress = this.state.progress + 0.01;
+ this.setState({ progress });
+ this.requestAnimationFrame(() => this.updateProgress());
+ },
+
+ getProgress(offset) {
+ var progress = this.state.progress + offset;
+ return Math.sin(progress % Math.PI) % 1;
+ },
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = 'ProgressViewIOS';
+exports.description = 'ProgressViewIOS';
+exports.examples = [{
+ title: 'ProgressViewIOS',
+ render() {
+ return (
+
+ );
+ }
+}];
+
+var styles = StyleSheet.create({
+ container: {
+ marginTop: -20,
+ backgroundColor: 'transparent',
+ },
+ progressView: {
+ marginTop: 20,
+ }
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/props.md b/docs/docs/0.41/props.md
new file mode 100644
index 0000000..0f9b238
--- /dev/null
+++ b/docs/docs/0.41/props.md
@@ -0,0 +1,60 @@
+大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为`props`(属性)。
+
+以常见的基础组件`Image`为例,在创建一个图片时,可以传入一个名为`source`的prop来指定要显示的图片的地址,以及使用名为`style`的prop来控制其尺寸。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Image } from 'react-native';
+
+class Bananas extends Component {
+ render() {
+ let pic = {
+ uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
+ };
+ return (
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('Bananas', () => Bananas);
+```
+
+译注:在iOS上使用http链接的图片地址可能不会显示,参见[这篇说明修改](https://segmentfault.com/a/1190000002933776)。
+
+请注意`{pic}`外围有一层括号,我们需要用括号来把`pic`这个变量嵌入到JSX语句中。括号的意思是括号内部为一个js变量或表达式,需要执行后取值。因此我们可以把任意合法的JavaScript表达式通过括号嵌入到JSX语句中。
+
+自定义的组件也可以使用`props`。通过在不同的场景使用不同的属性定制,可以尽量提高自定义组件的复用范畴。只需在`render`函数中引用`this.props`,然后按需处理即可。下面是一个例子:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+class Greeting extends Component {
+ render() {
+ return (
+ Hello {this.props.name}!
+ );
+ }
+}
+
+class LotsOfGreetings extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('LotsOfGreetings', () => LotsOfGreetings);
+```
+
+我们在`Greeting`组件中将`name`作为一个属性来定制,这样可以复用这一组件来制作各种不同的“问候语”。上面的例子把`Greeting`组件写在JSX语句中,用法和内置组件并无二致——这正是React体系的魅力所在——如果你想搭建一套自己的基础UI框架,那就放手做吧!
+
+上面的例子出现了一样新的名为[`View`](view.html)的组件。[`View`](view.html) 常用作其他组件的容器,来帮助控制布局和样式。
+
+仅仅使用`props`和基础的[`Text`](text.html)、[`Image`](image.html)以及[`View`](view.html)组件,你就已经足以编写各式各样的UI组件了。要学习如何动态修改你的界面,那就需要进一步[学习State(状态)的概念](state.html)。
diff --git a/docs/docs/0.41/pushnotificationios.md b/docs/docs/0.41/pushnotificationios.md
new file mode 100644
index 0000000..a8adf39
--- /dev/null
+++ b/docs/docs/0.41/pushnotificationios.md
@@ -0,0 +1,372 @@
+本模块帮助你处理应用的推送通知,包括权限控制以及应用图标上的角标数(未读消息数)。
+
+要使用推送通知功能,首先[在苹果后台配置推送通知服务](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6)并且准备好服务端的系统。设置的过程可以参考[Parse的教程](https://parse.com/tutorials/ios-push-notifications)
+
+首先请[手动链接](linking-libraries-ios.html)PushNotificationIOS的库(以下操作如果不熟悉,请自行补习Xcode的使用教程):
+- 将`node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj`文件拖到Xcode界面中
+- 在Xcode的`Link Binary With Libraries`中添加`libRCTPushNotification.a`
+- 在`Header Search Paths`中添加: `$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS`
+- 将搜索选项设为`recursive`
+
+然后你需要在AppDelegate中启用推送通知的支持以及注册相应的事件。
+
+在`AppDelegate.m`开头:
+
+```objective-c
+#import "RCTPushNotificationManager.h"
+```
+
+然后在AppDelegate实现中添加如下的代码:
+
+```objective-c
+ // Required to register for notifications
+ - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
+ {
+ [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
+ }
+ // Required for the register event.
+ - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
+ {
+ [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+ }
+ // Required for the notification event.
+ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
+ {
+ [RCTPushNotificationManager didReceiveRemoteNotification:notification];
+ }
+ // Required for the localNotification event.
+ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+ {
+ [RCTPushNotificationManager didReceiveLocalNotification:notification];
+ }
+```
+
+### 方法
+
+
+
+
static presentLocalNotification(details: Object) #
+
+
立即产生一个本地通知
+
details参数是一个对象,包含:
+
+ alertBody : 要在通知提示中显示的消息。
+ alertAction : 在交互式通知提示下显示的"action"。默认为"view"。
+ soundName : 通知触发时播放的声音名字(可选)。
+ category : 可选的通知类型,但对于交互式通知为必填。
+ userInfo : 提供一个可选的object,可以在其中提供额外的数据。
+ applicationIconBadgeNumber : 指定显示在应用右上角的数字角标(可选)。默认值为0,即不显示角标。
+
+
+
+
+
static scheduleLocalNotification(details: Object) #
+
+
计划一个本地通知,在将来进行提示。
+
details参数是一个对象,包含:
+
+ fireDate : 系统发送这个提示的日期和时间。
+ alertBody : 要在通知提示中显示的消息。
+ alertAction : 在交互式通知提示下显示的"action"。默认为"view"。
+ soundName : 通知触发时播放的声音名字(可选)。
+ category : 可选的通知类型,但对于交互式通知为必填。
+ userInfo : 提供一个可选的object,可以在其中提供额外的数据。
+ applicationIconBadgeNumber : 指定显示在应用右上角的数字角标(可选)。默认值为0,即不显示角标。
+
+
+
+
+
static cancelAllLocalNotifications() #
+
+
+
+
static setApplicationIconBadgeNumber(number: number) #
+
+
设置要在手机主屏幕应用图标上显示的角标数(未读消息数)。
+
+
+
+
static getApplicationIconBadgeNumber(callback: Function) #
+
+
获取目前在手机主屏幕应用图标上显示的角标数(未读消息数)。
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听器,监听远程或本地推送的通知事件,不论应用在前台还是在后台运行
+
事件类型有:
+
+ notification : 当收到来自远程的推送通知时调用handler函数,第一个参数是一个PushNotificationIOS实例。
+ localNotification : 当收到来自本地的推送通知时调用handler函数,第一个参数是一个PushNotificationIOS实例。
+ register: 当用户注册远程通知的时候调用handler函数。参数是一个十六进制的字符串,表示了设备标识(deviceToken)。
+
+
+
+
+
static requestPermissions(permissions?: {
+ alert?: boolean,
+ badge?: boolean,
+ sound?: boolean
+ }) #
+
+
向iOS系统请求通知权限,给用户展示一个对话框。默认情况下,它会请求所有的权限。不过你可以通过传递一个映射(map)到permissions参数来请求指定的权限子集。可以请求的权限类型有:
+
+ alert
+ badge
+ sound
+
+
如果提供了一个映射(map)作为参数,只有值为真值的权限才会被请求。
+
+
+
+
static abandonPermissions() #
+
+
注销所有从苹果推送通知服务收到的远程消息。
+
你应该只会在极少的情况下需要调用此函数,譬如一个新版本的App要取消所有远程推送通知的支持。如果是用户希望关闭推送通知,他可以打开系统设置的推送通知一栏来暂时屏蔽。应用通过此方法注销后,可以随时重新注册。
+
+
+
+
static checkPermissions(callback: Function) #
+
+
检查哪些推送通知权限被开启。 callback函数会被调用,参数为permissions 对象:
+
+ alert :boolean
+ badge :boolean
+ sound :boolean
+
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
移除注册事件监听器。在componentWillUnmount中调用此函数以避免内存泄露。
+
+
+
+
static popInitialNotification() #
+
+
如果用户通过点击推送通知来冷启动应用(即:之前应用不在运行状态),此函数会返回一个初始的通知。
+
第一次调用popInitialNotification会返回初始的通知对象,或者返回null。后续的调用全部会返回null.
+
+
+
+
constructor(nativeNotif: Object) #
+
你应该永远不需要自己实例化PushNotificationIOS对象。监听notification事件和调用popInitialNotification应当足够了。
+
+
+
+
getMessage() #
+
+
getAlert方法的别名。获取推送通知的主消息内容。
+
+
+
+
+
+
getBadgeCount() #
+
+
从aps对象中获取推送通知的角标数(未读消息数)。
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ AlertIOS,
+ PushNotificationIOS,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+var Button = React.createClass({
+ render: function() {
+ return (
+
+
+ {this.props.label}
+
+
+ );
+ }
+});
+
+class NotificationExample extends React.Component {
+ componentWillMount() {
+ // Add listener for push notifications
+ PushNotificationIOS.addEventListener('notification', this._onNotification);
+ // Add listener for local notifications
+ PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification);
+ }
+
+ componentWillUnmount() {
+ // Remove listener for push notifications
+ PushNotificationIOS.removeEventListener('notification', this._onNotification);
+ // Remove listener for local notifications
+ PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification);
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ _sendNotification() {
+ require('RCTDeviceEventEmitter').emit('remoteNotificationReceived', {
+ aps: {
+ alert: 'Sample notification',
+ badge: '+1',
+ sound: 'default',
+ category: 'REACT_NATIVE'
+ },
+ });
+ }
+
+ _sendLocalNotification() {
+ require('RCTDeviceEventEmitter').emit('localNotificationReceived', {
+ aps: {
+ alert: 'Sample local notification',
+ badge: '+1',
+ sound: 'default',
+ category: 'REACT_NATIVE'
+ },
+ });
+ }
+
+ _onNotification(notification) {
+ AlertIOS.alert(
+ 'Push Notification Received',
+ 'Alert message: ' + notification.getMessage(),
+ [{
+ text: 'Dismiss',
+ onPress: null,
+ }]
+ );
+ }
+
+ _onLocalNotification(notification){
+ AlertIOS.alert(
+ 'Local Notification Received',
+ 'Alert message: ' + notification.getMessage(),
+ [{
+ text: 'Dismiss',
+ onPress: null,
+ }]
+ );
+ }
+}
+
+class NotificationPermissionExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {permissions: null};
+ }
+
+ render() {
+ return (
+
+
+
+ {JSON.stringify(this.state.permissions)}
+
+
+ );
+ }
+
+ _showPermissions() {
+ PushNotificationIOS.checkPermissions((permissions) => {
+ this.setState({permissions});
+ });
+ }
+}
+
+var styles = StyleSheet.create({
+ button: {
+ padding: 10,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ buttonLabel: {
+ color: 'blue',
+ },
+});
+
+exports.title = 'PushNotificationIOS';
+exports.description = 'Apple PushNotification and badge value';
+exports.examples = [
+{
+ title: 'Badge Number',
+ render(): ReactElement {
+ PushNotificationIOS.requestPermissions();
+
+ return (
+
+ PushNotificationIOS.setApplicationIconBadgeNumber(42)}
+ label="Set app's icon badge to 42"
+ />
+ PushNotificationIOS.setApplicationIconBadgeNumber(0)}
+ label="Clear app's icon badge"
+ />
+
+ );
+ },
+},
+{
+ title: 'Push Notifications',
+ render(): ReactElement {
+ return ;
+ }
+},
+{
+ title: 'Notifications Permissions',
+ render(): ReactElement {
+ return ;
+ }
+}];
+```
diff --git a/docs/docs/0.41/refreshcontrol.md b/docs/docs/0.41/refreshcontrol.md
new file mode 100644
index 0000000..b56dfea
--- /dev/null
+++ b/docs/docs/0.41/refreshcontrol.md
@@ -0,0 +1,159 @@
+这一组件可以用在ScrollView或ListView内部,为其添加下拉刷新的功能。当ScrollView处于竖直方向的起点位置(scrollY: 0),此时下拉会触发一个`onRefresh`事件。
+
+### 属性
+
+
onRefresh function
+#
+
+
+
+
android colors
+[ColorPropType] #
+
+
+
android enabled
+bool #
+
+
+
android progressBackgroundColor
+ColorPropType #
+
+
+
android size
+RefreshLayoutConsts.SIZE.DEFAULT #
+
指定刷新指示器的大小,具体数值可参阅RefreshControl.SIZE.
+
+
android progressViewOffset
+React.PropTypes.number #
+
指定刷新指示器的垂直起始位置(top offset)。
+
+
ios tintColor
+ColorPropType #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ ScrollView,
+ StyleSheet,
+ RefreshControl,
+ Text,
+ TouchableWithoutFeedback,
+ View,
+} = ReactNative;
+
+const styles = StyleSheet.create({
+ row: {
+ borderColor: 'grey',
+ borderWidth: 1,
+ padding: 20,
+ backgroundColor: '#3a5795',
+ margin: 5,
+ },
+ text: {
+ alignSelf: 'center',
+ color: '#fff',
+ },
+ scrollview: {
+ flex: 1,
+ },
+});
+
+const Row = React.createClass({
+ _onClick: function() {
+ this.props.onClick(this.props.data);
+ },
+ render: function() {
+ return (
+
+
+
+ {this.props.data.text + ' (' + this.props.data.clicks + ' clicks)'}
+
+
+
+ );
+ },
+});
+
+const RefreshControlExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Adds pull-to-refresh support to a scrollview.'
+ },
+
+ getInitialState() {
+ return {
+ isRefreshing: false,
+ loaded: 0,
+ rowData: Array.from(new Array(20)).map(
+ (val, i) => ({text: 'Initial row ' + i, clicks: 0})),
+ };
+ },
+
+ _onClick(row) {
+ row.clicks++;
+ this.setState({
+ rowData: this.state.rowData,
+ });
+ },
+
+ render() {
+ const rows = this.state.rowData.map((row, ii) => {
+ return ;
+ });
+ return (
+
+ }>
+ {rows}
+
+ );
+ },
+
+ _onRefresh() {
+ this.setState({isRefreshing: true});
+ setTimeout(() => {
+ // prepend 10 items
+ const rowData = Array.from(new Array(10))
+ .map((val, i) => ({
+ text: 'Loaded row ' + (+this.state.loaded + i),
+ clicks: 0,
+ }))
+ .concat(this.state.rowData);
+
+ this.setState({
+ loaded: this.state.loaded + 10,
+ isRefreshing: false,
+ rowData: rowData,
+ });
+ }, 5000);
+ },
+});
+
+module.exports = RefreshControlExample;
+```
diff --git a/docs/docs/0.41/running-on-device-android.md b/docs/docs/0.41/running-on-device-android.md
new file mode 100644
index 0000000..5bc930b
--- /dev/null
+++ b/docs/docs/0.41/running-on-device-android.md
@@ -0,0 +1,51 @@
+## 前提条件:USB调试
+
+你需要开启USB调试才能在你的设备上安装你的APP。首先,确定[你已经打开设备的USB调试开关](https://www.baidu.com/s?wd=%E5%AE%89%E5%8D%93%E6%89%93%E5%BC%80usb%E8%B0%83%E8%AF%95)
+
+确保你的设备已经**成功连接**。可以输入`adb devices`来查看:
+
+ $ adb devices
+ List of devices attached
+ emulator-5554 offline # Google模拟器
+ 14ed2fcc device # 真实设备
+
+在右边那列看到**device**说明你的设备已经被正确连接了。注意,你只应当**连接仅仅一个设备**。
+
+__译注__:如果你连接了多个设备(包含模拟器在内),后续的一些操作可能会失败。拔掉不需要的设备,或者关掉模拟器,确保adb devices的输出只有一个是连接状态。
+
+现在你可以运行`react-native run-android`来在设备上安装并启动应用了。
+
+__译注__:在真机上运行时可能会遇到白屏的情况,请找到并开启`悬浮窗权限`。比如miui系统的设置[在此处](http://jingyan.baidu.com/article/f25ef25466c0fc482d1b824d.html)。
+
+> 提示
+>
+> 你还可以运行`react-native run-android --variant=release`来安装release版的应用。当然你需要[先配置好签名](signed-apk-android.html),且此时无法再开启开发者菜单。注意在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
+## 从设备上访问开发服务器。
+
+在启用开发服务器的情况下,你可以快速的迭代修改应用,然后在设备上查看结果。按照下面描述的任意一种方法来使你的运行在电脑上的开发服务器可以从设备上访问到。
+
+> 注意
+>
+> 大部分现代的安卓设备已经没有了硬件"Menu"按键,这是我们用来调出开发者菜单的。在这种情况下你可以通过摇晃设备来打开开发者菜单(重新加载、调试,等等……)
+
+### (Android 5.0及以上)使用adb reverse命令
+
+> 注意,这个选项只能在5.0以上版本(API 21+)的安卓设备上使用。
+
+首先把你的设备通过USB数据线连接到电脑上,并开启USB调试(关于如何开启USB调试,参见上面的章节)。
+
+1. 运行`adb reverse tcp:8081 tcp:8081`
+2. 不需要更多配置,你就可以使用`Reload JS`和其它的开发选项了。
+
+### (Android 5.0以下)通过Wi-Fi连接你的本地开发服务器
+
+1. 首先确保你的电脑和手机设备在**同一个Wi-Fi环境**下。
+2. 在设备上运行你的React Native应用。和打开其它App一样操作。
+3. 你应该会看到一个“红屏”错误提示。这是正常的,下面的步骤会解决这个报错。
+4. 摇晃设备,或者运行`adb shell input keyevent 82`,可以打开**开发者菜单**。
+5. 点击进入`Dev Settings`。
+6. 点击`Debug server host for device`。
+7. 输入你电脑的IP地址和端口号(譬如10.0.1.1:8081)。**在Mac上**,你可以在系统设置/网络里找查询你的IP地址。**在Windows上**,打开命令提示符并输入`ipconfig`来查询你的IP地址。**在Linux上**你可以在终端中输入`ifconfig`来查询你的IP地址。
+8. 回到**开发者菜单**然后选择`Reload JS`。
+
diff --git a/docs/docs/0.41/running-on-device-ios.md b/docs/docs/0.41/running-on-device-ios.md
new file mode 100644
index 0000000..f9d3894
--- /dev/null
+++ b/docs/docs/0.41/running-on-device-ios.md
@@ -0,0 +1,22 @@
+
+在真机上测试iOS应用需要一台Mac电脑,同时还需要注册一个Apple ID。如果你需要把应用发布到App Store,那么你还需要去苹果开发者网站购买一个开发者账户(在自己手机上测试则不用)。本文档只探讨React Native相关的发布问题。
+
+## 在真机上访问开发服务器(packager)
+
+你可以在真机上访问开发服务器以快速测试和迭代。首先需要确保设备已使用usb连接至电脑,同时和电脑处在同一wifi网络内,然后在Xcode中选择你的设备作为编译目标(左上角运行按钮的右边),然后点击运行按钮即可。
+如果你需要在真机上启用调试功能,则需要打开[RCTWebSocketExecutor.m](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m)文件,然后将其中的"localhost"改为你的电脑的IP地址,最后启用开发者菜单中的"Debug JS Remotely"选项。
+
+> 提示
+摇晃设备就可以打开开发者菜单。
+
+## 发布应用
+
+当你使用React Native做好一个漂亮的应用之后,一定跃跃欲试想要在App Store上发布了吧。发布的流程和其他iOS原生应用完全一样,除了以下一些注意事项。
+在App Store上发布应用首先需要编译一个“发布版本”(release)的应用。具体的做法是在Xcode中选择Product -> Scheme -> Edit Scheme (cmd + <),然后选择Run选项卡,将Build Configuration设置为release。
+Release版本的应用会自动禁用开发者菜单,同时也会将js文件和静态图片打包压缩后内置到包中,这样应用可以在本地读取而无需访问开发服务器(同时这样一来你也无法再调试,需要调试请将Buiid Configuration再改为debug)。
+由于发布版本已经内置了js文件,因而也无法再通过开发服务器来实时更新。面向用户的热更新,请使用专门的[热更新服务](http://update.reactnative.cn)。
+编译完成后,你就可以打包提交到TestFlight进行内测,或是提交到App Store进行发布。相关流程较为复杂,不熟悉原生应用发布流程的同学请自行搜索学习。
+
+### App Transport Security
+
+**App Transport Security**(简称ATS)是iOS 9中新增的一项安全特性。在默认设置下,只允许HTTPS的请求,而所有HTTP的请求都会被拒绝。详情可参考[这篇帖子](https://segmentfault.com/a/1190000002933776)。
\ No newline at end of file
diff --git a/docs/docs/0.41/running-on-simulator-ios.md b/docs/docs/0.41/running-on-simulator-ios.md
new file mode 100644
index 0000000..068c979
--- /dev/null
+++ b/docs/docs/0.41/running-on-simulator-ios.md
@@ -0,0 +1,9 @@
+## 启动模拟器
+
+当你完成了初始化React Native新项目后,就可以在项目目录下运行`react-native run-ios`来启动模拟器。如果一切配置都没有问题,应该很快就能看到你的应用在iOS模拟器上运行起来。
+
+## 指定模拟的设备类型
+
+你可以使用`--simulator`参数,在其后加上要使用的设备名称来指定要模拟的设备类型(目前默认为"iPhone 6")。如果你要模拟iPhone 4s,那么这样运行命令即可:`react-native run-ios --simulator "iPhone 4s"`。
+
+你可以在终端中运行`xcrun simctl list devices`来查看具体可用的设备名称。
diff --git a/docs/docs/0.41/sample-application-movies.md b/docs/docs/0.41/sample-application-movies.md
new file mode 100644
index 0000000..1a99bb3
--- /dev/null
+++ b/docs/docs/0.41/sample-application-movies.md
@@ -0,0 +1,504 @@
+## 简介
+
+在本示例教程中,我们将编写一个简单的应用,可以从电影数据库中取得最近正在上映的25部电影,并在一个`ListView`中展示出来。
+
+## 准备工作
+
+React Native需要一些基础的配置工作,你可以参考[开始使用React Native](getting-started.html)来进行。
+
+在所有依赖的软件都已经安装完毕后,只需要输入两条命令就可以创建一个React Native工程。
+
+1. `npm install -g react-native-cli`
+
+ react-native-cli是一个终端命令,它可以完成其余的设置工作。它可以通过npm安装。刚才这条命令会往你的终端安装一个叫做`react-native`的命令。这个安装过程你只需要进行一次。
+
+2. `react-native init SampleAppMovies`
+
+ 这个命令会初始化一个工程、下载React Native的所有源代码和依赖包,最后在`SampleAppMovies/iOS/SampleAppMovies.xcodeproj`和`SampleAppMovies/android/app`下分别创建一个新的XCode工程和一个gradle工程。
+
+__译注__:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请先将npm仓库源替换为国内镜像:
+
+```bash
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+另,执行init时切记`不要`在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题。如果你这样做了,请使用chown命令修复)。
+
+## 开发
+
+想开发iOS版本,你现在可以在XCode中打开刚刚创建的工程(`SampleAppMovies/iOS/SampleAppMovies.xcodeproj`),然后只要按下`⌘+R`就可以构建并运行。这个操作会同时打开一个用于实现动态代码加载的Node服务(React Packager)。所以每当你修改代码,你只需要在模拟器中按下`⌘+R`,而无需重新在XCode中编译。
+
+想开发Android版本,先连接你的设备或启动模拟器,然后在`SampleAppMovies`目录下运行`react-native run-android`,就会构建工程并自动安装到你的模拟器或者设备,同时启动用于实现动态代码加载的Node服务。当你修改代码之后,你需要打开摇一摇菜单(摇一下设备,或者按下设备的Menu键,或者在模拟器上按下F2或Page Up,Genymotion按下⌘+M),然后在菜单中点击“Reload JS”。
+
+### Hello World
+
+`react-native init`命令会创建一个指定名字的应用,我们刚才输入的命令就创建了一个名为SampleAppMovies的应用。这是一个简单的Hello World应用。对于iOS版本,你可以编辑`index.ios.js`来做一些改动,然后在模拟器中按⌘+R来看到修改的结果。对Android版本,你可以编辑`index.android.js`来做一些改动,然后在摇一摇菜单中点击“Reload JS”来看到修改的结果。
+
+### 模拟数据
+
+__译注__:本文的示例代码改用了ES6语法,可能和其他文档写法不一致。但React Native从0.18之后,新建项目默认已经采用了ES6语法,故我们推荐不熟悉ES6与ES5区别的朋友先读读[这篇文章](http://bbs.reactnative.cn/topic/15),另外还可以看看[阮一峰老师的书](http://es6.ruanyifeng.com/)。
+
+在我们真正从Rotten Tomatoes(_译注:一个国外的电影社区_)抓取数据之前,我们先制造一些模拟数据来练一练手。在Facebook我们通常在JS文件的开头,紧跟着import语句之后声明一个常量,不过这不重要,你可以把它放在`index.ios.js`和`index.android.js`的任意位置:
+
+```javascript
+var MOCKED_MOVIES_DATA = [
+ {title: '标题', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
+];
+```
+
+译注:在iOS上使用http链接的图片地址可能不会显示,参见[这篇说明修改](https://segmentfault.com/a/1190000002933776)。
+
+### 展现一个电影
+
+我们接下来要展现一个电影,绘制它的标题、年份、以及缩略图(_译注:这个过程我们通常会叫做“渲染/render”,后面我们都会用“渲染”这个词_)。渲染缩略图需要用到Image组件,所以把Image添加到对React的import列表中。
+
+```javascript
+import React, {
+ Component,
+} from 'react';
+import {
+ AppRegistry,
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+```
+
+然后修改一下render函数,这样我们可以把上面创建的模拟数据渲染出来。
+
+```javascript
+ render() {
+ var movie = MOCKED_MOVIES_DATA[0];
+ return (
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+```
+
+按下`⌘+R`或者`Reload JS`,现在你应该能看到文字"Title"和"2015",但现在Image组件没渲染任何东西,这是因为我们还没有为图片指定我们想要渲染的宽和高。这通过样式来实现。当我们修改样式的时候,我们也应该清理掉我们不再使用的样式。
+
+```javascript
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ thumbnail: {
+ width: 53,
+ height: 81,
+ },
+});
+```
+
+然后把它应用到Image组件上:
+
+```javascript
+
+```
+
+按下`⌘+R`或者`Reload JS`,现在图片应该可以被渲染出来了。
+
+| | |
+|--|--|
+| ||
+
+### 添加样式
+
+现在我们已经成功的把我们的数据渲染出来了,下面让我们把它弄的更好看一些。我想把文字放在图片的右边,然后把标题弄的大一些,并且水平居中:
+
+```
++---------------------------------+
+|+-------++----------------------+|
+|| || 标题 ||
+|| 图片 || ||
+|| || 年份 ||
+|+-------++----------------------+|
++---------------------------------+
+```
+
+所以我们需要增加一个container来实现一个水平布局内嵌套一个垂直布局。
+
+```javascript
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+```
+
+和之前相比并没有太多变化,我们增加了一个container来包装文字,然后把它移到了Image的后面(因为他们最终在图片的右边)。然后我们来看看样式要怎么改:
+
+```javascript
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+```
+
+我们用Flexbox来布局。如果你想了解更多,可以读读[这篇文章](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)。
+
+在上面的代码片段中,我们用了一句`flexDirection: 'row'`来让我们的主容器的成员从左到右横向布局,而非默认的从上到下纵向布局。
+
+现在我们往`style`对象里增加另一个样式:
+
+```javascript
+ rightContainer: {
+ flex: 1,
+ },
+```
+
+这句话的作用是让`rightContainer`在父容器中占据Image之外剩下的全部空间。如果你还不是很理解的话,你可以往`rightContainer`里增加一个`backgroundColor`看一看,然后再去掉`flex:1`对比一下。你会发现去掉这一句后,容器会变成能容纳它孩子的最小大小。
+
+给文字添加样式就简单的多了:
+
+```javascript
+ title: {
+ fontSize: 20,
+ marginBottom: 8,
+ textAlign: 'center',
+ },
+ year: {
+ textAlign: 'center',
+ },
+```
+
+再按一次`⌘+R`或者`Reload JS`来看看最新的结果。
+
+| | |
+|--|--|
+| ||
+
+### 拉取真正的数据
+
+从Rotten Tomatoes的API拉取数据和学习React Native并没有什么直接关系,所以你也可以直接跳过本节。
+
+把下面的常量放到文件的最开头(通常在import下面)来创建我们请求数据所需的地址常量REQUEST_URL
+
+```javascript
+/**
+ * 为了避免骚扰,我们用了一个样例数据来替代Rotten Tomatoes的API
+ * 请求,这个样例数据放在React Native的Github库中。
+ * 当然,由于众所周知的原因,这个地址可能国内访问也比较困难。
+ */
+var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
+```
+
+首先在应用中创建一个初始的null状态,这样可以通过`this.state.movies == null`来判断我们的数据是不是已经被抓取到了。我们在服务器响应返回的时候执行`this.setState({movies: moviesData})`来改变这个状态。把下面这段代码放到我们的React类的render函数之前(下面注释中的“绑定操作”你可以看看这个[短视频教程](http://v.youku.com/v_show/id_XMTgyNzM0NjQzMg==.html)):
+
+```javascript
+ constructor(props) {
+ super(props); //这一句不能省略,照抄即可
+ this.state = {
+ movies: null, //这里放你自己定义的state变量及初始值
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+```
+
+组件加载完毕之后,就可以向服务器请求数据。`componentDidMount`是React组件的一个生命周期方法,它会在组件刚加载完成的时候调用一次,以后不会再被调用。React中的各种生命周期方法请[参阅此文档](http://facebook.github.io/react/docs/component-specs.html)。
+
+```javascript
+ componentDidMount() {
+ this.fetchData();
+ }
+```
+
+现在我们来为组件添加`fetchData`函数。你所需要做的就是在Promise调用链结束后执行`this.setState({movies:data})`。在React的工作机制下,`setState`实际上会触发一次`重新渲染`的流程,此时render函数被触发,发现this.state.movies不再是`null`。
+
+```javascript
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ movies: responseData.movies,
+ });
+ });
+ }
+```
+
+现在我们来修改render函数。在电影数据加载完毕之前,先渲染一个“加载中”的视图;而如果电影数据已经加载完毕了,则渲染第一个电影数据。
+
+
+```javascript
+ render() {
+ if (!this.state.movies) {
+ return this.renderLoadingView();
+ }
+
+ var movie = this.state.movies[0];
+ return this.renderMovie(movie);
+ }
+
+ renderLoadingView() {
+ return (
+
+
+ 正在加载电影数据……
+
+
+ );
+ }
+
+ renderMovie(movie) {
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+```
+
+现在再按一次`⌘+R`或者`Reload JS`,你会首先看到“正在加载电影数据……”,然后在响应数据到达之后,看到第一个电影的信息。
+
+| | |
+|--|--|
+| ||
+
+## ListView
+
+现在我们来让我们的应用能够渲染所有的数据而不是仅仅第一部电影。我们要用到的就是ListView组件。
+
+为什么建议把内容放到ListView里?比起直接渲染出所有的元素,或是放到一个ScrollView里有什么优势?这是因为尽管React很高效,渲染一个可能很大的元素列表还是会很慢。`ListView`会安排视图的渲染,只显示当前在屏幕上的那些元素。而那些已经渲染好了但移动到了屏幕之外的元素,则会从原生视图结构中移除(以提高性能)。
+
+首先要做的事情:在文件最开头,从React中引入`ListView`。
+
+```javascript
+import React, {
+ Component,
+} from 'react';
+import {
+ AppRegistry,
+ Image,
+ ListView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+```
+
+现在来修改render函数。当我们已经有了数据之后,渲染一个包含多个电影信息的ListView,而不仅仅是单个的电影。
+
+```javascript
+ render() {
+ if (!this.state.loaded) {
+ return this.renderLoadingView();
+ }
+
+ return (
+
+ );
+ }
+```
+
+`dataSource`接口用来在ListView的整个更新过程中判断哪些数据行发生了变化。
+
+你会注意到我们现在用到了`this.state`中的`dataSource`。下一步就是在`constructor`生成的初始状态中添加一个空白的`dataSource`。另外,我们现在要把数据存储在`dataSource`中了,所以不再另外用`this.state.movies`来保存数据。我们可以在state里用一个布尔型的属性(`this.state.loaded`)来判断数据加载是否已经完成了。
+
+```javascript
+ constructor(props) {
+ super(props);
+ this.state = {
+ dataSource: new ListView.DataSource({
+ rowHasChanged: (row1, row2) => row1 !== row2,
+ }),
+ loaded: false,
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+```
+
+同时我们也要修改`fetchData`方法来把数据更新到dataSource里:
+
+```javascript
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
+ loaded: true,
+ });
+ });
+ }
+```
+
+最后,我们再在`styles`对象里给`ListView`添加一些样式。
+
+```javascript
+ listView: {
+ paddingTop: 20,
+ backgroundColor: '#F5FCFF',
+ },
+```
+
+现在可以体现最终的结果了:
+
+| | |
+|--|--|
+| ||
+
+为了实现一个完整功能的应用,接下来其实还有一些工作要做,譬如:添加导航器,搜索,加载更多,等等等等。可以在[Movies示例](https://github.com/facebook/react-native/tree/master/Examples/Movies)中看看我们是怎么做的。
+
+### 最终的代码
+
+```javascript
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+
+import React, {
+ Component,
+} from 'react';
+
+import {
+ AppRegistry,
+ Image,
+ ListView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+
+var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
+
+class SampleAppMovies extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ dataSource: new ListView.DataSource({
+ rowHasChanged: (row1, row2) => row1 !== row2,
+ }),
+ loaded: false,
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向会变为空
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+
+ componentDidMount() {
+ this.fetchData();
+ }
+
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
+ loaded: true,
+ });
+ });
+ }
+
+ render() {
+ if (!this.state.loaded) {
+ return this.renderLoadingView();
+ }
+
+ return (
+
+ );
+ }
+
+ renderLoadingView() {
+ return (
+
+
+ Loading movies...
+
+
+ );
+ }
+
+ renderMovie(movie) {
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ rightContainer: {
+ flex: 1,
+ },
+ title: {
+ fontSize: 20,
+ marginBottom: 8,
+ textAlign: 'center',
+ },
+ year: {
+ textAlign: 'center',
+ },
+ thumbnail: {
+ width: 53,
+ height: 81,
+ },
+ listView: {
+ paddingTop: 20,
+ backgroundColor: '#F5FCFF',
+ },
+});
+
+AppRegistry.registerComponent('SampleAppMovies', () => SampleAppMovies);
+```
diff --git a/docs/docs/0.41/scrollview.md b/docs/docs/0.41/scrollview.md
new file mode 100644
index 0000000..05ed38b
--- /dev/null
+++ b/docs/docs/0.41/scrollview.md
@@ -0,0 +1,542 @@
+一个包装了平台的ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。
+
+记住ScrollView必须有一个确定的高度才能正常工作,因为它实际上所做的就是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作)。要给一个ScrollView确定一个高度的话,要么直接给它设置高度(不建议),要么确定所有的父容器都已经绑定了高度。在视图栈的任意一个位置忘记使用`{flex:1}`都会导致错误,你可以使用元素查看器来查找问题的原因。
+
+ScrollView内部的其他响应者尚无法阻止ScrollView本身成为响应者。
+
+`ScrollView`和`ListView/FlatList`应该如何选择?ScrollView会简单粗暴地把所有子元素一次性全部渲染出来。其原理浅显易懂,使用上自然也最简单。然而这样简单的渲染逻辑自然带来了性能上的不足。想象一下你有一个特别长的列表需要显示,可能有好几屏的高度。创建和渲染那些屏幕以外的JS组件和原生视图,显然对于渲染性能和内存占用都是一种极大的拖累和浪费。
+
+这就是为什么我们还有专门的`ListView`组件。`ListView`会惰性渲染子元素,只在它们将要出现在屏幕中时开始渲染。这种惰性渲染逻辑要复杂很多,因而API在使用上也更为繁琐。除非你要渲染的数据特别少,否则你都应该尽量使用`ListView`,哪怕它们用起来更麻烦。
+
+`FlatList`是0.43版本开始新出的改进版的`ListView`,性能更优,但可能不够稳定,尚待时间考验。
+
+### 属性
+
+
+
+
+
contentContainerStyle StyleSheetPropType(ViewStylePropTypes) #
+
+
这些样式会应用到一个内层的内容容器上,所有的子视图都会包裹在内容容器内。例子:
+
return (
+ <ScrollView contentContainerStyle ={styles.contentContainer} >
+ </ScrollView >
+ ) ;
+ ...
+ var styles = StyleSheet.create({
+ contentContainer: {
+ paddingVertical: 20
+ }
+ });
+
+
+
+
+
horizontal bool #
+
+
当此属性为true的时候,所有的子视图会在水平方向上排成一行,而不是默认的在垂直方向上排成一列。默认值为false。
+
+
+
+
keyboardDismissMode enum('none', "interactive", 'on-drag') #
+
+
用户拖拽滚动视图的时候,是否要隐藏软键盘。
+
+
+
+
+
keyboardShouldPersistTaps enum('always', 'never', 'handled', false, true) #
+
如果当前界面有软键盘,那么点击scrollview后是否收起键盘,取决于本属性的设置。(译注:很多人反应TextInput无法自动失去焦点/需要点击多次切换到其他组件等等问题,其关键都是需要将TextInput放到ScrollView中再设置本属性)
+
+ 'never'(默认值),点击TextInput以外的子组件会使当前的软键盘收起。此时子元素不会收到点击事件。
+ 'always',键盘不会自动收起,ScrollView也不会捕捉点击事件,但子组件可以捕获。
+ 'handled',当点击事件被子组件捕获时,键盘不会自动收起。这样切换TextInput时键盘可以保持状态。多数带有TextInput的情况下你应该选择此项。
+ false,已过期,请使用'never'代替。
+ true,已过期,请使用'always'代替。
+
+
+
+
onContentSizeChange function #
+
此函数会在ScrollView内部可滚动内容的视图发生变化时调用。
+
调用参数为内容视图的宽和高: (contentWidth,
+ contentHeight)
+
此方法是通过绑定在内容容器上的onLayout来实现的。
+
+
+
onMomentumScrollStart?: function #
+
+
+
+
onMomentumScrollEnd?: function #
+
+
+
+
onScroll function #
+
+
在滚动的过程中,每帧最多调用一次此回调函数。调用的频率可以用scrollEventThrottle属性来控制。
+
+
+
refreshControl element #
+
+
+
+
removeClippedSubviews bool #
+
+
(实验特性):当此属性为true时,屏幕之外的子视图(子视图的overflow样式需要设为hidden)会被移除。这个可以提升大列表的滚动性能。默认值为true。
+
+
+
+
showsHorizontalScrollIndicator bool #
+
+
当此属性为true的时候,显示一个水平方向的滚动条。
+
+
+
+
showsVerticalScrollIndicator bool #
+
+
当此属性为true的时候,显示一个垂直方向的滚动条。
+
+
+
+
style style #
+
+
+
+
+
+
backfaceVisibility enum('visible', 'hidden')
+
+
+
backgroundColor string
+
+
+
borderColor string
+
+
+
borderTopColor string
+
+
+
borderRightColor string
+
+
+
borderBottomColor string
+
+
+
borderLeftColor string
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius number
+
+
+
borderTopRightRadius number
+
+
+
borderBottomLeftRadius number
+
+
+
borderBottomRightRadius number
+
+
+
borderStyle enum('solid', 'dotted', 'dashed')
+
+
+
borderWidth number
+
+
+
borderTopWidth number
+
+
+
borderRightWidth number
+
+
+
borderBottomWidth number
+
+
+
borderLeftWidth number
+
+
+
opacity number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
shadowColor string
+
+
+
shadowOffset {width: number, height: number}
+
+
+
shadowOpacity number
+
+
+
shadowRadius number
+
+
+
+
+
+
+ android endFillColor
+ color
+ #
+
+
+
有时候滚动视图会占据比实际内容更多的空间。这种情况下可以使用此属性,指定以某种颜色来填充多余的空间,以避免设置背景和创建不必要的绘制开销。一般情况下并不需要这种高级优化技巧。
+
+
+
+
android overScrollMode enum('auto', 'always', 'never') #
+
覆盖默认的overScroll模式
+
可选的值有:
+
+ 'auto' - 默认值,允许用户在内容超出视图高度之后可以滚动视图。
+
+ 'always' - 无论内容尺寸,用户始终可以滚动视图。
+ 'never' - 始终不允许用户滚动视图。
+
+
+
+
+
android scrollPerfTag
+ string #
+
Tag used to log scroll performance on this scroll view. Will force
+ momentum events to be turned on (see sendMomentumEvents). This doesn't do
+ anything out of the box and you need to implement a custom native
+ FpsListener for it to be useful.
+
+
+
+
ios alwaysBounceHorizontal bool #
+
+
当此属性为true时,水平方向即使内容比滚动视图本身还要小,也可以弹性地拉动一截。当horizontal={true}时默认值为true,否则为false。
+
+
+
+
ios alwaysBounceVertical bool #
+
+
当此属性为true时,垂直方向即使内容比滚动视图本身还要小,也可以弹性地拉动一截。当horizontal={true}时默认值为false,否则为true。
+
+
+
+
ios automaticallyAdjustContentInsets bool #
+
+
当滚动视图放在一个导航条或者工具条后面的时候,iOS系统是否要自动调整内容的范围。默认值为true。(译注:如果你的ScrollView或ListView的头部出现莫名其妙的空白,尝试将此属性置为false)
+
+
+
+
ios bounces bool #
+
+
当值为true时,如果内容范围比滚动视图本身大,在到达内容末尾的时候,可以弹性地拉动一截。如果为false,尾部的所有弹性都会被禁用,即使alwaysBounce属性为true。默认值为true。
+
+
+
+
ios bouncesZoom bool #
+
+
当值为true时,使用手势缩放内容可以超过min/max的限制,然后在手指抬起之后弹回min/max的缩放比例。否则的话,缩放不能超过限制。
+
+
+
+
ios canCancelContentTouches bool #
+
+
当值为false时,一旦有子节点响应触摸操作,即使手指开始移动也不会拖动滚动视图。默认值为true(在以上情况下可以拖动滚动视图。)
+
+
+
+
ios centerContent bool #
+
+
当值为true时,如果滚动视图的内容比视图本身小,则会自动把内容居中放置。当内容比滚动视图大的时候,此属性没有作用。默认值为false。
+
+
+
+
ios contentInset {top: number, left: number, bottom: number, right: number} #
+
+
内容范围相对滚动视图边缘的坐标。默认为{0, 0, 0, 0}。
+
+
+
+
ios contentOffset PointPropType #
+
+
用来手动设置初始的滚动坐标。默认值为{x: 0, y: 0}。
+
+
+
+
ios decelerationRate number #
+
+
一个浮点数,用于决定当用户抬起手指之后,滚动视图减速停下的速度。常见的选项有:
+
+ Normal: 0.998 (默认值)
+ Fast: 0.9
+
+
+
+
+
ios directionalLockEnabled bool #
+
+
当值为真时,滚动视图在拖拽的时候会锁定只有垂直或水平方向可以滚动。默认值为false。
+
+
+
+
ios indicatorStyle
+ enum('default', 'black', 'white') #
+
+
设置滚动条的样式。
+
+ default,默认值,等同black.
+ black,黑色滚动条。
+ white,白色滚动条。
+
+
+
+
+
ios maximumZoomScale number #
+
+
+
+
ios minimumZoomScale number #
+
+
+
+
ios onRefreshStart function #
+
+
已过期
+
请使用refreshControl 属性代替。
+
+
+
+
+
+
pagingEnabled bool #
+
+
当值为true时,滚动条会停在滚动视图的尺寸的整数倍位置。这个可以用在水平分页上。默认值为false。
+
+
+
+
scrollEnabled bool #
+
+
当值为false的时候,内容不能滚动,默认值为true。
+
+
+
+
ios scrollEventThrottle number #
+
+
这个属性控制在滚动过程中,scroll事件被调用的频率(单位是每秒事件数量)。更大的数值能够更及时的跟踪滚动位置,不过可能会带来性能问题,因为更多的信息会通过bridge传递。默认值为0,意味着每次视图被滚动,scroll事件只会被调用一次。
+
+
+
+
ios scrollIndicatorInsets {top: number, left: number, bottom: number, right: number} #
+
+
决定滚动条距离视图边缘的坐标。这个值应该和contentInset一样。默认值为{0, 0, 0, 0}。
+
+
+
+
ios scrollsToTop bool #
+
+
当此值为true时,点击状态栏的时候视图会滚动到顶部。默认值为true。
+
+
+
+
ios snapToAlignment enum('start', "center", 'end') #
+
+
当设置了snapToInterval,snapToAlignment会定义停驻点与滚动视图之间的关系。
+
+
+
+
+
ios snapToInterval number #
+
+
当设置了此属性时,会让滚动视图滚动停止后,停止在snapToInterval的倍数的位置。这可以在一些子视图比滚动视图本身小的时候用于实现分页显示。与snapToAlignment组合使用。
+
+
+
+
stickyHeaderIndices [number] #
+
+
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。举个例子,传递stickyHeaderIndices={[0]}会让第一个成员固定在滚动视图顶端。这个属性不能和horizontal={true}一起使用。
+
+
+
+
ios zoomScale number #
+
+
滚动视图内容初始的缩放比例。默认值为1.0。
+
+
+
+
+
+### 方法
+
+
scrollTo(y: number | { x?: number, y?: number, animated?: boolean }, x: number, animated: boolean)
+ #
+
滚动到指定的x, y偏移处。第三个参数为是否启用平滑滚动动画。
+
使用示例:
+
scrollTo({x: 0, y: 0, animated: true})
+
+
scrollToEnd(options?) #
+
+
滚动到视图底部(水平方向的视图则滚动到最右边)。
加上动画参数 scrollToEnd({animated: true})则启用平滑滚动动画,或是调用
+scrollToEnd({animated: false})来立即跳转。如果不使用参数,则animated选项默认启用。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ScrollView,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+ Image
+} = ReactNative;
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Component that enables scrolling through child components';
+exports.examples = [
+{
+ title: '',
+ description: 'To make content scrollable, wrap it within a component',
+ render: function() {
+ var _scrollView: ScrollView;
+ return (
+
+ { _scrollView = scrollView; }}
+ automaticallyAdjustContentInsets={false}
+ onScroll={() => { console.log('onScroll!'); }}
+ scrollEventThrottle={200}
+ style={styles.scrollView}>
+ {THUMBS.map(createThumbRow)}
+
+ { _scrollView.scrollTo({y: 0}); }}>
+ Scroll to top
+
+ { _scrollView.scrollToEnd({animated: true}); }}>
+ Scroll to bottom
+
+
+ );
+ }
+}, {
+ title: ' (horizontal = true)',
+ description: 'You can display \'s child components horizontally rather than vertically',
+ render: function() {
+ var _scrollView: ScrollView;
+ return (
+
+ { _scrollView = scrollView; }}
+ automaticallyAdjustContentInsets={false}
+ horizontal={true}
+ style={[styles.scrollView, styles.horizontalScrollView]}>
+ {THUMBS.map(createThumbRow)}
+
+ { _scrollView.scrollTo({x: 0}); }}>
+ Scroll to start
+
+ { _scrollView.scrollToEnd({animated: true}); }}>
+ Scroll to end
+
+
+ );
+ }
+}];
+
+class Thumb extends React.Component {
+ shouldComponentUpdate(nextProps, nextState) {
+ return false;
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+var THUMBS = ['https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851549_767334479959628_274486868_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851561_767334496626293_1958532586_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851579_767334503292959_179092627_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851589_767334513292958_1747022277_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851563_767334559959620_1193692107_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851593_767334566626286_1953955109_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851591_767334523292957_797560749_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851567_767334529959623_843148472_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851548_767334489959627_794462220_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851575_767334539959622_441598241_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851573_767334549959621_534583464_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851583_767334573292952_1519550680_n.png'];
+THUMBS = THUMBS.concat(THUMBS); // double length of THUMBS
+var createThumbRow = (uri, i) => ;
+
+var styles = StyleSheet.create({
+ scrollView: {
+ backgroundColor: '#6A85B1',
+ height: 300,
+ },
+ horizontalScrollView: {
+ height: 120,
+ },
+ containerPage: {
+ height: 50,
+ width: 50,
+ backgroundColor: '#527FE4',
+ padding: 5,
+ },
+ text: {
+ fontSize: 20,
+ color: '#888888',
+ left: 80,
+ top: 20,
+ height: 40,
+ },
+ button: {
+ margin: 7,
+ padding: 5,
+ alignItems: 'center',
+ backgroundColor: '#eaeaea',
+ borderRadius: 3,
+ },
+ buttonContents: {
+ flexDirection: 'row',
+ width: 64,
+ height: 64,
+ },
+ img: {
+ width: 64,
+ height: 64,
+ }
+});
+```
diff --git a/docs/docs/0.41/segmentedcontrolios.md b/docs/docs/0.41/segmentedcontrolios.md
new file mode 100644
index 0000000..bd5c6ba
--- /dev/null
+++ b/docs/docs/0.41/segmentedcontrolios.md
@@ -0,0 +1,214 @@
+使用`SegmentedControlIOS`来在iOS设备上渲染一个`UISegmentedControl`组件。这是一个分段显示多个选项的组件。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
enabled bool #
+
+
如果为false,用户不能与此控件交互。默认为true。
+
+
+
+
momentary bool #
+
+
如果为true,选中的段不会一直保持特效。但onValueChange回调还是会正常工作。
+
+
+
+
onChange function #
+
+
当用户点击某一段的时候调用。参数是一个事件对象。
+
+
+
+
onValueChange function #
+
+
当用户点击某一段的时候调用。参数是被选中段的值。
+
+
+
+
selectedIndex number #
+
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ SegmentedControlIOS,
+ Text,
+ View,
+ StyleSheet
+} = ReactNative;
+
+var BasicSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+});
+
+var PreSelectedSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+});
+
+var MomentarySegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+});
+
+var DisabledSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ },
+});
+
+var ColorSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+var EventSegmentedControlExample = React.createClass({
+ getInitialState() {
+ return {
+ values: ['One', 'Two', 'Three'],
+ value: 'Not selected',
+ selectedIndex: undefined
+ };
+ },
+
+ render() {
+ return (
+
+
+ Value: {this.state.value}
+
+
+ Index: {this.state.selectedIndex}
+
+
+
+ );
+ },
+
+ _onChange(event) {
+ this.setState({
+ selectedIndex: event.nativeEvent.selectedSegmentIndex,
+ });
+ },
+
+ _onValueChange(value) {
+ this.setState({
+ value: value,
+ });
+ }
+});
+
+var styles = StyleSheet.create({
+ text: {
+ fontSize: 14,
+ textAlign: 'center',
+ fontWeight: '500',
+ margin: 10,
+ },
+});
+
+exports.title = '';
+exports.displayName = 'SegmentedControlExample';
+exports.description = 'Native segmented control';
+exports.examples = [
+ {
+ title: 'Segmented controls can have values',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can have a pre-selected value',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can be momentary',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can be disabled',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Custom colors can be provided',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Change events can be detected',
+ render(): ReactElement { return ; }
+ }
+];
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/shadow-props.md b/docs/docs/0.41/shadow-props.md
new file mode 100644
index 0000000..fa31388
--- /dev/null
+++ b/docs/docs/0.41/shadow-props.md
@@ -0,0 +1,22 @@
+### 属性
+
+
+
ios shadowColor
+ color #
+
+
+
+
ios shadowOffset
+ {width: number, height: number} #
+
+
+
+
ios shadowOpacity
+ number #
+
+
+
ios shadowRadius
+ number #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/share.md b/docs/docs/0.41/share.md
new file mode 100644
index 0000000..d4cd169
--- /dev/null
+++ b/docs/docs/0.41/share.md
@@ -0,0 +1,162 @@
+### 方法
+
+
+
static share(content, options) #
+
Open a dialog to share text content.
+
In iOS, Returns a Promise which will be invoked an object containing action, activityType.
+ If the user dismissed the dialog, the Promise will still be resolved with action being Share.dismissedAction
+ and all the other keys being undefined.
+
In Android, Returns a Promise which always be resolved with action being Share.sharedAction.
+
+
Content #
+
+
+ message - a message to share
+ title - title of the message
+
+
iOS #
+
+ url - an URL to share
+
+
At least one of URL and message is required.
+
Options #
+ iOS #
+
+ excludedActivityTypes
+ tintColor
+
+
Android #
+
+
+
+
+
static sharedAction() #
+
+
The content was successfully shared.
+
+
static dismissedAction() #
+
The dialog has been dismissed.
+ @platform ios
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ Share,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Share';
+exports.description = 'Share data with other Apps.';
+exports.examples = [{
+ title: 'Share Text Content',
+ render() {
+ return ;
+ }
+}];
+
+class ShareMessageExample extends React.Component {
+ _shareMessage: Function;
+ _shareText: Function;
+ _showResult: Function;
+ state: any;
+
+ constructor(props) {
+ super(props);
+
+ this._shareMessage = this._shareMessage.bind(this);
+ this._shareText = this._shareText.bind(this);
+ this._showResult = this._showResult.bind(this);
+
+ this.state = {
+ result: ''
+ };
+ }
+
+ render() {
+ return (
+
+
+
+ Click to share message
+
+
+
+
+ Click to share message, URL and title
+
+
+ {this.state.result}
+
+ );
+ }
+
+ _shareMessage() {
+ Share.share({
+ message: 'React Native | A framework for building native apps using React'
+ })
+ .then(this._showResult)
+ .catch((error) => this.setState({result: 'error: ' + error.message}));
+ }
+
+ _shareText() {
+ Share.share({
+ message: 'A framework for building native apps using React',
+ url: 'http://facebook.github.io/react-native/',
+ title: 'React Native'
+ }, {
+ dialogTitle: 'Share React Native website',
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ],
+ tintColor: 'green'
+ })
+ .then(this._showResult)
+ .catch((error) => this.setState({result: 'error: ' + error.message}));
+ }
+
+ _showResult(result) {
+ if (result.action === Share.sharedAction) {
+ if (result.activityType) {
+ this.setState({result: 'shared with an activityType: ' + result.activityType});
+ } else {
+ this.setState({result: 'shared'});
+ }
+ } else if (result.action === Share.dismissedAction) {
+ this.setState({result: 'dismissed'});
+ }
+ }
+
+}
+
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/signed-apk-android.md b/docs/docs/0.41/signed-apk-android.md
new file mode 100644
index 0000000..32e7036
--- /dev/null
+++ b/docs/docs/0.41/signed-apk-android.md
@@ -0,0 +1,107 @@
+Android要求所有应用都有一个数字签名才会被允许安装在用户手机上,所以在把应用发布到类似[Google Play store](https://play.google.com/store)这样的应用市场之前,你需要先生成一个签名的APK包。Android开发者官网上的[如何给你的应用签名](https://developer.android.com/tools/publishing/app-signing.html)文档描述了签名的细节。本指南旨在提供一个简化的签名和打包js的操作步骤,不会涉及太多理论。
+
+### 生成一个签名密钥
+
+你可以用`keytool`命令生成一个私有密钥。在Windows上`keytool`命令放在JDK的bin目录中(比如`C:\Program Files\Java\jdkx.x.x_x\bin`),你可能需要在命令行中先进入那个目录才能执行此命令。
+
+ $ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
+
+这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息。最后它会生成一个叫做`my-release-key.keystore`的密钥库文件。
+
+在运行上面这条语句之后,密钥库里应该已经生成了一个单独的密钥,有效期为10000天。--alias参数后面的别名是你将来为应用签名时所需要用到的,所以记得记录这个别名。
+
+**注意:请记得妥善地保管好你的密钥库文件,不要上传到版本库或者其它的地方。**
+
+### 设置gradle变量
+
+1. 把`my-release-key.keystore`文件放到你工程中的`android/app`文件夹下。
+2. 编辑`~/.gradle/gradle.properties`(没有这个文件你就创建一个),添加如下的代码(注意把其中的`****`替换为相应密码)
+
+**注意:~表示用户目录,比如windows上可能是`C:\Users\用户名`,而mac上可能是`/Users/用户名`。**
+
+```
+MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
+MYAPP_RELEASE_KEY_ALIAS=my-key-alias
+MYAPP_RELEASE_STORE_PASSWORD=*****
+MYAPP_RELEASE_KEY_PASSWORD=*****
+```
+
+上面的这些会作为全局的gradle变量,我们在后面的步骤中可以用来给应用签名。
+
+
+> __关于密钥库的注意事项:__
+
+> 一旦你在Play Store发布了你的应用,如果想修改签名,就必须用一个不同的包名来重新发布你的应用(这样也会丢失所有的下载数和评分)。所以请务必备份好你的密钥库和密码。
+
+提示:如果你不想以明文方式保存密码,同时你使用的是macOS系统,那么你也可以把密码[保存到钥匙串(Keychain)中](https://pilloxa.gitlab.io/posts/safer-passwords-in-gradle/)。这样一来你就可以省略掉上面配置中的后两行(即MYAPP_RELEASE_STORE_PASSWORD和MYAPP_RELEASE_KEY_PASSWORD)。
+
+
+### 添加签名到项目的gradle配置文件
+
+编辑你项目目录下的`android/app/build.gradle`,添加如下的签名配置:
+
+```gradle
+...
+android {
+ ...
+ defaultConfig { ... }
+ signingConfigs {
+ release {
+ storeFile file(MYAPP_RELEASE_STORE_FILE)
+ storePassword MYAPP_RELEASE_STORE_PASSWORD
+ keyAlias MYAPP_RELEASE_KEY_ALIAS
+ keyPassword MYAPP_RELEASE_KEY_PASSWORD
+ }
+ }
+ buildTypes {
+ release {
+ ...
+ signingConfig signingConfigs.release
+ }
+ }
+}
+...
+```
+
+### 生成发行APK包
+
+只需在终端中运行以下命令:
+
+```sh
+$ cd android && ./gradlew assembleRelease
+```
+
+译注:cd android表示进入android目录(如果你已经在android目录中了那就不用输入了)。`./gradlew assembleRelease`在macOS和Linux系统中表示执行当前目录下的名为gradlew的脚本文件,运行参数为assembleRelease,注意这个`./`不可省略;而在windows命令行下则需要去掉`./`。
+
+Gradle的`assembleRelease`参数会把所有用到的JavaScript代码都打包到一起,然后内置到APK包中。如果你想调整下这个行为(比如js代码以及静态资源打包的默认文件名或是目录结构等),可以看看`android/app/build.gradle`文件,然后琢磨下应该怎么修改以满足你的需求。
+
+生成的APK文件位于`android/app/build/outputs/apk/app-release.apk`,它已经可以用来发布了。
+
+
+### 测试应用的发行版本
+
+在把发行版本提交到Play Store之前,你应该做一次最终测试。输入以下命令可以在设备上安装发行版本:
+
+```sh
+$ cd android && ./gradlew installRelease
+```
+
+注意`installRelease`参数只能在你完成了上面的签名配置之后才可以使用。
+你现在可以关掉运行中的packager了,因为你所有的代码和框架依赖已经都被打包到apk包中,可以离线运行了。
+
+> 在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
+### 启用Proguard代码混淆来缩小APK文件的大小(可选)
+
+Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少APK的大小。
+
+**重要**:启用Proguard之后,你必须再次全面地测试你的应用。Proguard有时候需要为你引入的每个原生库做一些额外的配置。参见`app/proguard-rules.pro`文件。
+
+要启用Proguard,设置`minifyEnabled`选项为`true`:
+
+```gradle
+/**
+ * 在release发行版中启用Proguard来减小 to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = true
+```
diff --git a/docs/docs/0.41/slider.md b/docs/docs/0.41/slider.md
new file mode 100644
index 0000000..4f4474e
--- /dev/null
+++ b/docs/docs/0.41/slider.md
@@ -0,0 +1,251 @@
+用于选择一个范围值的组件。
+
+### 属性
+
+
+
+
+
disabled bool #
+
+
如果为true,用户就不能移动滑块。默认为false。
+
+
+
+
ios maximumTrackImage Image.propTypes.source #
+
指定一个滑块右侧轨道背景图。仅支持静态图片。图片最左边的像素会被平铺直至填满轨道。
+
+
maximumTrackTintColor string #
+
+
滑块右侧轨道的颜色。默认为一个蓝色的渐变色。
+
+
+
+
ios maximumValue number #
+
+
滑块的最大值(当滑块滑到最右端时表示的值)。默认为1。
+
+
+
+
ios minimumTrackImage Image.propTypes.source #
+
指定一个滑块左侧轨道背景图。仅支持静态图片。图片最右边的像素会被平铺直至填满轨道。
+
+
minimumTrackTintColor string #
+
+
滑块左侧轨道的颜色。默认为一个蓝色的渐变色。
+
+
+
+
ios minimumValue number #
+
+
滑块的最小值(当滑块滑到最左侧时表示的值)。默认为0。
+
+
+
+
onSlidingComplete function #
+
+
+
+
onValueChange function #
+
+
+
+
step number #
+
+
滑块的最小步长。这个值应该在0到(maximumValue - minimumValue)之间。默认值为0。
+
+
+
+
+
thumbImage Image.propTypes.source #
+
+
+
+
android thumbTintColor ColorPropType #
+
+
Color of the foreground switch grip.
+
+
+
+
trackImage Image.propTypes.source #
+
+
给轨道设置一张背景图。只支持静态图片。图片最中央的像素会被平铺直至填满轨道。
+
+
+
+
value number #
+
+
滑块的初始值。这个值应该在最小值和最大值之间。默认值是0。
+
这不是一个受约束的组件。 也就是说,如果你不更新值,在用户操作后,这个组件也不会还原到初始值。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Slider,
+ Text,
+ StyleSheet,
+ View,
+} = ReactNative;
+
+var SliderExample = React.createClass({
+ getDefaultProps() {
+ return {
+ value: 0,
+ }
+ },
+
+ getInitialState() {
+ return {
+ value: this.props.value,
+ };
+ },
+
+ render() {
+ return (
+
+
+ {this.state.value && +this.state.value.toFixed(3)}
+
+ this.setState({value: value})} />
+
+ );
+ }
+});
+
+var SlidingCompleteExample = React.createClass({
+ getInitialState() {
+ return {
+ slideCompletionValue: 0,
+ slideCompletionCount: 0,
+ };
+ },
+
+ render() {
+ return (
+
+ this.setState({
+ slideCompletionValue: value,
+ slideCompletionCount: this.state.slideCompletionCount + 1})} />
+
+ Completions: {this.state.slideCompletionCount} Value: {this.state.slideCompletionValue}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ slider: {
+ height: 10,
+ margin: 10,
+ },
+ text: {
+ fontSize: 14,
+ textAlign: 'center',
+ fontWeight: '500',
+ margin: 10,
+ },
+});
+
+exports.title = '';
+exports.displayName = 'SliderExample';
+exports.description = 'Slider input for numeric values';
+exports.examples = [
+ {
+ title: 'Default settings',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Initial value: 0.5',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'minimumValue: -1, maximumValue: 2',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'step: 0.25',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'onSlidingComplete',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Custom min/max track tint color',
+ platform: 'ios',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Custom thumb image',
+ platform: 'ios',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Custom track image',
+ platform: 'ios',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Custom min/max track image',
+ platform: 'ios',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+];
+```
diff --git a/docs/docs/0.41/state.md b/docs/docs/0.41/state.md
new file mode 100644
index 0000000..f08ea2f
--- /dev/null
+++ b/docs/docs/0.41/state.md
@@ -0,0 +1,51 @@
+我们使用两种数据来控制一个组件:`props`和`state`。`props`是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用`state`。
+
+一般来说,你需要在constructor中初始化`state`(译注:这是ES6的写法,早期的很多ES5的例子使用的是getInitialState方法来初始化state,这一做法会逐渐被淘汰),然后在需要修改时调用`setState`方法。
+
+假如我们需要制作一段不停闪烁的文字。文字内容本身在组件创建时就已经指定好了,所以文字内容应该是一个`prop`。而文字的显示或隐藏的状态(快速的显隐切换就产生了闪烁的效果)则是随着时间变化的,因此这一状态应该写到`state`中。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+class Blink extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showText: true };
+
+ // 每1000毫秒对showText状态做一次取反操作
+ setInterval(() => {
+ this.setState({ showText: !this.state.showText });
+ }, 1000);
+ }
+
+ render() {
+ // 根据当前showText的值决定是否显示text内容
+ let display = this.state.showText ? this.props.text : ' ';
+ return (
+ {display}
+ );
+ }
+}
+
+class BlinkApp extends Component {
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('BlinkApp', () => BlinkApp);
+```
+
+实际开发中,我们一般不会在定时器函数(setInterval、setTimeout等)中来操作state。典型的场景是在接收到服务器返回的新数据,或者在用户输入数据之后。你也可以使用一些“状态容器”比如[Redux](http://redux.js.org/index.html)来统一管理数据流(译注:但我们不建议新手过早去学习redux)。
+
+State的工作原理和React.js完全一致,所以对于处理state的一些更深入的细节,你可以参阅[React.Component API](https://facebook.github.io/react/docs/component-api.html)。
+
+看到这里,你可能觉得我们的例子总是千篇一律的黑色文本,太特么无聊了。那么我们一起来[学习一下样式](style.html)吧。
diff --git a/docs/docs/0.41/statusbar.md b/docs/docs/0.41/statusbar.md
new file mode 100644
index 0000000..52ae9ab
--- /dev/null
+++ b/docs/docs/0.41/statusbar.md
@@ -0,0 +1,522 @@
+用于控制应用状态栏的组件。
+
+### 与Navigator搭配的用法
+`StatusBar`组件可以同时加载多个。此时属性会按照加载顺序合并(后者覆盖前者)。一个典型的用法就是在使用`Navigator`时,针对不同的路由指定不同的状态栏样式,如下:
+```js
+
+
+
+
+
+ ...
+
+ }
+ />
+
+```
+
+### 常量
+
+`currentHeight` 状态栏的当前高度。
+
+
+### 属性
+
+
+
animated bool #
+
指定状态栏的变化是否应以动画形式呈现。目前支持这几种样式:backgroundColor, barStyle和hidden。
+
+
+
android backgroundColor color
+ #
+
+
+
android translucent bool #
+
+
指定状态栏是否透明。设置为true时,应用会在状态栏之下绘制(即所谓“沉浸式”——被状态栏遮住一部分)。常和带有半透明背景色的状态栏搭配使用。
+
+
barStyle
+ enum('default', 'light-content', 'dark-content') #
+
+
+
ios networkActivityIndicatorVisible bool #
+
+
+
ios showHideTransition enum('fade', 'slide') #
+
通过hidden属性来显示或隐藏状态栏时所使用的动画效果。默认值为'fade'。
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Component for controlling the status bar';
+
+const colors = [
+ '#ff0000',
+ '#00ff00',
+ '#0000ff',
+];
+
+const barStyles = [
+ 'default',
+ 'light-content',
+];
+
+const showHideTransitions = [
+ 'fade',
+ 'slide',
+];
+
+function getValue(values: Array, index: number): T {
+ return values[index % values.length];
+}
+
+const StatusBarHiddenExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ hidden: false,
+ showHideTransition: getValue(showHideTransitions, 0),
+ };
+ },
+
+ _showHideTransitionIndex: 0,
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ _onChangeHidden() {
+ this.setState({hidden: !this.state.hidden});
+ },
+
+ _onChangeTransition() {
+ this._showHideTransitionIndex++;
+ this.setState({
+ showHideTransition: getValue(showHideTransitions, this._showHideTransitionIndex),
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+ hidden: {this.state.hidden ? 'true' : 'false'}
+
+
+
+
+ animated (ios only): {this.state.animated ? 'true' : 'false'}
+
+
+
+
+
+ showHideTransition (ios only):
+ '{getValue(showHideTransitions, this._showHideTransitionIndex)}'
+
+
+
+
+ );
+ },
+});
+
+const StatusBarStyleExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ barStyle: getValue(barStyles, this._barStyleIndex),
+ };
+ },
+
+ _barStyleIndex: 0,
+
+ _onChangeBarStyle() {
+ this._barStyleIndex++;
+ this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
+ },
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ render() {
+ return (
+
+
+
+
+ style: '{getValue(barStyles, this._barStyleIndex)}'
+
+
+
+
+ animated: {this.state.animated ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+const StatusBarNetworkActivityExample = React.createClass({
+ getInitialState() {
+ return {
+ networkActivityIndicatorVisible: false,
+ };
+ },
+
+ _onChangeNetworkIndicatorVisible() {
+ this.setState({
+ networkActivityIndicatorVisible: !this.state.networkActivityIndicatorVisible,
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+
+ networkActivityIndicatorVisible:
+ {this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
+
+
+
+
+ );
+ },
+});
+
+const StatusBarBackgroundColorExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ backgroundColor: getValue(colors, 0),
+ };
+ },
+
+ _colorIndex: 0,
+
+ _onChangeBackgroundColor() {
+ this._colorIndex++;
+ this.setState({backgroundColor: getValue(colors, this._colorIndex)});
+ },
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ render() {
+ return (
+
+
+
+
+ backgroundColor: '{getValue(colors, this._colorIndex)}'
+
+
+
+
+ animated: {this.state.animated ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+
+const StatusBarTranslucentExample = React.createClass({
+ getInitialState() {
+ return {
+ translucent: false,
+ };
+ },
+
+ _onChangeTranslucent() {
+ this.setState({
+ translucent: !this.state.translucent,
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+ translucent: {this.state.translucent ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+const StatusBarStaticIOSExample = React.createClass({
+ render() {
+ return (
+
+ {
+ StatusBar.setHidden(true, 'slide');
+ }}>
+
+ setHidden(true, 'slide')
+
+
+ {
+ StatusBar.setHidden(false, 'fade');
+ }}>
+
+ setHidden(false, 'fade')
+
+
+ {
+ StatusBar.setBarStyle('default', true);
+ }}>
+
+ setBarStyle('default', true)
+
+
+ {
+ StatusBar.setBarStyle('light-content', true);
+ }}>
+
+ setBarStyle('light-content', true)
+
+
+ {
+ StatusBar.setNetworkActivityIndicatorVisible(true);
+ }}>
+
+ setNetworkActivityIndicatorVisible(true)
+
+
+ {
+ StatusBar.setNetworkActivityIndicatorVisible(false);
+ }}>
+
+ setNetworkActivityIndicatorVisible(false)
+
+
+
+ );
+ },
+});
+
+const StatusBarStaticAndroidExample = React.createClass({
+ render() {
+ return (
+
+ {
+ StatusBar.setHidden(true);
+ }}>
+
+ setHidden(true)
+
+
+ {
+ StatusBar.setHidden(false);
+ }}>
+
+ setHidden(false)
+
+
+ {
+ StatusBar.setBackgroundColor('#ff00ff', true);
+ }}>
+
+ setBackgroundColor('#ff00ff', true)
+
+
+ {
+ StatusBar.setBackgroundColor('#00ff00', true);
+ }}>
+
+ setBackgroundColor('#00ff00', true)
+
+
+ {
+ StatusBar.setTranslucent(true);
+ StatusBar.setBackgroundColor('rgba(0, 0, 0, 0.4)', true);
+ }}>
+
+ setTranslucent(true) and setBackgroundColor('rgba(0, 0, 0, 0.4)', true)
+
+
+ {
+ StatusBar.setTranslucent(false);
+ StatusBar.setBackgroundColor('black', true);
+ }}>
+
+ setTranslucent(false) and setBackgroundColor('black', true)
+
+
+
+ );
+ },
+});
+
+const examples = [{
+ title: 'StatusBar hidden',
+ render() {
+ return ;
+ },
+}, {
+ title: 'StatusBar style',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar network activity indicator',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar background color',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar background color',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar static API',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar static API',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar dimensions',
+ render() {
+ return (
+
+ Height: {StatusBar.currentHeight} pts
+
+ );
+ }
+}];
+
+exports.examples = examples;
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ borderRadius: 5,
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+ title: {
+ marginTop: 16,
+ marginBottom: 8,
+ fontWeight: 'bold',
+ }
+});
+```
diff --git a/docs/docs/0.41/style.md b/docs/docs/0.41/style.md
new file mode 100644
index 0000000..09fc6d6
--- /dev/null
+++ b/docs/docs/0.41/style.md
@@ -0,0 +1,42 @@
+在React Native中,你并不需要学习什么特殊的语法来定义样式。我们仍然是使用JavaScript来写样式。所有的核心组件都接受名为`style`的属性。这些样式名基本上是遵循了web上的CSS的命名,只是按照JS的语法要求使用了驼峰命名法,例如将`background-color`改为`backgroundColor`。
+
+`style`属性可以是一个普通的JavaScript对象。这是最简单的用法,因而在示例代码中很常见。你还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
+
+实际开发中组件的样式会越来越复杂,我们建议使用`StyleSheet.create`来集中定义组件的样式。比如像下面这样:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, StyleSheet, Text, View } from 'react-native';
+
+class LotsOfStyles extends Component {
+ render() {
+ return (
+
+ just red
+ just bigblue
+ bigblue, then red
+ red, then bigblue
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ bigblue: {
+ color: 'blue',
+ fontWeight: 'bold',
+ fontSize: 30,
+ },
+ red: {
+ color: 'red',
+ },
+});
+
+AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
+```
+
+常见的做法是按顺序声明和使用`style`属性,以借鉴CSS中的“层叠”做法(即后声明的属性会覆盖先声明的同名属性)。
+
+文本的样式定义请参阅[Text组件的文档](text.html)。
+
+现在你已经了解如何调整文本样式了,下面我们要学习的是[如何控制组件的尺寸](height-and-width.html)。
diff --git a/docs/docs/0.41/stylesheet.md b/docs/docs/0.41/stylesheet.md
new file mode 100644
index 0000000..1309da6
--- /dev/null
+++ b/docs/docs/0.41/stylesheet.md
@@ -0,0 +1,124 @@
+StyleSheet提供了一种类似CSS样式表的抽象。
+
+创建一个样式表:
+
+```javascript
+var styles = StyleSheet.create({
+ container: {
+ borderRadius: 4,
+ borderWidth: 0.5,
+ borderColor: '#d6d7da',
+ },
+ title: {
+ fontSize: 19,
+ fontWeight: 'bold',
+ },
+ activeTitle: {
+ color: 'red',
+ },
+});
+```
+
+使用一个样式表:
+
+```javascript
+
+
+
+```
+
+从代码质量角度:
+
+* 从render函数中移除具体的样式内容,可以使代码更清晰易懂。
+* 给样式命名也是对render函数中的原始组件的作用的一种标记。
+
+从性能角度:
+
+* 创建一个样式表,就可以使得我们后续更容易通过ID来引用样式,而不是每次都创建一个新的对象。
+* 它还使得样式只会在JavaScript和原生之间传递一次,随后的过程都可以只传递一个ID(这个优化还未实现)。
+
+### 方法
+
+
+
static create(obj: {[key: string]: any}) #
+
+
+### 属性
+
+
+
hairlineWidth: CallExpression #
+
这一常量定义了当前平台上的最细的宽度。可以用作边框或是两个元素间的分隔线。例如:
+
{
+ borderBottomColor: '#bbb' ,
+ borderBottomWidth: StyleSheet. hairlineWidth
+ }
+
这一常量始终是一个整数的像素值(线看起来会像头发丝一样细),并会尽量符合当前平台最细的线的标准。然而,你不能把它“视为一个常量”,因为不同的平台和不同的屏幕像素密度会导致不同的结果。
+
+
absoluteFill: CallExpression
+ #
+
A very common pattern is to create overlays with position absolute and zero positioning,
+ so absoluteFill can be used for convenience and to reduce duplication of these repeated
+ styles.
+
+
absoluteFillObject: ObjectExpression #
+
Sometimes you may want absoluteFill but with a couple tweaks - absoluteFillObject
+ can be
+ used to create a customized entry in a StyleSheet, e.g.:
+
const styles = StyleSheet.create({
+ wrapper: {
+ ...StyleSheet.absoluteFillObject,
+ top: 10,
+ backgroundColor: 'transparent',
+ },
+ });
+
+
flatten: CallExpression
+ #
+
Flattens an array of style objects, into one aggregated style object.
+ Alternatively, this method can be used to lookup IDs, returned by
+ StyleSheet.register.
+
NOTE : Exercise caution as abusing this can tax you in terms of
+ optimizations.
+ IDs enable optimizations through the bridge and memory in general. Refering
+ to style objects directly will deprive you of these optimizations.
+
Example:
+
var styles = StyleSheet. create( {
+ listItem: {
+ flex: 1 ,
+ fontSize: 16 ,
+ color: 'white'
+ } ,
+ selectedListItem: {
+ color: 'green'
+ }
+ } ) ;
+
+ StyleSheet. flatten( [ styles. listItem,
+ styles. selectedListItem])
+
Alternative use:
+
StyleSheet. flatten( styles. listItem) ;
+
This method internally uses StyleSheetRegistry.getStyleByID(style)
+ to resolve style objects represented by IDs. Thus, an array of style
+ objects (instances of StyleSheet.create), are individually resolved to,
+ their respective objects, merged as one and then returned. This also explains
+ the alternative use.
+
+
+
diff --git a/docs/docs/0.41/switch.md b/docs/docs/0.41/switch.md
new file mode 100644
index 0000000..56a8040
--- /dev/null
+++ b/docs/docs/0.41/switch.md
@@ -0,0 +1,54 @@
+跨平台通用的可以在两个状态中切换的组件。
+注意这是一个“受控组件”(controlled component)。你必须使用`onValueChange`回调来更新`value`属性以响应用户的操作。如果不更新`value`属性,组件只会按一开始给定的`value`值来渲染且保持不变,看上去就像完全点不动。
+
+@keyword checkbox @keyword toggle @keyword 单选 @keyword 多选
+
+### 截图
+
+
+
+
+### 属性
+
+
+
+
+
+
onValueChange function #
+
+
当值改变的时候调用此回调函数,参数为新的值。
+
+
+
+
+
value bool #
+
+
表示此开关是否打开。默认为false(关闭状态)。
+
+
+
+
onTintColor ColorPropType #
+
+
+
+
thumbTintColor ColorPropType #
+
+
+
+
tintColor ColorPropType #
+
关闭状态时的边框颜色(iOS)或背景颜色(Android)。
+
+
+
diff --git a/docs/docs/0.41/systrace.md b/docs/docs/0.41/systrace.md
new file mode 100644
index 0000000..fecbe8c
--- /dev/null
+++ b/docs/docs/0.41/systrace.md
@@ -0,0 +1,67 @@
+### 方法
+
+
+
static setEnabled(enabled) #
+
+
static beginEvent(profileName?, args?) #
+
beginEvent/endEvent for starting and then ending a profile within the same call stack frame
+
+
+
static beginAsyncEvent(profileName?) #
+
beginAsyncEvent/endAsyncEvent for starting and then ending a profile where the end can either
+ occur on another thread or out of the current stack frame, eg await
+ the returned cookie variable should be used as input into the endAsyncEvent call to end the profile
+
+
+
static endAsyncEvent(profileName?, cookie?) #
+
static counterEvent(profileName?, value?) #
+
counterEvent registers the value to the profileName on the systrace timeline
+
+
static attachToRelayProfiler(relayProfiler) #
+
Relay profiles use await calls, so likely occur out of current stack frame
+ therefore async variant of profiling is used
+
+
static swizzleJSON() #
+
+
This is not called by default due to perf overhead but it's useful
+ if you want to find traces which spend too much time in JSON.
+
+
static measureMethods(object, objectName, methodNames) #
+
+
Measures multiple methods of a class. For example, you can do:
+ Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']);
+
@param object
+ @param objectName
+ @param methodNames Map from method names to method display names.
+
+
static measure(objName, fnName, func) #
+
Returns an profiled version of the input function. For example, you can:
+ JSON.parse = Systrace.measure('JSON', 'parse', JSON.parse);
+
@param objName
+ @param fnName
+ @param {function} func
+ @return {function} replacement function
+
+
+
diff --git a/docs/docs/0.41/tabbarios-item.md b/docs/docs/0.41/tabbarios-item.md
new file mode 100644
index 0000000..50a7df7
--- /dev/null
+++ b/docs/docs/0.41/tabbarios-item.md
@@ -0,0 +1,52 @@
+### 属性
+
+
+
+
+
badge string, number #
+
+
+
+
icon Image.propTypes.source #
+
+
给当前标签指定一个自定义的图标。如果定义了systemIcon属性, 这个属性会被忽略。
+
+
+
+
onPress function #
+
+
当此标签被选中时调用。你应该修改组件的状态来使得selected={true}。
+
+
+
+
selected bool #
+
+
这个属性决定了子视图是否可见。如果你看到一个空白的页面,很可能是没有选中任何一个标签。
+
+
+
+
selectedIcon Image.propTypes.source #
+
+
当标签被选中的时候显示的自定义图标。如果定义了systemIcon属性,这个属性会被忽略。如果定义了icon而没定义这个属性,在选中的时候图标会染上蓝色。
+
+
+
+
+
systemIcon enum('bookmarks', 'contacts', 'downloads', 'favorites', 'featured', 'history', 'more', 'most-recent', 'most-viewed', 'recents', 'search', 'top-rated') #
+
+
一些预定义的系统图标。注意如果你使用了此属性,标题和自定义图标都会被覆盖为系统定义的值。
+
+
+
+
title string #
+
+
在图标下面显示的标题文字。如果定义了systemIcon属性,这个属性会被忽略。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/tabbarios.md b/docs/docs/0.41/tabbarios.md
new file mode 100644
index 0000000..eb9cc92
--- /dev/null
+++ b/docs/docs/0.41/tabbarios.md
@@ -0,0 +1,143 @@
+#### __译注__:本组件,以及一切带IOS或Android后缀的组件,都不能跨平台运行。如果需要替代品,请到[js.coach](https://js.coach/react-native?search=tab)或[github](https://github.com/search?utf8=%E2%9C%93&q=react+native+tab)上搜索。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
barTintColor string #
+
+
+
+
+
+
unselectedItemTintColor string #
+
+
当前没有被选中的标签图标的颜色。仅在iOS 10及以上版本有效
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ TabBarIOS,
+ Text,
+ View,
+} = ReactNative;
+
+var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
+
+var TabBarExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Tab-based navigation.',
+ },
+
+ displayName: 'TabBarExample',
+
+ getInitialState: function() {
+ return {
+ selectedTab: 'redTab',
+ notifCount: 0,
+ presses: 0,
+ };
+ },
+
+ _renderContent: function(color: string, pageText: string, num?: number) {
+ return (
+
+ {pageText}
+ {num} re-renders of the {pageText}
+
+ );
+ },
+
+ render: function() {
+ return (
+
+ {
+ this.setState({
+ selectedTab: 'blueTab',
+ });
+ }}>
+ {this._renderContent('#414A8C', 'Blue Tab')}
+
+ 0 ? this.state.notifCount : undefined}
+ selected={this.state.selectedTab === 'redTab'}
+ onPress={() => {
+ this.setState({
+ selectedTab: 'redTab',
+ notifCount: this.state.notifCount + 1,
+ });
+ }}>
+ {this._renderContent('#783E33', 'Red Tab', this.state.notifCount)}
+
+ {
+ this.setState({
+ selectedTab: 'greenTab',
+ presses: this.state.presses + 1
+ });
+ }}>
+ {this._renderContent('#21551C', 'Green Tab', this.state.presses)}
+
+
+ );
+ },
+
+});
+
+var styles = StyleSheet.create({
+ tabContent: {
+ flex: 1,
+ alignItems: 'center',
+ },
+ tabText: {
+ color: 'white',
+ margin: 50,
+ },
+});
+
+module.exports = TabBarExample;
+```
diff --git a/docs/docs/0.41/testing.md b/docs/docs/0.41/testing.md
new file mode 100644
index 0000000..957d650
--- /dev/null
+++ b/docs/docs/0.41/testing.md
@@ -0,0 +1,77 @@
+## 运行测试与贡献代码
+
+React Native的官方代码仓库里有一些测试代码,你可以在贡献代码之后回归测试一下,以检测有没有引起别的问题。这些测试是通过[Travis](http://docs.travis-ci.com/)持续集成系统来运行的,并且会自动针对你提交的代码给出测试结果。
+
+当然我们的测试不可能有完整的覆盖率(尤其对于复杂的用户交互),所以很多更改也还需要仔细的人工审查。我们期待你能帮助我们提高测试覆盖率,以及提供更多的测试代码或是测试用例。
+
+## 使用Jest来测试
+
+[Jest](http://facebook.github.io/jest/)是在命令行通过node来执行的纯js测试工具。测试代码放置在`__tests__`目录下。有一些功能我们还没有完成模拟(jest中需要模拟一些接口),因而没有纳入测试,以避免测试不通过和提高测试速度,但我们正在尽最大努力去逐渐补完这些功能的模拟。你可以在react-native源代码的根目录中使用如下命令来运行现有的jest测试代码:
+
+```
+npm test
+```
+
+我们建议你在贡献代码的时候也添加自己的测试代码。你可以参考这个简单的例子[`getImageSource-test.js`](https://github.com/facebook/react-native/blob/master/Examples/Movies/__tests__/getImageSource-test.js)。
+
+注意:要运行你自己的测试代码,请首先去jest的官网阅读指导文档,然后在`package.json`中加入`jest`对象,在其中包含一些预备测试环境的脚本。下面是一个示例:
+
+```
+...
+"scripts": {
+ ...
+ "test": "jest"
+},
+...
+"jest": {
+ "scriptPreprocessor": "node_modules/react-native/jestSupport/preprocessor.js",
+ "setupEnvScriptFile": "node_modules/react-native/jestSupport/env.js",
+ "testPathIgnorePatterns": [
+ "/node_modules/",
+ "packager/react-packager/src/Activity/"
+ ],
+ "testFileExtensions": [
+ "js"
+ ],
+ "unmockedModulePathPatterns": [
+ "promise",
+ "source-map"
+ ]
+},
+...
+```
+
+注意:你可能需要先在当前的环境中安装、更新或是链接Node.js和其他的一些工具,不然测试可能无法正常运行。点这里查看最新的[测试配置文件.travis.yml](https://github.com/facebook/react-native/blob/master/.travis.yml#L11-24)。
+
+## 单元测试 (Android)
+
+React Native使用[Buck](https://github.com/facebook/buck)编译工具来运行测试。 单元测试部分直接在本地运行,不需要模拟器。运行下面的命令来执行这些测试:
+
+```bash
+$ cd react-native
+$ ./scripts/run-android-local-unit-tests.sh
+```
+
+## 集成测试 (Android)
+
+React Native使用[Buck](https://github.com/facebook/buck)编译工具来运行测试。 集成测试需要在模拟器/真机上运行,以验证模块、组件以及React Native的内核部分(比如bridge)在端对端测试中运作正常。
+
+确保你正确安装和配置了Android NDK,具体配置参见[这篇文档](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md#prerequisites),然后运行下面的命令来执行测试:
+
+```bash
+$ cd react-native
+$ npm install
+$ ./scripts/run-android-local-integration-tests.sh
+```
+
+## 集成测试 (iOS)
+
+React Native提供了一些工具来简化跨原生与JS端的组件的集成测试。这套工具的两个主要部分是`RCTTestRunner`与`RCTTestModule`。`RCTTestRunner`预设了ReactNative的环境,并且可以以`XCTestCase`的形式在Xcode中直接运行测试 (最简单的方法就是使用`runTest:module`)。而`RCTTestModule`则是以 `NativeModules.TestModule`对象导出到了JS环境中。测试代码需要以JS写成的,并且必须在测试完成后调用`TestModule.markTestCompleted()`方法,否则测试过程会超时并且失败。失败的表现一般是抛出一个JS异常。测试错误条件也是可行的,使用`runTest:module:initialProps:expectErrorRegex:`或是`runTest:module:initialProps:expectErrorBlock:`方法,它们会按提供的条件去验证抛出的错误是否符合。你可以参考[`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestHarnessTest.js)、[`IntegrationTests.m`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m)以及 [IntegrationTestsApp.js](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js)来看具体怎么做集成测试。
+
+Xcode中运行IntegrationTest和UIExplorer两个官方示例应用时,可以按下`cmd + U`键来直接在本地运行集成测试。
+
+## 快照测试 (iOS)
+
+快照测试是集成测试的一种常见类型。这类测试首先渲染一个组件,然后使用`TestModule.verifySnapshot()`比对屏幕截图与参考效果图,其原理是利用了[`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case)这个库。参考效果图是通过在`RCTTestRunner`中设置`recordMode = YES`,然后在运行测试时录制的。屏幕截图在32位和64位色深以及不同的操作系统版本上可能会有细微的差别,所以建议强制在指定的配置环境中执行测试。此外我们还强烈建议所有的网络数据和其他的潜在依赖项都应该事先模拟。你可以参考[`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/IntegrationTests/SimpleSnapshotTest.js)这个例子。
+
+如果你提交的PR(Pull Request,即提交你贡献的代码,并请求官方人员合并到仓库中)会影响到快照测试,比如给现有的快照测试添加一个新的测试用例,那么首先需要重新录制参考效果图。只需在[UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42)中设置`_runner.recordMode = YES;`,然后重新运行先前失败的测试代码,再之后将这一设置改回去,最后提交/更新你的PR,看Travis的自动测试能否通过。
diff --git a/docs/docs/0.41/text.md b/docs/docs/0.41/text.md
new file mode 100644
index 0000000..de9fbdf
--- /dev/null
+++ b/docs/docs/0.41/text.md
@@ -0,0 +1,1079 @@
+一个用于显示文本的React组件,并且它也支持嵌套、样式,以及触摸处理。在下面的例子里,嵌套的标题和正文文字会继承来自`styles.baseText`的`fontFamily`字体样式,不过标题上还附加了它自己额外的样式。标题和文本会在顶部依次堆叠,并且被代码中内嵌的换行符分隔开。
+
+```javascript
+renderText: function() {
+ return (
+
+
+ {this.state.titleText + '\n\n'}
+
+
+ {this.state.bodyText}
+
+
+ );
+},
+...
+var styles = StyleSheet.create({
+ baseText: {
+ fontFamily: 'Cochin',
+ },
+ titleText: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ },
+};
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
adjustsFontSizeToFit bool #
+
+
指定字体是否随着给定样式的限制而自动缩放。
+
+
+
+
allowFontScaling bool #
+
+
控制字体是否要根据系统的“字体大小”辅助选项来进行缩放。
+
+
+
+
ios minimumFontScale bool #
+
+
当adjustsFontSizeToFit开启时,指定最小的缩放比(即不能低于这个值)。可设定的值为0.01 - 1.0
+
+
+
+
numberOfLines number #
+
+
用来当文本过长的时候裁剪文本。包括折叠产生的换行在内,总的行数不会超过这个属性的限制。
+
+
+
+
onLayout function #
+
+
当挂载或者布局变化以后调用,参数为如下的内容:
+
{nativeEvent: {layout: {x, y, width, height}}}
+
+
+
+
onLongPress function #
+
+
+
+
+
selectable function #
+
+
决定用户是否可以长按选择文本,以便复制和粘贴。
+
+
style style #
+
+
+
+
fontFamily string
+
fontSize number
+
fontStyle enum('normal', 'italic')
+
+
+
fontWeight enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900')
+ 指定字体的粗细。大多数字体都支持'normal'和'bold'值。并非所有字体都支持所有的数字值。如果某个值不支持,则会自动选择最接近的值。
+
+
+
lineHeight number
+
+
textAlign enum('auto', 'left', 'right', 'center', 'justify')
+ 指定文本的对齐方式。其中'justify'值仅iOS支持,在Android上会变为left
+
+
+
textDecorationLine enum('none', 'underline', 'line-through', 'underline line-through')
+
+
+
textShadowOffset {width: number, height: number}
+
textShadowRadius number
+
+
android includeFontPadding bool
+ Android在默认情况下会为文字额外保留一些padding,以便留出空间摆放上标或是下标的文字。对于某些字体来说,这些额外的padding可能会导致文字难以垂直居中。如果你把textAlignVertical设置为center之后,文字看起来依然不在正中间,那么可以尝试将本属性设置为false.
+
+
+
+
android textAlignVertical enum('auto', 'top', 'bottom', 'center')
+
ios fontVariant [enum('small-caps', 'oldstyle-nums', 'lining-nums', 'tabular-nums', 'proportional-nums')]
+
+
ios letterSpacing number
+
+
ios textDecorationColor color
+
ios textDecorationStyle enum('solid', 'double', 'dotted', 'dashed')
+
ios writingDirection enum('auto', 'ltr', 'rtl')
+
+
+
+
+
ios suppressHighlighting bool #
+
+
当为true时,如果文本被按下,则没有任何视觉效果。默认情况下,文本被按下时会有一个灰色的、椭圆形的高光。
+
+
+
+
+
+## 嵌套文本
+
+在iOS当中,显示一个格式化文本的方法就是使用`NSAttributedString`:提供你想显示的文本内容,并且使用范围标注来指定一些格式。这种用法非常繁琐。在React Native中,我们决定采用和Web一致的设计,这样你可以把相同格式的文本嵌套包裹起来:
+
+```javascript
+
+ I am bold
+
+ and red
+
+
+```
+
+而实际上在框架内部,这会生成一个扁平结构的`NSAttributedString`,包含以下的信息:
+
+```javascript
+"I am bold and red"
+0-9: bold
+9-17: bold, red
+```
+
+## 容器
+
+``元素在布局上不同于其它组件:在Text内部的元素不再使用flexbox布局,而是采用文本布局。这意味着``内部的元素不再是一个个矩形,而可能会在行末进行折叠。
+
+```javascript
+
+ First part and
+ second part
+
+// Text container: all the text flows as if it was one
+// |First part |
+// |and second |
+// |part |
+
+
+ First part and
+ second part
+
+// View container: each text is its own block
+// |First part |
+// |and |
+// |second part|
+```
+
+## 样式继承限制
+
+在Web上,要想指定整个文档的字体和大小,我们只需要写:
+
+```css
+/* 这段代码是CSS, *不是*React Native */
+html {
+ font-family: 'lucida grande', tahoma, verdana, arial, sans-serif;
+ font-size: 11px;
+ color: #141823;
+}
+```
+
+当浏览器尝试渲染一个文本节点的时候,它会在树中一路向上查询,直到根节点,来找到一个具备`font-size`属性的元素。这个系统一个不好的地方在于**任何**节点都可能会有`font-size`属性,包括``标签。这个设计为了方便而设计,但实际上语义上并不太正确。
+
+在React Native中,我们把这个问题设计的更加严谨:**你必须把你的文本节点放在`
`组件内**。你不能直接在``下放置一段文本。
+
+```javascript
+// 错误的做法:会导致一个错误。下不能直接放一段文本。
+
+ 一些文本
+
+
+// 正确的做法
+
+
+ 一些文本
+
+
+```
+
+并且你也不能直接设置一整颗子树的默认样式。使用一个一致的文本和尺寸的推荐方式是创建一个包含相关样式的组件`MyAppText`,然后在你的App中反复使用它。你还可以创建更多特殊的组件譬如`MyAppHeaderText`来表达不同样式的文本。
+
+```javascript
+
+ 这个组件包含了一个默认的字体样式,用于整个应用的文本
+ 这个组件包含了用于标题的样式
+
+```
+
+React Native实际上还是有一部分样式继承的实现,不过仅限于文本标签的子树。在下面的代码里,第二部分会在加粗的同时又显示为红色:
+
+```javascript
+
+ I am bold
+
+ and red
+
+
+```
+
+我们相信这种看起来不太舒服的给文本添加样式的方法反而会帮助我们生产更好的App:
+
+- (对开发者来说) React组件在概念上被设计为强隔离性的:你应当可以在应用的任何位置放置一个组件,而且只要属性相同,其外观和表现都将完全相同。文本如果能够继承外面的样式属性,将会打破这种隔离性。
+
+- (对实现者来说) React Native的实现也被简化了。我们不需要在每个元素上都添加一个`fontFamily`字段,并且我们也不需要隐含地在显示文本的时候向上遍历树。唯一的样式继承在原生Text组件中编码,也不会影响到其它组件或者系统本身。
+
+### 例子
+
+#### iOS
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+var Entity = React.createClass({
+ render: function() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var AttributeToggler = React.createClass({
+ getInitialState: function() {
+ return {fontWeight: 'bold', fontSize: 15};
+ },
+ toggleWeight: function() {
+ this.setState({
+ fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
+ });
+ },
+ increaseSize: function() {
+ this.setState({
+ fontSize: this.state.fontSize + 1
+ });
+ },
+ render: function() {
+ var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
+ return (
+
+
+ Tap the controls below to change attributes.
+
+
+ See how it will even work on this nested text
+
+
+ Toggle Weight
+
+
+ Increase Size
+
+
+ );
+ }
+});
+
+exports.title = '';
+exports.description = 'Base component for rendering styled text.';
+exports.displayName = 'TextExample';
+exports.examples = [
+{
+ title: 'Wrap',
+ render: function() {
+ return (
+
+ The text should wrap if it goes on multiple lines. See, this is going to
+ the next line.
+
+ );
+ },
+}, {
+ title: 'Padding',
+ render: function() {
+ return (
+
+ This text is indented by 10px padding on all sides.
+
+ );
+ },
+}, {
+ title: 'Font Family',
+ render: function() {
+ return (
+
+
+ Cochin
+
+
+ Cochin bold
+
+
+ Helvetica
+
+
+ Helvetica bold
+
+
+ Verdana
+
+
+ Verdana bold
+
+
+ );
+ },
+}, {
+ title: 'Font Size',
+ render: function() {
+ return (
+
+
+ Size 23
+
+
+ Size 8
+
+
+ );
+ },
+}, {
+ title: 'Color',
+ render: function() {
+ return (
+
+
+ Red color
+
+
+ Blue color
+
+
+ );
+ },
+}, {
+ title: 'Font Weight',
+ render: function() {
+ return (
+
+
+ Move fast and be ultralight
+
+
+ Move fast and be light
+
+
+ Move fast and be normal
+
+
+ Move fast and be bold
+
+
+ Move fast and be ultrabold
+
+
+ );
+ },
+}, {
+ title: 'Font Style',
+ render: function() {
+ return (
+
+
+ Normal text
+
+
+ Italic text
+
+
+ );
+ },
+}, {
+ title: 'Text Decoration',
+ render: function() {
+ return (
+
+
+ Solid underline
+
+
+ Double underline with custom color
+
+
+ Dashed underline with custom color
+
+
+ Dotted underline with custom color
+
+
+ None textDecoration
+
+
+ Solid line-through
+
+
+ Double line-through with custom color
+
+
+ Dashed line-through with custom color
+
+
+ Dotted line-through with custom color
+
+
+ Both underline and line-through
+
+
+ );
+ },
+}, {
+ title: 'Nested',
+ description: 'Nested text components will inherit the styles of their ' +
+ 'parents (only backgroundColor is inherited from non-Text parents). ' +
+ ' only supports other and raw text (strings) as children.',
+ render: function() {
+ return (
+
+
+ (Normal text,
+
+ (and bold
+
+ (and tiny inherited bold blue)
+
+ )
+
+ )
+
+
+ (opacity
+
+ (is inherited
+
+ (and accumulated
+
+ (and also applies to the background)
+
+ )
+
+ )
+
+ )
+
+
+ Entity Name
+
+
+ );
+ },
+}, {
+ title: 'Text Align',
+ render: function() {
+ return (
+
+
+ auto (default) - english LTR
+
+
+ أحب اللغة العربية auto (default) - arabic RTL
+
+
+ left left left left left left left left left left left left left left left
+
+
+ center center center center center center center center center center center
+
+
+ right right right right right right right right right right right right right
+
+
+ justify: this text component{"'"}s contents are laid out with "textAlign: justify"
+ and as you can see all of the lines except the last one span the
+ available width of the parent container.
+
+
+ );
+ },
+}, {
+ title: 'Letter Spacing',
+ render: function() {
+ return (
+
+
+ letterSpacing = 0
+
+
+ letterSpacing = 2
+
+
+ letterSpacing = 9
+
+
+ letterSpacing = -1
+
+
+ );
+ },
+}, {
+ title: 'Spaces',
+ render: function() {
+ return (
+
+ A {'generated'} {' '} {'string'} and some spaces
+
+ );
+ },
+}, {
+ title: 'Line Height',
+ render: function() {
+ return (
+
+
+ A lot of space between the lines of this long passage that should
+ wrap once.
+
+
+ );
+ },
+}, {
+ title: 'Empty Text',
+ description: 'It\'s ok to have Text with zero or null children.',
+ render: function() {
+ return (
+
+ );
+ },
+}, {
+ title: 'Toggling Attributes',
+ render: function(): ReactElement {
+ return ;
+ },
+}, {
+ title: 'backgroundColor attribute',
+ description: 'backgroundColor is inherited from all types of views.',
+ render: function() {
+ return (
+
+ Yellow container background,
+
+ {' '}red background,
+
+ {' '}blue background,
+
+ {' '}inherited blue background,
+
+ {' '}nested green background.
+
+
+
+
+
+ );
+ },
+}, {
+ title: 'numberOfLines attribute',
+ render: function() {
+ return (
+
+
+ Maximum of one line, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after one line.
+
+
+ Maximum of two lines, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after two lines.
+
+
+ No maximum lines specified, no matter how much I write here. If I keep writing, it{"'"}ll just keep going and going.
+
+
+ );
+ },
+}, {
+ title: 'Text highlighting (tap the link to see highlight)',
+ render: function() {
+ return (
+
+ Lorem ipsum dolor sit amet, null}>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+ );
+ },
+}, {
+ title: 'allowFontScaling attribute',
+ render: function() {
+ return (
+
+
+ By default, text will respect Text Size accessibility setting on iOS.
+ It means that all font sizes will be increased or descreased depending on the value of Text Size setting in
+ {" "}Settings.app - Display & Brightness - Text Size
+
+
+ You can disable scaling for your Text component by passing {"\""}allowFontScaling={"{"}false{"}\""} prop.
+
+
+ This text will not scale.
+
+
+ );
+ },
+}, {
+ title: 'Inline images',
+ render: function() {
+ return (
+
+
+ This text contains an inline image . Neat, huh?
+
+
+ );
+ },
+}, {
+ title: 'Text shadow',
+ render: function() {
+ return (
+
+
+ Demo text shadow
+
+
+ );
+ },
+}];
+
+var styles = StyleSheet.create({
+ backgroundColorText: {
+ margin: 5,
+ marginBottom: 0,
+ backgroundColor: 'rgba(100, 100, 100, 0.3)'
+ },
+});
+```
+
+#### Android
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var Entity = React.createClass({
+ render: function() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var AttributeToggler = React.createClass({
+ getInitialState: function() {
+ return {fontWeight: 'bold', fontSize: 15};
+ },
+ toggleWeight: function() {
+ this.setState({
+ fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
+ });
+ },
+ increaseSize: function() {
+ this.setState({
+ fontSize: this.state.fontSize + 1
+ });
+ },
+ render: function() {
+ var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
+ return (
+
+
+ Tap the controls below to change attributes.
+
+
+ See how it will even work on this nested text
+
+
+ Toggle Weight
+ {' (with highlight onPress)'}
+
+
+ Increase Size (suppressHighlighting true)
+
+
+ );
+ }
+});
+
+var TextExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Base component for rendering styled text.',
+ },
+ render: function() {
+ return (
+
+
+
+ The text should wrap if it goes on multiple lines.
+ See, this is going to the next line.
+
+
+
+
+ This text is indented by 10px padding on all sides.
+
+
+
+
+ Sans-Serif
+
+
+ Sans-Serif Bold
+
+
+ Serif
+
+
+ Serif Bold
+
+
+ Monospace
+
+
+ Monospace Bold (After 5.0)
+
+
+
+
+
+
+ Roboto Regular
+
+
+ Roboto Italic
+
+
+ Roboto Bold
+
+
+ Roboto Bold Italic
+
+
+ Roboto Light
+
+
+ Roboto Light Italic
+
+
+ Roboto Thin (After 4.2)
+
+
+ Roboto Thin Italic (After 4.2)
+
+
+ Roboto Condensed
+
+
+ Roboto Condensed Italic
+
+
+ Roboto Condensed Bold
+
+
+ Roboto Condensed Bold Italic
+
+
+ Roboto Medium (After 5.0)
+
+
+ Roboto Medium Italic (After 5.0)
+
+
+
+
+
+
+
+
+ NotoSerif Regular
+
+
+ NotoSerif Bold Italic
+
+
+ NotoSerif Italic (Missing Font file)
+
+
+
+
+
+
+
+ Size 23
+
+
+ Size 8
+
+
+
+
+ Red color
+
+
+ Blue color
+
+
+
+
+ Move fast and be bold
+
+
+ Move fast and be bold
+
+
+
+
+ Move fast and be bold
+
+
+ Move fast and be bold
+
+
+
+
+ Move fast and be bold
+
+
+
+
+ Solid underline
+
+
+ None textDecoration
+
+
+ Solid line-through
+
+
+ Both underline and line-through
+
+
+ Mixed text with underline and line-through text nodes
+
+
+
+ console.log('1st')}>
+ (Normal text,
+ console.log('2nd')}>
+ (and bold
+ console.log('3rd')}>
+ (and tiny bold italic blue
+ console.log('4th')}>
+ (and tiny normal blue)
+
+ )
+
+ )
+
+ )
+
+ console.log('1st')}>
+ (Serif
+ console.log('2nd')}>
+ (Serif Bold Italic
+ console.log('3rd')}>
+ (Monospace Normal
+ console.log('4th')}>
+ (Sans-Serif Bold
+ console.log('5th')}>
+ (and Sans-Serif Normal)
+
+ )
+
+ )
+
+ )
+
+ )
+
+
+ Entity Name
+
+
+
+
+ auto (default) - english LTR
+
+
+ أحب اللغة العربية auto (default) - arabic RTL
+
+
+ left left left left left left left left left left left left left left left
+
+
+ center center center center center center center center center center center
+
+
+ right right right right right right right right right right right right right
+
+
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。
+
+
+
+
+
+
+ A {'generated'} {' '} {'string'} and some spaces
+
+
+
+
+ Holisticly formulate inexpensive ideas before best-of-breed benefits. Continually expedite magnetic potentialities rather than client-focused interfaces.
+
+
+
+
+
+
+
+
+
+
+ Red background,
+
+ {' '}blue background,
+
+ {' '}inherited blue background,
+
+ {' '}nested green background.
+
+
+
+
+
+ Same alpha as background,
+
+ Inherited alpha from background,
+
+ Reapply alpha
+
+
+
+
+
+
+
+
+
+
+ Default containerBackgroundColor (inherited) + backgroundColor wash
+
+
+ {"containerBackgroundColor: 'transparent' + backgroundColor wash"}
+
+
+
+
+ Maximum of one line no matter now much I write here. If I keep writing it{"'"}ll just truncate after one line
+
+
+ Maximum of two lines no matter now much I write here. If I keep writing it{"'"}ll just truncate after two lines
+
+
+ No maximum lines specified no matter now much I write here. If I keep writing it{"'"}ll just keep going and going
+
+
+
+
+ This text contains an inline image . Neat, huh?
+
+
+
+
+ Demo text shadow
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ backgroundColorText: {
+ left: 5,
+ backgroundColor: 'rgba(100, 100, 100, 0.3)'
+ },
+});
+
+module.exports = TextExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/textinput.md b/docs/docs/0.41/textinput.md
new file mode 100644
index 0000000..1a92fcc
--- /dev/null
+++ b/docs/docs/0.41/textinput.md
@@ -0,0 +1,1971 @@
+TextInput是一个允许用户在应用中通过键盘输入文本的基本组件。本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。
+
+最简单的用法就是丢一个`TextInput`到应用里,然后订阅它的`onChangeText`事件来读取用户的输入。注意,从TextInput里取值这就是目前唯一的做法!即使用`onChangeText`写入state,然后从this.state中取出值。它还有一些其它的事件,譬如`onSubmitEditing`和`onFocus`。一个简单的例子如下:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, TextInput } from 'react-native';
+
+class UselessTextInput extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { text: 'Useless Placeholder' };
+ }
+
+ render() {
+ return (
+ this.setState({text})}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+// App registration and rendering
+AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
+```
+
+注意有些属性仅在`multiline`为true或者为false的时候有效。此外,当`multiline=false`时,为元素的某一个边添加边框样式(例如:`borderBottomColor`,`borderLeftWidth`等)将不会生效。为了能够实现效果你可以使用一个`View`来包裹`TextInput`:
+
+``` ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View, TextInput } from 'react-native';
+
+class UselessTextInput extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+class UselessTextInputMultiline extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'Useless Multiline Placeholder',
+ };
+ }
+
+ // 你可以试着输入一种颜色,比如red,那么这个red就会作用到View的背景色样式上
+ render() {
+ return (
+
+ this.setState({text})}
+ value={this.state.text}
+ />
+
+ );
+ }
+}
+
+// App registration and rendering
+AppRegistry.registerComponent(
+ 'AwesomeProject',
+ () => UselessTextInputMultiline
+);
+```
+
+`TextInput`在安卓上默认有一个底边框,同时会有一些padding。如果要想使其看起来和iOS上尽量一致,则需要设置`padding: 0`,同时设置`underlineColorAndroid="transparent"`来去掉底边框。
+
+又,在安卓上如果设置`multiline = {true}`,文本默认会垂直居中,可设置`textAlignVertical: top`样式来使其居顶显示。
+
+又又,在安卓上长按选择文本会导致`windowSoftInputMode`设置变为`adjustResize`,这样可能导致绝对定位的元素被键盘给顶起来。要解决这一问题你需要在AndroidManifest.xml中明确指定合适的`windowSoftInputMode`( )值,或是自己监听事件来处理布局变化。
+
+
+### 截图
+
+
+### 属性
+
+
+
+
autoCapitalize enum('none', 'sentences', 'words', 'characters') #
+
+
控制TextInput是否要自动将特定字符切换为大写:
+
+ characters: 所有的字符。
+ words: 每个单词的第一个字符。
+ sentences: 每句话的第一个字符(默认)。
+ none: 不自动切换任何字符为大写。
+
+
+
+
+
autoCorrect bool #
+
+
如果为false,会关闭拼写自动修正。默认值是true。
+
+
+
+
autoFocus bool #
+
+
如果为true,在componentDidMount后会获得焦点。默认值为false。
+
+
+
+
blurOnSubmit bool #
+
+
如果为true,文本框会在提交的时候失焦。对于单行输入框默认值为true,多行则为false。注意:对于多行输入框来说,如果将blurOnSubmit设为true,则在按下回车键时就会失去焦点同时触发onSubmitEditing事件,而不会换行。
+
+
+
+
defaultValue string #
+
+
提供一个文本框中的初始值。当用户开始输入的时候,值就可以改变。
+
在一些简单的使用情形下,如果你不想用监听消息然后更新value属性的方法来保持属性和状态同步的时候,就可以用defaultValue来代替。
+
+
+
+
editable bool #
+
+
如果为false,文本框是不可编辑的。默认值为true。
+
+
+
+
keyboardType enum("default", 'numeric', 'email-address', "ascii-capable", 'numbers-and-punctuation', 'url', 'number-pad', 'phone-pad', 'name-phone-pad', 'decimal-pad', 'twitter', 'web-search') #
+
+
决定弹出的何种软键盘的,譬如numeric(纯数字键盘)。
+
这些值在所有平台都可用:
+
+ default
+ numeric
+ email-address
+
+
+
+
+
maxLength number #
+
+
限制文本框中最多的字符数。使用这个属性而不用JS逻辑去实现,可以避免闪烁的现象。
+
+
+
+
multiline bool #
+
+
如果为true,文本框中可以输入多行文字。默认值为false。
+
+
+
+
+
onChange function #
+
+
+
+
onChangeText function #
+
+
当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。
+
+
+
+
onEndEditing function #
+
+
+
+
+
onLayout function #
+
+
当组件挂载或者布局变化的时候调用,参数为{x, y, width, height}。
+
+
+
+
onScroll function #
+
+
Invoked on content scroll with { nativeEvent: { contentOffset: { x, y } } }.
+ May also contain other properties from ScrollEvent but on Android contentSize is not provided for performance reasons.
+
+
+
+
onSelectionChange function #
+
+
Callback that is called when the text input selection is changed. This will be called with
+ { nativeEvent: { selection: { start, end } } }.
+
+
+
+
onSubmitEditing function #
+
+
此回调函数当软键盘的`确定`/`提交`按钮被按下的时候调用此函数。如果multiline={true},此属性不可用。
+
+
+
+
placeholder string #
+
+
+
+
placeholderTextColor color #
+
+
+
+
ios returnKeyType enum('done', 'go', 'next', 'search', 'send', 'none', 'previous', 'default', 'emergency-call', 'google', 'join', 'route', 'yahoo') #
+
决定“确定”按钮显示的内容。 On Android you can also use
+returnKeyLabel.
Cross platform
The following values work across platforms:
+
+ done
+ go
+ next
+ search
+ send
+
+
Android Only
The following values work on Android only:
+
+
iOS Only
The following values work on iOS only:
+
+ default
+ emergency-call
+ google
+ join
+ route
+ yahoo
+
+
+
+
+
secureTextEntry bool #
+
+
如果为true,文本框会遮住之前输入的文字,这样类似密码之类的敏感文字可以更加安全。默认值为false。
+
+
+
+
selectTextOnFocus bool #
+
+
如果为true,当获得焦点的时候,所有的文字都会被选中。
+
+
+
+
selection {start: number, end: number} #
+
+
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
+
+
+
+
selectionColor color #
+
+
设置输入框高亮时的颜色(在iOS上还包括光标)
+
+
+
+
+
+
译注:这意味着本组件继承了所有Text的样式。
+
+
+
+
value string #
+
+
文本框中的文字内容。
+
TextInput是一个受约束的(Controlled)的组件,意味着如果提供了value属性,原生值会被强制与value属性保持一致。在大部分情况下这都工作的很好,不过有些情况下会导致一些闪烁现象——一个常见的原因就是通过不改变value来阻止用户进行编辑。如果你希望阻止用户输入,可以考虑设置editable={false};如果你是希望限制输入的长度,可以考虑设置maxLength属性,这两个属性都不会导致闪烁。
+
+
+
+
android disableFullscreenUI bool #
+
+
When false, if there is a small amount of space available around a text input
+ (e.g. landscape orientation on a phone), the OS may choose to have the user edit
+ the text inside of a full screen text input mode. When true, this feature is
+ disabled and users will always edit the text directly inside of the text input.
+ Defaults to false.
+
+
+
+
android inlineImageLeft string #
+
If defined, the provided image resource will be rendered on the left.
+
+
+
android inlineImagePadding number #
+
Padding between the inline image, if any, and the text input itself.
+
+
+
android returnKeyLabel string #
+
Sets the return key to the label. Use it instead of returnKeyType.
+
+
+
android textBreakStrategy enum('simple', 'highQuality', 'balanced') #
+
Set text break strategy on Android API Level 23+, possible values are simple, highQuality, balanced
+The default value is simple.
+
+
+
ios clearButtonMode enum('never', 'while-editing', 'unless-editing', 'always') #
+
+
+
+
ios clearTextOnFocus bool #
+
+
如果为true,每次开始输入的时候都会清除文本框的内容。
+
+
+
+
ios enablesReturnKeyAutomatically bool #
+
+
如果为true,键盘会在文本框内没有文字的时候禁用确认按钮。默认值为false。
+
+
+
+
ios dataDetectorTypes enum('phoneNumber', 'link', 'address', 'calendarEvent', 'none', 'all'), [object Object] #
+
+
Determines the types of data converted to clickable URLs in the text input. Only valid if multiline={true} and editable={false}. By default no data types are detected.
You can provide one type or an array of many types.
Possible values for dataDetectorTypes are:
+
+ 'phoneNumber'
+ 'link'
+ 'address'
+ 'calendarEvent'
+ 'none''all'
+
+
+
+
+
ios keyboardAppearance enum('default', 'light', 'dark') #
+
+
+
+
ios onKeyPress function #
+
+
当一个键被按下的时候调用此回调。传递给回调函数的参数为{ nativeEvent: { key: keyValue } },其中keyValue即为被按下的键。会在onChange之前调用。
+
+
+
+
ios selectionState DocumentSelectionState #
+
+
+
+
android numberOfLines number #android
+
+
设置输入框的行数。当multiline设置为true时使用它,可以占据对应的行数。
+
+
+
+
android underlineColorAndroid string #
+
+
文本框的下划线颜色(译注:如果要去掉文本框的边框,请将此属性设为透明transparent)。
+
+
+
+
ios spellCheck bool #
+
如果设置为false,则禁用拼写检查的样式(比如错误拼写的单词下的红线)。默认值继承自autoCorrect.
+
+
+
+
+
+### 方法
+
+
+
isFocused(): boolean
+ #
+
+
+
+
+
+### 例子
+
+#### iOS
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Text,
+ TextInput,
+ View,
+ StyleSheet,
+} = ReactNative;
+
+class WithLabel extends React.Component {
+ render() {
+ return (
+
+
+ {this.props.label}
+
+ {this.props.children}
+
+ );
+ }
+}
+
+class TextEventsExample extends React.Component {
+ state = {
+ curText: '',
+ prevText: '',
+ prev2Text: '',
+ prev3Text: '',
+ };
+
+ updateText = (text) => {
+ this.setState((state) => {
+ return {
+ curText: text,
+ prevText: state.curText,
+ prev2Text: state.prevText,
+ prev3Text: state.prev2Text,
+ };
+ });
+ };
+
+ render() {
+ return (
+
+ this.updateText('onFocus')}
+ onBlur={() => this.updateText('onBlur')}
+ onChange={(event) => this.updateText(
+ 'onChange text: ' + event.nativeEvent.text
+ )}
+ onEndEditing={(event) => this.updateText(
+ 'onEndEditing text: ' + event.nativeEvent.text
+ )}
+ onSubmitEditing={(event) => this.updateText(
+ 'onSubmitEditing text: ' + event.nativeEvent.text
+ )}
+ onSelectionChange={(event) => this.updateText(
+ 'onSelectionChange range: ' +
+ event.nativeEvent.selection.start + ',' +
+ event.nativeEvent.selection.end
+ )}
+ onKeyPress={(event) => {
+ this.updateText('onKeyPress key: ' + event.nativeEvent.key);
+ }}
+ style={styles.default}
+ />
+
+ {this.state.curText}{'\n'}
+ (prev: {this.state.prevText}){'\n'}
+ (prev2: {this.state.prev2Text}){'\n'}
+ (prev3: {this.state.prev3Text})
+
+
+ );
+ }
+}
+
+class AutoExpandingTextInput extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
+ height: 0,
+ };
+ }
+ render() {
+ return (
+ {
+ this.setState({text});
+ }}
+ onContentSizeChange={(event) => {
+ this.setState({height: event.nativeEvent.contentSize.height});
+ }}
+ style={[styles.default, {height: Math.max(35, this.state.height)}]}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+class RewriteExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ var limit = 20;
+ var remainder = limit - this.state.text.length;
+ var remainderColor = remainder > 5 ? 'blue' : 'red';
+ return (
+
+ {
+ text = text.replace(/ /g, '_');
+ this.setState({text});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ {remainder}
+
+
+ );
+ }
+}
+
+class RewriteExampleInvalidCharacters extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ return (
+
+ {
+ this.setState({text: text.replace(/\s/g, '')});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ );
+ }
+}
+
+class TokenizedTextExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: 'Hello #World'};
+ }
+ render() {
+
+ //define delimiter
+ let delimiter = /\s+/;
+
+ //split string
+ let _text = this.state.text;
+ let token, index, parts = [];
+ while (_text) {
+ delimiter.lastIndex = 0;
+ token = delimiter.exec(_text);
+ if (token === null) {
+ break;
+ }
+ index = token.index;
+ if (token[0].length === 0) {
+ index = 1;
+ }
+ parts.push(_text.substr(0, index));
+ parts.push(token[0]);
+ index = index + token[0].length;
+ _text = _text.slice(index);
+ }
+ parts.push(_text);
+
+ //highlight hashtags
+ parts = parts.map((text) => {
+ if (/^#/.test(text)) {
+ return {text} ;
+ } else {
+ return text;
+ }
+ });
+
+ return (
+
+ {
+ this.setState({text});
+ }}>
+ {parts}
+
+
+ );
+ }
+}
+
+class BlurOnSubmitExample extends React.Component {
+ focusNextField = (nextField) => {
+ this.refs[nextField].focus();
+ };
+
+ render() {
+ return (
+
+ this.focusNextField('2')}
+ />
+ this.focusNextField('3')}
+ />
+ this.focusNextField('4')}
+ />
+ this.focusNextField('5')}
+ />
+
+
+ );
+ }
+}
+
+type SelectionExampleState = {
+ selection: {
+ start: number;
+ end?: number;
+ };
+ value: string;
+};
+
+class SelectionExample extends React.Component {
+ state: SelectionExampleState;
+
+ _textInput: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ selection: {start: 0, end: 0},
+ value: props.value
+ };
+ }
+
+ onSelectionChange({nativeEvent: {selection}}) {
+ this.setState({selection});
+ }
+
+ getRandomPosition() {
+ var length = this.state.value.length;
+ return Math.round(Math.random() * length);
+ }
+
+ select(start, end) {
+ this._textInput.focus();
+ this.setState({selection: {start, end}});
+ }
+
+ selectRandom() {
+ var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
+ this.select(...positions);
+ }
+
+ placeAt(position) {
+ this.select(position, position);
+ }
+
+ placeAtRandom() {
+ this.placeAt(this.getRandomPosition());
+ }
+
+ render() {
+ var length = this.state.value.length;
+
+ return (
+
+ this.setState({value})}
+ onSelectionChange={this.onSelectionChange.bind(this)}
+ ref={textInput => (this._textInput = textInput)}
+ selection={this.state.selection}
+ style={this.props.style}
+ value={this.state.value}
+ />
+
+
+ selection = {JSON.stringify(this.state.selection)}
+
+
+ Place at Start (0, 0)
+
+
+ Place at End ({length}, {length})
+
+
+ Place at Random
+
+
+ Select All
+
+
+ Select Random
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ page: {
+ paddingBottom: 300,
+ },
+ default: {
+ height: 26,
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ flex: 1,
+ fontSize: 13,
+ padding: 4,
+ },
+ multiline: {
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ flex: 1,
+ fontSize: 13,
+ height: 50,
+ padding: 4,
+ marginBottom: 4,
+ },
+ multilineWithFontStyles: {
+ color: 'blue',
+ fontWeight: 'bold',
+ fontSize: 18,
+ fontFamily: 'Cochin',
+ height: 60,
+ },
+ multilineChild: {
+ width: 50,
+ height: 40,
+ position: 'absolute',
+ right: 5,
+ backgroundColor: 'red',
+ },
+ eventLabel: {
+ margin: 3,
+ fontSize: 12,
+ },
+ labelContainer: {
+ flexDirection: 'row',
+ marginVertical: 2,
+ flex: 1,
+ },
+ label: {
+ width: 115,
+ alignItems: 'flex-end',
+ marginRight: 10,
+ paddingTop: 2,
+ },
+ rewriteContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ remainder: {
+ textAlign: 'right',
+ width: 24,
+ },
+ hashtag: {
+ color: 'blue',
+ fontWeight: 'bold',
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Single and multi-line text inputs.';
+exports.examples = [
+ {
+ title: 'Auto-focus',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: "Live Re-Write ( -> '_') + maxLength",
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Live Re-Write (no spaces allowed)',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Auto-capitalize',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-correct',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Keyboard types',
+ render: function() {
+ var keyboardTypes = [
+ 'default',
+ 'ascii-capable',
+ 'numbers-and-punctuation',
+ 'url',
+ 'number-pad',
+ 'phone-pad',
+ 'name-phone-pad',
+ 'email-address',
+ 'decimal-pad',
+ 'twitter',
+ 'web-search',
+ 'numeric',
+ ];
+ var examples = keyboardTypes.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Keyboard appearance',
+ render: function() {
+ var keyboardAppearance = [
+ 'default',
+ 'light',
+ 'dark',
+ ];
+ var examples = keyboardAppearance.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Return key types',
+ render: function() {
+ var returnKeyTypes = [
+ 'default',
+ 'go',
+ 'google',
+ 'join',
+ 'next',
+ 'route',
+ 'search',
+ 'send',
+ 'yahoo',
+ 'done',
+ 'emergency-call',
+ ];
+ var examples = returnKeyTypes.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Enable return key automatically',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Secure text entry',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Event handling',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Colored input text',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Colored highlight/cursor for text input',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Clear button mode',
+ render: function () {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Clear and select',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Blur on submit',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Multiline blur on submit',
+ render: function() {
+ return (
+
+ alert(event.nativeEvent.text)}
+ />
+
+ );
+ }
+ },
+ {
+ title: 'Multiline',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-expanding',
+ render: function() {
+ return (
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Attributed text',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Text selection & cursor placement',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'TextInput maxLength',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+];
+```
+
+#### Android
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Text,
+ TextInput,
+ View,
+ StyleSheet,
+} = ReactNative;
+
+class TextEventsExample extends React.Component {
+ state = {
+ curText: '',
+ prevText: '',
+ prev2Text: '',
+ };
+
+ updateText = (text) => {
+ this.setState((state) => {
+ return {
+ curText: text,
+ prevText: state.curText,
+ prev2Text: state.prevText,
+ };
+ });
+ };
+
+ render() {
+ return (
+
+ this.updateText('onFocus')}
+ onBlur={() => this.updateText('onBlur')}
+ onChange={(event) => this.updateText(
+ 'onChange text: ' + event.nativeEvent.text
+ )}
+ onEndEditing={(event) => this.updateText(
+ 'onEndEditing text: ' + event.nativeEvent.text
+ )}
+ onSubmitEditing={(event) => this.updateText(
+ 'onSubmitEditing text: ' + event.nativeEvent.text
+ )}
+ style={styles.singleLine}
+ />
+
+ {this.state.curText}{'\n'}
+ (prev: {this.state.prevText}){'\n'}
+ (prev2: {this.state.prev2Text})
+
+
+ );
+ }
+}
+
+class AutoExpandingTextInput extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
+ height: 0,
+ };
+ }
+ render() {
+ return (
+ {
+ this.setState({height: event.nativeEvent.contentSize.height});
+ }}
+ onChangeText={(text) => {
+ this.setState({text});
+ }}
+ style={[styles.default, {height: Math.max(35, this.state.height)}]}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+class RewriteExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ var limit = 20;
+ var remainder = limit - this.state.text.length;
+ var remainderColor = remainder > 5 ? 'blue' : 'red';
+ return (
+
+ {
+ text = text.replace(/ /g, '_');
+ this.setState({text});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ {remainder}
+
+
+ );
+ }
+}
+
+class TokenizedTextExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: 'Hello #World'};
+ }
+ render() {
+
+ //define delimiter
+ let delimiter = /\s+/;
+
+ //split string
+ let _text = this.state.text;
+ let token, index, parts = [];
+ while (_text) {
+ delimiter.lastIndex = 0;
+ token = delimiter.exec(_text);
+ if (token === null) {
+ break;
+ }
+ index = token.index;
+ if (token[0].length === 0) {
+ index = 1;
+ }
+ parts.push(_text.substr(0, index));
+ parts.push(token[0]);
+ index = index + token[0].length;
+ _text = _text.slice(index);
+ }
+ parts.push(_text);
+
+ //highlight hashtags
+ parts = parts.map((text) => {
+ if (/^#/.test(text)) {
+ return {text} ;
+ } else {
+ return text;
+ }
+ });
+
+ return (
+
+ {
+ this.setState({text});
+ }}>
+ {parts}
+
+
+ );
+ }
+}
+
+class BlurOnSubmitExample extends React.Component {
+ focusNextField = (nextField) => {
+ this.refs[nextField].focus();
+ };
+
+ render() {
+ return (
+
+ this.focusNextField('2')}
+ />
+ this.focusNextField('3')}
+ />
+ this.focusNextField('4')}
+ />
+ this.focusNextField('5')}
+ />
+
+
+ );
+ }
+}
+
+class ToggleDefaultPaddingExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {hasPadding: false};
+ }
+ render() {
+ return (
+
+
+ this.setState({hasPadding: !this.state.hasPadding})}>
+ Toggle padding
+
+
+ );
+ }
+}
+
+type SelectionExampleState = {
+ selection: {
+ start: number;
+ end: number;
+ };
+ value: string;
+};
+
+class SelectionExample extends React.Component {
+ state: SelectionExampleState;
+
+ _textInput: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ selection: {start: 0, end: 0},
+ value: props.value
+ };
+ }
+
+ onSelectionChange({nativeEvent: {selection}}) {
+ this.setState({selection});
+ }
+
+ getRandomPosition() {
+ var length = this.state.value.length;
+ return Math.round(Math.random() * length);
+ }
+
+ select(start, end) {
+ this._textInput.focus();
+ this.setState({selection: {start, end}});
+ }
+
+ selectRandom() {
+ var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
+ this.select(...positions);
+ }
+
+ placeAt(position) {
+ this.select(position, position);
+ }
+
+ placeAtRandom() {
+ this.placeAt(this.getRandomPosition());
+ }
+
+ render() {
+ var length = this.state.value.length;
+
+ return (
+
+ this.setState({value})}
+ onSelectionChange={this.onSelectionChange.bind(this)}
+ ref={textInput => (this._textInput = textInput)}
+ selection={this.state.selection}
+ style={this.props.style}
+ value={this.state.value}
+ />
+
+
+ selection = {JSON.stringify(this.state.selection)}
+
+
+ Place at Start (0, 0)
+
+
+ Place at End ({length}, {length})
+
+
+ Place at Random
+
+
+ Select All
+
+
+ Select Random
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ multiline: {
+ height: 60,
+ fontSize: 16,
+ padding: 4,
+ marginBottom: 10,
+ },
+ eventLabel: {
+ margin: 3,
+ fontSize: 12,
+ },
+ singleLine: {
+ fontSize: 16,
+ padding: 4,
+ },
+ singleLineWithHeightTextInput: {
+ height: 30,
+ },
+ hashtag: {
+ color: 'blue',
+ fontWeight: 'bold',
+ },
+});
+
+exports.title = '';
+exports.description = 'Single and multi-line text inputs.';
+exports.examples = [
+ {
+ title: 'Auto-focus',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: "Live Re-Write ( -> '_')",
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Auto-capitalize',
+ render: function() {
+ var autoCapitalizeTypes = [
+ 'none',
+ 'sentences',
+ 'words',
+ 'characters',
+ ];
+ var examples = autoCapitalizeTypes.map((type) => {
+ return (
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Auto-correct',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Keyboard types',
+ render: function() {
+ var keyboardTypes = [
+ 'default',
+ 'email-address',
+ 'numeric',
+ 'phone-pad',
+ ];
+ var examples = keyboardTypes.map((type) => {
+ return (
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Blur on submit',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Event handling',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Colors and text inputs',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+ Darker backgroundColor
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Text input, themes and heights',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'fontFamily, fontWeight and fontStyle',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Passwords',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Editable',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Multiline',
+ render: function() {
+ return (
+
+
+
+
+ multiline with children, aligned bottom-right
+
+
+ );
+ }
+ },
+ {
+ title: 'Fixed number of lines',
+ platform: 'android',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-expanding',
+ render: function() {
+ return (
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Attributed text',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Return key',
+ render: function() {
+ var returnKeyTypes = [
+ 'none',
+ 'go',
+ 'search',
+ 'send',
+ 'done',
+ 'previous',
+ 'next',
+ ];
+ var returnKeyLabels = [
+ 'Compile',
+ 'React Native',
+ ];
+ var examples = returnKeyTypes.map((type) => {
+ return (
+
+ );
+ });
+ var types = returnKeyLabels.map((type) => {
+ return (
+
+ );
+ });
+ return {examples}{types} ;
+ }
+ },
+ {
+ title: 'Inline Images',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Toggle Default Padding',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Text selection & cursor placement',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+];
+```
diff --git a/docs/docs/0.41/timepickerandroid.md b/docs/docs/0.41/timepickerandroid.md
new file mode 100644
index 0000000..8f83d20
--- /dev/null
+++ b/docs/docs/0.41/timepickerandroid.md
@@ -0,0 +1,49 @@
+本组件会打开一个标准的Android时间选择器的对话框。
+
+### 示例
+```js
+try {
+ const {action, hour, minute} = await TimePickerAndroid.open({
+ hour: 14,
+ minute: 0,
+ is24Hour: false, // 会显示为'2 PM'
+ });
+ if (action !== TimePickerAndroid.dismissedAction) {
+ // 这里开始可以处理用户选好的时分两个参数:hour (0-23), minute (0-59)
+ }
+} catch ({code, message}) {
+ console.warn('Cannot open time picker', message);
+}
+```
+
+### 方法
+
+
+
static open(options: Object) #
+
+
打开一个标准的Android时间选择器的对话框。
+
可选的options对象的key值如下:
+
+ hour (0-23) - 要显示的小时,默认为当前时间。
+ minute (0-59) - 要显示的分钟,默认为当前时间。
+ is24Hour (boolean) - 如果设为true,则选择器会使用24小时制。如果设为false,则会额外显示AM/PM的选项。如果不设定,则采取当前地区的默认设置。
+
+ 在用户选好时间后返回一个Promise,回调参数为一个对象,其中包含有action, hour (0-23),
+ minute (0-59)。如果用户取消了对话框,Promise仍然会执行,返回的action为TimePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必 先检查action的值。
+
+
+
static timeSetAction() #
+
+
+
+
static dismissedAction() #
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/timers.md b/docs/docs/0.41/timers.md
new file mode 100644
index 0000000..5ed023c
--- /dev/null
+++ b/docs/docs/0.41/timers.md
@@ -0,0 +1,87 @@
+定时器是一个应用中非常重要的部分。React Native实现了和浏览器一致的[定时器Timer](https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Timers)。
+
+## 定时器
+
+- setTimeout, clearTimeout
+- setInterval, clearInterval
+- setImmediate, clearImmediate
+- requestAnimationFrame, cancelAnimationFrame
+
+`requestAnimationFrame(fn)`和`setTimeout(fn, 0)`不同,前者会在每帧刷新之后执行一次,而后者则会尽可能快的执行(在iPhone5S上有可能每秒1000次以上)。
+
+`setImmediate`则会在当前JavaScript执行块结束的时候执行,就在将要发送批量响应数据到原生之前。注意如果你在`setImmediate`的回调函数中又执行了`setImmediate`,它会紧接着立刻执行,而不会在调用之前等待原生代码。
+
+`Promise`的实现就使用了`setImmediate`来执行异步调用。
+
+## InteractionManager
+
+原生应用感觉如此流畅的一个重要原因就是在互动和动画的过程中避免繁重的操作。在React Native里,我们目前受到限制,因为我们只有一个JavaScript执行线程。不过你可以用`InteractionManager`来确保在执行繁重工作之前所有的交互和动画都已经处理完毕。
+
+应用可以通过以下代码来安排一个任务,使其在交互结束之后执行:
+
+```javascript
+InteractionManager.runAfterInteractions(() => {
+ // ...需要长时间同步执行的任务...
+});
+```
+
+我们来把它和之前的几个任务安排方法对比一下:
+
+- requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
+- setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
+- runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
+
+触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将`runAfterInteractions()`的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
+
+InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
+
+```javascript
+var handle = InteractionManager.createInteractionHandle();
+// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
+// 在动画完成之后
+InteractionManager.clearInteractionHandle(handle);
+// 在所有句柄都清除之后,现在开始依序执行队列中的任务
+```
+
+## TimerMixin
+
+我们发现很多React Native应用发生致命错误(闪退)是与计时器有关。具体来说,是在某个组件被卸载(unmount)之后,计时器却仍然被激活。为了解决这个问题,我们引入了`TimerMixin`。如果你在组件中引入`TimerMixin`,就可以把你原本的`setTimeout(fn, 500)`改为`this.setTimeout(fn, 500)`(只需要在前面加上`this.`),然后当你的组件卸载时,所有的计时器事件也会被正确的清除。
+
+这个库并没有跟着React Native一起发布。你需要在项目文件夹下输入`npm i react-timer-mixin --save`来单独安装它。
+
+```javascript
+var TimerMixin = require('react-timer-mixin');
+
+var Component = React.createClass({
+ mixins: [TimerMixin],
+ componentDidMount: function() {
+ this.setTimeout(
+ () => { console.log('这样我就不会导致内存泄露!'); },
+ 500
+ );
+ }
+});
+```
+
+我们强烈建议您使用react-timer-mixin提供的`this.setTimeout(...)`来代替`setTimeout(...)`。这可以规避许多难以排查的BUG。
+
+__译注__:Mixin属于ES5语法,对于ES6代码来说,__无法直接使用Mixin__。如果你的项目是用ES6代码编写,同时又使用了计时器,那么你只需铭记`在unmount组件时清除(clearTimeout/clearInterval)所有用到的定时器`,那么也可以实现和TimerMixin同样的效果。例如:
+```js
+import React,{
+ Component
+} from 'react';
+
+export default class Hello extends Component {
+ componentDidMount() {
+ this.timer = setTimeout(
+ () => { console.log('把一个定时器的引用挂在this上'); },
+ 500
+ );
+ }
+ componentWillUnmount() {
+ // 如果存在this.timer,则使用clearTimeout清空。
+ // 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear
+ this.timer && clearTimeout(this.timer);
+ }
+};
+```
diff --git a/docs/docs/0.41/toastandroid.md b/docs/docs/0.41/toastandroid.md
new file mode 100644
index 0000000..f1166fd
--- /dev/null
+++ b/docs/docs/0.41/toastandroid.md
@@ -0,0 +1,115 @@
+本模块将原生的ToastAndroid模块导出为一个JS模块,用于在Android设备上显示一个悬浮的提示信息。本模块包含一个`show`方法接受以下的参数:
+
+1. String message: 一个字符串,表示将要显示的文本内容。
+2. int duration: 提示信息持续显示的时间。可以是`ToastAndroid.SHORT`或者`ToastAndroid.LONG`。
+
+还有一个名为`showWithGravity`的方法可以指定弹出的位置。可选项有:ToastAndroid.TOP, ToastAndroid.BOTTOM, ToastAndroid.CENTER.
+
+用法示例:
+```javascript
+ToastAndroid.show('A pikachu appeared nearby !', ToastAndroid.SHORT);
+ToastAndroid.showWithGravity('All Your Base Are Belong To Us', ToastAndroid.SHORT, ToastAndroid.CENTER);
+```
+
+### 截图
+
+
+### 方法
+
+
+
+
static show(message: string, duration: number) #
+
static showWithGravity(message, duration, gravity) #
+
+
+### 属性
+
+ SHORT: MemberExpression # // Toast duration constants
TOP: MemberExpression # // Toast gravity constants
BOTTOM: MemberExpression # CENTER: MemberExpression #
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ ToastAndroid,
+ TouchableWithoutFeedback,
+} = ReactNative;
+
+var UIExplorerBlock = require('UIExplorerBlock');
+var UIExplorerPage = require('UIExplorerPage');
+
+class ToastExample extends React.Component {
+ static title = 'Toast Example';
+ static description = 'Example that demonstrates the use of an Android Toast to provide feedback.';
+ state = {};
+
+ render() {
+ return (
+
+
+
+ ToastAndroid.show('This is a toast with short duration', ToastAndroid.SHORT)}>
+ Click me.
+
+
+
+
+ ToastAndroid.show('This is a toast with long duration', ToastAndroid.LONG)}>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with top gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.TOP,
+ )
+ }>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with center gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.CENTER,
+ )
+ }>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with bottom gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.BOTTOM,
+ )
+ }>
+ Click me.
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ text: {
+ color: 'black',
+ },
+});
+
+module.exports = ToastExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/toolbarandroid.md b/docs/docs/0.41/toolbarandroid.md
new file mode 100644
index 0000000..d4889a2
--- /dev/null
+++ b/docs/docs/0.41/toolbarandroid.md
@@ -0,0 +1,252 @@
+ToolbarAndroid是一个包装了仅限Android平台的`工具栏(Toolbar)`[部件][0]的React组件。一个Toolbar可以显示一个徽标,一个导航图标(譬如汉堡形状的菜单按钮),一个标题与副标题,以及一个功能列表。标题和副标题会在中间显示,徽标和导航图标会在左侧显示,而功能列表则在右侧显示。
+
+如果工具栏只有一个子节点,它会在标题和功能列表之间显示。
+
+尽管Toolbar支持在徽标、导航和功能图标上使用远程图片,这也只应该在开发(DEV)模式下使用。在发行(release)模式下,你永远都应该用图片资源来渲染这些图标。使用`require('./some_icon.png')`会自动帮你包装好,所以只要你不直接用`{uri:'http://...'}`,就没什么问题。
+
+[0]: https://developer.android.com/reference/android/support/v7/widget/Toolbar.html
+
+例子:
+
+```javascript
+render: function() {
+ return (
+
+ )
+},
+onActionSelected: function(position) {
+ if (position === 0) { // index of 'Settings'
+ showSettings();
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
actions [{title: string, icon: optionalImageSource, show: enum('always', 'ifRoom', 'never'), showWithText: bool}] #
+
+
设置功能菜单中的可用功能。他们会显示为部件右侧的图标或文字。如果放不下,则会被放进一个弹出菜单里。
+
这个属性接受一个对象数组,每个对象可以有如下的字段:
+
+ title: 必须的 , 功能的标题
+ icon: 这个功能的图标,例如require('./some_icon')
+ show: 是直接作为icon显示还是先隐藏,而在弹出菜单里显示:always总是显示,ifRoom如果放的下则显示,或者never从不显示。
+ showWithText: 值为布尔类型,指定是否在图标旁边同时还显示文字
+
+
+
+
+
contentInsetEnd number #
+
+
设置Toolbar的右边缘和屏幕右边缘的距离。
+
除了导航按钮和菜单以外,设置这一属性也会影响Toolbar的内容区域。它定义了Toolbar与屏幕边沿的最小边距,可以用来使Toolbar的内容和一些设计上的网格线对齐。
+
+
+
+
contentInsetStart number #
+
设置Toolbar的左边缘和屏幕左边缘的距离。
作用同上。
+
+
+
logo optionalImageSource #
+
+
+
+
navIcon optionalImageSource #
+
+
+
+
onActionSelected function #
+
+
当一个功能被选中的时候调用此回调。传递给此回调的唯一参数是该功能在actions数组中的位置。
+
+
+
+
onIconClicked function #
+
+
+
+
overflowIcon optionalImageSource #
+
+
+
+
rtl bool #
+
+
设置toolbar的排列顺序为从右到左。除了将这一属性设为true以外,你还需要在AndroidManifest.xml中添加:
+
android:supportsRtl="true"
+
以及在Main.Activity的onCreate方法中调用
+ setLayoutDirection(LayoutDirection.RTL)
+
+
+
+
+
+
subtitleColor string #
+
+
+
+
+
+
titleColor string #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var SwitchAndroid = require('SwitchAndroid');
+var ToolbarAndroid = require('ToolbarAndroid');
+
+var ToolbarAndroidExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Examples of using the Android toolbar.'
+ },
+ getInitialState: function() {
+ return {
+ actionText: 'Example app with toolbar component',
+ toolbarSwitch: false,
+ colorProps: {
+ titleColor: '#3b5998',
+ subtitleColor: '#6a7180',
+ },
+ };
+ },
+ render: function() {
+ return (
+
+
+ this.setState({actionText: 'Icon clicked'})}
+ style={styles.toolbar}
+ subtitle={this.state.actionText}
+ title="Toolbar" />
+ {this.state.actionText}
+
+
+
+
+ this.setState({'toolbarSwitch': value})} />
+ {'\'Tis but a switch'}
+
+
+
+
+
+
+
+
+
+
+ this.setState({colorProps: {}})}
+ title="Wow, such toolbar"
+ style={styles.toolbar}
+ subtitle="Much native"
+ {...this.state.colorProps} />
+
+ Touch the icon to reset the custom colors to the default (theme-provided) ones.
+
+
+
+
+
+
+
+
+
+ );
+ },
+ _onActionSelected: function(position) {
+ this.setState({
+ actionText: 'Selected ' + toolbarActions[position].title,
+ });
+ },
+});
+
+var toolbarActions = [
+ {title: 'Create', icon: require('image!ic_create_black_48dp'), show: 'always'},
+ {title: 'Filter'},
+ {title: 'Settings', icon: require('image!ic_settings_black_48dp'), show: 'always'},
+];
+
+var styles = StyleSheet.create({
+ toolbar: {
+ backgroundColor: '#e9eaed',
+ height: 56,
+ },
+});
+
+module.exports = ToolbarAndroidExample;
+```
diff --git a/docs/docs/0.41/touchablehighlight.md b/docs/docs/0.41/touchablehighlight.md
new file mode 100644
index 0000000..11b0838
--- /dev/null
+++ b/docs/docs/0.41/touchablehighlight.md
@@ -0,0 +1,62 @@
+本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低,同时会有一个底层的颜色透过而被用户看到,使得视图变暗或变亮。在底层实现上,实际会创建一个新的视图到视图层级中,如果使用的方法不正确,有时候会导致一些不希望出现的视觉效果。譬如没有给视图的backgroundColor显式声明一个不透明的颜色。
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+
+ );
+},
+```
+
+> **注意**:TouchableHighlight只支持一个子节点
+>
+> 如果你希望包含多个子组件,用一个View来包装它们。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
activeOpacity number #
+
+
指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在0到1之间)。
+
+
+
+
onHideUnderlay function #
+
+
+
+
onShowUnderlay function #
+
+
+
+
+
underlayColor string #
+
+
+
diff --git a/docs/docs/0.41/touchablenativefeedback.md b/docs/docs/0.41/touchablenativefeedback.md
new file mode 100644
index 0000000..befbeee
--- /dev/null
+++ b/docs/docs/0.41/touchablenativefeedback.md
@@ -0,0 +1,39 @@
+本组件用于封装视图,使其可以正确响应触摸操作(仅限Android平台)。在Android设备上,这个组件利用原生状态来渲染触摸的反馈。目前它只支持一个单独的View实例作为子节点。在底层实现上,实际会创建一个新的RCTView结点替换当前的子View,并附带一些额外的属性。
+
+原生触摸操作反馈的背景可以使用`background`属性来自定义。
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+ Button
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
background backgroundPropType #
+
+
决定在触摸反馈的时候显示什么类型的背景。它接受一个有着type属性和一些基于type属性的额外数据的对象。我们推荐使用以下的静态方法之一来创建这个对象:
+
1) TouchableNativeFeedback.SelectableBackground() - 会创建一个对象,表示安卓主题默认的对于被选中对象的背景。(?android:attr/selectableItemBackground)
+
2) TouchableNativeFeedback.SelectableBackgroundBorderless() - 会创建一个对象,表示安卓主题默认的对于被选中的无边框对象的背景。(?android:attr/selectableItemBackgroundBorderless)。只在Android API level 21+适用。
+
3) TouchableNativeFeedback.Ripple(color, borderless) - 会创建一个对象,当按钮被按下时产生一个涟漪状的背景,你可以通过color参数来指定颜色,如果参数borderless是true,那么涟漪还会渲染到视图的范围之外。(参见原生的actionbar buttons作为该效果的一个例子)。这个背景类型只在Android API level 21+适用。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/touchableopacity.md b/docs/docs/0.41/touchableopacity.md
new file mode 100644
index 0000000..2002e30
--- /dev/null
+++ b/docs/docs/0.41/touchableopacity.md
@@ -0,0 +1,33 @@
+本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低。这个过程并不会真正改变视图层级,大部分情况下很容易添加到应用中而不会带来一些奇怪的副作用。(__译注__:此组件与TouchableHighlight的区别在于并没有额外的颜色变化,更适于一般场景)
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
activeOpacity number #
+
+
指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在0到1之间)。
+
+
+
diff --git a/docs/docs/0.41/touchablewithoutfeedback.md b/docs/docs/0.41/touchablewithoutfeedback.md
new file mode 100644
index 0000000..ee2ac49
--- /dev/null
+++ b/docs/docs/0.41/touchablewithoutfeedback.md
@@ -0,0 +1,78 @@
+除非你有一个很好的理由,否则不要用这个组件。所有能够响应触屏操作的元素在触屏后都应该有一个视觉上的反馈(然而本组件没有任何视觉反馈)。这也是为什么一个"web"应用总是显得不够"原生"的主要原因之一。
+
+> **注意**:TouchableWithoutFeedback只支持一个子节点
+>
+> 如果你希望包含多个子组件,用一个View来包装它们。
+
+### 属性
+
+
+
+
accessibilityComponentType View.AccessibilityComponentType #
+
+
+
accessibilityTraits View.AccessibilityTraits, [View.AccessibilityTraits] #
+
+
+
+
delayLongPress number #
+
+
单位是毫秒,从onPressIn开始,到onLongPress被调用的延迟。
+
+
+
+
delayPressIn number #
+
+
单位是毫秒,从触摸操作开始到onPressIn被调用的延迟。
+
+
+
+
delayPressOut number #
+
+
单位是毫秒,从触摸操作结束开始到onPressOut被调用的延迟。
+
+
+
+
+ disabled bool #
+
+
+
+
+
+ hitSlop {top: number, left: number, bottom: number, right: number} #
+
+
这一属性定义了按钮的外延范围。这一范围也会使pressRetentionOffset(见下文)变得更大。
+ 注意: 触摸范围不会超过父视图的边界,也不会影响原先和本组件层叠的视图(保留原先的触摸优先级)。
+
+
+
onLayout function #
+
+
当加载或者布局改变的时候被调用,参数为:
+
{nativeEvent: {layout: {x, y, width, height}}}
+
+
+
+
onLongPress function #
+
+
+
onPress function #
+
+
当触摸操作结束时调用,但如果被取消了则不调用(譬如响应者被一个滚动操作取代)
+
+
+
+
+
onPressOut function #
+
+
+
pressRetentionOffset {top: number, left: number, bottom: number, right: number} #
+
+
在当前视图不能滚动的前提下指定这个属性,可以决定当手指移开多远距离之后,会不再激活按钮。但如果手指再次移回范围内,按钮会被再次激活。只要视图不能滚动,你可以来回多次这样的操作。确保你传入一个常量来减少内存分配。
+
+
+
diff --git a/docs/docs/0.41/transforms.md b/docs/docs/0.41/transforms.md
new file mode 100644
index 0000000..7eb6d04
--- /dev/null
+++ b/docs/docs/0.41/transforms.md
@@ -0,0 +1,14 @@
+### 属性列表
+
+
+
+
+ transform [{perspective: number}, {rotate: string}, {rotateX: string}, {rotateY: string}, {rotateZ: string}, {scale: number}, {scaleX: number}, {scaleY: number}, {translateX: number}, {translateY: number}, {skewX: string}, {skewY: string}] #
+
+
+
+
+ transformMatrix TransformMatrixPropType #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.41/troubleshooting.md b/docs/docs/0.41/troubleshooting.md
new file mode 100644
index 0000000..46c28eb
--- /dev/null
+++ b/docs/docs/0.41/troubleshooting.md
@@ -0,0 +1,122 @@
+## Cmd-R在模拟器里不能重新加载应用
+
+在菜单`Hardware > KeyboardMenu`中启用iOS模拟器的"Connect hardware keyboard"。
+
+
+
+如果你使用的键盘不是QWERTY或AZERTY布局,你可以在菜单中选择`Hardware > Shake Gesture`来打开开发者菜单,然后点击"Reload"刷新应用。
+
+## 端口已被使用
+
+可能别的进程正在使用8081端口,你可以尝试关闭它或者尝试修改packager所监听的端口。
+
+##### 关闭使用8081端口的进程
+
+```bash
+$ sudo lsof -n -i4TCP:8081 | grep LISTEN`
+```
+
+然后
+
+```bash
+$ kill -9 <上面显示的进程ID>
+```
+
+##### Windows用户
+
+```bash
+> netstat -o -p TCP
+```
+
+结果的第二列中冒号后面的部分为端口号,找到端口号为8081的行,该行最后一列的数字为进程ID
+
+```bash
+> tskill <进程ID>
+```
+
+##### 在XCode中改变端口号
+
+编辑`AppDelegate.m`来更换端口号
+
+```
+ // OPTION 1
+ // Load from development server. Start the server from the repository root:
+ //
+ // $ npm start
+ //
+ // To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
+ // iOS device are on the same Wi-Fi network.
+ jsCodeLocation = [NSURL URLWithString:@"http://localhost:9381/index.ios.bundle"];
+```
+
+## Mac系统下提示错误提示“Watchman took to long to load”
+
+某些版本的Watchman存在一个BUG,权限设置会导致它无法正常启动。最近的一个更新解决了这个问题,如果你遇到了这个错误提示,重新安装最新版本的Watchman:
+
+```bash
+brew uninstall watchman
+brew install --HEAD watchman
+```
+
+## NPM locking error
+
+如果你在执行`react-native init `的过程中遇到npm报错:"npm WARN locking Error: EACCESS",可以尝试执行:
+
+```bash
+sudo chown -R $USER ~/.npm
+sudo chown -R $USER /usr/local/lib/node_modules
+```
+
+## 在Chrome中调试卡住或者不能正常调试
+
+有可能你的某个Chrome扩展正在和调试器进行意外的交互。如果你遇到了这个问题,可以尝试禁用你的全部扩展,然后逐个启用,直到找到导致问题的扩展。
+
+## XCode构建失败
+
+检查导致构建失败的具体原因,在左侧边栏进入"Issue"页面
+
+##### 缺少React库
+
+如果你使用CocoaPods,检查你是否已经在`Podfile`中增加了React的相关声明。举例来说,如果你正在使用` `, ` `和`fetch()`三个API,你需要在`Podfile`中增加以下内容:
+
+```
+pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'RCTText',
+ 'RCTImage',
+ 'RCTNetwork',
+ 'RCTWebSocket',
+]
+```
+
+接下来,确保你执行过`pod install`命令,并且`Pods/`目录已经被创建,并且React的相关库已经被安装。CocoaPods会引导你从此使用生成的`.xcworkspace`文件,以使用刚刚安装的依赖。
+
+如果你手动添加React库,确保你已经引用了全部的相关依赖,譬如`RCTText.xcodeproj`,`RCTImage.xcodeproj`。要添加哪些依赖取决于你使用了哪些功能。接下来,每个依赖工程所产生的二进制文件要被链接到你的应用程序中。在XCode的工程设置里,找到`Linked Frameworks and Binarys`区域。更多的详细步骤参考[使用链接库](/docs/linking-libraries-ios.html#content)。
+
+##### 报错:“Argument list too long: recursive header expansion failed”
+
+在工程的`Build Settings`面板中,`User Search Header Paths`和`Header Search Paths`选项用于控制XCode在什么目录下寻找代码中`#import`所引用的头文件。对Pods来说,CocoaPods会配置一个默认的查找目录的数组。检查这个选项确保它没有被一个新配置覆盖,并且其中没有配置一个很大的目录。如果其中的某个目录很大,XCode在尝试递归搜索整个目录结构的时候可能会报出以上的错误。
+
+要想把`User Search Header Paths`和`Header Search Paths`恢复到CocoaPods所指定的默认值,首先选中Build Settings面板中的这两个字段,然后按下Delete键。这将会删除自定义的配置,然后恢复到CocoaPods所指定的默认配置。
+
+## 无法连接到开发服务器
+
+##### iOS
+
+确保你的设备和你的电脑在同一个网段下。如果你的设备正在使用2G/3G/4G上网,就没有办法访问你的电脑的本地IP。
+
+##### Android
+
+对于Android 5.0以上设备,你可以运行`adb reverse tcp:8081 tcp:8081`来使得你的设备可以访问到你的电脑。
+
+## 使用`WebSocket`的模块(譬如Firebase)抛出了异常
+
+React Native实现了一套WebSockets的接口兼容(POLYFILLS)。这些兼容组件作为react-native模块的一部分来初始化,所以如果你在`require('react-native')`之前引用了使用WebSockets的模块,就可能会产生错误。确保在你的程序中,最先`require('react-native')`
+
+像这样:
+
+```
+var ReactNative = require('react-native');
+var Firebase = require('firebase');
+```
+
+感谢Issue [#3645](https://github.com/facebook/react-native/issues/3645)发现此问题。如果你对相关内容好奇,可以阅读[InitializeJavaScriptAppEngine.js](https://github.com/facebook/react-native/blob/master/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js),WebSocket的接口兼容在这个文件中被初始化。
\ No newline at end of file
diff --git a/docs/docs/0.41/tutorial-core-components.md b/docs/docs/0.41/tutorial-core-components.md
new file mode 100644
index 0000000..23903fd
--- /dev/null
+++ b/docs/docs/0.41/tutorial-core-components.md
@@ -0,0 +1,139 @@
+组件是React Native应用的基石。一个典型的RN应用的用户界面(UI)是如何产生的?首先是声明组件(以及嵌套组件),然后组件被转换为了对应平台的原生UI组件。
+
+下面介绍的是一些React Native应用中常用的核心组件,它们既可以单独使用,也可以组合使用。
+
+## Text
+
+React Native中最基础的组件莫过于[`Text`](text.html#content)组件了。`Text` 就是用于显示文本。
+
+下面的代码演示了如何在设备上显示一个`"Hello"`。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text } from 'react-native';
+
+const App = () => {
+ return (
+ Hello World!
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## Image
+
+另一个基础的React Native组件就是[`Image`](image.html#content)组件了。类似`Text`,`Image`也就是用于显示图片。
+
+> `Image`就好比是网站中的`img`标签。
+
+最简单的渲染图片的方法就是在`source`属性中指定一个源文件。
+
+下面的代码在设备上显示了一个名为`check.png`的图片。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Image } from 'react-native';
+
+const App = () => {
+ return (
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## View
+
+[`View`](view.html#content)是React Native应用中最基础的“容器”。`View`是对不同目标平台基础视图控件的抽象封装,比如它对应iOS上的`UIView` 。
+
+> `View`就好比是网站中的`div`标签。
+
+虽然像`Text`和`Image`这样的基础组件无需包装在`View`里也可以正常显示,但这并不是我们提倡的做法。将它们包装在`View`组件里,才更好控制其样式和布局。
+
+下面的例子创建了一个`View`组件并将`Hello`这串字符对齐到了设备的顶端中部,而这如果仅仅依靠`Text`组件自身是实现不了的。(你尝试在这里只放一个`Text`组件而不用`View`包装起来,则文字只会显示在左上角):
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+const App = () => {
+ return (
+
+ Hello!
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## TextInput
+
+很多应用还离不开用户的直接输入。发帖或者写评论就是一个典型的例子。[`TextInput`](textinput.html#content)就是让用户输入文本的基础组件。
+
+下面的例子创建了一个简单的`TextInput`输入框,其中有空白时的占位文字`Hello`。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, TextInput, View } from 'react-native';
+
+const App = () => {
+ return (
+
+
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## ListView
+
+在很多移动应用中,列表是个非常核心的元素。[`ListView`](listview.html#content) 组件是一个特制的[`View`](view.html#content),用于显示数据可变的垂直滚动列表。
+
+`ListView`组件有两个必需的属性:`dataSource`和`renderRow`。`dataSource`即为列表内容的实际数据来源。`renderRow`则根据数据渲染实际内容。
+
+下面的例子创建了一个简单的`ListView`,并预设了一些模拟数据。它会首先初始化`datasource`,然后根据其数据来渲染`ListView` 。
+
+> 要使用`ListView`,`rowHasChanged`函数也是必须的。这里我们只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text, View, ListView} from 'react-native';
+
+class SimpleList extends React.Component {
+ // 初始化模拟数据
+ constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows(['John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie'])
+ };
+ }
+ render() {
+ return (
+
+ {rowData} }
+ />
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => SimpleList);
+```
diff --git a/docs/docs/0.41/tutorial.md b/docs/docs/0.41/tutorial.md
new file mode 100644
index 0000000..2250bec
--- /dev/null
+++ b/docs/docs/0.41/tutorial.md
@@ -0,0 +1,43 @@
+React Native看起来很像React,只不过其基础组件是原生组件而非web组件。要理解React Native应用的基本结构,首先需要了解一些基本的React的概念,比如JSX语法、组件、`state`状态以及`props`属性。如果你已经了解了React,那么还需要掌握一些React Native特有的知识,比如原生组件的使用。这篇教程可以供任何基础的读者学习,不管你是否有React方面的经验。
+
+让我们开始吧!
+
+## Hello World
+
+根据历史悠久的“传统”,我们也来写一个“Hello World”:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text } from 'react-native';
+
+class HelloWorldApp extends Component {
+ render() {
+ return (
+ Hello world!
+ );
+ }
+}
+
+// 注意,这里用引号括起来的'HelloWorldApp'必须和你init创建的项目名一致
+AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
+```
+
+你可以新建一个项目,然后用上面的代码覆盖你的`index.ios.js`或是`index.android.js` 文件,然后运行看看。
+
+## 那这段代码是什么意思呢?
+
+初看这段代码,可能觉得并不像JavaScript——没错,这是“未来”的JavaScript.
+
+首先你需要了解ES2015 (也叫作ES6)——这是一套对JavaScript的语法改进的官方标准。但是这套标准目前还没有在所有的浏览器上完整实现,所以目前而言web开发中还很少使用。React Native内置了对ES2015标准的支持,你可以放心使用而无需担心兼容性问题。上面的示例代码中的`import`、`from`、`class`、`extends`、以及`() =>`箭头函数等新语法都是ES2015中的特性。如果你不熟悉ES2015的话,可以看看[阮一峰老师的书](http://es6.ruanyifeng.com/),还有论坛的这篇[总结](http://bbs.reactnative.cn/topic/15)。
+
+示例中的这一行`Hello world! `恐怕很多人看起来也觉得陌生。这叫做JSX——是一种在JavaScript中嵌入XML结构的语法。很多传统的应用框架会设计自有的模板语法,让你在结构标记中嵌入代码。React反其道而行之,设计的JSX语法却是让你在代码中嵌入结构标记。初看起来,这种写法很像web上的HTML,只不过使用的并不是web上常见的标签如``或是`
`等,这里我们使用的是React Native的组件。上面的示例代码中,使用的是内置的``组件,它专门用来显示文本。
+
+## 组件与AppRegistry
+
+上面的代码定义了一个名为`HelloWorldApp`的新的`组件(Component)`,并且使用了名为`AppRegistry`的内置模块进行了“注册”操作。你在编写React Native应用时,肯定会写出很多新的组件。而一个App的最终界面,其实也就是各式各样的组件的组合。组件本身结构可以非常简单——唯一必须的就是在`render`方法中返回一些用于渲染结构的JSX语句。
+
+`AppRegistry`模块则是用来告知React Native哪一个组件被注册为整个应用的根容器。你无需在此深究,因为一般在整个应用里`AppRegistry.registerComponent`这个方法只会调用一次。上面的代码里已经包含了具体的用法,你只需整个复制到`index.ios.js`或是`index.android.js`文件中即可运行。
+
+## 这个示例弱爆了!
+
+……是的。如果想做些更有意思的东西,请[接着学习Props属性](props.html)。或者可以看看一个[稍微复杂些的“电影列表”例子](sample-application-movies.html)。
diff --git a/docs/docs/0.41/upgrading.md b/docs/docs/0.41/upgrading.md
new file mode 100644
index 0000000..d21a305
--- /dev/null
+++ b/docs/docs/0.41/upgrading.md
@@ -0,0 +1,103 @@
+时刻将React Native更新到最新的版本,可以获得更多API、视图、开发者工具以及其他一些好东西(译注:官方开发任务繁重,人手紧缺,几乎不会对旧版本提供维护支持,所以即便更新可能带来一些兼容上的变更,但建议开发者还是尽一切可能第一时间更新)。由于一个完整的React Native项目是由Android项目、iOS项目和JavaScript项目组成的,且都打包在一个npm包中,所以升级可能会有一些麻烦。我们会尽量简化这一流程。你可以在项目目录下使用`react-native -v`命令查看当前的版本。以下是目前所需的升级步骤:
+
+__译注__:[更新日志点这里查看](http://bbs.reactnative.cn/category/1)
+
+
+## 基于Git的自动合并更新
+
+**重要提示:** 现在你不需要运行npm install去下载新版本的React Native了,按照下面的步骤即可自动进行更新。
+
+### 1. 安装Git
+你需要安装Git,但这并不要求你自己使用Git去管理项目。只是我们的更新过程会使用到Git罢了。你可以在[这里](https://git-scm.com/downloads)下载安装Git,注意要把git的路径添加到`PATH`变量中。
+
+### 2. 安装`react-native-git-upgrade`工具模块
+
+```sh
+$ npm install -g react-native-git-upgrade
+```
+
+`react-native-git-upgrade`提供了豪华的一条龙自动合并更新流程,主要包含两个服务:
+
+* 首先它会利用Git工具计算新旧版本文件间的差异并生成补丁
+* 然后在用户的项目文件上应用补丁
+
+### 3. 运行更新命令
+
+```sh
+$ react-native-git-upgrade
+# 这样会直接把react native升级到最新版本
+
+# 或者是:
+
+$ react-native-git-upgrade X.Y.Z
+# 这样把react native升级到指定的X.Y.Z版本
+```
+
+升级过程会如丝般顺滑。当然在少数情况下,取决于具体的版本和你修改的程度,Git的合并算法也可能遭遇失败产生一些冲突,需要你人工介入。
+
+### 4. 解决冲突
+
+文件中的冲突会以分隔线隔开,并清楚的标记出处,例如下面这样:
+
+```
+13B07F951A680F5B00A75B9A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+<<<<<<< ours
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/HockeySDK.embeddedframework",
+ "$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
+ );
+=======
+ CURRENT_PROJECT_VERSION = 1;
+>>>>>>> theirs
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ "$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
+ );
+```
+
+上面代码中的"ours"表示你自己的代码,而"theirs"表示React Native的官方代码。然后你可以根据实际情况判断,选择某一方晋级,另一方出局(
+
+## 老式升级方案
+
+如果上面的自动升级流程有问题,那么你可以尝试一下下面的老的升级方案。
+
+## 1. 更新`react-native`的node依赖包
+
+请去下面的网址查看`react-native`的npm包的最新版本,或使用`npm info react-native`命令查看。
+
+* [https://www.npmjs.com/package/react-native](https://www.npmjs.com/package/react-native)
+
+打开项目目录下的`package.json`文件,然后在`dependencies`模块下找到`react-native`,将当前版本号改到最新,然后在命令行中运行(译注:如果提示权限错误,就在命令前加上sudo):
+
+```sh
+$ npm install
+```
+
+译注:从0.24版本开始,react-native还需要额外安装react模块,且对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react模块版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm install react@某.某.某版本 --save`。
+
+## 2. 升级项目模板文件
+
+新版本的npm包通常还会包含一些动态生成的文件,这些文件是在运行`react-native init`创建新项目时生成的,比如iOS和Android的项目文件。为了使老项目的项目文件也能得到更新(不重新init),你需要在命令行中运行:
+
+```sh
+$ react-native upgrade
+```
+
+这一命令会检查最新的项目模板,然后进行如下操作:
+
+* 如果是新添加的文件,则直接创建。
+* 如果文件和当前版本的文件相同,则跳过。
+* 如果文件和当前版本的文件不同,则会提示你一些选项:查看两者的不同,选择保留你的版本或是用新的模板覆盖。你可以按下`h`键来查看所有可以使用的命令。
+
+__译注__:如果你有修改原生代码,那么在使用upgrade升级前,`先备份,再覆盖`。覆盖完成后,使用比对工具找出差异,将你之前修改的代码逐步搬运到新文件中。
+
+# 手动升级
+
+有时候React Native的项目结构改动较大,此时还需要手动做一些修改,例如从0.13到0.14版本,或是0.28到0.29版本。所以在升级时请先阅读一下[更新日志](http://bbs.reactnative.cn/category/1/),以确定是否需要做一些额外的手动修改。
diff --git a/docs/docs/0.41/using-a-listview.md b/docs/docs/0.41/using-a-listview.md
new file mode 100644
index 0000000..fe365b4
--- /dev/null
+++ b/docs/docs/0.41/using-a-listview.md
@@ -0,0 +1,43 @@
+`ListView`组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。
+
+`ListView`更适于长列表数据,且元素个数可以增删。和[`ScrollView`](using-a-scrollview.html)不同的是,`ListView`并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
+
+`ListView`组件必须的两个属性是`dataSource`和`renderRow`。`dataSource`是列表的数据源,而`renderRow`则逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。
+
+下面的例子创建了一个简单的`ListView`,并预设了一些模拟数据。首先是初始化`ListView`所需的`dataSource`,其中的每一项(行)数据之后都在`renderRow`中被渲染成了`Text`组件,最后构成整个`ListView`。
+
+> `rowHasChanged`函数也是`ListView`的必需属性。这里我们只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, ListView, Text, View } from 'react-native';
+
+class ListViewBasics extends Component {
+ // 初始化模拟数据
+ constructor(props) {
+ super(props);
+ const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows([
+ 'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
+ ])
+ };
+ }
+ render() {
+ return (
+
+ {rowData} }
+ />
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('ListViewBasics', () => ListViewBasics);
+```
+
+`ListView`的一个常用场景就是从服务器端取回列表数据然后显示,要实现这一过程,你可能还需要学习[React Native的网络相关用法](network.html).
diff --git a/docs/docs/0.41/using-a-scrollview.md b/docs/docs/0.41/using-a-scrollview.md
new file mode 100644
index 0000000..31c0a76
--- /dev/null
+++ b/docs/docs/0.41/using-a-scrollview.md
@@ -0,0 +1,58 @@
+[`ScrollView`](scrollview.html)是一个通用的可滚动的容器,你可以在其中放入多个组件和视图,而且这些组件并不需要是同类型的。ScrollView不仅可以垂直滚动,还能水平滚动(通过`horizontal`属性来设置)。
+
+下面的示例代码创建了一个垂直滚动的`ScrollView`,其中还混杂了图片和文字组件。
+
+注:下面的这个`./img/favicon.png`并不实际存在,请自己准备图片素材,并改为相对应的正确路径,具体请参考[图片文档](images.html)。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import{ AppRegistry, ScrollView, Image, Text, View } from 'react-native'
+
+class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
+ render() {
+ return(
+
+ Scroll me plz
+
+
+
+
+
+ If you like
+
+
+
+
+
+ Scrolling down
+
+
+
+
+
+ What's the best
+
+
+
+
+
+ Framework around?
+
+
+
+
+
+ React Native
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent(
+ 'IScrolledDownAndWhatHappenedNextShockedMe',
+ () => IScrolledDownAndWhatHappenedNextShockedMe);
+```
+
+`ScrollView`适合用来显示数量不多的滚动元素。放置在`ScollView`中的所有组件都会被渲染,哪怕有些组件因为内容太长被挤出了屏幕外。如果你需要显示较长的滚动列表,那么应该使用功能差不多但性能更好的`ListView`组件。下面我们来看看[如何使用ListView](using-a-listview.html)。
diff --git a/docs/docs/0.41/using-navigators.md b/docs/docs/0.41/using-navigators.md
new file mode 100644
index 0000000..361d5c4
--- /dev/null
+++ b/docs/docs/0.41/using-navigators.md
@@ -0,0 +1,170 @@
+移动应用很少只包含一个页面。从你添加第二个页面开始,就得考虑如何管理多个页面间的跳转了。
+
+导航器正是为此而生。它可以管理多个页面间的跳转,也包含了一些常见的过渡动画,包括水平翻页、垂直弹出等等。
+
+## Navigator
+
+React Native目前有几个内置的导航器组件,一般来说我们首推`Navigator`。它使用纯JavaScript实现了一个导航栈,因此可以跨平台工作,同时也便于定制。
+
+
+
+### 场景(Scene)的概念与使用
+
+无论是`View`中包含`Text`,还是一个排满了图片的`ScrollView`,渲染各种组件现在对你来说应该已经得心应手了。这些摆放在一个屏幕中的组件,就共同构成了一个“场景(Scene)”。
+
+场景简单来说其实就是一个全屏的React组件。与之相对的是单个的`Text`、`Image`又或者是你自定义的什么组件,仅仅占据页面中的一部分。你其实已经不知不觉地接触到了场景——在前面的教程中,[“编写HelloWorld”](tutorial.html)、[“使用Flexbox布局”](layout-with-flexbox.html)、[“如何使用ListView”](using-a-listview.html)中的组件都是完整的场景示例。
+
+下面我们来定义一个仅显示一些文本的简单场景。创建一个名为“MyScene.js”的文件,然后粘贴如下代码:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+export default class MyScene extends Component {
+ static defaultProps = {
+ title: 'MyScene'
+ };
+
+ render() {
+ return (
+
+ Hi! My name is {this.props.title}.
+
+ )
+ }
+}
+```
+
+注意组件声明前面的`export default`关键字。它的意思是**导出(export)**当前组件,以允许其他组件**引入(import)**和使用当前组件,就像下面这样(下面的代码你可以写在index.ios.js或是index.android.js中):
+
+```javascript
+import React, { Component } from 'react';
+import { AppRegistry } from 'react-native';
+
+// ./MyScene表示的是当前目录下的MyScene.js文件,也就是我们刚刚创建的文件
+// 注意即便当前文件和MyScene.js在同一个目录中,"./"两个符号也是不能省略的!
+// 但是.js后缀是可以省略的
+
+import MyScene from './MyScene';
+
+class YoDawgApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp);
+```
+
+我们现在已经创建了只有单个场景的App。其中的`MyScene`同时也是一个[可复用的React组件](https://facebook.github.io/react/docs/reusable-components.html)的例子。
+
+### 使用Navigator
+
+场景已经说的够多了,下面我们开始尝试导航跳转。首先要做的是渲染一个`Navigator`组件,然后通过此组件的`renderScene`属性方法来渲染其他场景。
+
+```javascript
+render() {
+ return (
+ {
+ return
+ }}
+ />
+ );
+}
+```
+
+使用导航器经常会碰到“路由(route)”的概念。“路由”抽象自现实生活中的路牌,在RN中专指包含了场景信息的对象。`renderScene`方法是完全根据路由提供的信息来渲染场景的。你可以在路由中任意自定义参数以区分标记不同的场景,我们在这里仅仅使用`title`作为演示。
+
+#### 将场景推入导航栈
+
+要过渡到新的场景,你需要了解`push`和`pop`方法。这两个方法由`navigator`对象提供,而这个对象就是上面的`renderScene`方法中传递的第二个参数。 我们使用这两个方法来把路由对象推入或弹出导航栈。
+
+```javascript
+navigator.push({
+ title: 'Next Scene',
+ index: 1,
+});
+
+navigator.pop();
+```
+
+下面是一个更完整的示例:
+
+```javascript
+import React, { Component } from 'react';
+import { AppRegistry, Navigator, Text, View } from 'react-native';
+
+import MyScene from './MyScene';
+
+class SimpleNavigationApp extends Component {
+ render() {
+ return (
+
+ {
+ const nextIndex = route.index + 1;
+ navigator.push({
+ title: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+
+ // Function to call to go back to the previous scene
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+ )
+ }
+}
+
+AppRegistry.registerComponent('SimpleNavigationApp', () => SimpleNavigationApp);
+```
+
+对应的MyScene.js代码如下:
+```js
+import React, { Component, PropTypes } from 'react';
+import { View, Text, TouchableHighlight } from 'react-native';
+
+export default class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ onForward: PropTypes.func.isRequired,
+ onBack: PropTypes.func.isRequired,
+ }
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ 点我进入下一场景
+
+
+ 点我返回上一场景
+
+
+ )
+ }
+}
+```
+
+在这个例子中,`MyScene`通过`title`属性接受了路由对象中的title值。它还包含了两个可点击的组件`TouchableHighlight`,会在点击时分别调用通过props传入的`onForward`和`onBack`方法,而这两个方法各自调用了`navigator.push()`和`navigator.pop()`,从而实现了场景的变化。
+
+查看[Navigator API文档](navigator.html)来了解更多`Navigator`的信息。同时推荐你阅读[导航器对比](navigation.html)和论坛中的一个[详细教程](http://bbs.reactnative.cn/topic/20/)来加深理解。
+
+## 恭喜!
+
+如果你一字不漏地看完了本教程,恭喜你获得成就:毅力+1!我们暂时没有更多的东西可以教你了,你可以看看一些[社区的参考资源](more-resources.html)。
diff --git a/docs/docs/0.41/vibration.md b/docs/docs/0.41/vibration.md
new file mode 100644
index 0000000..3f710f3
--- /dev/null
+++ b/docs/docs/0.41/vibration.md
@@ -0,0 +1,145 @@
+本模块导出函数`Vibration.vibrate()`用于控制设备震动。震动触发是异步的,也就是说这个函数会立即返回而非等待震动结束。
+
+在不支持震动的设备上(如iOS模拟器),调用此方法没有任何效果。
+
+注意对于android来说需要在`AndroidManifest.xml`中添加` `权限。
+
+### 方法
+
+
+
+
static vibrate(pattern, repeat) #
+
+
+
pattern参数为一个不定长的数组。在Andriod上,数组第一个元素表示开始震动前的等待时间,然后是震动持续时长和等待时长的交替,例如[0, 500, 1000, 500]表示立刻开始震动500ms,然后等待1000ms,再震动500ms;但在iOS上震动时长是固定的,所以从数组第二个元素开始都是表示震动的间隔时长。
+
repeat参数为布尔类型,表示是否持续循环震动。为true时只有调用cancel才会停止。
+
+
+
+
static cancel() #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ Vibration,
+ Platform,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Vibration';
+exports.description = 'Vibration API';
+
+var pattern, patternLiteral, patternDescription;
+if (Platform.OS === 'android') {
+ pattern = [0, 500, 200, 500];
+ patternLiteral = '[0, 500, 200, 500]';
+ patternDescription = `${patternLiteral}
+arg 0: duration to wait before turning the vibrator on.
+arg with odd: vibration length.
+arg with even: duration to wait before next vibration.
+`;
+} else {
+ pattern = [0, 1000, 2000, 3000];
+ patternLiteral = '[0, 1000, 2000, 3000]';
+ patternDescription = `${patternLiteral}
+vibration length on iOS is fixed.
+pattern controls durations BETWEEN each vibration only.
+
+arg 0: duration to wait before turning the vibrator on.
+subsequent args: duration to wait before next vibrattion.
+`;
+}
+
+exports.examples = [
+ {
+ title: 'Pattern Descriptions',
+ render() {
+ return (
+
+ {patternDescription}
+
+ );
+ },
+ },
+ {
+ title: 'Vibration.vibrate()',
+ render() {
+ return (
+ Vibration.vibrate()}>
+
+ Vibrate
+
+
+ );
+ },
+ },
+ {
+ title: `Vibration.vibrate(${patternLiteral})`,
+ render() {
+ return (
+ Vibration.vibrate(pattern)}>
+
+ Vibrate once
+
+
+ );
+ },
+ },
+ {
+ title: `Vibration.vibrate(${patternLiteral}, true)`,
+ render() {
+ return (
+ Vibration.vibrate(pattern, true)}>
+
+ Vibrate until cancel
+
+
+ );
+ },
+ },
+ {
+ title: 'Vibration.cancel()',
+ render() {
+ return (
+ Vibration.cancel()}>
+
+ Cancel
+
+
+ );
+ },
+ },
+];
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/vibrationios.md b/docs/docs/0.41/vibrationios.md
new file mode 100644
index 0000000..4eeb22d
--- /dev/null
+++ b/docs/docs/0.41/vibrationios.md
@@ -0,0 +1,57 @@
+注意:`VibrationIOS`已经过期。请使用[`Vibration`](vibration.html)代替。
+本模块导出函数`VibrationIOS.vibrate()`用于控制设备震动。在iOS设备上,调用这个函数会触发一个一秒钟的震动。震动触发是异步的,也就是说这个函数会立即返回而非等待震动结束。
+
+在不支持震动的设备上(如iOS模拟器),调用此方法没有任何效果。
+
+震动模式设置现在还不支持。
+
+### 方法
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ VibrationIOS
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'VibrationIOS';
+exports.description = 'Vibration API for iOS';
+exports.examples = [{
+ title: 'VibrationIOS.vibrate()',
+ render() {
+ return (
+ VibrationIOS.vibrate()}>
+
+ Vibrate
+
+
+ );
+ },
+}];
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/view.md b/docs/docs/0.41/view.md
new file mode 100644
index 0000000..276e733
--- /dev/null
+++ b/docs/docs/0.41/view.md
@@ -0,0 +1,268 @@
+作为创建UI时最基础的组件,`View`是一个支持Flexbox布局、样式、一些触摸处理、和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图。不论在什么平台上,`View`都会直接对应一个平台的原生视图,无论它是`UIView`、``还是`android.view.View`。下面的例子创建了一个`View`,包含了两个有颜色的方块和一个自定义的组件,并且设置了一个内边距:
+
+```javascript
+
+
+
+
+
+```
+
+`View`的设计初衷是和`StyleSheet`搭配使用,这样可以使代码更清晰并且获得更高的性能。尽管内联样式也同样可以使用。
+
+### 截图
+
+
+### 属性
+
+
+
+
accessibilityLabel string #
+
+
设置当用户与此元素交互时,“读屏器”(对视力障碍人士的辅助功能)阅读的文字。默认情况下,这个文字会通过遍历所有的子元素并累加所有的文本标签来构建。
+
+
+
+
accessible bool #
+
+
当此属性为true时,表示此视图时一个启用了无障碍功能的元素。默认情况下,所有可触摸操作的元素都是无障碍功能元素。
+
+
+
+
onAccessibilityTap function #
+
+
当accessible为true时,如果用户对一个已选中的无障碍元素做了一个双击手势时,系统会调用此函数。(译注:此事件是针对残障人士,并非是一个普通的点击事件。如果要为View添加普通点击事件,请直接使用Touchable系列组件替代View,然后添加onPress函数 )。
+
+
+
+
onLayout function #
+
+
当组件挂载或者布局变化的时候调用,参数为:
+
{nativeEvent: { layout: {x, y, width, height}}}
+
这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。
+
+
+
+
onMagicTap function #
+
+
当accessible为true时,如果用户做了一个双指轻触(Magic tap)手势,系统会调用此函数。
+
+
+
+
onMoveShouldSetResponder function #
+
+
+
onMoveShouldSetResponderCapture function #
+
+
+
onResponderGrant function #
+
+
对于大部分的触摸处理,你只需要用TouchableHighlight或TouchableOpacity包装你的组件。阅读Touchable.js、ScrollResponder.js和ResponderEventPlugin.js来了解更多信息。
+
+
+
+
onResponderMove function #
+
+
+
onResponderReject function #
+
+
+
onResponderRelease function #
+
+
+
onResponderTerminate function #
+
+
+
onResponderTerminationRequest function #
+
+
+
onStartShouldSetResponder function #
+
+
+
onStartShouldSetResponderCapture function #
+
+
+
pointerEvents enum('box-none', 'none', 'box-only', 'auto') #
+
+
用于控制当前视图是否可以作为触控事件的目标。
+
+
+
+
+
removeClippedSubviews bool #
+
+
这是一个特殊的性能相关的属性,由RCTView导出。在制作滑动控件时,如果控件有很多不在屏幕内的子视图,会非常有用。
+
要让此属性生效,首先要求视图有很多超出范围的子视图,并且子视图和容器视图(或它的某个祖先视图)都应该有样式overflow: hidden。
+
+
+
+
style style #
+
+
+
+
+
backfaceVisibility enum('visible', 'hidden')
+
+
+
backgroundColor string
+
+
+
borderColor string
+
+
+
borderTopColor string
+
+
+
borderRightColor string
+
+
+
borderBottomColor string
+
+
+
borderLeftColor string
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius number
+
+
+
borderTopRightRadius number
+
+
+
borderBottomLeftRadius number
+
+
+
borderBottomRightRadius number
+
+
+
borderStyle enum('solid', 'dotted', 'dashed')
+
+
+
borderWidth number
+
+
+
borderTopWidth number
+
+
+
borderRightWidth number
+
+
+
borderBottomWidth number
+
+
+
borderLeftWidth number
+
+
+
opacity number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
+ android
+ elevation number
+
(限Android)使用Android原生的
+elevation API 来设置视图的高度(elevation)。这样可以为视图添加一个投影,并且会影响视图层叠的顺序。此属性仅支持Android5.0及以上版本。
+
+
+
+
+
+
+
+
android accessibilityComponentType AccessibilityComponentType #
+
+
使无障碍服务对这个UI组件与原生组件一致处理。仅对Android平台有效。
+
+
+
+
android accessibilityLiveRegion enum('none', 'polite', 'assertive') #
+
+
+
+
ios accessibilityTraits AccessibilityTraits, [AccessibilityTraits] #
+
+
为读屏器提供更多属性。除非在元素里指定,默认情况下不提供任何属性。
+
+
+
+
android collapsable bool #
+
+
如果一个View只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除。 把此属性设为false可以禁用这个优化,以确保对应视图在原生结构中存在。
+
+
+
+
android importantForAccessibility enum('auto', 'yes', 'no', 'no-hide-descendants') #
+
+
+
+
android needsOffscreenAlphaCompositing bool #
+
+
决定这个视图是否要先离屏渲染再进行半透明度处理,来确保颜色和混合效果正确。默认值(false)会在渲染组件和它的所有子节点的时候直接应用透明通道,而不会先离屏渲染整个组件再将它附加一个透明通道后渲染到屏幕上。有时候当你给视图设置了一个透明度,且其中有较多元素层叠在一起的时候,默认的设置就会导致看起来不太正常(会比正常显得更加不透明)。
+
为了正确的透明表现而进行离屏渲染会带来极大的开销,而且对于非原生开发者来说很难调试。这就是为啥它被默认关闭。如果你需要在一个动画中启用这个属性,考虑与renderToHardwareTextureAndroid组合使用,前提是视图的内容 不会发生变化(即:它不需要每帧重绘一次)。如果开启了renderToHardwareTextureAndroid,则视图只会离屏渲染一次之后保存为一个硬件纹理,然后以正确的透明度绘制到屏幕上,这样就不会导致GPU频繁切换渲染目标(GPU切换渲染目标会带来极大的开销)。
+
+
+
+
android renderToHardwareTextureAndroid bool #
+
+
决定这个视图是否要把它自己(以及所有的子视图)渲染到一个GPU上的硬件纹理中。
+
在Android上,这对于只修改不透明度、旋转、位移、或缩放的动画和交互十分有用:在这些情况下,视图不必每次都重新绘制,显示列表也不需要重新执行。纹理可以被重用于不同的参数。负面作用是这会大量消耗显存,所以当交互/动画结束后应该把此属性设置回false。
+
+
+
+
ios shouldRasterizeIOS bool #
+
+
决定这个视图是否需要在被混合之前绘制到一个位图上。
+
在iOS上,这对于不会修改组件的尺寸和孩子的动画和交互十分有用。举例来说,当我们移动一个静态视图的位置的时候,预渲染允许渲染器重用一个缓存了静态视图的位图,并快速合成。
+
预渲染会产生一个离屏的渲染过程,并且位图会消耗内存。所以使用此属性需要进行充分的测试和评估。
+
+
+
diff --git a/docs/docs/0.41/viewpagerandroid.md b/docs/docs/0.41/viewpagerandroid.md
new file mode 100644
index 0000000..30c607c
--- /dev/null
+++ b/docs/docs/0.41/viewpagerandroid.md
@@ -0,0 +1,358 @@
+一个允许在子视图之间左右翻页的容器。每一个`ViewPagerAndroid`的子容器会被视作一个单独的页,并且会被拉伸填满`ViewPagerAndroid`。
+
+注意所有的子视图都必须是纯View,而不能是自定义的复合容器。你可以给每个子视图设置样式属性譬如`padding`或`backgroundColor`。
+
+例子:
+
+```javascript
+render: function() {
+ return (
+
+
+ First page
+
+
+ Second page
+
+
+ );
+}
+
+...
+
+var styles = {
+ ...
+ pageStyle: {
+ alignItems: 'center',
+ padding: 20,
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
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 #
+
+
页面滑动状态变化时调用此回调函数。页面滑动状态可能为以下三种之一:
+
+
+
+
+
onPageSelected function #
+
+
这个回调会在页面切换完成后(当用户在页面间滑动)调用。
+
回调参数中的event.nativeEvent对象会包含如下的字段:
+
+
+
+
scrollEnabled bool
+ #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ TouchableWithoutFeedback,
+ TouchableOpacity,
+ View,
+ ViewPagerAndroid,
+} = ReactNative;
+
+import type { ViewPagerScrollState } from 'ViewPagerAndroid';
+
+var PAGES = 5;
+var BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
+var IMAGE_URIS = [
+ 'http://apod.nasa.gov/apod/image/1410/20141008tleBaldridge001h990.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/volcanicpillar_vetter_960.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/m27_snyder_960.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/PupAmulti_rot0.jpg',
+ 'http://apod.nasa.gov/apod/image/1510/lunareclipse_27Sep_beletskycrop4.jpg',
+];
+
+var LikeCount = React.createClass({
+ getInitialState: function() {
+ return {
+ likes: 7,
+ };
+ },
+ onClick: function() {
+ this.setState({likes: this.state.likes + 1});
+ },
+ render: function() {
+ var thumbsUp = '\uD83D\uDC4D';
+ return (
+
+
+
+ {thumbsUp + ' Like'}
+
+
+
+ {this.state.likes + ' likes'}
+
+
+ );
+ },
+});
+
+var Button = React.createClass({
+ _handlePress: function() {
+ if (this.props.enabled && this.props.onPress) {
+ this.props.onPress();
+ }
+ },
+ render: function() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+});
+
+var ProgressBar = React.createClass({
+ render: function() {
+ var fractionalPosition = (this.props.progress.position + this.props.progress.offset);
+ var progressBarSize = (fractionalPosition / (PAGES - 1)) * this.props.size;
+ return (
+
+
+
+ );
+ }
+});
+
+var ViewPagerAndroidExample = React.createClass({
+ statics: {
+ title: '
',
+ description: 'Container that allows to flip left and right between child views.'
+ },
+ getInitialState: function() {
+ return {
+ page: 0,
+ animationsAreEnabled: true,
+ scrollEnabled: true,
+ progress: {
+ position: 0,
+ offset: 0,
+ },
+ };
+ },
+
+ onPageSelected: function(e) {
+ this.setState({page: e.nativeEvent.position});
+ },
+
+ onPageScroll: function(e) {
+ this.setState({progress: e.nativeEvent});
+ },
+
+ onPageScrollStateChanged: function(state : ViewPagerScrollState) {
+ this.setState({scrollState: state});
+ },
+
+ move: function(delta) {
+ var page = this.state.page + delta;
+ this.go(page);
+ },
+
+ go: function(page) {
+ if (this.state.animationsAreEnabled) {
+ this.viewPager.setPage(page);
+ } else {
+ this.viewPager.setPageWithoutAnimation(page);
+ }
+
+ this.setState({page});
+ },
+
+ render: function() {
+ var pages = [];
+ for (var i = 0; i < PAGES; i++) {
+ var pageStyle = {
+ backgroundColor: BGCOLOR[i % BGCOLOR.length],
+ alignItems: 'center',
+ padding: 20,
+ };
+ pages.push(
+
+
+
+
+ );
+ }
+ var { page, animationsAreEnabled } = this.state;
+ return (
+
+ { this.viewPager = viewPager; }}>
+ {pages}
+
+
+ this.setState({scrollEnabled: !this.state.scrollEnabled})}
+ />
+
+
+ { animationsAreEnabled ?
+ this.setState({animationsAreEnabled: false})}
+ /> :
+ this.setState({animationsAreEnabled: true})}
+ /> }
+ ScrollState[ {this.state.scrollState} ]
+
+
+ 0} onPress={() => this.go(0)}/>
+ 0} onPress={() => this.move(-1)}/>
+ Page {page + 1} / {PAGES}
+
+ this.move(1)}/>
+ this.go(PAGES - 1)}/>
+
+
+ );
+ },
+});
+
+var styles = StyleSheet.create({
+ buttons: {
+ flexDirection: 'row',
+ height: 30,
+ backgroundColor: 'black',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ button: {
+ flex: 1,
+ width: 0,
+ margin: 5,
+ borderColor: 'gray',
+ borderWidth: 1,
+ backgroundColor: 'gray',
+ },
+ buttonDisabled: {
+ backgroundColor: 'black',
+ opacity: 0.5,
+ },
+ buttonText: {
+ color: 'white',
+ },
+ scrollStateText: {
+ color: '#99d1b7',
+ },
+ container: {
+ flex: 1,
+ backgroundColor: 'white',
+ },
+ image: {
+ width: 300,
+ height: 200,
+ padding: 20,
+ },
+ likeButton: {
+ backgroundColor: 'rgba(0, 0, 0, 0.1)',
+ borderColor: '#333333',
+ borderWidth: 1,
+ borderRadius: 5,
+ flex: 1,
+ margin: 8,
+ padding: 8,
+ },
+ likeContainer: {
+ flexDirection: 'row',
+ },
+ likesText: {
+ flex: 1,
+ fontSize: 18,
+ alignSelf: 'center',
+ },
+ progressBarContainer: {
+ height: 10,
+ margin: 10,
+ borderColor: '#eeeeee',
+ borderWidth: 2,
+ },
+ progressBar: {
+ alignSelf: 'flex-start',
+ flex: 1,
+ backgroundColor: '#eeeeee',
+ },
+ viewPager: {
+ flex: 1,
+ },
+});
+
+module.exports = ViewPagerAndroidExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.41/webview.md b/docs/docs/0.41/webview.md
new file mode 100644
index 0000000..0ede453
--- /dev/null
+++ b/docs/docs/0.41/webview.md
@@ -0,0 +1,579 @@
+创建一个原生的WebView,可以用于访问一个网页。
+
+### 截图
+
+
+### 属性
+
+
+
+
ios allowsInlineMediaPlayback bool #
+
指定HTML5视频是在网页当前位置播放还是使用原生的全屏播放器播放。
+ 默认值为false。
+
注意 : 要让视频在网页中播放,不光要将这个属性设为true,HTML中的视频元素本身也需要包含webkit-playsinline属性。
+
+
+
automaticallyAdjustContentInsets bool #
+
+
+
+
contentInset {top: number, left: number, bottom: number, right: number} #
+
+
+
ios dataDetectorTypes enum('phoneNumber', 'link', 'address', 'calendarEvent', 'none', 'all'), [object Object] #
+
探测网页中某些特殊数据类型,自动生成可点击的链接,默认情况下仅允许探测电话号码。
你可以指定探测下述类型中的一种,或者使用数组来指定多个类型。
+
dataDetectorTypes的可选值:
+
+ 'phoneNumber'
+ 'link'
+ 'address'
+ 'calendarEvent'
+ 'none'
+ 'all'
+
+
+
+
ios decelerationRate
+ ScrollView.propTypes.decelerationRate #
+
指定一个浮点数,用于设置在用户停止触摸之后,此视图应以多快的速度停止滚动。也可以指定预设的字符串值,如"normal"和"fast",分别对应UIScrollViewDecelerationRateNormal 和UIScrollViewDecelerationRateFast。
+
+ Normal(正常速度): 0.998
+ Fast(较快速度): 0.9 (iOS WebView的默认值)
+
+
+
+
android domStorageEnabled bool #
+
+
仅限Android平台。指定是否开启DOM本地存储。
+
+
+
+
injectedJavaScript string #
+
+
+
+
mediaPlaybackRequiresUserAction bool #
+
+
设置页面中的HTML5音视频是否需要在用户点击后再开始播放。默认值为true.
+
+
+
+
+
+
onLoadStart function
+ #
+
+
+
onMessage function
+ #
+
+
在webview内部的网页中调用window.postMessage方法时可以触发此属性对应的函数,从而实现网页和RN之间的数据交换。
+ 设置此属性的同时会在webview中注入一个postMessage的全局函数并覆盖可能已经存在的同名实现。
+
网页端的window.postMessage只发送一个参数data,此参数封装在RN端的event对象中,即event.nativeEvent.data。data
+ 只能是一个字符串。
+
+
+
+
android javaScriptEnabled bool #
+
+
仅限Android平台。iOS平台JavaScript是默认开启的。
+
+
+
+
onNavigationStateChange function #
+
+
+
ios onShouldStartLoadWithRequest function #
+
+
允许为webview发起的请求运行一个自定义的处理函数。返回true或false表示是否要继续执行响应的请求。
+
+
+
+
renderError function #
+
+
+
+
renderLoading function #
+
+
+
source {uri: string, method: string, headers: object, body: string}, {html: string, baseUrl: string}, number
+ #
+
在WebView中载入一段静态的html代码或是一个url(还可以附带一些header选项)。
+
+
+
scalesPageToFit bool #
+
+
设置是否要把网页缩放到适应视图的大小,以及是否允许用户改变缩放比例。
+
+
+
+
ios scrollEnabled bool #
+
+
+
startInLoadingState bool #
+
+
强制WebView在第一次加载时先显示loading视图。默认为true。
+
+
+
+
+
+
+
+ android userAgent
+ string #
+
+
为WebView设置user-agent字符串标识。这一字符串也可以在原生端用WebViewConfig来设置,但js端的设置会覆盖原生端的设置。
+
+
+
+### 例子
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableWithoutFeedback,
+ TouchableOpacity,
+ View,
+ WebView
+} = ReactNative;
+
+var HEADER = '#3b5998';
+var BGWASH = 'rgba(255,255,255,0.8)';
+var DISABLED_WASH = 'rgba(255,255,255,0.25)';
+
+var TEXT_INPUT_REF = 'urlInput';
+var WEBVIEW_REF = 'webview';
+var DEFAULT_URL = 'https://m.facebook.com';
+
+class WebViewExample extends React.Component {
+ state = {
+ url: DEFAULT_URL,
+ status: 'No Page Loaded',
+ backButtonEnabled: false,
+ forwardButtonEnabled: false,
+ loading: true,
+ scalesPageToFit: true,
+ };
+
+ inputText = '';
+
+ handleTextInputChange = (event) => {
+ var url = event.nativeEvent.text;
+ if (!/^[a-zA-Z-_]+:/.test(url)) {
+ url = 'http://' + url;
+ }
+ this.inputText = url;
+ };
+
+ render() {
+ this.inputText = this.state.url;
+
+ return (
+
+
+
+
+ {'<'}
+
+
+
+
+ {'>'}
+
+
+
+
+
+
+ Go!
+
+
+
+
+
+
+ {this.state.status}
+
+
+ );
+ }
+
+ goBack = () => {
+ this.refs[WEBVIEW_REF].goBack();
+ };
+
+ goForward = () => {
+ this.refs[WEBVIEW_REF].goForward();
+ };
+
+ reload = () => {
+ this.refs[WEBVIEW_REF].reload();
+ };
+
+ onShouldStartLoadWithRequest = (event) => {
+ // Implement any custom loading logic here, don't forget to return!
+ return true;
+ };
+
+ onNavigationStateChange = (navState) => {
+ this.setState({
+ backButtonEnabled: navState.canGoBack,
+ forwardButtonEnabled: navState.canGoForward,
+ url: navState.url,
+ status: navState.title,
+ loading: navState.loading,
+ scalesPageToFit: true
+ });
+ };
+
+ onSubmitEditing = (event) => {
+ this.pressGoButton();
+ };
+
+ pressGoButton = () => {
+ var url = this.inputText.toLowerCase();
+ if (url === this.state.url) {
+ this.reload();
+ } else {
+ this.setState({
+ url: url,
+ });
+ }
+ // dismiss keyboard
+ this.refs[TEXT_INPUT_REF].blur();
+ };
+}
+
+class Button extends React.Component {
+ _handlePress = () => {
+ if (this.props.enabled !== false && this.props.onPress) {
+ this.props.onPress();
+ }
+ };
+
+ render() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+}
+
+class ScaledWebView extends React.Component {
+ state = {
+ scalingEnabled: true,
+ };
+
+ render() {
+ return (
+
+
+
+ { this.state.scalingEnabled ?
+ this.setState({scalingEnabled: false})}
+ /> :
+ this.setState({scalingEnabled: true})}
+ /> }
+
+
+ );
+ }
+}
+
+class MessagingTest extends React.Component {
+ webview = null
+
+ state = {
+ messagesReceivedFromWebView: 0,
+ message: '',
+ }
+
+ onMessage = e => this.setState({
+ messagesReceivedFromWebView: this.state.messagesReceivedFromWebView + 1,
+ message: e.nativeEvent.data,
+ })
+
+ postMessage = () => {
+ if (this.webview) {
+ this.webview.postMessage('"Hello" from React Native!');
+ }
+ }
+
+ render(): ReactElement {
+ const {messagesReceivedFromWebView, message} = this.state;
+
+ return (
+
+
+ Messages received from web view: {messagesReceivedFromWebView}
+ {message || '(No message)'}
+
+
+
+
+
+ { this.webview = webview; }}
+ style={{
+ backgroundColor: BGWASH,
+ height: 100,
+ }}
+ source={require('./messagingtest.html')}
+ onMessage={this.onMessage}
+ />
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: HEADER,
+ },
+ addressBarRow: {
+ flexDirection: 'row',
+ padding: 8,
+ },
+ webView: {
+ backgroundColor: BGWASH,
+ height: 350,
+ },
+ addressBarTextInput: {
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ borderWidth: 1,
+ height: 24,
+ paddingLeft: 10,
+ paddingTop: 3,
+ paddingBottom: 3,
+ flex: 1,
+ fontSize: 14,
+ },
+ navButton: {
+ width: 20,
+ padding: 3,
+ marginRight: 3,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ },
+ disabledButton: {
+ width: 20,
+ padding: 3,
+ marginRight: 3,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: DISABLED_WASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ },
+ goButton: {
+ height: 24,
+ padding: 3,
+ marginLeft: 8,
+ alignItems: 'center',
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ alignSelf: 'stretch',
+ },
+ statusBar: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingLeft: 5,
+ height: 22,
+ },
+ statusBarText: {
+ color: 'white',
+ fontSize: 13,
+ },
+ spinner: {
+ width: 20,
+ marginRight: 6,
+ },
+ buttons: {
+ flexDirection: 'row',
+ height: 30,
+ backgroundColor: 'black',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ button: {
+ flex: 0.5,
+ width: 0,
+ margin: 5,
+ borderColor: 'gray',
+ borderWidth: 1,
+ backgroundColor: 'gray',
+ },
+});
+
+const HTML = `
+\n
+
+
+ Hello Static World
+
+
+
+
+
+ Hello Static World
+
+
+`;
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Base component to display web content';
+exports.examples = [
+ {
+ title: 'Simple Browser',
+ render(): React.Element { return ; }
+ },
+ {
+ title: 'Scale Page to Fit',
+ render(): React.Element { return ; }
+ },
+ {
+ title: 'Bundled HTML',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Static HTML',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'POST Test',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Mesaging Test',
+ render(): ReactElement { return ; }
+ }
+];
+```
diff --git a/docs/docs/0.42/accessibility.md b/docs/docs/0.42/accessibility.md
new file mode 100644
index 0000000..2ed438c
--- /dev/null
+++ b/docs/docs/0.42/accessibility.md
@@ -0,0 +1,161 @@
+## iOS与Android原生App的无障碍功能(accessibility)
+__译注__:accessibility一词常见多种译法:可访问性、无障碍性、辅助功能等等,其中文意思都不太能准确表达其功能的本质——即为残障人士提供便利。本文主要采用“无障碍功能”和“辅助技术/服务”的说法。如果你或你的公司暂时没有资源和精力去服务这些用户,那么你可以跳过本文。但是,`译者个人希望借本文档,呼吁有能力有资源的商业公司/组织/个人,重视残障人士使用智能手机的权利`。
+
+iOS和Android都提供了便于残障人士无障碍使用App的API。此外,两个平台都提供了整套的辅助技术,比如都有针对视力受损人士的读屏软件(iOS的VoiceOver和Android的TalkBack)。同样地,在React Native中我们也封装了对应的API,使开发者能够在App中集成无障碍功能。注意:iOS与Android在具体方法上会有所区别,因此React Native的实现也会因平台而异。
+
+## 使App能够无障碍使用
+
+### 无障碍功能属性
+
+#### accessible (iOS, Android)
+
+设置为`true`时表示当前视图是一个“无障碍元素”(accessibility element)。无障碍元素会将其所有子组件视为一整个可以选中的组件。默认情况下,所有可点击的组件(Touchable系列组件)都是无障碍元素。
+
+在Android上,React Native视图的‘accessible={true}’属性会被转译为原生视图对应的‘focusable={true}’属性。
+
+```javascript
+
+ text one
+ text two
+
+```
+
+在上面这个例子中,当父视图开启无障碍属性后,我们就无法单独选中'text one'和'text two',而只能选中整个父视图。
+
+
+
+#### 无障碍标签accessibilityLabel (iOS, Android)
+
+当一个视图启用无障碍属性后,最好再加上一个accessibilityLabel(无障碍标签),这样可以让使用VoiceOver的人们清楚地知道自己选中了什么。VoiceOver会读出选中元素的无障碍标签。
+
+设定`accessibilityLabel`属性并赋予一个字符串内容即可在视图中启用无障碍标签:
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+在上面这段示例代码中,如果不在TouchableOpacity上设置无障碍标签,那么其默认值就会是"Press me!"(即Text子组件的文本值)。此时无障碍标签是通过自动取所有Text子节点的值,然后用空格连起来生成。
+
+#### 无障碍元素特性accessibilityTraits (iOS)
+
+无障碍元素特性可以使VoiceOver的用户知道自己选中的是什么类型的元素。是文本标签?是按钮?还是头部?`accessibilityTraits`回答了这一问题。
+
+设定`accessibilityTraits`属性并赋予以下一个或多个(以数组的形式)特性字符串即可启用无障碍元素特性:
+
+* **none** 无特性元素。
+* **button** 具有按钮特性。
+* **link** 具有链接特性。
+* **header** 作为内容区域的头部(比如导航栏的标题)。
+* **search** 用作搜索框的文本框。
+* **image** 具有图片特性。可以和按钮或链接等连用。
+* **selected** 元素被选中时使用。比如表格中被选中的一行或是[segmented control](segmentedcontrolios.html)中被选中的一个按钮。
+* **plays** 在元素被点击后播放音效时使用。
+* **key** 元素作为虚拟键盘的一个键使用。
+* **text** 具有不可修改的文本的特性。
+* **summary** 在App冷启动(指完全退出后台后再进入)时提供当前的简要总结信息的元素。比如当天气应用冷启动时,显示当前天气情况的元素就会被标记为**summary**。
+* **disabled** 在元素被禁用,不接受用户输入时使用。
+* **frequentUpdates** 有些元素会频繁更新其标签或值,但我们又不希望太频繁地接受到通知,那么就使用这一特性标记。这一特性标记会使无障碍功能的客户端隔一段时间后再去检查变化(避免频繁打扰用户)。秒表就是个典型的例子。
+* **startsMedia** 在元素启动一个多媒体会话时使用(比如播放电影或是录音),此时不应该被VoiceOver这样的辅助技术打断。
+* **adjustable** 元素具有可调整的特性(比如一个滑块)。
+* **allowsDirectInteraction** 在元素可以接受VoiceOver用户的直接触摸交互时使用(比如展示钢琴键盘的视图)。
+* **pageTurn** 用于通知VoiceOver当前页面已经阅读完毕,可以滚动到下一个页面了。
+
+#### 无障碍元素的点击事件onAccessibilityTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户双击某个已经选中的无障碍元素时调用。
+
+#### MagicTap双指双击事件onMagicTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户执行"magic tap"操作(即使用两个指头来双击)时调用。magic tap的事件处理函数应该做与当前组件相关性最高的操作,比如在电话应用中,magic tap的操作就应该接通电话,或是挂断已经接通的电话。如果当前选中的元素并没有`onMagicTap`函数,则系统会自动遍历视图层,直到找到一个可以响应此操作的。
+
+#### 无障碍组件类型accessibilityComponentType (Android)
+
+在某些情况下,我们也希望告知用户他选中的组件的类型(比如是个按钮)。如果我们使用的是原生按钮,这一行为会自动进行。但既然我们主要是使用javascript,则还需要为Android的TalkBack技术提供更多信息。要实现这一点,就必须为所有UI组件指定`accessibilityComponentType`属性。比如可以指定`button`,`radiobutton_checked`以及`radiobutton_unchecked`等值。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+上面这个例子里,TouchableWithoutFeedback在TalkBack中被声明为一个原生按钮。
+
+#### 无障碍的动态区域accessibilityLiveRegion (Android)
+
+组件发生动态变化时,我们希望TalkBack能够提醒用户。这一行为可以通过设置`accessibilityLiveRegion`属性来实现。具体值可以设置为`none`,`polite`以及`assertive`:
+
+* **none** 辅助服务不应该提醒用户当前视图的变化。
+* **polite** 辅助服务应该提醒用户当前视图的变化。
+* **assertive** 辅助服务应该立即打断当前的语音会话,提醒用户当前视图的变化。
+
+```javascript
+
+
+ Click me
+
+
+
+ Clicked {this.state.count} times
+
+```
+
+上面这个例子中,_addOne方法会改变state.count这个变量。那么只要用户点击了 TouchableWithoutFeedback,TalkBack就会读出Text组件中的值,因为它设置了`accessibilityLiveRegion=”polite”`属性。
+
+#### 无障碍功能优先级importantForAccessibility (Android)
+
+如果有两个UI组件同时层叠覆盖在父视图之上,那么默认的无障碍功能的焦点位置就可能难以预料。`importantForAccessibility`属性解决了这一问题,它可以控制某个视图是否触发无障碍功能事件,以及是否将其报告给辅助服务。具体值可以设置为`auto`,`yes`,`no`和`no-hide-descendants`(最后一个值会强制辅助服务忽略当前组件及其所有子组件)。
+
+```javascript
+
+
+ First layout
+
+
+ Second layout
+
+
+```
+
+上面这个例子里,第二个View的组件对于TalkBack和其他一些辅助服务来说是完全不可见的。这样我们就可以轻易地把两个视图覆盖到同一个父容器上,而不用担心影响TalkBack服务。
+
+
+
+### 发送无障碍功能的相关事件 (Android)
+
+有时候需要在UI组件上主动触发一个无障碍功能的事件(比如当某个自定义的视图出现在屏幕上或是某个自定义的单选框被选中)。为此Native UIManager模块提供了一个`sendAccessibilityEvent`方法。它接受两个参数:view标签和事件类型。
+
+```javascript
+_onPress: function() {
+ this.state.radioButton = this.state.radioButton === “radiobutton_checked” ?
+ “radiobutton_unchecked” : “radiobutton_checked”;
+ if (this.state.radioButton === “radiobutton_checked”) {
+ RCTUIManager.sendAccessibilityEvent(
+ React.findNodeHandle(this),
+ RCTUIManager.AccessibilityEventTypes.typeViewClicked);
+ }
+}
+
+
+```
+
+在上面这个例子里我们创建了一个自定义的单选框(CustomRadioButton),并且使其具有了和原生单选框一样的无障碍功能。具体来说,也就是TalkBack可以正确地通知用户当前选项的变更了。
+
+
+## 测试VoiceOver (iOS)
+
+要开启VoiceOver功能,先打开iOS设备的设置选项。点击“通用”,然后是“辅助选项”,你会看到很多为残障人群使用手机减少障碍的工具,比如更大的字体、更高的对比度以及VoiceOver。
+
+在“视觉”菜单下点击VoiceOver,将开关置为打开状态即可启用。
+
+在辅助选项的最底部,有一个“辅助选项快捷键”,开启之后可以通过点击三次Home按钮来快速关闭或打开VoiceOver工具。
diff --git a/docs/docs/0.42/actionsheetios.md b/docs/docs/0.42/actionsheetios.md
new file mode 100644
index 0000000..a9764ea
--- /dev/null
+++ b/docs/docs/0.42/actionsheetios.md
@@ -0,0 +1,249 @@
+### 截图
+
+
+
+
+### 方法
+
+
+
static showActionSheetWithOptions(options: Object, callback: Function) #
+
+
在iOS设备上显示一个ActionSheet弹出框,其中options参数为一个对象,其属性必须包含以下一项或多项:
+
+ options(字符串数组) - 一组按钮的标题(必选)
+ cancelButtonIndex(整型) - 选项中取消按钮所在的位置(索引)
+ destructiveButtonIndex(整型) - 选项中删除按钮所在的位置(索引)
+ title(字符串) - 弹出框顶部的标题
+ message(字符串) - 弹出框顶部标题下方的信息
+
+
+
+
static showShareActionSheetWithOptions(options: Object, failureCallback: Function, successCallback: Function) #
+
+
+
在iOS设备上显示一个分享弹出框,其中options参数为一个对象,其属性包含以下几项(必须至少有message或url):
+
+ message(字符串) - 要分享的信息
+ url(字符串) - 要分享的URL地址
+ subject(字符串) - 要分享的信息主题
+ excludedActivityTypes(数组) - 指定在actionsheet中不显示的活动
+
+
注:如果url指向本地文件,或者是一个base64编码的url,则会直接读取并分享相应的文件。你可以用这样的方式来分享图片、视频以及PDF文件等。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActionSheetIOS,
+ StyleSheet,
+ Text,
+ UIManager,
+ View,
+} = ReactNative;
+
+var BUTTONS = [
+ 'Option 0',
+ 'Option 1',
+ 'Option 2',
+ 'Delete',
+ 'Cancel',
+];
+var DESTRUCTIVE_INDEX = 3;
+var CANCEL_INDEX = 4;
+
+var ActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ActionSheetTintExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ tintColor: 'green',
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ShareActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: this.props.url,
+ message: 'message to go with the shared url',
+ subject: 'a subject to go in the email heading',
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }
+});
+
+var ShareScreenshotExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ // Take the snapshot (returns a temp file uri)
+ UIManager.takeSnapshot('window').then((uri) => {
+ // Share image data
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: uri,
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }).catch((error) => alert(error));
+ }
+});
+
+var style = StyleSheet.create({
+ button: {
+ marginBottom: 10,
+ fontWeight: '500',
+ }
+});
+
+exports.title = 'ActionSheetIOS';
+exports.description = 'Interface to show iOS\' action sheets';
+exports.examples = [
+ {
+ title: 'Show Action Sheet',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Action Sheet with tinted buttons',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Share Action Sheet',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Local Image',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Screenshot',
+ render(): ReactElement {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.42/activityindicator.md b/docs/docs/0.42/activityindicator.md
new file mode 100644
index 0000000..0092a18
--- /dev/null
+++ b/docs/docs/0.42/activityindicator.md
@@ -0,0 +1,196 @@
+显示一个圆形的loading提示符号。
+
+### 属性
+
+
+
+
+
animating bool #
+
+
是否要显示指示器,默认为true,表示显示。
+
+
+
+
+
ios hidesWhenStopped bool #
+
+
在没有动画的时候,是否要隐藏指示器(默认为true)。
+
+
+
+
size enum('small', 'large') #
+
+
指示器的大小。small的高度为20,large为36。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ ActivityIndicator,
+ StyleSheet,
+ View,
+} = ReactNative;
+const TimerMixin = require('react-timer-mixin');
+
+const ToggleAnimatingActivityIndicator = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState() {
+ return {
+ animating: true,
+ };
+ },
+
+ setToggleTimeout() {
+ this.setTimeout(() => {
+ this.setState({animating: !this.state.animating});
+ this.setToggleTimeout();
+ }, 2000);
+ },
+
+ componentDidMount() {
+ this.setToggleTimeout();
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Animated loading indicators.';
+
+exports.examples = [
+ {
+ title: 'Default (small, white)',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Gray',
+ render() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Large',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Large, custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Start/stop',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom size',
+ render() {
+ return (
+
+ );
+ }
+ },
+];
+
+const styles = StyleSheet.create({
+ centering: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 8,
+ },
+ gray: {
+ backgroundColor: '#cccccc',
+ },
+ horizontal: {
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ padding: 8,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/adsupportios.md b/docs/docs/0.42/adsupportios.md
new file mode 100644
index 0000000..29cbc09
--- /dev/null
+++ b/docs/docs/0.42/adsupportios.md
@@ -0,0 +1,111 @@
+
+### 方法
+
+
+
+
+
+ static getAdvertisingId(onSuccess, onFailure)
+ #
+
+
+
+
+
+ static getAdvertisingTrackingEnabled(onSuccess, onFailure)
+ #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ AdSupportIOS,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Advertising ID';
+exports.description = 'Example of using the ad support API.';
+
+exports.examples = [
+ {
+ title: 'Ad Support IOS',
+ render: function(): ReactElement {
+ return ;
+ },
+ }
+];
+
+class AdSupportIOSExample extends React.Component {
+ state = {
+ deviceID: 'No IDFA yet',
+ hasAdvertiserTracking: 'unset',
+ };
+
+ componentDidMount() {
+ AdSupportIOS.getAdvertisingId(
+ this._onDeviceIDSuccess,
+ this._onDeviceIDFailure
+ );
+
+ AdSupportIOS.getAdvertisingTrackingEnabled(
+ this._onHasTrackingSuccess,
+ this._onHasTrackingFailure
+ );
+ }
+
+ _onHasTrackingSuccess = (hasTracking) => {
+ this.setState({
+ 'hasAdvertiserTracking': hasTracking,
+ });
+ };
+
+ _onHasTrackingFailure = (e) => {
+ this.setState({
+ 'hasAdvertiserTracking': 'Error!',
+ });
+ };
+
+ _onDeviceIDSuccess = (deviceID) => {
+ this.setState({
+ 'deviceID': deviceID,
+ });
+ };
+
+ _onDeviceIDFailure = (e) => {
+ this.setState({
+ 'deviceID': 'Error!',
+ });
+ };
+
+ render() {
+ return (
+
+
+ Advertising ID:
+ {JSON.stringify(this.state.deviceID)}
+
+
+ Has Advertiser Tracking:
+ {JSON.stringify(this.state.hasAdvertiserTracking)}
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: '500',
+ },
+});
+```
diff --git a/docs/docs/0.42/alert.md b/docs/docs/0.42/alert.md
new file mode 100644
index 0000000..9925778
--- /dev/null
+++ b/docs/docs/0.42/alert.md
@@ -0,0 +1,146 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+本接口可以在iOS和Android上显示一个静态的提示框。如果要在显示提示框的同时接受用户输入一些信息,那你可能需要[`AlertIOS`](alertios.html)。
+
+### iOS
+在iOS上你可以指定任意数量的按钮。每个按钮还都可以指定自己的样式,此外还可以指定提示的类别。参阅[AlertIOS](alertios.html)来了解更多细节。
+
+### Android
+在Android上最多能指定三个按钮,这三个按钮分别具有“中间态”、“消极态”和“积极态”的概念:
+
+如果你只指定一个按钮,则它具有“积极态”的属性(比如“确定”);两个按钮,则分别是“消极态”和“积极态”(比如“取消”和“确定”);三个按钮则意味着“中间态”、“消极态”和“积极态”(比如“稍候再说”,“取消”,“确定”)。
+
+### 方法
+
+
+
static alert(title: string, message?: string, button?: Buttons, type?: AlertType) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Alert,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+
+// corporate ipsum > lorem ipsum
+var alertMessage = 'Credibly reintermediate next-generation potentialities after goal-oriented ' +
+ 'catalysts for change. Dynamically revolutionize.';
+
+/**
+ * Simple alert examples.
+ */
+var SimpleAlertExampleBlock = React.createClass({
+
+ render: function() {
+ return (
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ )}>
+
+ Alert with message and default button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with one button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'Cancel', onPress: () => console.log('Cancel Pressed!')},
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with two buttons
+
+
+ Alert.alert(
+ 'Alert Title',
+ null,
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ {text: 'Baz', onPress: () => console.log('Baz Pressed!')},
+ ]
+ )}>
+
+ Alert with three buttons
+
+
+ Alert.alert(
+ 'Foo Title',
+ alertMessage,
+ '..............'.split('').map((dot, index) => ({
+ text: 'Button ' + index,
+ onPress: () => console.log('Pressed ' + index)
+ }))
+ )}>
+
+ Alert with too many buttons
+
+
+
+ );
+ },
+});
+
+var AlertExample = React.createClass({
+ statics: {
+ title: 'Alert',
+ description: 'Alerts display a concise and informative message ' +
+ 'and prompt the user to make a decision.',
+ },
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+
+module.exports = {
+ AlertExample,
+ SimpleAlertExampleBlock,
+};
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/alertios.md b/docs/docs/0.42/alertios.md
new file mode 100644
index 0000000..a078b66
--- /dev/null
+++ b/docs/docs/0.42/alertios.md
@@ -0,0 +1,204 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+这个API主要用于需要iOS特有功能的场景,比如提示用户输入一些信息等。其他情况下,尤其是仅仅显示一个静态的提示框时,应该使用跨平台的[`Alert`](alert.html)接口。
+
+```javascript
+AlertIOS.alert(
+ 'Foo Title',
+ 'My Alert Msg',
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ ]
+)
+```
+### 截图
+
+
+
+
+### 方法
+
+
+
static alert(title: string, message?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, type?: AlertType) #
+
static prompt(title: string, value?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, callback?: Function) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ AlertIOS,
+} = ReactNative;
+
+var { SimpleAlertExampleBlock } = require('./AlertExample');
+
+exports.framework = 'React';
+exports.title = 'AlertIOS';
+exports.description = 'iOS alerts and action sheets';
+exports.examples = [{
+ title: 'Alerts',
+ render() {
+ return ;
+ }
+},
+{
+ title: 'Prompt Options',
+ render(): ReactElement {
+ return ;
+ }
+},
+{
+ title: 'Prompt Types',
+ render() {
+ return (
+
+ AlertIOS.prompt('Plain Text Entry')}>
+
+
+
+ plain-text
+
+
+
+
+ AlertIOS.prompt('Secure Text', null, null, 'secure-text')}>
+
+
+
+ secure-text
+
+
+
+
+ AlertIOS.prompt('Login & Password', null, null, 'login-password')}>
+
+
+
+ login-password
+
+
+
+
+
+ );
+ }
+}];
+
+class PromptOptions extends React.Component {
+ state: any;
+ customButtons: Array;
+
+ constructor(props) {
+ super(props);
+
+ // $FlowFixMe this seems to be a Flow bug, `saveResponse` is defined below
+ this.saveResponse = this.saveResponse.bind(this);
+
+ this.customButtons = [{
+ text: 'Custom OK',
+ onPress: this.saveResponse
+ }, {
+ text: 'Custom Cancel',
+ style: 'cancel',
+ }];
+
+ this.state = {
+ promptValue: undefined,
+ };
+ }
+
+ render() {
+ return (
+
+
+ Prompt value: {this.state.promptValue}
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse)}>
+
+
+
+ prompt with title & callback
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons)}>
+
+
+
+ prompt with title & custom buttons
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse, undefined, 'Default value')}>
+
+
+
+ prompt with title, callback & default value
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons, 'login-password', 'admin@site.com')}>
+
+
+
+ prompt with title, custom buttons, login/password & default value
+
+
+
+
+ );
+ }
+
+ saveResponse(promptValue) {
+ this.setState({ promptValue: JSON.stringify(promptValue) });
+ }
+}
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/android-building-from-source.md b/docs/docs/0.42/android-building-from-source.md
new file mode 100644
index 0000000..459f04e
--- /dev/null
+++ b/docs/docs/0.42/android-building-from-source.md
@@ -0,0 +1,143 @@
+如果你想使用新的功能,获得官方的修复补丁,尝试还没发布的最新特性,或者维护你自己的不能合并到核心版本的补丁,你可能需要自己从源代码编译React Native。
+
+# 预备条件
+
+如果你已经安装了安卓SDK,那么运行`android`命令打开安卓SDK管理器。
+
+确保你已经安装了以下模块:
+
+* Android SDK version 23 (编译SDK版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* SDK build tools version 23.0.1(编译工具版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* Android Support Repository >= 17
+* Android NDK(下载及解压指南看[这里](http://developer.android.com/ndk/downloads/index.html))
+
+将Gradle指向你的安卓SDK: 设置`$ANDROID_SDK`和`$ANDORID_NDK`为对应的目录,或者按照以下内容在react-native根目录下创建local.properties文件(注意:windows下需要使用反双斜杠)。
+
+```
+sdk.dir=指向android sdk目录的绝对路径
+ndk.dir=指向android ndk目录的绝对路径
+```
+例如:
+
+```
+sdk.dir=/Users/your_unix_name/android-sdk-macosx
+ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
+```
+# 从下载链接安装Android NDK
+
+1. Mac OS (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip
+2. Linux (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip
+3. Windows (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip
+4. Windows (32-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86.zip
+
+更多参考您可以访问官网NDK界面 [official page](http://developer.android.com/ndk/downloads/index.html).
+
+__译注__:建议安装r10e版本,否则在编译过程可能会出错。
+
+# 编译源代码:
+
+## 1.在你的分支代码中进行安装
+
+首先,在你的分支代码中安装react-native。例如从官方地址安装主干版本:
+
+```
+npm install --save github:facebook/react-native#master
+```
+
+或者,你也可以把仓库克隆到你的`node_modules`目录,然后运行`npm install`进行安装
+
+## 2.添加gradle依赖
+
+在`android/build.gradle`中添加`gradle-download-task`依赖
+
+```
+...
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.1'
+ classpath 'de.undercouch:gradle-download-task:3.1.2'
+
+ // 注意:不要把你的应用的依赖放在这里;
+ // 它们应该放在各自模块的build.gradle文件中
+ }
+...
+```
+
+## 添加`:ReactAndroid `项目
+
+在`android/settings.gradle`中添加`:ReactAndroid`项目
+
+```
+...
+include ':ReactAndroid'
+
+project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
+...
+```
+
+修改你的`android/app/build.gradle`文件,使用`:ReactAndroid`替换预编译库。例如用`compile project(':ReactAndroid')`替换`compile 'com.facebook.react:react-native:0.16.+'`
+
+```
+...
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.android.support:appcompat-v7:23.0.1'
+
+ compile project(':ReactAndroid')
+
+ ...
+}
+...
+```
+
+## 让第三方模块使用你的分支
+如果你使用第三方的React Native模块,你需要重写它们的依赖以避免它们仍然打包官方的预编译库。否则当你编译时会报错-`Error: more than one library with package name 'com.facebook.react'.`(错误:有几个重名的'com.facebook.react'的包)
+
+修改你的`android/app/build.gradle`文件,添加如下内容:
+
+```
+configurations.all {
+ exclude group: 'com.facebook.react', module: 'react-native'
+}
+```
+
+# 在Android Studio中构建您的项目
+
+在Android Studio欢迎页中选择`Import project`,随后选择您应用所在的文件夹。
+
+您还需要使用_Run_按钮(__译注__:Android Studio中绿色的运行按钮)来在设备上运行您的app,此外Android Studio不会自动开启服务,你还需要通过`npm start`来启动。
+
+# 其他注意事项
+从源码进行编译将会花费很长时间,尤其是第一次编译,需要下载接近200M的文件然后编译原生代码。每次你在自己的仓库更新`react-native`版本时,构建的目录可能会被删除,所有的文件都需要重新下载。为了避免构建目录被删,你需要编辑`~/.gradle/init.gradle`文件来修改构建目录路径。
+
+```
+gradle.projectsLoaded {
+ rootProject.allprojects {
+ buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+ }
+}
+```
+
+## Additional notes
+
+Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of artifacts and compile the native code. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file:
+
+```gradle
+gradle.projectsLoaded {
+ rootProject.allprojects {
+ buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+ }
+}
+```
+
+## Building for Maven/Nexus deployment
+
+If you find that you need to push up a locally compiled React Native .aar and related files to a remote Nexus repository, you can.
+
+Start by following the `Point Gradle to your Android SDK` section of this page. Once you do this, assuming you have Gradle configured properly, you can then run the following command from the root of your React Native checkout to build and package all required files:
+
+```
+./gradlew ReactAndroid:installArchives
+```
+
+This will package everything that would typically be included in the `android` directory of your `node_modules/react-native/` installation in the root directory of your React Native checkout.
+
diff --git a/docs/docs/0.42/android-setup.md b/docs/docs/0.42/android-setup.md
new file mode 100644
index 0000000..549954c
--- /dev/null
+++ b/docs/docs/0.42/android-setup.md
@@ -0,0 +1,86 @@
+本指南主要介绍在Android模拟器上运行React Native Android应用所必须的准备步骤。
+
+### 安装Git
+
+ - **Mac**上如果你已经安装了[XCode](https://developer.apple.com/xcode/),那么Git也就随之安装了,否则请使用homebrew进行安装:
+
+ brew install git
+
+ - **Linux**上请使用你系统对应的[包管理器](https://git-scm.com/download/linux)来安装Git。
+
+ - **Windows**上请下载并安装[Git for Windows](https://git-for-windows.github.io/)。在安装过程中,请务必记得勾选`Run Git from Windows Command Prompt`,这样会把Git的可执行程序加入到`PATH`环境变量中,这样其他程序才能在命令行中正确调用Git。
+
+
+### 安装Android SDK(已安装的请跳过这一步)
+
+1. [安装最新版的JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+
+2. 安装Android SDK:
+ - **Mac**: `brew install android-sdk`
+ - **Linux或Windows**: [从Android开发者官网下载](https://developer.android.com/sdk/installing/index.html)
+__译注__:国内用户推荐从[AndroidDevTools](http://androiddevtools.cn/)下载。
+
+### 定义ANDROID_HOME环境变量
+
+__重要__: 确保`ANDROID_HOME`环境变量指向你已经安装的Android SDK目录:
+
+ - **Mac**, 往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+ (__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这两个文件有可能还没有被创建。请在终端下使用`sudo vi ~/.bashrc`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+ # 如果你是通过Homebrew安装SDK的,则加入下列路径
+ export ANDROID_HOME=/usr/local/opt/android-sdk
+ # 否则可能是(当然具体视你把SDK放在哪):
+ export ANDROID_HOME=~/Library/Android/sdk
+ - **Linux**,往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+
+ export ANDROID_HOME=<你把Android SDK解压后放置的位置>
+
+ - **Windows**,打开控制面板,选择`系统和安全`->`系统`->`高级系统设置`->`高级`->`环境变量`->`新建`,变量名填写ANDROID_HOME,变量值填写你把Android SDK解压后放置的位置。
+
+__译注__: 如果你在windows下找不到对应的控制面板项,也可以右键点击`我的电脑`,然后在菜单中选择`属性`,然后选择`高级系统设置`->`高级`->`环境变量`->`新建`。__注意__:必须将现有的CMD窗口全部关闭,重新打开后新的环境变量才能生效。
+
+
+### 开启gradle daemon
+
+React Native Android使用的构建系统是[gradle](https://docs.gradle.org)。我们建议你开启gradle daemon功能,它可以带来高达50%的java编译速度提升。点击[这里](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)来了解如何针对你的平台开启这一功能。
+
+
+### 设置SDK
+
+1. 打开Android SDK Manager(**Mac**用户在终端下输入`android`)。
+2. 选中以下项目:
+ * Android SDK Build-tools version 23.0.1(这个必须版本严格匹配23.0.1)
+ * Android 6.0 (API 23)
+ * Local Maven repository for Support Libraries(之前叫做Android Support Repository)
+3. 点击"Install Packages"
+ (__译注__:国内用户推荐使用[腾讯Bugly的镜像](http://android-mirror.bugly.qq.com:8080/include/usage.html)来加速下载)
+ 
+
+### 安装Genymotion
+
+Genymotion是一个第三方模拟器,它比Google官方的模拟器更易设置且性能更好。但是,它只针对个人用户免费。如果你想使用Google模拟器,请往下看。
+
+1. 下载并安装[Genymotion](https://www.genymotion.com/)。
+2. 打开Genymotion。如果你尚未安装VirtualBox,它有可能会提示你安装。
+3. 创建一个模拟器并启动。
+4. 按下`⌘+M`可以打开开发者菜单(在安装并启动了React Native应用之后)。
+
+### 备选方案:使用Google官方模拟器
+
+1. 打开Android SDK Manager(参见"设置SDK"一步)
+2. 选中以下项目:
+ * Intel x86 Atom System Image (for Android 5.1.1 - API 22)
+ * Intel x86 Emulator Accelerator (HAXM installer)
+3. 点击"Install Packages"
+4. [配置硬件加速(HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac),否则模拟器会运行的相当缓慢。
+5. 创建Android虚拟设备(AVD):
+ 1. 运行`android avd`并且点击**Create...**
+ (__译注__:在Windows系统下,android.bat在Android SDK的`tools`文件夹下,请注意设置PATH环境变量以便于使用)
+ 
+ 2. 选中新创建的虚拟设备,并点击`Start...`
+
+__译注__:对于Windows用户而言,Intel x86 Emulator Accelerator和HyperV(系统内置的虚拟机功能)不能同时启用。所以要么选择关闭HyperV(控制面板-程序-启动和关闭Windows功能,取消选择HyperV并点确定),要么选择Genymotion、Bluestacks或Visual Studio Emulator for Android作为模拟器。
+
+### 在Android Studio中编辑Java代码
+
+对于JavaScript代码,你可以使用任何编辑器来编辑。如果你想在Android Studio中编辑原生Java代码的话,请在Android Studio的欢迎屏幕上选择"Import project",然后选择你的项目目录中的`android`文件夹即可。
diff --git a/docs/docs/0.42/android-ui-performance.md b/docs/docs/0.42/android-ui-performance.md
new file mode 100644
index 0000000..842da69
--- /dev/null
+++ b/docs/docs/0.42/android-ui-performance.md
@@ -0,0 +1,147 @@
+我们尽最大的努力来争取使UI组件的性能如丝般顺滑,但有的时候这根本不可能做到。要知道,Android有超过一万种不同型号的手机,而在框架底层进行软件渲染的时候是统一处理的,这意味着你没办法像iOS那样自由。不过有些时候,你还是可以想办法提升应用的性能(有的时候问题根本不是出在原生代码上!)
+
+要想解决应用的性能问题,第一步就是搞明白在每个16毫秒的帧中,时间都去哪儿了。为此,我们会使用一个标准的Android性能分析工具`systrace`,不过在此之前……
+
+> 请先确定JS的开发者模式已经关闭!
+>
+> 你应该在应用的日志里看到`__DEV__ === false, development-level warning are OFF, performance optimizations are ON`等字样(你可以通过adb logcat来查看应用日志)
+
+## 使用Systrace进行性能分析
+
+Systrace是一个标准的基于标记的Android性能分析工具(如果你安装了Android platform-tool包,它也会一同安装)。被调试的代码段在开始和结束处加上标记,在执行的过程中标记会被记录,最后会以图表形式展现统计结果。包括Android SDK自己和React Native框架都已经提供了标准的标记供你查看。
+
+### 收集一次数据
+
+> 注意:
+>
+> Systrace从React Native `v0.15`版本开始支持。你需要在此版本下构建项目才能收集相应的性能数据。
+
+首先,把你想分析的、运行不流畅的设备使用USB线链接到电脑上,然后操作应用来到你想分析的导航/动画之前,接着这样运行systrace:
+
+```
+$ /platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a <你的应用包名>
+```
+
+对于此命令做一个简单的说明:
+
+- `time`参数控制本次数据收集的持续时间,单位是秒。
+- `schd`, `gfx`, 和`view`是我们所关心的Android SDK内置的tag(标记的集合):`schd`提供了你的设备的每个CPU核心正在做什么的信息,`gfx`提供了你的图形相关信息,譬如每帧的时间范围,而`view`提供了一些关于视图布局和渲染相关性能的信息。
+- `-a <你的应用包名>`启用了针对应用的过滤。在这里填写你用React Native创建的应用包名。`你的应用包名`可以在你应用中的`AndroidManifest.xml`里找到,形如`com.example.app`
+
+_译注_:实际上,AndroidManifest.xml里的应用包名会被`app/build.gradle`里的`applicationId`取代。如果二者不一致,应当以`app/build.gradle`里的为准。
+
+一旦systrace开始收集数据,你可以操作应用执行你所关心的动画和操作。在收集结束后,systrace会给你提供一个链接,你可以在浏览器中打开这个链接来查看数据收集的结果。
+
+## 查看性能数据
+
+在浏览器中打开数据页面(建议使用Chrome),你应该能看到类似这样的结果:
+
+
+
+**提示**: 你可以使用WSAD键来滚动和缩放性能数据图表。
+
+### 启用垂直同步高亮
+
+接下来你首先应该启用16毫秒帧区间的高亮。在屏幕顶端点击对应的复选框:
+
+
+
+然后你应该能在屏幕上看到类似上图的斑马状条纹。如果你无法看到这样的条纹,可以尝试换一台设备来进行分析:部分三星手机显示垂直同步高亮存在已知问题,而Nexus系列大部分情况都相当可靠。
+
+### 找到你的进程
+
+滚动图表直到你找到你的应用包名。在上面的例子里,我正在分析`com.facebook.adsmanager`,由于内核的线程名字长度限制,它会显示成`book.adsmanager`。
+
+在左侧,你应该能看到一系列线程对应着右边的时间轴。有3到4个线程是我们必须关注的:UI线程(名字可能是`UI Thread`或者是你的包名), `mqt_js`和`mqt_native_modules`。如果你在Android 5.0以上版本运行,我们还需要关注`Render`(渲染)线程。
+
+### UI 线程
+
+标准的Android布局和绘制都在UI线程里发生。右侧显示的线程名字会是你的包名(在我的例子里是book.adsmanager)或者UI Thread.你在这个线程里看到的事件可能会是一些`Choreographer`, `traversals`或者`DispatchUI`:
+
+
+
+### JS线程
+
+这是用于执行JavaScript代码的线程。根据Android系统版本或者设备的不同,线程名可能是`mqt_js`或者`<...>`。如果看不到对应的名字的话,寻找类似`JSCall`,`Bridge.executeJSCall`这样的事件。
+
+
+
+### 原生模块线程
+
+这里是用于原生模块执行代码(譬如`UIManager`)的线程,线程名可能是`mqt_native_modules`或`<...>`。在后一种情况下,寻找类似`NativeCall`, `CallJavaModuleMethod`, 还有`onBatchComplete`这样的事件名:
+
+
+
+### 额外的:渲染线程
+
+如果你在使用Android L(5.0)或者更高版本,你应该还会在你的应用里看到一个渲染线程。这个线程真正生成OpenGL渲染序列来渲染你的UI。这个线程的名字可能为`RenderThread`或者`<...>`,在后一种情况下,寻找类似`DrawFrame`或`queueBuffer`这样的事件:
+
+
+
+## 寻找导致卡顿的罪魁祸首
+
+一个流畅的动画应该看起来像这样:
+
+
+
+每个背景颜色不同的部分我们称作“一帧”——记住要渲染一个流畅的帧,我们所有的界面工作都需要在16毫秒内完成。注意没有任何一个线程在靠近帧的边界处工作。类似这样的一个应用程序就正在60FPS(帧每秒)的情况下流畅表现。
+
+如果你发现一些起伏的地方,譬如这样:
+
+
+
+注意在上图中JS线程基本上一直在执行,并且超越了帧的边界。这个应用就没法以60FPS渲染了。在这种情况下,**问题出在JS中**。
+
+你还有可能会看到一些类似这样的东西:
+
+
+
+在这种情况下,UI和渲染线程有一些重负荷的工作,以至于超越了帧的边界。这可能是由于我们每帧试图渲染的UI太多了导致的。在这种情况下,**问题出在需要渲染的原生视图上**。
+
+并且,你还应该能看到一些可以指导接下来优化工作的有用的信息。
+
+## JS的问题
+
+如果你发现问题出在JS上,在你正在执行的JS代码中寻找线索。在上面的图中,我们会发现`RCTEventEmitter`每帧被执行了很多次。这是上面的数据统计放大后的内容:
+
+
+
+这看起来不是很正常,为什么事件被调用的如此频繁?它们是不同的事件吗?具体的答案取决于你的产品的代码。在许多情况下,你可能需要看看[shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate)的介绍。
+
+> **TODO**: 我们还在准备更多的JS性能分析的工具,会在将来的版本中加入。
+
+## 原生UI问题
+
+如果你发现问题出在原生UI上,有两种常见的情况:
+
+1. 你每帧在渲染的UI给GPU带来了太重的负载,或者:
+2. 你在动画、交互的过程中不断创建新的UI对象(譬如在scroll的过程中加载新的内容)
+
+### GPU负担过重
+
+在第一种情况下,你应该能看到UI线程的图表类似这样:
+
+
+
+注意`DrawFrame`花费了很多时间,超越了帧的边界。这些时间用来等待GPU获取它的操作缓存。
+
+要缓解这个问题,你应该:
+
+- 检查`renderToHardwareTextureAndroid`的使用,有这个属性的View的子节点正在进行动画或变形会导致性能大幅下降(譬如`Navigator`提供的滑动、淡入淡出动画)。
+- 确保你**没有**使用`needsOffscreenAlphaCompositing`,这个默认是关闭的,因为它在大部分情况下都会带来GPU消耗的大幅提升。
+
+如果这还不能帮你解决问题,你可能需要更深入的探索GPU到底在做什么。参见[Tracer for OpenGL ES](http://developer.android.com/tools/help/gltracer.html)。
+
+### 在UI线程创建大量视图
+
+如果是第二种情况,你可能会看到类似这样的结果:
+
+
+
+注意一开始JS线程工作了很久,然后你看到原生模块线程干了些事情,最后带来了UI线程的巨大开销。
+
+这个问题并没有什么简单直接的优化办法,除非你能把创建UI的步骤推迟到交互结束以后去进行,或者你能直接简化你所要创建的UI。React Native小组正在架构层设法提供一个方案,使得新的UI视图可以在主线程之外去创建和配置,这样就可以使得交互变得更加流畅。
+
+## 还是没搞定?
+
+如果你还是很迷惑或者不知如何进展,你可以在[Stack Overflow的react-native标签下](http://stackoverflow.com/tags/react-native)提交一个问题。如果你在这里得不到响应,或者找到了一个核心组件的问题,你可以[提交一个Github issue](https://github.com/facebook/react-native/issues)给我们。
diff --git a/docs/docs/0.42/animated.md b/docs/docs/0.42/animated.md
new file mode 100644
index 0000000..3fa515c
--- /dev/null
+++ b/docs/docs/0.42/animated.md
@@ -0,0 +1,535 @@
+动画是现代用户体验中非常重要的一个部分,`Animated`库就是用来创造流畅、强大、并且易于构建和维护的动画。
+
+最简单的工作流程就是创建一个`Animated.Value`,把它绑定到组件的一个或多个样式属性上。然后可以通过动画驱动它,譬如`Animated.timing`,或者通过`Animated.event`把它关联到一个手势上,譬如拖动或者滑动操作。除了样式,`Animated.value`还可以绑定到props上,并且一样可以被插值。这里有一个简单的例子,一个容器视图会在加载的时候淡入显示:
+
+```javascript
+class FadeInView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // init opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {toValue: 1}, // Configuration
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+ // Binds
+ {this.props.children}
+
+ );
+ }
+ }
+ ```
+
+
+ 注意只有声明为可动画化的组件才能被关联动画。`View`、`Text`,还有`Image`都是可动画化的。如果你想让自定义组件可动画化,可以用`createAnimatedComponent`。这些特殊的组件里面用了一些黑魔法,来把动画数值绑定到属性上,然后在每帧去执行原生更新,来避免每次render和同步过程的开销。他们还处理了在节点卸载时的清理工作以确保使用安全。
+
+ 动画具备很强的可配置性。自定义或者预定义的过渡函数、延迟、时间、衰减比例、刚度等等。取决于动画类型的不同,你还可以配置更多的参数。
+
+ 一个`Animated.Value`可以驱动任意数量的属性,并且每个属性可以配置一个不同的插值函数。插值函数把一个输入的范围映射到输出的范围,通常我们用线性插值,不过你也可以使用其他的过渡函数。默认情况下,当输入超出范围时,它也会对应的进行转换,不过你也可以把输出约束到范围之内。
+
+ 举个例子,你可能希望你的`Animated.Value`从0变化到1时,把组件的位置从150px移动到0px,不透明度从0到1。可以通过以下的方法修改`style`属性来实现:
+
+ ```javascript
+ style={{
+ opacity: this.state.fadeAnim, // Binds directly
+ transform: [{
+ translateY: this.state.fadeAnim.interpolate({
+ inputRange: [0, 1],
+ outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
+ }),
+ }],
+ }}>
+ ```
+
+ 动画还可以被更复杂地组合,通过一些辅助函数例如`sequence`或者`parallel`(它们分别用于先后执行多个动画和同时执行多个动画),而且还可以通过把toValue设置为另一个Animated.Value来产生一个动画序列。
+
+ `Animated.ValueXY`则用来处理一些2D动画,譬如滑动。并且还有一些辅助功能譬如`setOffset`和`getLayout`来帮助实现一些常见的交互效果,譬如拖放操作(Drag and drop)。
+
+ 你可以在`AnimationExample.js`中找到一些更复杂的例子。你还可以看看Gratuitous Animation App,以及[动画指南文档](animations.html)。
+
+注意`Animated`模块被设计为可完全序列化的,这样动画可以脱离JavaScript事件循环,以一种高性能的方式运行。这可能会导致API看起来比较难懂,与一个完全同步的动画系统相比稍微有一些奇怪。`Animated.Value.addListener`可以帮助你解决一些相关限制,不过使用它的时候需要小心,因为将来的版本中它可能会牵扯到性能问题。
+
+### 方法
+
+
+
+
static decay(value: AnimatedValue | AnimatedValueXY, config: DecayAnimationConfig) #
+
+
推动一个值以一个初始的速度和一个衰减系数逐渐变为0。
+
+
+
+
static timing(value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig) #
+
+
推动一个值按照一个过渡曲线而随时间变化。Easing模块定义了一大堆曲线,你也可以使用你自己的函数。
+
+
+
+
static spring(value: AnimatedValue | AnimatedValueXY, config: SpringAnimationConfig) #
+
+
产生一个基于Rebound和Origami实现的Spring动画。它会在toValue值更新的同时跟踪当前的速度状态,以确保动画连贯。可以链式调用。
+
+
+
static add(a: Animated, b: Animated) #
+
static multiply(a: Animated, b: Animated) #
+
+
static delay(time: number) #
+
+
+
+
static sequence(animations: Array<CompositeAnimation>) #
+
+
按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行。
+
+
+
+
static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig) #
+
+
同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。你可以通过stopTogether选项来改变这个效果。
+
+
+
+
static stagger(time: number, animations: Array<CompositeAnimation>) #
+
+
一个动画数组,里面的动画有可能会同时执行(重叠),不过会以指定的延迟来开始。用来制作拖尾效果非常合适。
+
+
+
+
static event(argMapping: Array<Mapping>, config?: EventConfig) #
+
+
接受一个映射的数组,对应的解开每个值,然后调用所有对应的输出的setValue方法。例如:
+
onScroll={this .AnimatedEvent(
+ [{nativeEvent: {contentOffset: {x: this ._scrollX}}}]
+ {listener},
+ )
+ ...
+ onPanResponderMove: this .AnimatedEvent([
+ null ,
+ {dx: this ._panX},
+ ]),
+
+
+
+
+
static createAnimatedComponent(Component: any) #
+
+
使得任何一个React组件支持动画。用它来创建Animated.View等等。
+
+
+
+
+### 属性
+
+
+
+
Value: AnimatedValue #
+
+
表示一个数值的类,用于驱动动画。通常用new Animated.Value(0);来初始化。
+
+
+
+
ValueXY: AnimatedValueXY #
+
+
表示一个2D值的类,用来驱动2D动画,例如拖动操作等。
+
+
+
+
+## class AnimatedValue
+
+用于驱动动画的标准值。一个`Animated.Value`可以用一种同步的方式驱动多个属性,但同时只能被一个行为所驱动。启用一个新的行为(譬如开始一个新的动画,或者运行`setValue`)会停止任何之前的动作。
+
+### 方法
+
+
+
+
constructor(value: number) #
+
+
+
setValue(value: number) #
+
+
直接设置它的值。这个会停止任何正在进行的动画,然后更新所有绑定的属性。
+
+
+
+
setOffset(offset: number) #
+
+
设置一个相对值,不论接下来的值是由setValue、一个动画,还是Animated.event产生的,都会加上这个值。常用来在拖动操作一开始的时候用来记录一个修正值(譬如当前手指位置和View位置)。
+
+
+
+
flattenOffset() #
+
+
把当前的相对值合并到值里,并且将相对值设为0。最终输出的值不会变化。常在拖动操作结束后调用。
+
+
+
+
addListener(callback: ValueListenerCallback) #
+
+
添加一个异步监听函数,这样你就可以监听动画值的变更。这有时候很有用,因为你没办法同步的读取动画的当前值,因为有时候动画会在原生层次运行。
+
+
+
+
removeListener(id: string) #
+
+
+
removeAllListeners() #
+
+
+
stopAnimation(callback?: ?(value: number) => void) #
+
+
停止任何正在运行的动画或跟踪值。callback会被调用,参数是动画结束后的最终值,这个值可能会用于同步更新状态与动画位置。
+
+
+
+
interpolate(config: InterpolationConfigType) #
+
+
在更新属性之前对值进行插值。譬如:把0-1映射到0-10。
+
+
+
+
animate(animation: Animation, callback: EndCallback) #
+
+
一般仅供内部使用。不过有可能一个自定义的动画类会用到此方法。
+
+
+
+
+
track(tracking: Animated) #
+
+
+
+
+## class AnimatedValueXY
+
+用来驱动2D动画的2D值,譬如滑动操作等。API和普通的`Animated.Value`几乎一样,只不过是个复合结构。它实际上包含两个普通的`Animated.Value`。
+
+例子:
+
+```javascript
+class DraggableView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ pan: new Animated.ValueXY(), // inits to zero
+ };
+ this.state.panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: () => true,
+ onPanResponderMove: Animated.event([null, {
+ dx: this.state.pan.x, // x,y are Animated.Value
+ dy: this.state.pan.y,
+ }]),
+ onPanResponderRelease: () => {
+ Animated.spring(
+ this.state.pan, // Auto-multiplexed
+ {toValue: {x: 0, y: 0}} // Back to zero
+ ).start();
+ },
+ });
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+```
+
+### 方法
+
+
+
+
constructor(valueIn?: ?{x: number | AnimatedValue; y: number | AnimatedValue}) #
+
+
+
+
setValue(value: {x: number; y: number}) #
+
+
+
+
setOffset(offset: {x: number; y: number}) #
+
+
+
+
+
stopAnimation(callback?: ?() => number) #
+
+
+
+
addListener(callback: ValueXYListenerCallback) #
+
+
+
+
removeListener(id: string) #
+
+
+
+
getLayout() #
+
+
将一个{x, y}组合转换为{left, top}以用于样式。例如:
+
style={this .state.anim.getLayout()}
+
+
+
+
+
getTranslateTransform() #
+
+
将一个{x, y} 组合转换为一个可用的位移变换(translation transform),例如:
+
style={{
+ transform: this .state.anim.getTranslateTransform()
+ }}
+
+
+
+
+
+ ### 例子
+
+ ```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Animated,
+ Easing,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerButton = require('./UIExplorerButton');
+
+exports.framework = 'React';
+exports.title = 'Animated - Examples';
+exports.description = 'Animated provides a powerful ' +
+ 'and easy-to-use API for building modern, ' +
+ 'interactive user experiences.';
+
+exports.examples = [
+ {
+ title: 'FadeInView',
+ description: 'Uses a simple timing animation to ' +
+ 'bring opacity from 0 to 1 when the component ' +
+ 'mounts.',
+ render: function() {
+ class FadeInView extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {
+ toValue: 1, // Target
+ duration: 2000, // Configuration
+ },
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+ class FadeInExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ show: true,
+ };
+ }
+ render() {
+ return (
+
+ {
+ this.setState((state) => (
+ {show: !state.show}
+ ));
+ }}>
+ Press to {this.state.show ?
+ 'Hide' : 'Show'}
+
+ {this.state.show &&
+
+ FadeInView
+
+ }
+
+ );
+ }
+ }
+ return ;
+ },
+ },
+ {
+ title: 'Transform Bounce',
+ description: 'One `Animated.Value` is driven by a ' +
+ 'spring with custom constants and mapped to an ' +
+ 'ordered set of transforms. Each transform has ' +
+ 'an interpolation to convert the value into the ' +
+ 'right range and units.',
+ render: function() {
+ this.anim = this.anim || new Animated.Value(0);
+ return (
+
+ {
+ Animated.spring(this.anim, {
+ toValue: 0, // Returns to the start
+ velocity: 3, // Velocity makes it move
+ tension: -10, // Slow
+ friction: 1, // Oscillate a lot
+ }).start(); }}>
+ Press to Fling it!
+
+
+ Transforms!
+
+
+ );
+ },
+ },
+ {
+ title: 'Composite Animations with Easing',
+ description: 'Sequence, parallel, delay, and ' +
+ 'stagger with different easing functions.',
+ render: function() {
+ this.anims = this.anims || [1,2,3].map(
+ () => new Animated.Value(0)
+ );
+ return (
+
+ {
+ var timing = Animated.timing;
+ Animated.sequence([ // One after the other
+ timing(this.anims[0], {
+ toValue: 200,
+ easing: Easing.linear,
+ }),
+ Animated.delay(400), // Use with sequence
+ timing(this.anims[0], {
+ toValue: 0,
+ easing: Easing.elastic(2), // Springy
+ }),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(
+ anim, {toValue: 200}
+ )).concat(
+ this.anims.map((anim) => timing(
+ anim, {toValue: 0}
+ ))),
+ ),
+ Animated.delay(400),
+ Animated.parallel([
+ Easing.inOut(Easing.quad), // Symmetric
+ Easing.back(1.5), // Goes backwards first
+ Easing.ease // Default bezier
+ ].map((easing, ii) => (
+ timing(this.anims[ii], {
+ toValue: 320, easing, duration: 3000,
+ })
+ ))),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(anim, {
+ toValue: 0,
+ easing: Easing.bounce, // Like a ball
+ duration: 2000,
+ })),
+ ),
+ ]).start(); }}>
+ Press to Animate
+
+ {['Composite', 'Easing', 'Animations!'].map(
+ (text, ii) => (
+
+ {text}
+
+ )
+ )}
+
+ );
+ },
+ },
+ {
+ title: 'Continuous Interactions',
+ description: 'Gesture events, chaining, 2D ' +
+ 'values, interrupting and transitioning ' +
+ 'animations, etc.',
+ render: () => (
+ Checkout the Gratuitous Animation App!
+ ),
+ }
+];
+
+var styles = StyleSheet.create({
+ content: {
+ backgroundColor: 'deepskyblue',
+ borderWidth: 1,
+ borderColor: 'dodgerblue',
+ padding: 20,
+ margin: 20,
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+});
+ ```
\ No newline at end of file
diff --git a/docs/docs/0.42/animations.md b/docs/docs/0.42/animations.md
new file mode 100644
index 0000000..75cd3c4
--- /dev/null
+++ b/docs/docs/0.42/animations.md
@@ -0,0 +1,414 @@
+流畅、有意义的动画对于移动应用用户体验来说是非常必要的。和React Native的其他部分一样,动画API也还在积极开发中,不过我们已经可以联合使用两个互补的系统:用于全局的布局动画`LayoutAnimation`,和用于创建更精细的交互控制的动画`Animated`。
+
+### Animated
+
+`Animated`库使得开发者可以非常容易地实现各种各样的动画和交互方式,并且具备极高的性能。`Animated`仅关注动画的输入与输出声明,在其中建立一个可配置的变化函数,然后使用简单的`start/stop`方法来控制动画按顺序执行。下面是一个在加载时带有简单的弹跳动画的组件示例:
+
+```javascript
+class Playground extends React.Component {
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ bounceValue: new Animated.Value(0),
+ };
+ }
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ componentDidMount() {
+ this.state.bounceValue.setValue(1.5); // 设置一个较大的初始值
+ Animated.spring( // 可选的基本动画类型: spring, decay, timing
+ this.state.bounceValue, // 将`bounceValue`值动画化
+ {
+ toValue: 0.8, // 将其值以动画的形式改到一个较小值
+ friction: 1, // Bouncier spring
+ }
+ ).start(); // 开始执行动画
+ }
+}
+```
+
+`bounceValue`在构造函数中初始化为`state`的一部分,然后和图片的缩放比例进行绑定。在动画执行的背后,其数值会被不断的计算并用于设置缩放比例。当组件刚刚挂载的时候,缩放比例被设置到1.5。然后紧跟着在`bounceValue`上执行了一个弹跳动画(spring),会逐帧刷新数值,并同步更新所有依赖本数值的绑定(在这个例子里,就是图片的缩放比例)。比起调用`setState`然后重新渲染,这一运行过程要快得多。因为整个配置都是声明式的,我们可以实现更进一步的优化,只要序列化好配置,然后我们可以在一个高优先级的线程执行动画。
+
+#### 核心API
+
+大部分你需要的东西都来自`Animated`模块。它包括两个值类型,`Value`用于单个的值,而`ValueXY`用于向量值;还包括三种动画类型,`spring`,`decay`,还有`timing`,以及三种组件类型,`View`,`Text`和`Image`。你可以使用`Animated.createAnimatedComponent`方法来对其它类型的组件创建动画。
+
+这三种动画类型可以用来创建几乎任何你需要的动画曲线,因为它们每一个都可以被自定义:
+
+* `spring`: 基础的单次弹跳物理模型,符合[Origami设计标准](https://facebook.github.io/origami/)
+ * `friction`: 摩擦力,默认为7.
+ * `tension`: 张力,默认40。
+* `decay`: 以一个初始速度开始并且逐渐减慢停止。
+ * `velocity`: 起始速度,必填参数。
+ * `deceleration`: 速度衰减比例,默认为0.997。
+* `timing`: 从时间范围映射到渐变的值。
+ * `duration`: 动画持续的时间(单位是毫秒),默认为500。
+ * `easing`:一个用于定义曲线的渐变函数。阅读`Easing`模块可以找到许多预定义的函数。iOS默认为`Easing.inOut(Easing.ease)`。
+ * `delay`: 在一段时间之后开始动画(单位是毫秒),默认为0。
+
+动画可以通过调用`start`方法来开始。`start`接受一个回调函数,当动画结束的时候会调用此回调函数。如果动画是因为正常播放完成而结束的,回调函数被调用时的参数为`{finished: true}`,但若动画是在结束之前被调用了`stop`而结束(可能是被一个手势或者其它的动画打断),它会收到参数`{finished: false}`。
+
+#### 组合动画
+
+多个动画可以通过`parallel`(同时执行)、`sequence`(顺序执行)、`stagger`和`delay`来组合使用。它们中的每一个都接受一个要执行的动画数组,并且自动在适当的时候调用start/stop。举个例子:
+
+```javascript
+Animated.sequence([ // 首先执行decay动画,结束后同时执行spring和twirl动画
+ Animated.decay(position, { // 滑行一段距离后停止
+ velocity: {x: gestureState.vx, y: gestureState.vy}, // 根据用户的手势设置速度
+ deceleration: 0.997,
+ }),
+ Animated.parallel([ // 在decay之后并行执行:
+ Animated.spring(position, {
+ toValue: {x: 0, y: 0} // 返回到起始点开始
+ }),
+ Animated.timing(twirl, { // 同时开始旋转
+ toValue: 360,
+ }),
+ ]),
+]).start(); // 执行这一整套动画序列
+```
+
+默认情况下,如果任何一个动画被停止或中断了,组内所有其它的动画也会被停止。Parallel有一个`stopTogether`属性,如果设置为`false`,可以禁用自动停止。
+
+#### 插值(interpolate)
+
+`Animated` API还有一个很强大的部分就是`interpolate`插值函数。它可以接受一个输入区间,然后将其映射到另一个的输出区间。下面是一个一个简单的从0-1区间到0-100区间的映射示例:
+
+```javascript
+value.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 100],
+});
+```
+
+`interpolate`还支持定义多个区间段落,常用来定义静止区间等。举个例子,要让输入在接近-300时取相反值,然后在输入接近-100时到达0,然后在输入接近0时又回到1,接着一直到输入到100的过程中逐步回到0,最后形成一个始终为0的静止区间,对于任何大于100的输入都返回0。具体写法如下:
+
+```javascript
+value.interpolate({
+ inputRange: [-300, -100, 0, 100, 101],
+ outputRange: [300, 0, 1, 0, 0],
+});
+```
+
+它的最终映射结果如下:
+
+输入 | 输出
+------|-------
+ -400| 450
+ -300| 300
+ -200| 150
+ -100| 0
+ -50| 0.5
+ 0| 1
+ 50| 0.5
+ 100| 0
+ 101| 0
+ 200| 0
+
+`interpolate`还支持到字符串的映射,从而可以实现颜色以及带有单位的值的动画变换。例如你可以像下面这样实现一个旋转动画:
+
+ ```javascript
+ value.interpolate({
+ inputRange: [0, 360],
+ outputRange: ['0deg', '360deg']
+ })
+ ```
+
+`interpolation`还支持任意的渐变函数,其中有很多已经在`Easing`类中定义了,包括二次、指数、贝塞尔等曲线以及step、bounce等方法。`interpolation`还支持限制输出区间`outputRange`。你可以通过设置`extrapolate`、`extrapolateLeft`或`extrapolateRight`属性来限制输出区间。默认值是`extend`(允许超出),不过你可以使用`clamp`选项来阻止输出值超过`outputRange`。
+
+#### 跟踪动态值
+
+动画中所设的值还可以通过跟踪别的值得到。你只要把toValue设置成另一个动态值而不是一个普通数字就行了。比如我们可以用弹跳动画来实现聊天头像的闪动,又比如通过`timing`设置`duration:0`来实现快速的跟随。他们还可以使用插值来进行组合:
+
+```javascript
+Animated.spring(follower, {toValue: leader}).start();
+Animated.timing(opacity, {
+ toValue: pan.x.interpolate({
+ inputRange: [0, 300],
+ outputRange: [1, 0],
+ }),
+}).start();
+```
+
+`ValueXY`是一个方便的处理2D交互的办法,譬如旋转或拖拽。它是一个简单的包含了两个`Animated.Value`实例的包装,然后提供了一系列辅助函数,使得`ValueXY`在许多时候可以替代`Value`来使用。比如在上面的代码片段中,`leader`和`follower`可以同时为`valueXY`类型,这样x和y的值都会被跟踪。
+
+#### 输入事件
+
+`Animated.event`是Animated API中与输入有关的部分,允许手势或其它事件直接绑定到动态值上。它通过一个结构化的映射语法来完成,使得复杂事件对象中的值可以被正确的解开。第一层是一个数组,允许同时映射多个值,然后数组的每一个元素是一个嵌套的对象。在下面的例子里,你可以发现`scrollX`被映射到了`event.nativeEvent.contentOffset.x`(`event`通常是回调函数的第一个参数),并且`pan.x`和`pan.y`分别映射到`gestureState.dx`和`gestureState.dy`(`gestureState`是传递给`PanResponder`回调函数的第二个参数)。
+
+```javascript
+onScroll={Animated.event(
+ [{nativeEvent: {contentOffset: {x: scrollX}}}] // scrollX = e.nativeEvent.contentOffset.x
+)}
+onPanResponderMove={Animated.event([
+ null, // 忽略原生事件
+ {dx: pan.x, dy: pan.y} // 从gestureState中解析出dx和dy的值
+]);
+```
+
+#### 响应当前的动画值
+
+你可能会注意到这里没有一个明显的方法来在动画的过程中读取当前的值——这是出于优化的角度考虑,有些值只有在原生代码运行阶段中才知道。如果你需要在JavaScript中响应当前的值,有两种可能的办法:
+
+* `spring.stopAnimation(callback)`会停止动画并且把最终的值作为参数传递给回调函数`callback`——这在处理手势动画的时候非常有用。
+* `spring.addListener(callback)` 会在动画的执行过程中持续异步调用`callback`回调函数,提供一个最近的值作为参数。这在用于触发状态切换的时候非常有用,譬如当用户拖拽一个东西靠近的时候弹出一个新的气泡选项。不过这个状态切换可能并不会十分灵敏,因为它不像许多连续手势操作(如旋转)那样在60fps下运行。
+
+#### 后续工作
+
+如前面所述,我们计划继续优化Animated,以进一步提升性能。我们还想尝试一些声明式的手势响应和触发动画,譬如垂直或者水平的倾斜操作。
+
+上面的API提供了一个强大的工具来简明、健壮、高效地组织各种各种不同的动画。你可以在[UIExplorer/AnimationExample](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/AnimatedGratuitousApp)中看到更多的样例代码。不过还有些时候`Animated`并不能支持你想要的效果,下面的章节包含了一些其它的动画系统。
+
+### LayoutAnimation
+
+`LayoutAnimation`允许你在全局范围内`创建`和`更新`动画,这些动画会在下一次渲染或布局周期运行。它常用来更新flexbox布局,因为它可以无需测量或者计算特定属性就能直接产生动画。尤其是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增加父节点的尺寸又会将位于本行之下的所有行向下推动)时,如果不使用`LayoutAnimation`,可能就需要显式声明组件的坐标,才能使得所有受影响的组件能够同步运行动画。
+
+注意尽管`LayoutAnimation`非常强大且有用,但它对动画本身的控制没有`Animated`或者其它动画库那样方便,所以如果你使用`LayoutAnimation`无法实现一个效果,那可能还是要考虑其他的方案。
+
+另外,如果要在**Android**上使用LayoutAnimation,那么目前还需要在`UIManager`中启用:
+```javascript
+UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
+```
+
+
+
+```javascript
+var App = React.createClass({
+ componentWillMount() {
+ // 创建动画
+ LayoutAnimation.spring();
+ },
+
+ getInitialState() {
+ return { w: 100, h: 100 }
+ },
+
+ _onPress() {
+ // 让视图的尺寸变化以动画形式展现
+ LayoutAnimation.spring();
+ this.setState({w: this.state.w + 15, h: this.state.h + 15})
+ },
+
+ render: function() {
+ return (
+
+
+
+
+ Press me!
+
+
+
+ );
+ }
+});
+```
+[运行这个例子](https://rnplay.org/apps/uaQrGQ)
+
+上面这个例子使用了一个预设值,不过你也可以自己配置你需要的动画。参见[LayoutAnimation.js](https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js)。
+
+### requestAnimationFrame
+
+`requestAnimationFrame`是一个对浏览器标准API的兼容实现,你可能已经熟悉它了。它接受一个函数作为唯一的参数,并且在下一次重绘之前调用此函数。一些基于JavaScript的动画库高度依赖于这一API。通常你不必直接调用它——那些动画库会替你管理好帧的更新。
+
+### react-tween-state(不推荐,用[Animated](#animated)来替代)
+
+[react-tween-state](https://github.com/chenglou/react-tween-state)是一个极小的库,正如它名字(tween:补间)表示的含义:它生成一个节点的状态的中间值,从一个**开始**值,结束于一个**到达**值。这意味着它会生成这两者之间的值,然后在每次`requestAnimationFrame`的时候修改状态。
+
+> 在[Wikipedia](https://en.wikipedia.org/wiki/Inbetweening)上对于补间动画(tweening)的定义:
+>
+> “补间是在两个图像之间生成中间帧的过程,以使得第一个图像能够平滑的变化为第二个图像”。补间帧是指在关键帧之间用于创建过渡假象的图画。”
+
+一个最基础的从一个值运动到另一个值的办法就是线性过渡:只需要将结束值减去开始值,然后除以动画总共需要经历的帧数,再在每一帧加到当前值上,一直到结束值位置。线性过渡有时候看起来怪异且不自然,所以react-tween-state提供了一系列常用的[过渡函数](http://easings.net/),可以用于使你的动画更加自然。
+
+这个库并未随React Native一起发布——要在你的工程中使用它,则需要先在你的工程目录下执行`npm i react-tween-state --save`来安装。
+
+```javascript
+import tweenState from 'react-tween-state';
+import reactMixin from 'react-mixin'; // https://github.com/brigand/react-mixin
+
+class App extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { opacity: 1 };
+ this._animateOpacity = this._animateOpacity.bind(this);
+ }
+
+ _animateOpacity() {
+ this.tweenState('opacity', {
+ easing: tweenState.easingTypes.easeOutQuint,
+ duration: 1000,
+ endValue: this.state.opacity === 0.2 ? 1 : 0.2,
+ });
+ }
+
+ render() {
+ return (
+
+
+ this._box = component}
+ style={{width: 200, height: 200, backgroundColor: 'red',
+ opacity: this.getTweeningValue('opacity')}} />
+
+
+ )
+ }
+}
+
+reactMixin.onClass(App, tweenState.Mixin);
+```
+[运行这个例子](https://rnplay.org/apps/4FUQ-A)
+
+
+
+在上面的例子里我们变化的是透明度,但你可能也猜到了,我们能变化任何数值的值。可以参考它的[说明文档](https://github.com/chenglou/react-tween-state)来了解更多信息。
+
+#### Rebound (不推荐 - 使用[Animated](#animated)来替代)
+
+[Rebound.js](https://github.com/facebook/rebound-js)是一个[安卓版Rebound](https://github.com/facebook/rebound)的JavaScript移植版。它在概念上类似react-tween-state:你有一个起始值,然后定义一个结束值,然后Rebound会生成所有中间的值并用于你的动画。Rebound基于弹性物理模型,你不需要提供一个动画的持续时间,它会自动根据弹性系数、助力、当前值和结束值来计算。我们[在React Native内部应用](https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=rebound)了Rebound,比如`Navigator`和`WarningBox`。
+
+
+
+需要注意的是Rebound动画可以被中断——如果你在按下动画的过程中释放手指,它会从当前状态弹回初始值。
+
+```javascript
+var rebound = require('rebound');
+
+var App = React.createClass({
+ // 首先我们初始化一个spring动画,并添加监听函数,
+ // 这个函数会在spring更新时调用setState
+ componentWillMount() {
+ // 初始化spring
+ this.springSystem = new rebound.SpringSystem();
+ this._scrollSpring = this.springSystem.createSpring();
+ var springConfig = this._scrollSpring.getSpringConfig();
+ springConfig.tension = 230;
+ springConfig.friction = 10;
+
+ this._scrollSpring.addListener({
+ onSpringUpdate: () => {
+ this.setState({scale: this._scrollSpring.getCurrentValue()});
+ },
+ });
+
+ // 将spring的初始值设为1
+ this._scrollSpring.setCurrentValue(1);
+ },
+
+ _onPressIn() {
+ this._scrollSpring.setEndValue(0.5);
+ },
+
+ _onPressOut() {
+ this._scrollSpring.setEndValue(1);
+ },
+
+ render: function() {
+ var imageStyle = {
+ width: 250,
+ height: 200,
+ transform: [{scaleX: this.state.scale}, {scaleY: this.state.scale}],
+ };
+
+ var imageUri = "https://facebook.github.io/react-native/img/ReboundExample.png";
+
+ return (
+
+
+
+
+
+ );
+ }
+});
+```
+
+你还可以为弹跳值启用边界,这样它们不会超出,而是会缓缓接近最终值。在上面的例子里,我们可以添加`this._scrollSpring.setOvershootClampingEnabled(true)`来启用边界。参见下面的gif动画来看一个启用了边界的效果:
+
+ 截图来自
+[react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view)。
+
+你可以在[这里](https://rnplay.org/apps/qHU_5w)看到一个类似的例子。
+
+#### 关于setNativeProps
+
+正如[直接操作](direct-manipulation.html)文档所说,`setNativeProps`方法可以使我们直接修改基于原生视图的组件的属性,而不需要使用`setState`来重新渲染整个组件树。
+
+我们可以把这个用在Rebound样例中来更新缩放比例——如果我们要更新的组件有一个非常深的内嵌结构,并且没有使用`shouldComponentUpdate`来优化,那么使用`setNativeProps`就将大有裨益。
+
+```javascript
+// 回到上面示例的那个组件中,找到componentWillMount方法,
+// 然后将scrollSpring的监听函数替换为如下代码:
+this._scrollSpring.addListener({
+ onSpringUpdate: () => {
+ if (!this._photo) { return }
+ var v = this._scrollSpring.getCurrentValue();
+ var newProps = {style: {transform: [{scaleX: v}, {scaleY: v}]}};
+ this._photo.setNativeProps(newProps);
+ },
+});
+
+// 最后,我们修改render方法,不再通过style来传入transform(避免
+// 重新渲染时产生冲突);然后给图片加上ref引用。
+render: function() {
+ return (
+
+
+ this._photo = component}
+ source={{uri: "https://facebook.github.io/react-native/img/ReboundExample.png"}}
+ style={{width: 250, height: 200}} />
+
+
+ );
+}
+```
+[运行这个例子](https://rnplay.org/apps/fUqjAg)
+
+不过你没办法把`setNativeProps`和react-tween-state结合使用,因为更新的补间值会自动被库设置到state上——Rebound则不同,它通过`onSprintUpdate`函数在每一帧中给我们提供一个更新后的值。
+
+如果你发现你的动画丢帧(低于60帧每秒),可以尝试使用`setNativeProps`或者`shouldComponentUpdate`来优化它们。你还可能需要将部分计算工作放在动画完成之后进行,这时可以使用[InteractionManager](/react-native/docs/interactionmanager.html)。你还可以使用应用内的开发者菜单中的“FPS Monitor”工具来监控应用的帧率。
+
+### 导航器场景切换
+
+正如文档[导航器对比](navigator-comparison.html#content)所说,`Navigator`使用JavaScript实现,而`NavigatoIOS`则是一个对于`UINavigationController`提供的原生功能的包装。所以这些场景切换动画仅仅对`Navigator`有效。为了在Navigator中重新创建`UINavigationController`所提供的动画并且使之可以被自定义,React Native导出了一个[NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js)API。
+
+```javascript
+import { Dimensions } from 'react-native';
+var SCREEN_WIDTH = Dimensions.get('window').width;
+var BaseConfig = Navigator.SceneConfigs.FloatFromRight;
+
+var CustomLeftToRightGesture = Object.assign({}, BaseConfig.gestures.pop, {
+ // 用户中断返回手势时,迅速弹回
+ snapVelocity: 8,
+
+ // 如下设置可以使我们在屏幕的任何地方拖动它
+ edgeHitWidth: SCREEN_WIDTH,
+});
+
+var CustomSceneConfig = Object.assign({}, BaseConfig, {
+ // 如下设置使过场动画看起来很快
+ springTension: 100,
+ springFriction: 1,
+
+ // 使用上面我们自定义的手势
+ gestures: {
+ pop: CustomLeftToRightGesture,
+ }
+});
+```
+[运行这个例子](https://rnplay.org/apps/HPy6UA)
+
+要了解更多有关自定义场景切换的信息,你可以[阅读相应的源码](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js)。
diff --git a/docs/docs/0.42/appregistry.md b/docs/docs/0.42/appregistry.md
new file mode 100644
index 0000000..f4d5dde
--- /dev/null
+++ b/docs/docs/0.42/appregistry.md
@@ -0,0 +1,16 @@
+`AppRegistry`是JS运行所有React Native应用的入口。应用的根组件应当通过`AppRegistry.registerComponent`方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用`AppRegistry.runApplication`来真正运行应用。
+
+要“结束”一个应用并销毁视图的话,请调用`AppRegistry.unmountApplicationComponentAtRootTag`方法,参数为在`runApplication`中使用的标签名。它们必须严格匹配。
+
+`AppRegistry`应当在`require`序列中尽可能早的被require到,以确保JS运行环境在其它模块之前被准备好。
+
+### 方法
+
+
+
static registerConfig(config: Array<AppConfig>) #
+
static registerComponent(appKey: string, getComponentFunc: ComponentProvider) #
+
static registerRunnable(appKey: string, func: Function) #
+
+
static runApplication(appKey: string, appParameters: any) #
+
static unmountApplicationComponentAtRootTag(rootTag: number) #
+
diff --git a/docs/docs/0.42/appstate.md b/docs/docs/0.42/appstate.md
new file mode 100644
index 0000000..a824b94
--- /dev/null
+++ b/docs/docs/0.42/appstate.md
@@ -0,0 +1,157 @@
+`AppState`能告诉你应用当前是在前台还是在后台,并且能在状态变化的时候通知你。
+
+AppState通常在处理推送通知的时候用来决定内容和对应的行为。
+
+### App States
+
+* `active` - 应用正在前台运行
+* `background` - 应用正在后台运行。用户既可能在别的应用中,也可能在桌面。
+* `inactive` - 这是一个过渡状态,不会在正常的React Native应用中出现。
+
+要了解更多信息,可以阅读[Apple的文档](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)。
+
+### 基本用法
+
+要获取当前的状态,你可以使用`AppState.currentState`,这个变量会一直保持更新。不过在启动的过程中,`currentState`可能为null,直到`AppState`从原生代码得到通知为止。
+
+```javascript
+constructor(props) {
+ super(props);
+ this.state = {
+ currentAppState: AppState.currentState,
+ };
+}
+componentDidMount() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+}
+componentWillUnmount() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+}
+_handleAppStateChange = (nextAppState) => {
+ if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
+ console.log('App has come to the foreground!')
+ }
+ this.setState({appState: nextAppState});
+}
+render() {
+ return (
+ Current state is: {this.state.currentAppState}
+ );
+}
+```
+
+上面的这个例子只会显示"Current state is: active",这是因为应用只有在`active`状态下才能被用户看到。并且null状态只会在一开始的一瞬间出现。
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听函数,用于监听应用状态的变化。type参数应填`change` 。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
移除一个监听函数。type参数应填change。
+
+
+
+
+### 属性
+
+
+
+
currentState: TypeCastExpression #
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ AppState,
+ Text,
+ View
+} = ReactNative;
+
+var AppStateSubscription = React.createClass({
+ getInitialState() {
+ return {
+ appState: AppState.currentState,
+ previousAppStates: [],
+ memoryWarnings: 0,
+ };
+ },
+ componentDidMount: function() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+ AppState.addEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ componentWillUnmount: function() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+ AppState.removeEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ _handleMemoryWarning: function() {
+ this.setState({memoryWarnings: this.state.memoryWarnings + 1});
+ },
+ _handleAppStateChange: function(appState) {
+ var previousAppStates = this.state.previousAppStates.slice();
+ previousAppStates.push(this.state.appState);
+ this.setState({
+ appState,
+ previousAppStates,
+ });
+ },
+ render() {
+ if (this.props.showMemoryWarnings) {
+ return (
+
+ {this.state.memoryWarnings}
+
+ );
+ }
+ if (this.props.showCurrentOnly) {
+ return (
+
+ {this.state.appState}
+
+ );
+ }
+ return (
+
+ {JSON.stringify(this.state.previousAppStates)}
+
+ );
+ }
+});
+
+exports.title = 'AppState';
+exports.description = 'app background status';
+exports.examples = [
+ {
+ title: 'AppState.currentState',
+ description: 'Can be null on app initialization',
+ render() { return {AppState.currentState} ; }
+ },
+ {
+ title: 'Subscribed AppState:',
+ description: 'This changes according to the current state, so you can only ever see it rendered as "active"',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Previous states:',
+ render(): ReactElement { return ; }
+ },
+ {
+ platform: 'ios',
+ title: 'Memory Warnings',
+ description: 'In the IOS simulator, hit Shift+Command+M to simulate a memory warning.',
+ render(): ReactElement { return ; }
+ },
+];
+```
diff --git a/docs/docs/0.42/asyncstorage.md b/docs/docs/0.42/asyncstorage.md
new file mode 100644
index 0000000..d1cc11d
--- /dev/null
+++ b/docs/docs/0.42/asyncstorage.md
@@ -0,0 +1,76 @@
+AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统,它对于App来说是全局性的。它用来代替LocalStorage。
+
+我们推荐您在AsyncStorage的基础上做一层抽象封装,而不是直接使用AsyncStorage。
+
+__译注__:推荐由`React Native中文网`封装维护的[`react-native-storage`](https://github.com/sunnylqm/react-native-storage/blob/master/README-CHN.md)模块,提供了较多便利功能。
+
+本模块的JS代码提供了对原生实现的一个封装,以提供一个更清晰的JS API、返回真正的错误对象,以及简单的单项对象操作函数。每个方法都会返回一个`Promise`对象。
+
+### 方法
+
+
+
+
static getItem(key: string, callback?: ?(error: ?Error, result: ?string) => void) #
+
+
读取key字段并将结果作为第二个参数传递给callback。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static setItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
将key字段的值设置成value,并在完成后调用callback函数。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static removeItem(key: string, callback?: ?(error: ?Error) => void) #
+
+
删除一个字段。返回一个Promise对象。
+
+
+
+
static mergeItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
假设已有的值和新的值都是字符串化的JSON,则将两个值合并。返回一个Promise对象。还没有被所有原生实现都支持。
+
+
+
+
static clear(callback?: ?(error: ?Error) => void) #
+
+
删除全部的 AsyncStorage数据,不论来自什么库或调用者。通常不应该调用这个函数——使用removeItem或者multiRemove来清除你自己的key。返回一个Promise对象。
+
+
+
+
static getAllKeys(callback?: ?(error: ?Error, keys: ?Array<string>) => void) #
+
+
获取所有 本应用可以访问到的数据,不论来自什么库或调用者。返回一个Promise对象。
+
+
+
static flushGetRequests() #
+
+
static multiGet(keys: Array<string>, callback?: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void) #
+
+
获取keys所包含的所有字段的值,调用callback回调函数时返回一个key-value数组形式的数组。返回一个Promise对象。
+
multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
+
+
+
+
static multiSet(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
multiSet和multiMerge都接受一个与multiGet输出值一致的key-value数组的数组。返回一个Promise对象。
+
multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
+
+
+
+
static multiRemove(keys: Array<string>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
删除所有键在keys数组中的数据。返回一个Promise对象。
+
+
+
+
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
将多个输入的值和已有的值合并,要求都是字符串化的JSON。返回一个Promise对象。
+
还没有被所有原生实现都支持。
+
+
+
diff --git a/docs/docs/0.42/backandroid.md b/docs/docs/0.42/backandroid.md
new file mode 100644
index 0000000..b7c014a
--- /dev/null
+++ b/docs/docs/0.42/backandroid.md
@@ -0,0 +1,22 @@
+监听硬件的`back`键操作。如果没有任何监听函数,或者监听函数的返回值不是true,则会调用默认的back键功能来退出应用。
+
+例子:
+
+```javascript
+BackAndroid.addEventListener('hardwareBackPress', function() {
+ if (!this.onMainScreen()) {
+ this.goBack();
+ return true;
+ }
+ return false;
+});
+```
+__译注__:以上的`this.onMainScreen()`和`this.goBack()`两个方法都只是伪方法,需要你自己去实现!具体可以参考这篇[博文](http://bbs.reactnative.cn/topic/480)。
+
+### 方法
+
+
+
+
static addEventListener(eventName: BackPressEventName, handler: Function) #
+
static removeEventListener(eventName: BackPressEventName, handler: Function) #
+
diff --git a/docs/docs/0.42/button.md b/docs/docs/0.42/button.md
new file mode 100644
index 0000000..c8e75cc
--- /dev/null
+++ b/docs/docs/0.42/button.md
@@ -0,0 +1,134 @@
+一个简单的跨平台的按钮组件。可以进行一些简单的定制。
+
+
+
+如果这个组件外观并不怎么搭配你的设计,那你可以使用`TouchableOpacity`或是`TouchableNativeFeedback`组件来制作自己所需要的按钮,视频教程[如何制作一个按钮](http://v.youku.com/v_show/id_XMTQ5OTE3MjkzNg==.html?f=26822355&from=y1.7-1.3)讲述了完整的过程。或者你也可以在github.com网站上搜索'react native button'来看看社区其他人的作品。
+
+
+用法示例:
+
+```js
+
+```
+
+### 属性
+
+
accessibilityLabel string #
+
用于给残障人士显示的文本(比如读屏器软件可能会读取这一内容)
+
+
+
文本的颜色(iOS),或是按钮的背景色(Android)
+
+
+
+
+
+
+### 例子
+
+```javascript
+use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ Alert,
+ Button,
+ View,
+} = ReactNative;
+
+const onButtonPress = () => {
+ Alert.alert('Button has been pressed!');
+};
+
+exports.displayName = 'ButtonExample';
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Simple React Native button component.';
+
+exports.examples = [
+ {
+ title: 'Simple Button',
+ description: 'The title and onPress handler are required. It is ' +
+ 'recommended to set accessibilityLabel to help make your app usable by ' +
+ 'everyone.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Adjusted color',
+ description: 'Adjusts the color in a way that looks standard on each ' +
+ 'platform. On iOS, the color prop controls the color of the text. On ' +
+ 'Android, the color adjusts the background color of the button.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Fit to text layout',
+ description: 'This layout strategy lets the title define the width of ' +
+ 'the button',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Disabled Button',
+ description: 'All interactions for the component are disabled.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+];
+```
diff --git a/docs/docs/0.42/cameraroll.md b/docs/docs/0.42/cameraroll.md
new file mode 100644
index 0000000..da08b4d
--- /dev/null
+++ b/docs/docs/0.42/cameraroll.md
@@ -0,0 +1,175 @@
+`CameraRoll`模块提供了访问本地相册的功能。在iOS上使用这个模块之前,你需要先链接`RCTCameraRoll`库,具体做法请参考[链接原生库](linking-libraries-ios.html)文档。
+
+**译注**:本模块只提供了基本的访问图片的功能,并没有提供相册界面。对于多数开发者来说,可能[react-native-image-picker](https://github.com/marcshilling/react-native-image-picker)的功能更为完整易用。
+
+### iOS 10的权限要求
+从iOS10开始,访问相册需要用户授权。你需要在`Info.plist`中添加一条名为`NSCameraUsageDescription`的键,然后在其值中填写向用户请求权限的具体描述。编辑完成后这个键在Xcode中实际会显示为`Privacy - Camera Usage Description`。
+
+### 截图
+
+
+### 方法
+
+
+
+
static saveImageWithTag(tag) #
+
+
保存一个图片到相册。
+
@param {string} tag 在安卓上,本参数是一个本地URI,例如"file:///sdcard/img.png".
+
在iOS设备上可能是以下之一:
+
+ 本地URI
+ 资源库的标签
+ 非以上两种类型,表示图片数据将会存储在内存中(并且在本进程持续的时候一直会占用内存)。
+
+
返回一个Promise,操作成功时返回新的URI。
+
+
+
+
static saveToCameraRoll(tag, type?) #
+
把图片或视频保存到相册中。
+
On Android, the tag must be a local image or video URI, such as "file:///sdcard/img.png".
On iOS, the tag can be any image URI (including local, remote asset-library and base64 data URIs) or a local video file URI (remote or data URIs are not supported for saving video at this time).
+
If the tag has a file extension of .mov or .mp4, it will be inferred as a video. Otherwise it will be treated as a photo. To override the automatic choice, you can pass an optional
+type parameter that must be one of 'photo' or 'video'.
Returns a Promise which will resolve with the new URI.
+
+
+
+
static getPhotos(params: object) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ CameraRoll,
+ Image,
+ Slider,
+ StyleSheet,
+ Switch,
+ Text,
+ View,
+ TouchableOpacity
+} = ReactNative;
+
+const invariant = require('fbjs/lib/invariant');
+
+const CameraRollView = require('./CameraRollView');
+
+const AssetScaledImageExampleView = require('./AssetScaledImageExample');
+
+class CameraRollExample extends React.Component {
+ state = {
+ groupTypes: 'SavedPhotos',
+ sliderValue: 1,
+ bigImages: true,
+ };
+ _cameraRollView: ?CameraRollView;
+ render() {
+ return (
+
+
+ {(this.state.bigImages ? 'Big' : 'Small') + ' Images'}
+
+ {'Group Type: ' + this.state.groupTypes}
+ { this._cameraRollView = ref; }}
+ batchSize={20}
+ groupTypes={this.state.groupTypes}
+ renderImage={this._renderImage}
+ />
+
+ );
+ }
+
+ loadAsset = (asset) => {
+ if (this.props.navigator) {
+ this.props.navigator.push({
+ title: 'Camera Roll Image',
+ component: AssetScaledImageExampleView,
+ backButtonTitle: 'Back',
+ passProps: { asset: asset },
+ });
+ }
+ };
+
+ _renderImage = (asset) => {
+ const imageSize = this.state.bigImages ? 150 : 75;
+ const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
+ const {location} = asset.node;
+ const locationStr = location ? JSON.stringify(location) : 'Unknown location';
+ return (
+
+
+
+
+ {asset.node.image.uri}
+ {locationStr}
+ {asset.node.group_name}
+ {new Date(asset.node.timestamp).toString()}
+
+
+
+ );
+ };
+
+ _onSliderChange = (value) => {
+ const options = CameraRoll.GroupTypesOptions;
+ const index = Math.floor(value * options.length * 0.99);
+ const groupTypes = options[index];
+ if (groupTypes !== this.state.groupTypes) {
+ this.setState({groupTypes: groupTypes});
+ }
+ };
+
+ _onSwitchChange = (value) => {
+ invariant(this._cameraRollView, 'ref should be set');
+ this._cameraRollView.rendererChanged();
+ this.setState({ bigImages: value });
+ };
+}
+
+const styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ flex: 1,
+ },
+ url: {
+ fontSize: 9,
+ marginBottom: 14,
+ },
+ image: {
+ margin: 4,
+ },
+ info: {
+ flex: 1,
+ },
+});
+
+exports.title = 'Camera Roll';
+exports.description = 'Example component that uses CameraRoll to list user\'s photos';
+exports.examples = [
+ {
+ title: 'Photos',
+ render(): React.Element { return ; }
+ }
+];
+```
diff --git a/docs/docs/0.42/clipboard.md b/docs/docs/0.42/clipboard.md
new file mode 100644
index 0000000..94eae4b
--- /dev/null
+++ b/docs/docs/0.42/clipboard.md
@@ -0,0 +1,87 @@
+`Clipboard`组件可以在iOS和Android的剪贴板中读写内容。
+
+### 方法
+
+
+
static getString() #
+
获取剪贴板的文本内容,返回一个Promise你可以用下面的方式来调用。
+
async _getContent( ) {
+ var content = await
+ Clipboard. getString( ) ;
+ }
+
+
+
static setString(content: string) #
+
+
设置剪贴板的文本内容。你可以用下面的方式来调用。
+
_setContent( ) {
+ Clipboard. setString( 'hello world' ) ;
+ }
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Clipboard,
+ View,
+ Text,
+} = ReactNative;
+
+var ClipboardExample = React.createClass({
+ getInitialState() {
+ return {
+ content: 'Content will appear here'
+ };
+ },
+
+ async _setClipboardContent(){
+ Clipboard.setString('Hello World');
+ try {
+ var content = await Clipboard.getString();
+ this.setState({content});
+ } catch (e) {
+ this.setState({content:e.message});
+ }
+ },
+
+ render() {
+ return (
+
+
+ Tap to put "Hello World" in the clipboard
+
+
+ {this.state.content}
+
+
+ );
+ }
+});
+
+exports.title = 'Clipboard';
+exports.description = 'Show Clipboard contents.';
+exports.examples = [
+ {
+ title: 'Clipboard.setString() and getString()',
+ render() {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.42/colors.md b/docs/docs/0.42/colors.md
new file mode 100644
index 0000000..2912ede
--- /dev/null
+++ b/docs/docs/0.42/colors.md
@@ -0,0 +1,166 @@
+以下这些格式的颜色代码都是支持的:
+
+ - `'#f0f'` (#rgb)
+ - `'#f0fc'` (#rgba)
+ - `'#ff00ff'` (#rrggbb)
+ - `'#ff00ff00'` (#rrggbbaa)
+ - `'rgb(255, 255, 255)'`
+ - `'rgba(255, 255, 255, 1.0)'`
+ - `'hsl(360, 100%, 100%)'`
+ - `'hsla(360, 100%, 100%, 1.0)'`
+ - `'transparent'`
+ - `'red'`
+ - `0xff00ff00` (0xrrggbbaa)
+
+对于有称谓的颜色,React Native遵循的是[CSS3的规范](http://www.w3.org/TR/css3-color/#svg-color):
+
+
+ aliceblue (#f0f8ff)
+ antiquewhite (#faebd7)
+ aqua (#00ffff)
+ aquamarine (#7fffd4)
+ azure (#f0ffff)
+ beige (#f5f5dc)
+ bisque (#ffe4c4)
+ black (#000000)
+ blanchedalmond (#ffebcd)
+ blue (#0000ff)
+ blueviolet (#8a2be2)
+ brown (#a52a2a)
+ burlywood (#deb887)
+ cadetblue (#5f9ea0)
+ chartreuse (#7fff00)
+ chocolate (#d2691e)
+ coral (#ff7f50)
+ cornflowerblue (#6495ed)
+ cornsilk (#fff8dc)
+ crimson (#dc143c)
+ cyan (#00ffff)
+ darkblue (#00008b)
+ darkcyan (#008b8b)
+ darkgoldenrod (#b8860b)
+ darkgray (#a9a9a9)
+ darkgreen (#006400)
+ darkgrey (#a9a9a9)
+ darkkhaki (#bdb76b)
+ darkmagenta (#8b008b)
+ darkolivegreen (#556b2f)
+ darkorange (#ff8c00)
+ darkorchid (#9932cc)
+ darkred (#8b0000)
+ darksalmon (#e9967a)
+ darkseagreen (#8fbc8f)
+ darkslateblue (#483d8b)
+ darkslategray (#2f4f4f)
+ darkslategrey (#2f4f4f)
+ darkturquoise (#00ced1)
+ darkviolet (#9400d3)
+ deeppink (#ff1493)
+ deepskyblue (#00bfff)
+ dimgray (#696969)
+ dimgrey (#696969)
+ dodgerblue (#1e90ff)
+ firebrick (#b22222)
+ floralwhite (#fffaf0)
+ forestgreen (#228b22)
+ fuchsia (#ff00ff)
+ gainsboro (#dcdcdc)
+ ghostwhite (#f8f8ff)
+ gold (#ffd700)
+ goldenrod (#daa520)
+ gray (#808080)
+ green (#008000)
+ greenyellow (#adff2f)
+ grey (#808080)
+ honeydew (#f0fff0)
+ hotpink (#ff69b4)
+ indianred (#cd5c5c)
+ indigo (#4b0082)
+ ivory (#fffff0)
+ khaki (#f0e68c)
+ lavender (#e6e6fa)
+ lavenderblush (#fff0f5)
+ lawngreen (#7cfc00)
+ lemonchiffon (#fffacd)
+ lightblue (#add8e6)
+ lightcoral (#f08080)
+ lightcyan (#e0ffff)
+ lightgoldenrodyellow (#fafad2)
+ lightgray (#d3d3d3)
+ lightgreen (#90ee90)
+ lightgrey (#d3d3d3)
+ lightpink (#ffb6c1)
+ lightsalmon (#ffa07a)
+ lightseagreen (#20b2aa)
+ lightskyblue (#87cefa)
+ lightslategray (#778899)
+ lightslategrey (#778899)
+ lightsteelblue (#b0c4de)
+ lightyellow (#ffffe0)
+ lime (#00ff00)
+ limegreen (#32cd32)
+ linen (#faf0e6)
+ magenta (#ff00ff)
+ maroon (#800000)
+ mediumaquamarine (#66cdaa)
+ mediumblue (#0000cd)
+ mediumorchid (#ba55d3)
+ mediumpurple (#9370db)
+ mediumseagreen (#3cb371)
+ mediumslateblue (#7b68ee)
+ mediumspringgreen (#00fa9a)
+ mediumturquoise (#48d1cc)
+ mediumvioletred (#c71585)
+ midnightblue (#191970)
+ mintcream (#f5fffa)
+ mistyrose (#ffe4e1)
+ moccasin (#ffe4b5)
+ navajowhite (#ffdead)
+ navy (#000080)
+ oldlace (#fdf5e6)
+ olive (#808000)
+ olivedrab (#6b8e23)
+ orange (#ffa500)
+ orangered (#ff4500)
+ orchid (#da70d6)
+ palegoldenrod (#eee8aa)
+ palegreen (#98fb98)
+ paleturquoise (#afeeee)
+ palevioletred (#db7093)
+ papayawhip (#ffefd5)
+ peachpuff (#ffdab9)
+ peru (#cd853f)
+ pink (#ffc0cb)
+ plum (#dda0dd)
+ powderblue (#b0e0e6)
+ purple (#800080)
+ rebeccapurple (#663399)
+ red (#ff0000)
+ rosybrown (#bc8f8f)
+ royalblue (#4169e1)
+ saddlebrown (#8b4513)
+ salmon (#fa8072)
+ sandybrown (#f4a460)
+ seagreen (#2e8b57)
+ seashell (#fff5ee)
+ sienna (#a0522d)
+ silver (#c0c0c0)
+ skyblue (#87ceeb)
+ slateblue (#6a5acd)
+ slategray (#708090)
+ slategrey (#708090)
+ snow (#fffafa)
+ springgreen (#00ff7f)
+ steelblue (#4682b4)
+ tan (#d2b48c)
+ teal (#008080)
+ thistle (#d8bfd8)
+ tomato (#ff6347)
+ turquoise (#40e0d0)
+ violet (#ee82ee)
+ wheat (#f5deb3)
+ white (#ffffff)
+ whitesmoke (#f5f5f5)
+ yellow (#ffff00)
+ yellowgreen (#9acd32)
+
diff --git a/docs/docs/0.42/communication-ios.md b/docs/docs/0.42/communication-ios.md
new file mode 100644
index 0000000..a38a4d4
--- /dev/null
+++ b/docs/docs/0.42/communication-ios.md
@@ -0,0 +1,190 @@
+通过[植入原生应用](integration-with-existing-apps.html.html)和[原生UI组件](native-component-ios.html)两篇文档,我们学习了React Native和原生组件的互相整合。在整合的过程中,我们会需要在两个世界间互相通信。有些方法已经在其他的指南中提到了,这篇文章总结了所有可行的技术。
+## 简介
+React Native是从React中得到的灵感,因此基本的信息流是类似的。在React中信息是单向的。我们维护了组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(properties)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
+
+React Native也运用了相同的概念。只要我们完全在框架内构建应用,就可以通过属性和回调函数来调动整个应用。但是,当我们混合React Native和原生组件时,我们需要一些特殊的,跨语言的机制来传递信息。
+
+## 属性
+属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到React Native或者从React Native到原生组件。
+
+### 从原生组件传递属性到React Native
+
+我们使用`RCTRootView`将React Natvie视图封装到原生组件中。`RCTRootView`是一个`UIView`容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。
+
+通过`RCTRootView`的初始化函数你可以将任意属性传递给React Native应用。参数`initialProperties `必须是`NSDictionary`的一个实例。这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。
+```
+NSArray *imageList = @[@"http://foo.com/bar1.png",
+ @"http://foo.com/bar2.png"];
+
+NSDictionary *props = @{@"images" : imageList};
+
+RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"ImageBrowserApp"
+ initialProperties:props];
+```
+
+```
+'use strict';
+import React, { Component } from 'react';
+import {
+ AppRegistry,
+ View,
+ Image,
+} from 'react-native';
+
+class ImageBrowserApp extends Component {
+ renderImage(imgURI) {
+ return (
+
+ );
+ }
+ render() {
+ return (
+
+ {this.props.images.map(this.renderImage)}
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);
+```
+
+`RCTRootView`同样提供了一个可读写的属性`appProperties`。在`appProperties`设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。
+```
+NSArray *imageList = @[@"http://foo.com/bar3.png",
+ @"http://foo.com/bar4.png"];
+rootView.appProperties = @{@"images" : imageList};
+```
+你可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。
+更新属性时并不能做到只更新一部分属性。我们建议你自己封装一个函数来构造属性。
+
+> 注意:目前,最顶层的RN组件(即registerComponent方法中调用的那个)的`componentWillReceiveProps`和`componentWillUpdateProps`方法在属性更新后不会触发。但是,你可以通过`componentWillMount`访问新的属性值。
+
+## 从React Native传递属性到原生组件
+
+这篇[文档](native-component-ios.html#属性)详细讨论了暴露原生组件属性的问题。简而言之,在你自定义的原生组件中通过`RCT_CUSTOM_VIEW_PROPERTY`宏导出属性,就可以直接在React Native中使用,就好像它们是普通的React Native组件一样。
+
+## 属性的限制
+跨语言属性的主要缺点是不支持回调方法,因而无法实现自下而上的数据绑定。设想你有一个小的RN视图,当一个JS动作触发时你想从原生的父视图中移除它。此时你会发现根本做不到,因为信息需要自下而上进行传递。
+
+虽然我们有跨语言回调([参阅这里](native-modules-ios.html#回调函数)),但是这些回调函数并不总能满足需求。最主要的问题是它们并不是被设计来当作属性进行传递。这一机制的本意是允许我们从JS触发一个原生动作,然后用JS处理那个动作的处理结果。
+
+## 其他的跨语言交互(事件和原生模块)
+如上一章所说,使用属性总会有一些限制。有时候属性并不足以满足应用逻辑,因此我们需要更灵活的解决办法。这一章描述了其他的在React Native中可用的通信方法。他们可以用来内部通信(在JS和RN的原生层之间),也可以用作外部通信(在RN和纯原生部分之间)。
+
+React Native允许使用跨语言的函数调用。你可以在JS中调用原生代码,也可以在原生代码中调用JS。在不同端需要用不同的方法来实现相同的目的。在原生代码中我们使用事件机制来调度JS中的处理函数,而在React Native中我们直接使用原生模块导出的方法。
+
+### 从原生代码调用React Natvie函数(事件)
+事件的详细用法在这篇[文章](native-component-ios.html#事件)中进行了讨论。注意使用事件无法确保执行的时间,因为事件的处理函数是在单独的线程中执行。
+
+事件很强大,它可以不需要引用直接修改React Native组件。但是,当你使用时要注意下面这些陷阱:
+
+* 由于事件可以从各种地方产生,它们可能导致混乱的依赖。
+* 事件共享相同的命名空间,因此你可能遇到名字冲突。冲突不会在编写代码时被探测到,因此很难排错。
+* 如果你使用了同一个React Native组件的多个引用,然后想在事件中区分它们,name你很可能需要在事件中同时传递一些标识(你可以使用原生视图中的`reactTag`作为标识)。
+
+在React Native中嵌入原生组件时,通常的做法是用原生组件的RCTViewManager作为视图的代理,通过bridge向JS发送事件。这样可以集中在一处调用相关的事件。
+
+### 从React Native中调用原生方法(原生模块)
+
+原生模块是JS中也可以使用的Objective-C类。一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的。他们可以导出任意的函数和常量给React Native。相关细节可以参阅这篇[文章](native-modules-ios.html#content)。
+
+事实上原生模块的单实例模式限制了嵌入。假设我们有一个React Native组件被嵌入了一个原生视图,并且我们希望更新原生的父视图。使用原生模块机制,我们可以导出一个函数,不仅要接收预设参数,还要接收父视图的标识。这个标识将会用来获得父视图的引用以更新父视图。那样的话,我们需要维持模块中标识到原生模块的映射。
+虽然这个解决办法很复杂,它仍被用在了管理所有React Native视图的`RCTUIManager`类中,
+
+原生模块同样可以暴露已有的原生库给JS,[地理定位库](https://github.com/facebook/react-native/tree/master/Libraries/Geolocation)就是一个现成的例子。
+
+>警告:所有原生模块共享同一个命名空间。创建新模块时注意命名冲突。
+
+## 布局计算流
+
+当集成原生模块和React Natvie时,我们同样需要一个能协同不同的布局系统的办法。这一章节讨论了常见的布局问题,并且提供了解决机制的简单说明。
+
+### 在React Native中嵌入一个原生组件
+这个情况在[这篇文章](native-component-ios.html#样式)中进行了讨论。基本上,由于所有的原生视图都是`UIView`的子集,大多数类型和尺寸属性将和你期望的一样可以使用。
+
+### 在原生中嵌入一个React Native组件
+
+#### 固定大小的React Native内容
+
+最简单的情况是一个对于原生端已知的,固定大小的React Native应用,尤其是一个全屏的React Native视图。如果我们需要一个小一点的根视图,我们可以明确的设置`RCTRootView`的frame。
+比如说,创建一个200像素高,宿主视图那样宽的RN app,我们可以这样做:
+```
+// SomeViewController.m
+
+- (void)viewDidLoad
+{
+ [...]
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:appName
+ initialProperties:props];
+ rootView.frame = CGMakeRect(0, 0, self.view.width, 200);
+ [self.view addSubview:rootView];
+}
+```
+当我们创建了一个固定大小的根视图,则需要在JS中遵守它的边界。换句话说,我们需要确保React Native内容能够在固定的大小中放下。最简单的办法是使用flexbox布局。如果你使用绝对定位,并且React组件在根视图边界外可见,则React Native组件将会和原生视图重叠,导致某些不符合期望的行为。比如说,当你点击根视图边界之外的区域`TouchableHighlight`将不会高亮。
+通过重新设置frame的属性来动态更新根视图的大小是完全可行的。React Native将会关注内容布局的变化。
+
+#### 弹性大小的React Native
+有时候我们需要渲染一些不知道大小的内容。假设尺寸将会在JS中动态指定。我们有两个解决办法。
+
+* 你可以将React Native视图包裹在`ScrollView`中。这样可以保证你的内容总是可以访问,并且不会和原生视图重叠。
+* React Native允许你在JS中决定RN应用的尺寸,并且将它传递给宿主视图`RCTRootView`。然后宿主视图将重新布局子视图,保证UI统一。我们通过`RCTRootView`的弹性模式来达到目的。
+
+`RCTRootView`支持4种不同的弹性模式:
+```
+// RCTRootView.h
+
+typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
+ RCTRootViewSizeFlexibilityNone = 0,
+ RCTRootViewSizeFlexibilityWidth,
+ RCTRootViewSizeFlexibilityHeight,
+ RCTRootViewSizeFlexibilityWidthAndHeight,
+};
+```
+默认值是`RCTRootViewSizeFlexibilityNone`,表示使用固定大小的根视图(仍然可以通过`setFrame`更改)。其他三种模式可以跟踪React Native尺寸的变化。比如说,设置模式为`RCTRootViewSizeFlexibilityHeight`,React Native将会测量内容的高度然后传递回
+`RCTRootView`的代理。代理可以执行任意的行为,包括设置根视图的frame以使内容尺寸相匹配。
+代理仅仅在内容的尺寸发生变化时才进行调用。
+
+>注意:在JS和原生中都设置弹性尺寸可能导致不确定的行为。比如--不要在设置`RCTRootView`为`RCTRootViewSizeFlexibilityWidth`时同时指定最顶层的RN组件宽度可变(使用Flexbox)。
+
+看一个例子。
+```
+// FlexibleSizeExampleView.m
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ [...]
+
+ _rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"FlexibilityExampleApp"
+ initialProperties:@{}];
+
+ _rootView.delegate = self;
+ _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
+ _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0);
+}
+
+#pragma mark - RCTRootViewDelegate
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
+{
+ CGRect newFrame = rootView.frame;
+ newFrame.size = rootView.intrinsicSize;
+
+ rootView.frame = newFrame;
+}
+```
+在例子中我们使用一个`FlexibleSizeExampleView`视图来包含根视图。我们创建了根视图,初始化并且设置了代理。代理将会处理尺寸更新。然后,我们设置根视图的弹性尺寸为`RCTRootViewSizeFlexibilityHeight`,意味着`rootViewDidChangeIntrinsicSize:`方法将会在每次React Native内容高度变化时进行调用。最后,我们设置根视图的宽度和位置。注意我们也设置了高度,但是并没有效果,因为我们已经将高度设置为根据RN内容进行弹性变化了。
+
+你可以在这里查看完整的例子[源代码](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m)。
+
+动态改变根视图的弹性模式是可行的。改变根视图的弹性模式将会导致布局的重新计算,并且在重新量出内容尺寸时会调用`rootViewDidChangeIntrinsicSize`方法。
+
+>注意:React Native布局是通过一个特殊的线程进行计算,而原生UI视图是通过主线程更新。这可能导致短暂的原生端和React Native端的不一致。这是一个已知的问题,我们的团队已经在着手解决不同源的UI同步更新。
+>注意:除非根视图成为其他视图的子视图,否则React Native不会进行任何的布局计算。如果你想在还没有获得React Native视图的尺寸之前先隐藏视图,请将根视图添加为子视图并且在初始化的时候进行隐藏(使用`UIView`的`hidden`属性),然后在代理方法中改变它的可见性。
+
+
+
+
+
diff --git a/docs/docs/0.42/datepickerandroid.md b/docs/docs/0.42/datepickerandroid.md
new file mode 100644
index 0000000..6bf2f5b
--- /dev/null
+++ b/docs/docs/0.42/datepickerandroid.md
@@ -0,0 +1,57 @@
+本组件会打开一个标准的Android日期选择器的对话框。
+
+### 示例
+```js
+try {
+ const {action, year, month, day} = await DatePickerAndroid.open({
+ // 要设置默认值为今天的话,使用`new Date()`即可。
+ // 下面显示的会是2020年5月25日。月份是从0开始算的。
+ date: new Date(2020, 4, 25)
+ });
+ if (action !== DatePickerAndroid.dismissedAction) {
+ // 这里开始可以处理用户选好的年月日三个参数:year, month (0-11), day
+ }
+} catch ({code, message}) {
+ console.warn('Cannot open date picker', message);
+}
+```
+
+### 方法
+
+
+
static open(options: Object) #
+
+
打开一个标准的Android日期选择器的对话框。
+
可选的options对象的key值如下:
+
+ date (Date对象或毫秒时间戳) - 默认显示的日期
+ minDate (Date对象或毫秒时间戳) - 可选的最小日期
+ maxDate (Date对象或毫秒时间戳) - 可选的最大日期
+ mode ((enum('calendar', 'spinner', 'default')) - 设置选择器的模式:
+
+ calendar: Show a date picker in calendar mode.
+ spinner: Show a date picker in spinner mode.
+ default: Show a default native date picker(spinner/calendar) based on android versions.
+
+
+
+ 在用户选好日期后返回一个Promise,回调参数为一个对象,其中包含有action, year,
+ month (0-11),
+ day。如果用户取消了对话框,Promise仍然会执行,返回的action为DatePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必 先检查action的值。
+
+
+
static dateSetAction() #
+
+
+
+
static dismissedAction() #
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/datepickerios.md b/docs/docs/0.42/datepickerios.md
new file mode 100644
index 0000000..7621d1f
--- /dev/null
+++ b/docs/docs/0.42/datepickerios.md
@@ -0,0 +1,217 @@
+使用`DatePickerIOS`来在iOS平台上渲染一个日期/时间选择器。这是一个受约束的(Controlled)组件,所以你必须监听`onDateChange`回调函数并且及时更新`date`属性来使得组件更新,否则用户的修改会立刻被撤销来确保当前显示值和`props.date`一致。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
maximumDate Date #
+
+
可选的最大日期。
+
限制可选的日期/时间范围。
+
+
+
+
minimumDate Date #
+
+
可选的最小日期。
+
限制可选的日期/时间范围。
+
+
+
+
minuteInterval enum(1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30) #
+
+
+
+
mode enum('date', 'time', 'datetime') #
+
+
+
+
onDateChange function #
+
+
当用户修改日期或时间时调用此回调函数。
+
唯一的参数是一个日期对象,表示新的日期和时间。
+
+
+
+
timeZoneOffsetInMinutes number #
+
+
时区差,单位是分钟。
+
默认情况下,选择器会选择设备的默认时区。通过此参数,可以指定一个时区。举个例子,要使用北京时间(东八区),可以传递8 * 60。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ DatePickerIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ View,
+} = ReactNative;
+
+var DatePickerExample = React.createClass({
+ getDefaultProps: function () {
+ return {
+ date: new Date(),
+ timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ date: this.props.date,
+ timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
+ };
+ },
+
+ onDateChange: function(date) {
+ this.setState({date: date});
+ },
+
+ onTimezoneChange: function(event) {
+ var offset = parseInt(event.nativeEvent.text, 10);
+ if (isNaN(offset)) {
+ return;
+ }
+ this.setState({timeZoneOffsetInHours: offset});
+ },
+
+ render: function() {
+ // Ideally, the timezone input would be a picker rather than a
+ // text input, but we don't have any pickers yet :(
+ return (
+
+
+ {
+ this.state.date.toLocaleDateString() +
+ ' ' +
+ this.state.date.toLocaleTimeString()
+ }
+
+
+
+ hours from UTC
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+var WithLabel = React.createClass({
+ render: function() {
+ return (
+
+
+
+ {this.props.label}
+
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var Heading = React.createClass({
+ render: function() {
+ return (
+
+
+ {this.props.label}
+
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Select dates and times using the native UIDatePicker.';
+exports.examples = [
+{
+ title: '',
+ render: function(): ReactElement {
+ return ;
+ },
+}];
+
+var styles = StyleSheet.create({
+ textinput: {
+ height: 26,
+ width: 50,
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ padding: 4,
+ fontSize: 13,
+ },
+ labelContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginVertical: 2,
+ },
+ labelView: {
+ marginRight: 10,
+ paddingVertical: 2,
+ },
+ label: {
+ fontWeight: '500',
+ },
+ headingContainer: {
+ padding: 4,
+ backgroundColor: '#f6f7f8',
+ },
+ heading: {
+ fontWeight: '500',
+ fontSize: 14,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/debugging.md b/docs/docs/0.42/debugging.md
new file mode 100644
index 0000000..1c6cc0a
--- /dev/null
+++ b/docs/docs/0.42/debugging.md
@@ -0,0 +1,140 @@
+## 访问App内的开发菜单
+
+你可以通过摇晃设备或是选择iOS模拟器的"Hardware"菜单中的"Shake Gesture"选项来打开开发菜单。另外,如果是在iOS模拟器中运行,还可以按下**`Command`**`⌘` + **`D`** 快捷键,Android模拟器对应的则是**`Command`**`⌘` + **`M`**(windows上可能是F1或者F2)。
+
+
+
+> 注意:在成品(release/producation builds)中开发者菜单会被关闭。
+
+## 刷新JavaScript
+
+传统的原生应用开发中,每一次修改都需要重新编译,但在RN中你只需要刷新一下JavaScript代码,就能立刻看到变化。具体的操作就是在开发菜单中点击"Reload"选项。也可以在iOS模拟器中按下**`Command`**`⌘` + **`R`** ,Android模拟器上对应的则是按两下**`R`**。(注意,某些RN版本可能在windows中reload无效,请等待官方修复)
+
+> 如果在iOS模拟器中按下**`Command`**`⌘` + **`R`**没啥感觉,则注意检查Hardware菜单中,Keyboard选项下的"Connect Hardware Keyboard"是否被选中。
+
+### 自动刷新
+
+选择开发菜单中的"Enable Live Reload"可以开启自动刷新,这样可以节省你开发中的时间。
+
+更神奇的是,你还可以保持应用的当前运行状态,修改后的JavaScript文件会自动注入进来(就好比行驶中的汽车不用停下就能更换新的轮胎)。要实现这一特性只需开启开发菜单中的[Hot Reloading](https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html)选项。
+
+> 某些情况下hot reload并不能顺利实施。如果碰到任何界面刷新上的问题,请尝试手动完全刷新。
+
+但有些时候你必须要重新编译应用才能使修改生效:
+
+* 增加了新的资源(比如给iOS的`Images.xcassets`或是Andorid的`res/drawable`文件夹添加了图片)
+* 更改了任何的原生代码(objective-c/swift/java)
+
+## 应用内的错误与警告提示(红屏和黄屏)
+
+红屏或黄屏提示都只会在开发版本中显示,正式的离线包中是不会显示的。
+
+### 红屏错误
+
+应用内的报错会以全屏红色显示在应用中(调试模式下),我们称为红屏(red box)报错。你可以使用`console.error()`来手动触发红屏错误。
+
+### 黄屏警告
+
+应用内的警告会以全屏黄色显示在应用中(调试模式下),我们称为黄屏(yellow box)报错。点击警告可以查看详情或是忽略掉。
+和红屏报警类似,你可以使用`console.warn()`来手动触发黄屏警告。
+在默认情况下,开发模式中启用了黄屏警告。可以通过以下代码关闭:
+```js
+console.disableYellowBox = true;
+console.warn('YellowBox is disabled.');
+```
+你也可以通过代码屏蔽指定的警告,像下面这样设置一个数组:
+```js
+console.ignoredYellowBox = ['Warning: ...'];
+```
+数组中的字符串就是要屏蔽的警告的开头的内容。(例如上面的代码会屏蔽掉所有以Warning开头的警告内容)
+
+> 红屏和黄屏在发布版(release/production)中都是自动禁用的。
+
+## 访问控制台日志
+
+在运行RN应用时,可以在终端中运行如下命令来查看控制台的日志:
+
+```
+$ react-native log-ios
+$ react-native log-android
+```
+
+此外,你也可以在iOS模拟器的菜单中选择`Debug → Open System Log...`来查看。如果是Android应用,无论是运行在模拟器或是真机上,都可以通过在终端命令行里运行`adb logcat *:S ReactNative:V ReactNativeJS:V`命令来查看。
+
+## Chrome开发者工具
+
+在开发者菜单中选择"Debug JS Remotely"选项,即可以开始在Chrome中调试JavaScript代码。点击这个选项的同时会自动打开调试页面 .
+
+在Chrome的菜单中选择`Tools → Developer Tools`可以打开开发者工具,也可以通过键盘快捷键来打开(Mac上是**`Command`**`⌘` + **`Option`**`⌥` + **`I`**,Windows上是**`Ctrl`** + **`Shift`** + **`I`**或是F12)。打开[有异常时暂停(Pause On Caught Exceptions)](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511)选项,能够获得更好的开发体验。
+
+__译注__:Chrome中并不能直接看到App的用户界面,而只能提供console的输出,以及在sources项中断点调试js脚本。
+
+> [目前无法正常使用React开发插件](https://github.com/facebook/react-devtools/issues/229)(就是某些教程或截图上提到的Chrome开发工具上多出来的React选项),但这并不影响代码的调试。如果你需要像调试web页面那样查看RN应用的jsx结构,暂时只能使用Nuclide的"React Native Inspector"这一功能来代替。
+
+### 使用Chrome开发者工具来在设备上调试
+
+对于iOS真机来说,需要打开 [`RCTWebSocketExecutor.m`](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m)文件,然后将其中的"localhost"改为你的电脑的IP地址,最后启用开发者菜单中的"Debug JS Remotely"选项。
+
+对于Android 5.0+设备(包括模拟器)来说,将设备通过USB连接到电脑上后,可以使用[`adb`命令行工具](http://developer.android.com/tools/help/adb.html)来设定从设备到电脑的端口转发:
+
+`adb reverse tcp:8081 tcp:8081`
+
+如果设备Android版本在5.0以下,则可以在开发者菜单中选择"Dev Settings - Debug server host for device",然后在其中填入电脑的”IP地址:端口“。
+
+> 如果在Chrome调试时遇到一些问题,那有可能是某些Chrome的插件引起的。试着禁用所有的插件,然后逐个启用,以确定是否某个插件影响到了调试。
+
+### 使用自定义的JavaScript调试器来调试
+
+如果想用其他的JavaScript调试器来代替Chrome,可以设置一个名为`REACT_DEBUGGER`的环境变量,其值为启动自定义调试器的命令。调试的流程依然是从开发者菜单中的"Debug JS Remotely"选项开始。
+
+被指定的调试器需要知道项目所在的目录(可以一次传递多个目录参数,以空格隔开)。例如,如果你设定了`REACT_DEBUGGER="node /某个路径/launchDebugger.js --port 2345 --type ReactNative"`,那么启动调试器的命令就应该是`node /某个路径/launchDebugger.js --port 2345 --type ReactNative /某个路径/你的RN项目目录`。
+
+> 以这种方式执行的调试器最好是一个短进程(short-lived processes),同时最好也不要有超过200k的文字输出。
+
+### 在Android上使用[Stetho](http://facebook.github.io/stetho/)来调试
+
+1. 在```android/app/build.gradle```文件中添加:
+
+ ```gradle
+ compile 'com.facebook.stetho:stetho:1.3.1'
+ compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
+ ```
+
+2. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+
+ ```java
+ import com.facebook.react.modules.network.ReactCookieJarContainer;
+ import com.facebook.stetho.Stetho;
+ import okhttp3.OkHttpClient;
+ import com.facebook.react.modules.network.OkHttpClientProvider;
+ import com.facebook.stetho.okhttp3.StethoInterceptor;
+ import java.util.concurrent.TimeUnit;
+ ```
+
+3. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+ ```java
+ public void onCreate() {
+ super.onCreate();
+ Stetho.initializeWithDefaults(this);
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(0, TimeUnit.MILLISECONDS)
+ .readTimeout(0, TimeUnit.MILLISECONDS)
+ .writeTimeout(0, TimeUnit.MILLISECONDS)
+ .cookieJar(new ReactCookieJarContainer())
+ .addNetworkInterceptor(new StethoInterceptor())
+ .build();
+ OkHttpClientProvider.replaceOkHttpClient(client);
+ }
+ ```
+
+4. 运行```react-native run-android ```
+
+5. 打开一个新的Chrome选项卡,在地址栏中输入```chrome://inspect```并回车。在页面中选择'Inspect device' (标有"Powered by Stetho"字样)。
+
+## 调试原生代码
+
+在和原生代码打交道时(比如编写原生模块),可以直接从Android Studio或是Xcode中启动应用,并利用这些IDE的内置功能来调试(比如设置断点)。这一方面和开发原生应用并无二致。
+
+## 性能监测
+
+你可以在开发者菜单中选择"Pref Monitor"选项以开启一个悬浮层,其中会显示应用的当前帧数。
diff --git a/docs/docs/0.42/dimensions.md b/docs/docs/0.42/dimensions.md
new file mode 100644
index 0000000..b427a50
--- /dev/null
+++ b/docs/docs/0.42/dimensions.md
@@ -0,0 +1,23 @@
+__译注__:本模块用于获取设备屏幕的宽高。
+
+### 方法
+
+
+
+
static set(dims: {[key:string]: any}) #
+
+
这个函数只应该被原生代码调用。.
+
@param {object} dims 一个简单的字符串作为key的对象,包含了需要设置的尺寸信息。
+
+
+
+
static get(dim: string) #
+
+
初始的尺寸信息应该在runApplication之后被执行,所以它可以在任何其他的require被执行之前就可用。不过在稍后可能还会更新。
+
注意:尽管尺寸信息立即就可用,但它可能会在将来被修改(譬如设备的方向改变),所以基于这些常量的渲染逻辑和样式应当每次render之后都调用此函数,而不是将对应的值保存下来。(举例来说,你可能需要使用内联的样式而不是在StyleSheet中保存相应的尺寸)。
+
例子:var {height, width} = Dimensions.get('window');
+
@param {string} dim 想要获取的尺寸信息的字段名。
+
@returns {Object?} 返回的尺寸信息值。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/direct-manipulation.md b/docs/docs/0.42/direct-manipulation.md
new file mode 100644
index 0000000..f0b4b66
--- /dev/null
+++ b/docs/docs/0.42/direct-manipulation.md
@@ -0,0 +1,117 @@
+有时候我们需要直接改动组件并触发局部的刷新,但不使用state或是props。譬如在浏览器中使用React库,有时候会需要直接修改一个DOM节点,而在手机App中操作View时也会碰到同样的情况。在React Native中,`setNativeProps`就是等价于直接操作DOM节点的方法。
+
+> 什么时候使用setNativeProps呢?在(不得不)频繁刷新而又遇到了性能瓶颈的时候。
+>
+> 直接操作组件并不是应该经常使用的工具。一般来说只是用来创建连续的动画,同时避免渲染组件结构和同步太多视图变化所带来的大量开销。`setNativeProps`是一个“简单粗暴”的方法,它直接在底层(DOM、UIView等)而不是React组件中记录state,这样会使代码逻辑难以理清。所以在使用这个方法之前,请尽量先尝试用`setState`和[shouldComponentUpdate](http://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action)方法来解决问题。
+
+## setNativeProps与TouchableOpacity
+
+[TouchableOpacity](https://github.com/facebook/react-native/blob/master/Libraries/Components/Touchable/TouchableOpacity.js)这个组件就在内部使用了`setNativeProps`方法来更新其子组件的透明度:
+
+```javascript
+setOpacityTo: function(value) {
+ // Redacted: animation related code
+ this.refs[CHILD_REF].setNativeProps({
+ opacity: value
+ });
+},
+```
+
+由此我们可以写出下面这样的代码:子组件可以响应点击事件,更改自己的透明度。而子组件自身并不需要处理这件事情,也不需要在实现中做任何修改。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+如果不使用`setNativeProps`这个方法来实现这一需求,那么一种可能的办法是把透明值保存到state中,然后在`onPress`事件触发时更新这个值:
+
+```javascript
+getInitialState() {
+ return { myButtonOpacity: 1, }
+},
+
+render() {
+ return (
+ this.setState({myButtonOpacity: 0.5})}
+ onPressOut={() => this.setState({myButtonOpacity: 1})}>
+
+ Press me!
+
+
+ )
+}
+```
+
+比起之前的例子,这一做法会消耗大量的计算 —— 每一次透明值变更的时候React都要重新渲染组件结构,即便视图的其他属性和子组件并没有变化。一般来说这一开销也不足为虑,但当执行连续的动画以及响应用户手势的时候,只有正确地优化组件才能提高动画的流畅度。
+
+如果你看过[NativeMethodsMixin.js]()中的`setNativeProps`方法的实现,你就会发现它实际是对`RCTUIManager.updateView`的封装 —— 而这正是重渲染所触发的函数调用,具体可以参看[ReactNativeBaseComponent.js中的receiveComponent]().
+
+## 复合组件与setNativeProps
+
+复合组件并不是单纯的由一个原生视图构成,所以你不能对其直接使用`setNativeProps`。比如下面这个例子:
+
+```javascript
+var MyButton = React.createClass({
+ render() {
+ return (
+
+ {this.props.label}
+
+ )
+ },
+});
+
+var App = React.createClass({
+ render() {
+ return (
+
+
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/JXkgmQ)
+
+跑这个例子会马上看到一行报错: `Touchable child
+must either be native or forward setNativeProps to a native component`.
+这是因为`MyButton`并非直接由原生视图构成,而我们只能给原生视图设置透明值。你可以尝试这样去理解:如果你通过`React.createClass`方法自定义了一个组件,直接给它设置样式prop是不会生效的,你得把样式props层层向下传递给子组件,直到子组件是一个能够直接定义样式的原生组件。同理,我们也需要把`setNativeProps`传递给由原生组件封装的子组件。
+
+#### 将setNativeProps传递给子组件
+
+具体要做的就是在我们的自定义组件中再封装一个`setNativeProps`方法,其内容为对合适的子组件调用真正的`setNativeProps`方法,并传递要设置的参数。
+
+```javascript
+var MyButton = React.createClass({
+ setNativeProps(nativeProps) {
+ this._root.setNativeProps(nativeProps);
+ },
+
+ render() {
+ return (
+ this._root = component} {...this.props}>
+ {this.props.label}
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/YJxnEQ)
+
+现在你可以在`TouchableOpacity`中嵌入`MyButton`了!有一点需要特别说明:这里我们使用了[ref回调](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute)语法,而不是传统的字符串型ref引用。
+
+你可能还会注意到我们在向下传递props时使用了`{...this.props}`语法(这一用法的说明请参考[对象的扩展运算符](http://es6.ruanyifeng.com/#docs/object))。这是因为`TouchableOpacity`本身其实也是个复合组件, 它除了要求在子组件上执行`setNativeProps` 以外,还要求子组件对触摸事件进行处理。因此,它会传递多个props,其中包含了[onmoveshouldsetresponder](view.html#onmoveshouldsetresponder) 函数,这个函数需要回调给`TouchableOpacity`组件,以完成触摸事件的处理。与之相对的是`TouchableHighlight`组件,它本身是由原生视图构成,因而只需要我们实现`setNativeProps`。
+
+## 避免和render方法的冲突
+
+如果要更新一个由render方法来维护的属性,则可能会碰到一些出人意料的bug。因为每一次组件重新渲染都可能引起属性变化,这样一来,之前通过`setNativeProps`所设定的值就被完全忽略和覆盖掉了。[这个例子(可能需要科学上网)](https://rnplay.org/apps/bp1DvQ)
+演示了两者冲突时的情形 —— 注意看由于`setState`触发的重新渲染(每250ms)导致的动画卡顿。
+
+## setNativeProps与shouldComponentUpdate
+
+通过[巧妙运用
+`shouldComponentUpdate`方法](https://facebook.github.io/react/docs/advanced-performance.html#avoiding-reconciling-the-dom),可以避免重新渲染那些实际没有变化的子组件所带来的额外开销,此时使用`setState`的性能已经可以与`setNativeProps`相媲美了。
diff --git a/docs/docs/0.42/drawerlayoutandroid.md b/docs/docs/0.42/drawerlayoutandroid.md
new file mode 100644
index 0000000..3c81143
--- /dev/null
+++ b/docs/docs/0.42/drawerlayoutandroid.md
@@ -0,0 +1,108 @@
+封装了平台`DrawerLayout`(仅限安卓平台)的React组件。抽屉(通常用于导航切换)是通过`renderNavigationView`方法渲染的,并且DrawerLayoutAndroid的直接子视图会成为主视图(用于放置你的内容)。导航视图一开始在屏幕上并不可见,不过可以从`drawerPosition`指定的窗口侧面拖拽出来,并且抽屉的宽度可以使用`drawerWidth`属性来指定。
+
+### 截图
+
+
+### 例子
+
+```javascript
+render: function() {
+ var navigationView = (
+
+ I'm in the Drawer!
+
+ );
+ return (
+ navigationView}>
+
+ Hello
+ World!
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
drawerLockMode enum('unlocked', 'locked-closed', 'locked-open')
+ #
+
+
+
设置抽屉的锁定模式。有三种状态:
+
+ unlocked (默认值),意味着此时抽屉可以响应打开和关闭的手势操作。
+ locked-closed,意味着此时抽屉将保持关闭,不可用手势打开。
+ locked-open,意味着此时抽屉将保持打开,不可用手势关闭。
+
+ 无论抽屉处于那种状态,都仍然可以调用
openDrawer/
closeDrawer这两个方法打开和关闭。
+
+
+
+
+
+
drawerPosition enum(DrawerConsts.DrawerPosition.Left, DrawerConsts.DrawerPosition.Right) #
+
+
+
+
drawerWidth number #
+
+
指定抽屉的宽度,也就是从屏幕边缘拖进的视图的宽度。
+
+
+
+
keyboardDismissMode enum('none', "on-drag") #
+
+
指定在拖拽的过程中是否要隐藏软键盘。
+
+ none (默认值),拖拽不会隐藏软键盘。
+ on-drag 当拖拽开始的时候隐藏软键盘。
+
+
+
+
+
onDrawerClose function #
+
+
每当导航视图(抽屉)被关闭之后调用此回调函数。
+
+
+
+
onDrawerOpen function #
+
+
每当导航视图(抽屉)被打开之后调用此回调函数。
+
+
+
+
onDrawerSlide function #
+
+
每当导航视图(抽屉)产生交互的时候调用此回调函数。
+
+
+
+
onDrawerStateChanged function #
+
+
每当抽屉的状态变化时调用此回调函数。抽屉可以有3种状态:
+
+ idle(空闲),表示现在导航条上没有任何正在进行的交互。
+ dragging(拖拽中),表示用户正在与导航条进行交互。
+ settling(停靠中),表示用户刚刚结束与导航条的交互,导航条正在结束打开或者关闭的动画。
+
+
+
+
+
renderNavigationView function #
+
+
此方法用于渲染一个可以从屏幕一边拖入的导航视图。
+
+
+
diff --git a/docs/docs/0.42/easing.md b/docs/docs/0.42/easing.md
new file mode 100644
index 0000000..5a48b93
--- /dev/null
+++ b/docs/docs/0.42/easing.md
@@ -0,0 +1,63 @@
+This class implements common easing functions. The math is pretty obscure, but this cool website has nice visual illustrations of what they represent:
+
+### 方法
+
+
+
+
+
+
+
+
+
+
+
+
+
static elastic(bounciness) #
+
+
A simple elastic interaction, similar to a spring. Default bounciness
+ is 1, which overshoots a little bit once. 0 bounciness doesn't overshoot
+ at all, and bounciness of N > 1 will overshoot about N times.
+
Wolfram Plots:
+
http://tiny.cc/elastic_b_1 (default bounciness = 1)
+ http://tiny.cc/elastic_b_3 (bounciness = 3)
+
+
+
+
static bezier(x1, y1, x2, y2) #
+
+
+
static out(easing) #
+
Runs an easing function backwards.
+
+
static inOut(easing) #
+
Makes any easing function symmetrical.
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/geolocation.md b/docs/docs/0.42/geolocation.md
new file mode 100644
index 0000000..2cbee51
--- /dev/null
+++ b/docs/docs/0.42/geolocation.md
@@ -0,0 +1,111 @@
+定位API遵循[web标准](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation)。
+
+## iOS
+你需要在Info.plist中增加`NSLocationWhenInUseUsageDescription`字段来启用定位功能。如果你使用`react-native init`创建项目,定位会被默认启用。
+
+## Android
+要请求访问地理位置的权限,你需要在`AndroidManifest.xml`文件中加入如下一行:
+
+` `
+
+## 方法
+
+
static getCurrentPosition(geo_success: Function, geo_error?: Function, geo_options?: GeoOptions) #
+
成功时会调用geo_success回调,参数中包含最新的位置信息。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static watchPosition(success: Function, error?: Function, options?: GeoOptions)
+ #
+
持续监听位置,每当位置变化之后都调用success回调。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static clearWatch(watchID: number) #
+
static stopObserving() #
+
+
+
+## 例子
+
+```javascript
+/* eslint no-console: 0 */
+'use strict';
+
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Geolocation';
+exports.description = 'Examples of using the Geolocation API.';
+
+exports.examples = [
+ {
+ title: 'navigator.geolocation',
+ render: function(): ReactElement {
+ return ;
+ },
+ }
+];
+
+var GeolocationExample = React.createClass({
+ watchID: (null: ?number),
+
+ getInitialState: function() {
+ return {
+ initialPosition: 'unknown',
+ lastPosition: 'unknown',
+ };
+ },
+
+ componentDidMount: function() {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ var initialPosition = JSON.stringify(position);
+ this.setState({initialPosition});
+ },
+ (error) => alert(error.message),
+ {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
+ );
+ this.watchID = navigator.geolocation.watchPosition((position) => {
+ var lastPosition = JSON.stringify(position);
+ this.setState({lastPosition});
+ });
+ },
+
+ componentWillUnmount: function() {
+ navigator.geolocation.clearWatch(this.watchID);
+ },
+
+ render: function() {
+ return (
+
+
+ Initial position:
+ {this.state.initialPosition}
+
+
+ Current position:
+ {this.state.lastPosition}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: '500',
+ },
+});
+```
+
diff --git a/docs/docs/0.42/gesture-responder-system.md b/docs/docs/0.42/gesture-responder-system.md
new file mode 100644
index 0000000..7314e0c
--- /dev/null
+++ b/docs/docs/0.42/gesture-responder-system.md
@@ -0,0 +1,62 @@
+移动设备上的手势识别要比在web上复杂得多。用户的一次触摸操作的真实意图是什么,App要经过好几个阶段才能判断。比如App需要判断用户的触摸到底是在滚动页面,还是滑动一个widget,或者只是一个单纯的点击。甚至随着持续时间的不同,这些操作还会转化。此外,还有多点同时触控的情况。
+
+触摸响应系统可以使组件在不关心父组件或子组件的前提下自行处理触摸交互。具体的实现在`ResponderEventPlugin.js`文件中,你可以在源码中读到更多细节和文档。
+
+### 最佳实践
+
+用户之所以会觉得web app和原生app在体验上有巨大的差异,触摸响应是一大关键因素。用户的每一个操作都应该具有下列属性:
+
+- 反馈/高亮 —— 让用户看到他们到底按到了什么东西,以及松开手后会发生什么。
+- 取消功能 —— 当用户正在触摸操作时,应该是可以通过把手指移开来终止操作。
+
+这些特性使得用户在使用App时体验更好,因为它们可以让用户大胆试用,而不必担心点错了什么。
+
+### TouchableHighlight与Touchable系列组件
+
+响应系统用起来可能比较复杂。所以我们提供了一个抽象的`Touchable`实现,用来做“可触控”的组件。这一实现利用了响应系统,使得你可以简单地以声明的方式来配置触控处理。如果要做一个按钮或者网页链接,那么使用`TouchableHighlight`就可以。
+
+
+## 响应者的生命周期
+
+一个View只要实现了正确的协商方法,就可以成为触摸事件的响应者。我们通过两个方法去“询问”一个View是否愿意成为响应者:
+
+ - `View.props.onStartShouldSetResponder: (evt) => true,` - 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
+ - `View.props.onMoveShouldSetResponder: (evt) => true,` - 如果View不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?
+
+如果View返回true,并开始尝试成为响应者,那么会触发下列事件之一:
+
+ - `View.props.onResponderGrant: (evt) => {}` - View现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里。
+ - `View.props.onResponderReject: (evt) => {}` - 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。
+
+如果View已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:
+
+ - `View.props.onResponderMove: (evt) => {}` - 用户正在屏幕上移动手指时(没有停下也没有离开屏幕)。
+ - `View.props.onResponderRelease: (evt) => {}` - 触摸操作结束时触发,比如"touchUp"(手指抬起离开屏幕)。
+ - `View.props.onResponderTerminationRequest: (evt) => true` - 有其他组件请求接替响应者,当前的View是否“放权”?返回true的话则释放响应者权力。
+ - `View.props.onResponderTerminate: (evt) => {}` - 响应者权力已经交出。这可能是由于其他View通过`onResponderTerminationRequest`请求的,也可能是由操作系统强制夺权(比如iOS上的控制中心或是通知中心)。
+
+`evt`是一个合成事件,它包含以下结构:
+
+ - `nativeEvent`
+ + `changedTouches` - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
+ + `identifier` - 触摸点的ID
+ + `locationX` - 触摸点相对于父元素的横坐标
+ + `locationY` - 触摸点相对于父元素的纵坐标
+ + `pageX` - 触摸点相对于根元素的横坐标
+ + `pageY` - 触摸点相对于根元素的纵坐标
+ + `target` - 触摸点所在的元素ID
+ + `timestamp` - 触摸事件的时间戳,可用于移动速度的计算
+ + `touches` - 当前屏幕上的所有触摸点的集合
+
+### 捕获ShouldSet事件处理
+
+`onStartShouldSetResponder`与`onMoveShouldSetResponder`是以冒泡的形式调用的,即嵌套最深的节点最先调用。这意味着当多个View同时在`*ShouldSetResponder`中返回true时,最底层的View将优先“夺权”。在多数情况下这并没有什么问题,因为这样可以确保所有控件和按钮是可用的。
+
+但是有些时候,某个父View会希望能先成为响应者。我们可以利用“捕获期”来解决这一需求。响应系统在从最底层的组件开始冒泡之前,会首先执行一个“捕获期”,在此期间会触发`on*ShouldSetResponderCapture`系列事件。因此,如果某个父View想要在触摸操作开始时阻止子组件成为响应者,那就应该处理`onStartShouldSetResponderCapture`事件并返回true值。
+
+ - `View.props.onStartShouldSetResponderCapture: (evt) => true,`
+ - `View.props.onMoveShouldSetResponderCapture: (evt) => true,`
+
+### PanResponder
+
+要使用更高级的手势功能,请参看[PanResponder](panresponder.html).
diff --git a/docs/docs/0.42/getting-started.md b/docs/docs/0.42/getting-started.md
new file mode 100644
index 0000000..1da52f6
--- /dev/null
+++ b/docs/docs/0.42/getting-started.md
@@ -0,0 +1,760 @@
+欢迎使用React Native!这篇文档会帮助你搭建基本的React Native开发环境。如果你已经搭好了环境,那么可以尝试一下[编写Hello World](tutorial.html)。
+
+根据你所使用的操作系统、针对的目标平台不同,具体步骤有所不同。如果想同时开发iOS和Android也没问题,你只需要先选一个平台开始,另一个平台的环境搭建只是稍有不同。
+
+如果`阅读完本文档`后还碰到很多环境搭建的问题,我们建议你还可以再看看由本站提供的`环境搭建视频教程`([macOS iOS](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220865928921581&vid=a1417i5op7k)、[macOS Android](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220870223888877&vid=z1417kmxask)、[windows Android](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220874518856173&vid=d1417tgg1ez))、[windows环境搭建文字教程](http://bbs.reactnative.cn/topic/10)、以及[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+
+
+
+## 暂不支持
+
+苹果公司目前只允许在Mac电脑上开发iOS应用。如果你没有Mac电脑,那么只能考虑先开发Android应用了。
+
+
+
+
+
+
+
+
+## 安装
+
+### 必需的软件
+
+#### Homebrew
+
+[Homebrew](http://brew.sh/), Mac系统的包管理器,用于安装NodeJS和一些其他必需的工具软件。
+
+```
+/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+
+译注:在Max OS X 10.11(El Capitan)版本中,homebrew在安装软件时可能会碰到`/usr/local`目录不可写的权限问题。可以使用下面的命令修复:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+#### Node
+
+使用Homebrew来安装[Node.js](https://nodejs.org/).
+
+> React Native目前需要NodeJS 5.0或更高版本。本文发布时Homebrew默认安装的是最新版本,一般都满足要求。
+
+```
+brew install node
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+
+如果你看到`EACCES: permission denied`这样的权限报错,那么请参照上文的homebrew译注,修复`/usr/local`目录的所有权:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+
+
+#### Xcode
+
+React Native目前需要[Xcode](https://developer.apple.com/xcode/downloads/) 8.0 或更高版本。你可以通过App Store或是到[Apple开发者官网](https://developer.apple.com/xcode/downloads/)上下载。这一步骤会同时安装Xcode IDE和Xcode的命令行工具。
+
+> 虽然一般来说命令行工具都是默认安装了,但你最好还是启动Xcode,并在`Xcode | Preferences | Locations`菜单中检查一下是否装有某个版本的`Command Line Tools`。Xcode的命令行工具中也包含一些必须的工具,比如`git`等。
+
+
+
+#### Android Studio
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 勾选`Performance`和`Android Virtual Device`
+
+
+
+- 安装完成后,在Android Studio的启动欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom System Image`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。具体的做法是把下面的命令加入到`~/.bash_profile`文件中:(__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这个文件有可能并不存在。请在终端下使用`vi ~/.bash_profile`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ~/.bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+
+### 推荐安装的工具
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+```
+brew install watchman
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+
+```
+brew install flow
+```
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。具体做法仍然是在`~/.bash_profile`中添加:
+
+```
+export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
+```
+
+### 其他可选的安装项
+
+#### Git
+
+Git版本控制。如果你已经安装过[Xcode](https://developer.apple.com/xcode/),则Git也已经一并安装了。如若没有,则使用下列命令安装:
+
+```
+brew install git
+```
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下⌘+M来打开开发者菜单。
+
+
+
+
+## 安装
+
+### 必需的软件
+
+
+
+#### Chocolatey
+
+[Chocolatey](https://chocolatey.org)是一个Windows上的包管理器,类似于linux上的`yum`和
+`apt-get`。 你可以在其[官方网站](https://chocolatey.org)上查看具体的使用说明。一般的安装步骤应该是下面这样:
+
+```
+@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
+```
+
+> 一般来说,使用Chocolatey来安装软件的时候,需要以管理员的身份来运行命令提示符窗口。译注:chocolatey的网站可能在国内访问困难,导致上述安装命令无法正常完成。请使用稳定的翻墙工具。
+> 如果你实在装不上这个工具,也不要紧。下面所需的python2和nodejs你可以分别单独去对应的官方网站下载安装即可。
+
+#### Python 2
+
+打开命令提示符窗口,使用Chocolatey来安装Python 2.
+
+> 注意目前不支持Python 3版本。
+
+```
+choco install python2
+```
+
+
+
+#### Node
+
+
+
+打开终端窗口,输入下面的命令来安装NodeJS:
+
+```
+sudo apt-get install -y build-essential
+curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -
+sudo apt-get install -y nodejs
+sudo ln -s /usr/bin/nodejs /usr/bin/node
+```
+
+
+
+
+打开命令提示符窗口,使用Chocolatey来安装NodeJS。注意,目前已知Node 7.1版本在windows上无法正常工作,请避开这个版本!
+
+```
+choco install nodejs.install
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+> 如果你遇到`EACCES: permission denied`权限错误,可以尝试运行下面的命令(限linux系统):
+> `sudo npm install -g yarn react-native-cli`.
+
+#### Android Studio
+
+[Android Studio](http://developer.android.com/sdk/index.html) 2.0 or higher.
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+> 或是使用包管理器来安装(比如`choco install jdk8`或是
+> `apt-get install default-jdk`)
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 选择`Android Virtual Device`
+
+
+
+
+
+- 确定所有安装都勾选了,尤其是`Android SDK`和`Android Device Emulator`。
+
+- 在初步安装完成后,选择`Custom`安装项:
+
+
+
+- 检查已安装的组件,尤其是模拟器和HAXM加速驱动。
+
+
+
+
+
+- 安装完成后,在Android Studio的欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom System Image`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+
+
+
+
+
+
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。
+
+
+
+具体的做法是把下面的命令加入到`~/.bashrc`、`~/.bash_profile`文件中。如果你使用的是其他的shell,则选择对应的配置文件:
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ./bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> `新建`
+
+> 具体的路径可能和下图不一致,请自行确认。
+
+
+
+> 你需要关闭现有的命令符提示窗口然后重新打开,这样新的环境变量才能生效。
+
+
+
+### 推荐安装的工具
+
+
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+> 安装watchman还可以避免node的一个与文件监视有关的bug。
+
+在终端中输入以下命令来编译并安装watchman:
+
+```
+git clone https://github.com/facebook/watchman.git
+cd watchman
+git checkout v4.5.0 # 这是本文发布时的最新版本
+./autogen.sh
+./configure
+make
+sudo make install
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+在终端中输入以下命令来安装flow:
+
+```
+npm install -g flow-bin
+```
+
+
+
+
+#### Gradle Daemon
+
+开启[Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)可以极大地提升java代码的增量编译速度。
+
+
+
+
+```
+touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties
+```
+
+
+
+
+```
+(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo org.gradle.daemon=true >> "%USERPROFILE%/.gradle/gradle.properties")
+```
+
+
+
+
+#### Android模拟器加速器
+
+在安装Android Studio时你可能会看到下面这样的提示:
+
+
+
+如果你的系统支持KVM,那就应该安装[Intel的Android模拟器加速器](https://software.intel.com/en-us/android/articles/speeding-up-the-android-emulator-on-intel-architecture#_Toc358213272)。
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。
+
+
+
+在`~/.bashrc`或是`~/.bash_profile`文件中添加:
+
+```
+# 你的具体路径可能有所不同,请自行确认。
+PATH="~/Android/Sdk/tools:~/Android/Sdk/platform-tools:${PATH}"
+export PATH
+```
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> 选中`PATH` -> 双击进行编辑
+
+> 注意你的具体路径可能和下图不同
+
+
+
+
+
+### 可选的安装项
+
+#### Git
+
+
+
+[使用包管理器](https://git-scm.com/download/linux)来安装Git
+(例如`sudo apt-get install git-all`).
+
+
+
+你可以使用Chocolatey来安装`git`:
+
+```
+choco install git
+```
+
+另外你也可以直接去下载[Git for Windows](https://git-for-windows.github.io/)。
+在安装过程中注意勾选"Run Git from Windows Command Prompt",这样才会把`git`命令添加到`PATH`环境变量中。
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下F1来打开开发者菜单。
+
+
+
+#### Visual Studio Emulator for Android
+
+[Visual Studio Emulator for Android](https://www.visualstudio.com/zh-cn/features/msft-android-emulator-vs.aspx#中国 (简体中文))是利用了Hyper-V技术进行硬件加速的免费android模拟器。也是Android Studio自带的原装模拟器之外的一个很好的选择。而且你并不需要安装Visual Studio。
+在用于React Native开发前,需要先在注册表中进行一些修改:
+
+1. 打开运行命令(按下Windows+R键)
+2. 输入`regedit.exe`然后回车
+3. 在注册表编辑器中找到`HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools`条目
+4. 右键点击`Android SDK Tools`,选择`新建 > 字符串值`
+5. 名称设为`Path`
+6. 双击`Path`,将其值设为你的Android SDK的路径。(例如`C:\Program Files\Android\sdk`)
+
+
+
+
+## 测试安装
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-ios
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹
+然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line),或是双击`ios/AwesomeProject.xcodeproj`文件然后在Xcode中点击`Run`按钮。
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line)。
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+
+
+- 使用你喜欢的编辑器打开`index.ios.js`并随便改上几行。
+- 在iOS Emulator中按下`⌘-R`就可以刷新APP并看到你的最新修改!
+
+
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 测试安装
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+__Windows用户请注意,请不要在命令行默认的System32目录中init项目!会有各种权限限制导致不能运行!__
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 接下来
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-ios.html#content)。
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+## 接下来
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
diff --git a/docs/docs/0.42/handling-text-input.md b/docs/docs/0.42/handling-text-input.md
new file mode 100644
index 0000000..52bb4eb
--- /dev/null
+++ b/docs/docs/0.42/handling-text-input.md
@@ -0,0 +1,39 @@
+[`TextInput`](textinput.html#content)是一个允许用户输入文本的基础组件。它有一个名为`onChangeText`的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为`onSubmitEditing`的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。
+
+假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。我们假设这另一种文字来自某个吃货星球,只有一个单词: 🍕。所以"Hello there Bob"将会被翻译为"🍕🍕🍕"。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, TextInput, View } from 'react-native';
+
+class PizzaTranslator extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+
+ render() {
+ return (
+
+ this.setState({text})}
+ />
+
+ {this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
+
+
+ );
+ }
+}
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('PizzaTranslator', () => PizzaTranslator);
+```
+
+在上面的例子里,我们把`text`保存到state中,因为它会随着时间变化。
+
+文本输入方面还有很多其他的东西要处理。比如你可能想要在用户输入的时候进行验证,在[React的表单组件中的受限组件](http://reactjs.cn/react/docs/forms.html)一节中有一些详细的示例(注意react中的onChange对应的是rn中的onChangeText)。此外你还需要看看[TextInput的文档](textinput.html)。
+
+TextInput可能是天然具有“动态状态”的最简单的组件了。下面我们来看看另一类控制布局的组件,先从[ScrollView开始学习](using-a-scrollview.html)。
diff --git a/docs/docs/0.42/handling-touches.md b/docs/docs/0.42/handling-touches.md
new file mode 100644
index 0000000..3808eae
--- /dev/null
+++ b/docs/docs/0.42/handling-touches.md
@@ -0,0 +1,57 @@
+移动应用上的用户交互基本靠“摸”。当然,“摸”也是有各种姿势的:在一个按钮上点击,在一个列表上滑动,或是在一个地图上缩放。
+
+React Native提供了可以处理常见触摸手势(例如点击或滑动)的组件, 以及可用于识别更复杂的手势的完整的[手势响应系统](gesturerespondersystem.html)。
+
+## 可点击的组件
+
+在需要捕捉用户点击操作时,可以使用"Touchable"开头的一系列组件。这些组件通过`onPress`属性接受一个点击事件的处理函数。当一个点击操作开始并且终止于本组件时(即在本组件上按下手指并且抬起手指时也没有移开到组件外),此函数会被调用。
+
+示例:
+
+```javascript
+class MyButton extends Component {
+ _onPressButton() {
+ console.log("You tapped the button!");
+ }
+
+ render() {
+ return (
+
+ Button
+
+ );
+ }
+}
+```
+
+可点击的组件需要给用户提供视觉反馈,例如是哪个组件正在响应用户的操作,以及当用户抬起手指后会发生什么。用户也应该可以通过把手指移到一边来取消点击操作。
+
+具体使用哪种组件,取决于你希望给用户什么样的视觉反馈:
+
+- 一般来说,你可以使用[**TouchableHighlight**](touchablehighlight.html)来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。
+
+- 在Android上还可以使用[**TouchableNativeFeedback**](touchablenativefeedback.html),它会在用户手指按下时形成类似墨水涟漪的视觉效果。
+
+- [**TouchableOpacity**](touchableopacity.html)会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
+
+- 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用[**TouchableWithoutFeedback**](touchablewithoutfeedback.html)。
+
+### 长按
+
+某些场景中你可能需要检测用户是否进行了长按操作。可以在上面列出的任意组件中使用`onLongPress`属性来实现。
+
+## 在列表中上下滑动和在视图上左右滑动
+
+可滚动的列表是移动应用中一个常见的模式。用户会在列表中或快或慢的各种滑动。[ScrollView](using-a-scrollView.html)组件可以满足这一需求。
+
+ScrollView可以在垂直或水平方向滚动,还可以配置`pagingEnabled`属性来让用户整屏整屏的滑动。此外,水平方向的滑动还可以使用Android上的[ViewPagerAndroid](viewpagerandroid.html) 组件。
+
+[ListView](using-a-listview.html)则是一种特殊的ScrollView,用于显示比较长的垂直列表。它还可以显示分区块的头部和尾部,类似iOS上的`UITableView`控件。
+
+### 双指缩放
+
+如果在ScrollView中只放置一个组件,则可以用来实现缩放操作。设置`maximumZoomScale`和`minimumZoomScale`属性即可以使用户能够缩放其中的内容。
+
+## 处理其他的手势
+
+如果你想实现视图的拖拽,或是实现自定义的手势,那么请参阅[PanResponder](panresponder.html) API或是[手势识别系统](gesture-responder-system.html)的文档。
diff --git a/docs/docs/0.42/headless-js-android.md b/docs/docs/0.42/headless-js-android.md
new file mode 100644
index 0000000..0cc71fd
--- /dev/null
+++ b/docs/docs/0.42/headless-js-android.md
@@ -0,0 +1,49 @@
+Headless JS是一种使用js在后台执行任务的方法。它可以用来在后台同步数据、处理推送通知或是播放音乐等等。
+
+## JS端的API
+
+首先我们要通过`AppRegistry`来注册一个async函数,这个函数我们称之为“任务”。注册方式类似在index.js中注册RN应用:
+
+```js
+AppRegistry.registerHeadlessTask('SomeTaskName', () => require('SomeTaskName'));
+```
+
+然后创建require对应的`SomeTaskName.js`文件:
+
+```js
+module.exports = async (taskData) => {
+ // 要做的事情
+}
+```
+
+你可以在任务中处理任何事情(网络请求、定时器等等),但唯独**不要涉及用户界面**!在任务完成后(例如在promise中调用resolve),RN会进入一个“暂停”模式,直到有新任务需要执行或者是应用回到前台。
+
+## Java端的API
+
+没错,我们还需要一些原生代码,但是请放心并不麻烦。你需要像下面这样继承`HeadlessJsTaskService`,然后覆盖`getTaskConfig`方法的实现:
+
+```java
+public class MyTaskService extends HeadlessJsTaskService {
+
+ @Override
+ protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ return new HeadlessJsTaskConfig(
+ "SomeTaskName",
+ Arguments.fromBundle(extras),
+ 5000);
+ }
+ return null;
+ }
+}
+```
+
+好了,现在当你[启动服务时][0](例如一个周期性的任务或是响应一些系统事件/广播),JS任务就会开始执行。
+
+## 注意事项
+
+* 默认情况下,如果应用正在前台运行时尝试执行任务,那么应用会崩溃。这是为了防止开发者在任务中处理太多逻辑而拖慢用户界面。
+* 如果你是通过`BroadcastReceiver`来启动的服务,那么谨记在从`onReceive()`返回之前要调用`HeadlessJsTaskService.acquireWakelockNow()`。
+
+[0]: https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)
\ No newline at end of file
diff --git a/docs/docs/0.42/height-and-width.md b/docs/docs/0.42/height-and-width.md
new file mode 100644
index 0000000..6431b24
--- /dev/null
+++ b/docs/docs/0.42/height-and-width.md
@@ -0,0 +1,56 @@
+组件的高度和宽度决定了其在屏幕上显示的尺寸。
+
+#### 指定宽高
+
+最简单的给组件设定尺寸的方式就是在样式中指定固定的`width`和`height`。React Native中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FixedDimensionsBasics extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+};
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
+```
+这样给组件设置尺寸也是一种常见的模式,比如要求在不同尺寸的屏幕上都显示成一样的大小。
+
+#### 弹性(Flex)宽高
+
+在组件样式中使用`flex`可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用`flex:1`来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了`flex:1`,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的`flex`值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间`flex`值的比)。
+
+> 组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的`width`和`height`,也没有设定`flex`,则父容器的尺寸为零。其子组件如果使用了`flex`,也是无法显示的。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDimensionsBasics extends Component {
+ render() {
+ return (
+ // 试试去掉父View中的`flex: 1`。
+ // 则父View不再具有尺寸,因此子组件也无法再撑开。
+ // 然后再用`height: 300`来代替父View的`flex: 1`试试看?
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
+```
+
+当你熟练掌握了如何控制组件的尺寸后,下一步可以[学习如何在屏幕上排列组件了](layout-with-flexbox.html)。
diff --git a/docs/docs/0.42/image.md b/docs/docs/0.42/image.md
new file mode 100644
index 0000000..41e501d
--- /dev/null
+++ b/docs/docs/0.42/image.md
@@ -0,0 +1,956 @@
+一个用于显示多种不同类型图片的React组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。详细用法参阅[图片文档](images.html)。
+
+用法样例:
+
+```javascript
+renderImages() {
+ return (
+
+
+
+
+ );
+}
+```
+
+### 截图
+
+
+### 在Android上支持GIF和WebP格式图片
+
+默认情况下Android是不支持GIF和WebP格式的。你需要在`android/app/build.gradle`文件中根据需要手动添加以下模块:
+
+```
+dependencies {
+ // 如果你需要支持Android4.0(API level 14)之前的版本
+ compile 'com.facebook.fresco:animated-base-support:0.11.0'
+
+ // 如果你需要支持GIF动图
+ compile 'com.facebook.fresco:animated-gif:0.11.0'
+
+ // 如果你需要支持WebP格式,包括WebP动图
+ compile 'com.facebook.fresco:animated-webp:0.11.0'
+ compile 'com.facebook.fresco:webpsupport:0.11.0'
+
+ // 如果只需要支持WebP格式而不需要动图
+ compile 'com.facebook.fresco:webpsupport:0.11.0'
+}
+```
+
+如果你在使用GIF的同时还使用了ProGuard,那么需要在`proguard-rules.pro`中添加如下规则 :
+
+```
+-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl {
+ public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory, com.facebook.imagepipeline.core.ExecutorSupplier);
+}
+```
+
+### 属性
+
+
+
+
onLayout function #
+
+
当元素挂载或者布局改变的时候调用,参数为:{nativeEvent: {layout: {x, y, width, height}}}.
+
+
+
+
+
onLoadEnd function #
+
+
加载结束后,不论成功还是失败,调用此回调函数。
+
+
+
+
onLoadStart function #
+
+
+
+
resizeMode enum('cover', 'contain', 'stretch', 'repeat', 'center') #
+
+
决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。
+
+ cover: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全覆盖甚至超出容器,容器中不留任何空白。
+ contain: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全被包裹在容器中,容器中可能留有空白
+ stretch: 拉伸图片且不维持宽高比,直到宽高都刚好填满容器。
+ repeat: 重复平铺图片直到填满容器。图片会维持原始尺寸。仅iOS可用。
+ center: 居中不拉伸。
+
+
+
+
+
source {uri: string}, number #
+
+
uri是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+
+
+
style style #
+
+
+
+
+
+
backfaceVisibility ReactPropTypes.oneOf(['visible', 'hidden'])
+
+
+
resizeMode Object.keys(ImageResizeMode)
+
+
+
backgroundColor color
+
+
+
borderBottomLeftRadius ReactPropTypes.number
+
+
+
borderBottomRightRadius ReactPropTypes.number
+
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius ReactPropTypes.number
+
+
+
borderTopRightRadius ReactPropTypes.number
+
+
+
borderWidth number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
+
opacity number
+
+
+
android overlayColor ReactPropTypes.string
+
+
+
+
+
+
+
testID string #
+
+
一个唯一的资源标识符,用来在自动测试脚本中标识这个元素。
+
+
+
android resizeMethod
+ enum('auto', 'resize', 'scale') #
+
当图片实际尺寸和容器样式尺寸不一致时,决定以怎样的策略来调整图片的尺寸。默认值为auto。
+
+ auto:使用启发式算法来在resize和scale中自动决定。
+
+ resize: 在图片解码之前,使用软件算法对其在内存中的数据进行修改。当图片尺寸比容器尺寸大得多时,应该优先使用此选项。
+ scale:对图片进行缩放。和resize相比,
+ scale速度更快(一般有硬件加速),而且图片质量更优。在图片尺寸比容器尺寸小或者只是稍大一点时,应该优先使用此选项。
+
+
关于resize和scale的详细说明请参考http://frescolib.org/docs/resizing-rotating.html .
+
+
+
+
ios accessibilityLabel string #
+
+
当用户与图片交互时,读屏器(无障碍功能)会朗读的文字。
+
+
+
+
ios accessible bool #
+
+
当此属性为真的时候,表示这个图片是一个启用了无障碍功能的元素。
+
+
+
+
ios blurRadius number #
+
+
+
blurRadius(模糊半径):为图片添加一个指定半径的模糊滤镜。
+
+
+
+
ios capInsets {top: number, left: number, bottom: number, right: number} #
+
+
当图片被缩放的时候,capInsets指定的角上的尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用(译注:这就是常说的九宫格或者.9图。了解更多信息,可以参见苹果官方文档
+
+
+
ios defaultSource
+ {uri: string, width: number, height: number, scale: number}, number #
+
在读取图片时默认显示的加载提示图片
+
+ uri - 是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+ width, height - 如果你知道图片的尺寸,那么可以在这里指定。这一尺寸会被用作<Image/>组件的默认尺寸。
+
+ scale - 图片的缩放系数。默认是1.0,意味着每一个图片像素都对应一个设备独立像素(DIP)。
+
+ number - 本地图片引用语法require('./image.jpg')所返回的内部资源id。
+
+
+
+
+
ios onError function #
+
+
当加载错误的时候调用此回调函数,参数为{nativeEvent: {error}}
+
+
+
ios onPartialLoad
+ function #
+
如果图片本身支持逐步加载,则逐步加载的过程中会调用此方法。“逐步加载”的具体定义与具体的标准和实现有关。
+
+
+
ios onProgress function #
+
+
在加载过程中不断调用,参数为{nativeEvent: {loaded, total}}
+
+
+
+
+### 方法
+
+
+
static getSize(uri: string, success: (width: number, height: number) => void, failure: (error: any) => void)
+ #
+
在显示图片前获取图片的宽高(以像素为单位)。如果图片地址不正确或下载失败,此方法也会失败。
+
要获取图片的尺寸,首先需要加载或下载图片(同时会被缓存起来)。这意味着理论上你可以用这个方法来预加载图片,虽然此方法并没有针对这一用法进行优化,而且将来可能会换一些实现方案使得并不需要完整下载图片即可获取尺寸。所以更好的预加载方案是使用下面那个专门的预加载方法。
+
+
static prefetch(url: string) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActivityIndicator,
+ Image,
+ Platform,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
+
+var ImageCapInsetsExample = require('./ImageCapInsetsExample');
+const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
+var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
+
+var NetworkImageCallbackExample = React.createClass({
+ getInitialState: function() {
+ return {
+ events: [],
+ startLoadPrefetched: false,
+ mountTime: new Date(),
+ };
+ },
+
+ componentWillMount() {
+ this.setState({mountTime: new Date()});
+ },
+
+ render: function() {
+ var { mountTime } = this.state;
+
+ return (
+
+ this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => {
+ this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`);
+ this.setState({startLoadPrefetched: true}, () => {
+ prefetchTask.then(() => {
+ this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
+ }, error => {
+ this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
+ });
+ });
+ }}
+ />
+ {this.state.startLoadPrefetched ?
+ this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
+ />
+ : null}
+
+ {this.state.events.join('\n')}
+
+
+ );
+ },
+
+ _loadEventFired(event) {
+ this.setState((state) => {
+ return state.events = [...state.events, event];
+ });
+ }
+});
+
+var NetworkImageExample = React.createClass({
+ getInitialState: function() {
+ return {
+ error: false,
+ loading: false,
+ progress: 0
+ };
+ },
+ render: function() {
+ var loader = this.state.loading ?
+
+ {this.state.progress}%
+
+ : null;
+ return this.state.error ?
+ {this.state.error} :
+ this.setState({loading: true})}
+ onError={(e) => this.setState({error: e.nativeEvent.error, loading: false})}
+ onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})}
+ onLoad={() => this.setState({loading: false, error: false})}>
+ {loader}
+ ;
+ }
+});
+
+var ImageSizeExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 0,
+ height: 0,
+ };
+ },
+ componentDidMount: function() {
+ Image.getSize(this.props.source.uri, (width, height) => {
+ this.setState({width, height});
+ });
+ },
+ render: function() {
+ return (
+
+
+
+ Actual dimensions:{'\n'}
+ Width: {this.state.width}, Height: {this.state.height}
+
+
+ );
+ },
+});
+
+var MultipleSourcesExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 30,
+ height: 30,
+ };
+ },
+ render: function() {
+ return (
+
+
+
+ Decrease image size
+
+
+ Increase image size
+
+
+ Container image size: {this.state.width}x{this.state.height}
+
+
+
+
+ );
+ },
+ increaseImageSize: function() {
+ if (this.state.width >= 100) {
+ return;
+ }
+ this.setState({
+ width: this.state.width + 10,
+ height: this.state.height + 10,
+ });
+ },
+ decreaseImageSize: function() {
+ if (this.state.width <= 10) {
+ return;
+ }
+ this.setState({
+ width: this.state.width - 10,
+ height: this.state.height - 10,
+ });
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Base component for displaying different types of images.';
+
+exports.examples = [
+ {
+ title: 'Plain Network Image',
+ description: 'If the `source` prop `uri` property is prefixed with ' +
+ '"http", then it will be downloaded from the network.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Plain Static Image',
+ description: 'Static assets should be placed in the source code tree, and ' +
+ 'required in the same way as JavaScript modules.',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Image Loading Events',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Error Handler',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Download Progress',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'defaultSource',
+ description: 'Show a placeholder image when a network image is loading',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Border Color',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Width',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Radius',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Background Color',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Opacity',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Nesting',
+ render: function() {
+ return (
+
+
+ React
+
+
+ );
+ },
+ },
+ {
+ title: 'Tint Color',
+ description: 'The `tintColor` style prop changes all the non-alpha ' +
+ 'pixels to the tint color.',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ It also works with downloaded images:
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Resize Mode',
+ description: 'The `resizeMode` style prop controls how the image is ' +
+ 'rendered within the frame.',
+ render: function() {
+ return (
+
+ {[smallImage, fullImage].map((image, index) => {
+ return (
+
+
+
+
+ Contain
+
+
+
+
+
+ Cover
+
+
+
+
+
+
+
+ Stretch
+
+
+
+ { Platform.OS === 'ios' ?
+
+
+ Repeat
+
+
+
+ : null }
+ { Platform.OS === 'android' ?
+
+
+ Center
+
+
+
+ : null }
+
+
+ );
+ })}
+
+ );
+ },
+ },
+ {
+ title: 'Animated GIF',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Base64 image',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Cap Insets',
+ description:
+ 'When the image is resized, the corners of the size specified ' +
+ 'by capInsets will stay a fixed size, but the center content and ' +
+ 'borders of the image will be stretched. This is useful for creating ' +
+ 'resizable rounded buttons, shadows, and other resizable assets.',
+ render: function() {
+ return ;
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Size',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'MultipleSourcesExample',
+ description:
+ 'The `source` prop allows passing in an array of uris, so that native to choose which image ' +
+ 'to diplay based on the size of the of the target image',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'Legacy local image',
+ description:
+ 'Images shipped with the native bundle, but not managed ' +
+ 'by the JS packager',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Bundled images',
+ description:
+ 'Images shipped in a separate native bundle',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ platform: 'ios',
+ },
+];
+
+var fullImage = {uri: 'https://facebook.github.io/react/img/logo_og.png'};
+var smallImage = {uri: 'https://facebook.github.io/react/img/logo_small_2x.png'};
+
+var styles = StyleSheet.create({
+ base: {
+ width: 38,
+ height: 38,
+ },
+ progress: {
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ width: 100
+ },
+ leftMargin: {
+ marginLeft: 10,
+ },
+ background: {
+ backgroundColor: '#222222'
+ },
+ sectionText: {
+ marginVertical: 6,
+ },
+ nestedText: {
+ marginLeft: 12,
+ marginTop: 20,
+ backgroundColor: 'transparent',
+ color: 'white'
+ },
+ resizeMode: {
+ width: 90,
+ height: 60,
+ borderWidth: 0.5,
+ borderColor: 'black'
+ },
+ resizeModeText: {
+ fontSize: 11,
+ marginBottom: 3,
+ },
+ icon: {
+ width: 15,
+ height: 15,
+ },
+ horizontal: {
+ flexDirection: 'row',
+ },
+ gif: {
+ flex: 1,
+ height: 200,
+ },
+ base64: {
+ flex: 1,
+ height: 50,
+ resizeMode: 'contain',
+ },
+ touchableText: {
+ fontWeight: '500',
+ color: 'blue',
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/imageeditor.md b/docs/docs/0.42/imageeditor.md
new file mode 100644
index 0000000..b77155e
--- /dev/null
+++ b/docs/docs/0.42/imageeditor.md
@@ -0,0 +1,10 @@
+### 方法
+
+
+
static cropImage(uri, cropData, success, failure)
+ #
+
根据指定的URI参数剪裁对应的图片。如果URI指向一个远程图片,则首先会自动下载该图片。如果图片无法下载或读取,则调用failure回调函数。
+
如果剪裁成功完成,则剪裁好的图片会被存放在ImageStore 中,同时success回调函数中返回的URI参数会指向ImageStore中的此图片。请记得在完成处理逻辑后删除ImageStore中的图片。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/imagepickerios.md b/docs/docs/0.42/imagepickerios.md
new file mode 100644
index 0000000..06a8484
--- /dev/null
+++ b/docs/docs/0.42/imagepickerios.md
@@ -0,0 +1,28 @@
+### 方法
+
+
+
+
static canRecordVideos(callback)
+ #
+
+
+
+
static canUseCamera(callback)
+ #
+
+
+
+
static openCameraDialog(config, successCallback, cancelCallback)
+ #
+
+
+
+
static openSelectDialog(config, successCallback, cancelCallback)
+ #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/images.md b/docs/docs/0.42/images.md
new file mode 100644
index 0000000..9289385
--- /dev/null
+++ b/docs/docs/0.42/images.md
@@ -0,0 +1,136 @@
+## 静态图片资源
+
+从0.14版本开始,React Native提供了一个统一的方式来管理iOS和Android应用中的图片。要往App中添加一个静态图片,只需把图片文件放在代码文件夹中某处,然后像下面这样去引用它:
+
+```javascript
+
+```
+
+图片文件的查找会和JS模块的查找方式一样。在上面的这个例子里,是哪个组件引用了这个图片,Packager就会去这个组件所在的文件夹下查找`my-icon.png`。并且,如果你有`my-icon.ios.png`和`my-icon.android.png`,Packager就会根据平台而选择不同的文件。
+
+你还可以使用`@2x`,`@3x`这样的文件名后缀,来为不同的屏幕精度提供图片。比如下面这样的代码结构:
+
+```
+.
+├── button.js
+└── img
+ ├── check@2x.png
+ └── check@3x.png
+```
+
+并且`button.js`里有这样的代码:
+
+```javascript
+
+```
+
+Packager会打包所有的图片并且依据屏幕精度提供对应的资源。譬如说,iPhone 5s会使用`check@2x.png`,而Nexus 5上则会使用`check@3x.png`。如果没有图片恰好满足屏幕分辨率,则会自动选中最接近的一个图片。
+
+_注意_:如果你添加图片的时候packager正在运行,可能需要重启packager以便能正确引入新添加的图片。
+
+这样会带来如下的一些好处:
+
+1. iOS和Android一致的文件系统。
+2. 图片和JS代码处在相同的文件夹,这样组件就可以包含自己所用的图片而不用单独去设置。
+3. 不需要全局命名。你不用再担心图片名字的冲突问题了。
+4. 只有实际被用到(即被require)的图片才会被打包到你的app。
+5. 现在在开发期间,增加和修改图片不需要重新编译了,只要和修改js代码一样刷新你的模拟器就可以了。
+6. 与访问网络图片相比,Packager可以得知图片大小了,不需要在代码里再声明一遍尺寸。
+7. 现在通过npm来分发组件或库可以包含图片了。
+
+注意:为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串。
+
+```javascript
+// 正确
+
+
+// 错误
+var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
+
+
+// 正确
+var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png');
+
+```
+
+**本特性从0.14开始生效**。请注意:新的资源系统依靠修改打包脚本来实现,`react-native init`创建的新工程已经包含了这些修改:[Xcode](https://github.com/facebook/react-native/pull/3523)和[Gradle](https://github.com/facebook/react-native/commit/9dc036d2b99e6233297c55a3490bfc308e34e75f)。如果你的工程是在0.13或者更早版本创建的,你可能需要自行添加对应的代码来支持新的图片资源系统。请参考文档[升级版本](/docs/upgrading.html)文档中的升级操作说明。
+
+## 使用混合App的图片资源
+
+如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(通过Xcode的asset类目或者Android的drawable文件夹打包):
+
+```javascript
+
+```
+
+注意:这一做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸。
+
+
+## 网络图片
+
+很多要在App中显示的图片并不能在编译的时候获得,又或者有时候需要动态载入来减少打包后的二进制文件的大小。这些时候,与静态资源不同的是,`你需要手动指定图片的尺寸`。
+
+```javascript
+// 正确
+
+
+// 错误
+
+```
+
+## 本地文件系统中的图片
+
+参考[相册(CameraRoll)](cameraroll.html)这个例子来看如何使用在`Images.xcassets`以外的本地资源。
+
+### 最合适的相册图片
+
+iOS会为同一张图片在相册中保存多个不同尺寸的副本。为了性能考虑,从这些副本中挑出最合适的尺寸显得尤为重要。对于一处200x200大小的缩略图,显然不应该选择最高质量的3264x2448大小的图片。如果恰好有匹配的尺寸,那么React Native会自动为你选好。如果没有,则会选择最接近的尺寸进行缩放,但也至少缩放到比所需尺寸大出50%,以使图片看起来仍然足够清晰。这一切过程都是自动完成的,所以你不用操心自己去完成这些繁琐且易错的代码。
+
+## 为什么不在所有情况下都自动指定尺寸呢?
+
+`在浏览器中`,如果你不给图片指定尺寸,那么浏览器会首先渲染一个0x0大小的元素占位,然后下载图片,在下载完成后再基于正确的尺寸来渲染图片。这样做的最大问题是UI会在图片加载的过程中上下跳动,使得用户体验非常糟糕。
+
+`在React Native`中我们有意避免了这一行为。如此一来开发者就需要做更多工作来提前知晓远程图片的尺寸(或宽高比),但我们相信这样可以带来更好的用户体验。然而,从已经打包好的应用资源文件中读取图片(使用`require('image!x')`语法)则`无需指定尺寸`,因为它们的尺寸在加载时就可以立刻知道。
+
+比如这样一个引用`require('image!logo')`的实际输出结果可能是:
+
+```javascript
+{"__packager_asset":true,"isStatic":true,"path":"/Users/react/HelloWorld/iOS/Images.xcassets/react.imageset/logo.png","uri":"logo","width":591,"height":573}
+```
+
+## 资源属性是一个对象(object)
+
+在React Native中,另一个值得一提的变动是我们把`src`属性改为了`source`属性,而且并不接受字符串,正确的值是一个带有`uri`属性的对象。
+
+```javascript
+
+```
+
+深层次的考虑是,这样可以使我们在对象中添加一些元数据(metadata)。假设你在使用`require('./my-icon.png')`,那么我们就会在其中添加真实文件路径以及尺寸等信息(这只是举个例子,未来的版本中require的具体行为可能会变化)。此外这也是考虑了未来的扩展性,比如我们可能会加入精灵图(sprites)的支持:在输出`{uri: ...}`的基础上,我们可以进一步输出裁切信息`{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}`,这样理论上就可以在现有的代码中无缝支持精灵图的切分。
+
+对于开发者来说,则可以在其中标注一些有用的属性,例如图片的尺寸,这样可以使图片自己去计算将要显示的尺寸(而不必在样式中写死)。请在这一数据结构中自由发挥,存储你可能需要的任何图片相关的信息。
+
+## 通过嵌套来实现背景图片
+
+开发者们常面对的一种需求就是类似web中的背景图(`background-image`)。要实现这一用例,只需简单地创建一个``组件,然后把需要背景图的子组件嵌入其中即可。
+
+```javascript
+return (
+
+ Inside
+
+);
+```
+## iOS边框圆角的注意事项
+
+请注意下列边框圆角样式目前在iOS的图片组件上还不支持:
+
+* `borderTopLeftRadius`
+* `borderTopRightRadius`
+* `borderBottomLeftRadius`
+* `borderBottomRightRadius`
+
+## 在主线程外解码图片
+
+图片解码有可能会需要超过一帧的时间。在web上这是页面掉帧的一大因素,因为解码是在主线程中完成的。然而在React Native中,图片解码则是在另一线程中完成的。在实际开发中,一般对图片还没下载完成时的场景都做了处理(添加loading等),而图片解码时显示的占位符只占用几帧时间,并不需要你改动代码去额外处理。
diff --git a/docs/docs/0.42/imagestore.md b/docs/docs/0.42/imagestore.md
new file mode 100644
index 0000000..75b2759
--- /dev/null
+++ b/docs/docs/0.42/imagestore.md
@@ -0,0 +1,33 @@
+### 属性
+
+
+
+
static hasImageForTag(uri, callback) #
+
检查ImageStore中是否包含了指定URI的图片数据。目前仅限iOS。
+
+
+
static removeImageForTag(uri) #
+
从ImageStore中删除指定图片。存储在ImageStore中的图标必须手动删除,否则在应用退出之前将会一直占用内存。调用此删除方法并不需要先调用hasImageForTag()方法来检查,此方法会自动处理异常情况。目前仅限iOS。
+
+
+
static addImageFromBase64(base64ImageData, success, failure)
+ #
+
+
+
在ImageStore中以base64编码格式存储一幅图片,并返回一个URI以便访问或显示此图片。图片数据仅仅保存在内存中,在使用完毕后请调用removeImageForTag()方法来手动删除。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。目前仅限iOS。
+
+
+
static getBase64ForTag(uri, success, failure)
+ #
+
+
将ImageStore中的指定URI图片以base64编码格式的数据返回。如果找不到指定的URI,则会调用failure回调函数。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。如果只是为了显示图片,可以直接把URI传递给<Image/>组件,并不需要额外取base64数据。
+
+
+
diff --git a/docs/docs/0.42/img/AddToBuildPhases.png b/docs/docs/0.42/img/AddToBuildPhases.png
new file mode 100644
index 0000000..7b83937
Binary files /dev/null and b/docs/docs/0.42/img/AddToBuildPhases.png differ
diff --git a/docs/docs/0.42/img/AddToLibraries.png b/docs/docs/0.42/img/AddToLibraries.png
new file mode 100644
index 0000000..652cdfd
Binary files /dev/null and b/docs/docs/0.42/img/AddToLibraries.png differ
diff --git a/docs/docs/0.42/img/AddToSearchPaths.png b/docs/docs/0.42/img/AddToSearchPaths.png
new file mode 100644
index 0000000..ccbe819
Binary files /dev/null and b/docs/docs/0.42/img/AddToSearchPaths.png differ
diff --git a/docs/docs/0.42/img/AndroidSDK1.png b/docs/docs/0.42/img/AndroidSDK1.png
new file mode 100644
index 0000000..9b9add7
Binary files /dev/null and b/docs/docs/0.42/img/AndroidSDK1.png differ
diff --git a/docs/docs/0.42/img/AndroidSDK2.png b/docs/docs/0.42/img/AndroidSDK2.png
new file mode 100644
index 0000000..663b8cc
Binary files /dev/null and b/docs/docs/0.42/img/AndroidSDK2.png differ
diff --git a/docs/docs/0.42/img/AnimationExperimentalOpacity.gif b/docs/docs/0.42/img/AnimationExperimentalOpacity.gif
new file mode 100644
index 0000000..cdc7902
Binary files /dev/null and b/docs/docs/0.42/img/AnimationExperimentalOpacity.gif differ
diff --git a/docs/docs/0.42/img/AnimationExperimentalScaleXY.gif b/docs/docs/0.42/img/AnimationExperimentalScaleXY.gif
new file mode 100644
index 0000000..850cfd1
Binary files /dev/null and b/docs/docs/0.42/img/AnimationExperimentalScaleXY.gif differ
diff --git a/docs/docs/0.42/img/CreateAVD.png b/docs/docs/0.42/img/CreateAVD.png
new file mode 100644
index 0000000..5a3d494
Binary files /dev/null and b/docs/docs/0.42/img/CreateAVD.png differ
diff --git a/docs/docs/0.42/img/DeveloperMenu.png b/docs/docs/0.42/img/DeveloperMenu.png
new file mode 100644
index 0000000..bb29544
Binary files /dev/null and b/docs/docs/0.42/img/DeveloperMenu.png differ
diff --git a/docs/docs/0.42/img/EmbeddedAppAndroid.png b/docs/docs/0.42/img/EmbeddedAppAndroid.png
new file mode 100644
index 0000000..126ba2d
Binary files /dev/null and b/docs/docs/0.42/img/EmbeddedAppAndroid.png differ
diff --git a/docs/docs/0.42/img/EmbeddedAppContainerViewExample.png b/docs/docs/0.42/img/EmbeddedAppContainerViewExample.png
new file mode 100644
index 0000000..6130dfb
Binary files /dev/null and b/docs/docs/0.42/img/EmbeddedAppContainerViewExample.png differ
diff --git a/docs/docs/0.42/img/EmbeddedAppExample.png b/docs/docs/0.42/img/EmbeddedAppExample.png
new file mode 100644
index 0000000..fefd306
Binary files /dev/null and b/docs/docs/0.42/img/EmbeddedAppExample.png differ
diff --git a/docs/docs/0.42/img/LayoutAnimationExample.gif b/docs/docs/0.42/img/LayoutAnimationExample.gif
new file mode 100644
index 0000000..68fcfce
Binary files /dev/null and b/docs/docs/0.42/img/LayoutAnimationExample.gif differ
diff --git a/docs/docs/0.42/img/NavigationStack-Navigator.gif b/docs/docs/0.42/img/NavigationStack-Navigator.gif
new file mode 100644
index 0000000..c1f8313
Binary files /dev/null and b/docs/docs/0.42/img/NavigationStack-Navigator.gif differ
diff --git a/docs/docs/0.42/img/NavigationStack-NavigatorIOS.gif b/docs/docs/0.42/img/NavigationStack-NavigatorIOS.gif
new file mode 100644
index 0000000..c1d56a1
Binary files /dev/null and b/docs/docs/0.42/img/NavigationStack-NavigatorIOS.gif differ
diff --git a/docs/docs/0.42/img/Rebound.gif b/docs/docs/0.42/img/Rebound.gif
new file mode 100644
index 0000000..0371663
Binary files /dev/null and b/docs/docs/0.42/img/Rebound.gif differ
diff --git a/docs/docs/0.42/img/ReboundExample.png b/docs/docs/0.42/img/ReboundExample.png
new file mode 100644
index 0000000..db33e5f
Binary files /dev/null and b/docs/docs/0.42/img/ReboundExample.png differ
diff --git a/docs/docs/0.42/img/ReboundImage.gif b/docs/docs/0.42/img/ReboundImage.gif
new file mode 100644
index 0000000..9c1da74
Binary files /dev/null and b/docs/docs/0.42/img/ReboundImage.gif differ
diff --git a/docs/docs/0.42/img/StaticImageAssets.png b/docs/docs/0.42/img/StaticImageAssets.png
new file mode 100644
index 0000000..e79acdc
Binary files /dev/null and b/docs/docs/0.42/img/StaticImageAssets.png differ
diff --git a/docs/docs/0.42/img/SystraceBadCreateUI.png b/docs/docs/0.42/img/SystraceBadCreateUI.png
new file mode 100644
index 0000000..813b101
Binary files /dev/null and b/docs/docs/0.42/img/SystraceBadCreateUI.png differ
diff --git a/docs/docs/0.42/img/SystraceBadJS.png b/docs/docs/0.42/img/SystraceBadJS.png
new file mode 100644
index 0000000..c67c840
Binary files /dev/null and b/docs/docs/0.42/img/SystraceBadJS.png differ
diff --git a/docs/docs/0.42/img/SystraceBadJS2.png b/docs/docs/0.42/img/SystraceBadJS2.png
new file mode 100644
index 0000000..de972c6
Binary files /dev/null and b/docs/docs/0.42/img/SystraceBadJS2.png differ
diff --git a/docs/docs/0.42/img/SystraceBadUI.png b/docs/docs/0.42/img/SystraceBadUI.png
new file mode 100644
index 0000000..ebd9faf
Binary files /dev/null and b/docs/docs/0.42/img/SystraceBadUI.png differ
diff --git a/docs/docs/0.42/img/SystraceExample.png b/docs/docs/0.42/img/SystraceExample.png
new file mode 100644
index 0000000..521ee16
Binary files /dev/null and b/docs/docs/0.42/img/SystraceExample.png differ
diff --git a/docs/docs/0.42/img/SystraceHighlightVSync.png b/docs/docs/0.42/img/SystraceHighlightVSync.png
new file mode 100644
index 0000000..dc7595a
Binary files /dev/null and b/docs/docs/0.42/img/SystraceHighlightVSync.png differ
diff --git a/docs/docs/0.42/img/SystraceJSThreadExample.png b/docs/docs/0.42/img/SystraceJSThreadExample.png
new file mode 100644
index 0000000..736af7d
Binary files /dev/null and b/docs/docs/0.42/img/SystraceJSThreadExample.png differ
diff --git a/docs/docs/0.42/img/SystraceNativeModulesThreadExample.png b/docs/docs/0.42/img/SystraceNativeModulesThreadExample.png
new file mode 100644
index 0000000..7e919f2
Binary files /dev/null and b/docs/docs/0.42/img/SystraceNativeModulesThreadExample.png differ
diff --git a/docs/docs/0.42/img/SystraceRenderThreadExample.png b/docs/docs/0.42/img/SystraceRenderThreadExample.png
new file mode 100644
index 0000000..2fa05bd
Binary files /dev/null and b/docs/docs/0.42/img/SystraceRenderThreadExample.png differ
diff --git a/docs/docs/0.42/img/SystraceUIThreadExample.png b/docs/docs/0.42/img/SystraceUIThreadExample.png
new file mode 100644
index 0000000..4883e85
Binary files /dev/null and b/docs/docs/0.42/img/SystraceUIThreadExample.png differ
diff --git a/docs/docs/0.42/img/SystraceWellBehaved.png b/docs/docs/0.42/img/SystraceWellBehaved.png
new file mode 100644
index 0000000..9540873
Binary files /dev/null and b/docs/docs/0.42/img/SystraceWellBehaved.png differ
diff --git a/docs/docs/0.42/img/TutorialFinal.png b/docs/docs/0.42/img/TutorialFinal.png
new file mode 100644
index 0000000..2f05b13
Binary files /dev/null and b/docs/docs/0.42/img/TutorialFinal.png differ
diff --git a/docs/docs/0.42/img/TutorialFinal2.png b/docs/docs/0.42/img/TutorialFinal2.png
new file mode 100644
index 0000000..75ec47c
Binary files /dev/null and b/docs/docs/0.42/img/TutorialFinal2.png differ
diff --git a/docs/docs/0.42/img/TutorialMock.png b/docs/docs/0.42/img/TutorialMock.png
new file mode 100644
index 0000000..6a267d0
Binary files /dev/null and b/docs/docs/0.42/img/TutorialMock.png differ
diff --git a/docs/docs/0.42/img/TutorialMock2.png b/docs/docs/0.42/img/TutorialMock2.png
new file mode 100644
index 0000000..94c7f65
Binary files /dev/null and b/docs/docs/0.42/img/TutorialMock2.png differ
diff --git a/docs/docs/0.42/img/TutorialSingleFetched.png b/docs/docs/0.42/img/TutorialSingleFetched.png
new file mode 100644
index 0000000..914cb88
Binary files /dev/null and b/docs/docs/0.42/img/TutorialSingleFetched.png differ
diff --git a/docs/docs/0.42/img/TutorialSingleFetched2.png b/docs/docs/0.42/img/TutorialSingleFetched2.png
new file mode 100644
index 0000000..c7dfd69
Binary files /dev/null and b/docs/docs/0.42/img/TutorialSingleFetched2.png differ
diff --git a/docs/docs/0.42/img/TutorialStyledMock.png b/docs/docs/0.42/img/TutorialStyledMock.png
new file mode 100644
index 0000000..48fb1c5
Binary files /dev/null and b/docs/docs/0.42/img/TutorialStyledMock.png differ
diff --git a/docs/docs/0.42/img/TutorialStyledMock2.png b/docs/docs/0.42/img/TutorialStyledMock2.png
new file mode 100644
index 0000000..16e99c2
Binary files /dev/null and b/docs/docs/0.42/img/TutorialStyledMock2.png differ
diff --git a/docs/docs/0.42/img/TweenState.gif b/docs/docs/0.42/img/TweenState.gif
new file mode 100644
index 0000000..84f34d2
Binary files /dev/null and b/docs/docs/0.42/img/TweenState.gif differ
diff --git a/docs/docs/0.42/img/Upgrading1.png b/docs/docs/0.42/img/Upgrading1.png
new file mode 100644
index 0000000..b60a852
Binary files /dev/null and b/docs/docs/0.42/img/Upgrading1.png differ
diff --git a/docs/docs/0.42/img/Upgrading2.png b/docs/docs/0.42/img/Upgrading2.png
new file mode 100644
index 0000000..c9a109d
Binary files /dev/null and b/docs/docs/0.42/img/Upgrading2.png differ
diff --git a/docs/docs/0.42/img/Upgrading3.png b/docs/docs/0.42/img/Upgrading3.png
new file mode 100644
index 0000000..3150aab
Binary files /dev/null and b/docs/docs/0.42/img/Upgrading3.png differ
diff --git a/docs/docs/0.42/img/alertIOS.png b/docs/docs/0.42/img/alertIOS.png
new file mode 100644
index 0000000..b35a2a4
Binary files /dev/null and b/docs/docs/0.42/img/alertIOS.png differ
diff --git a/docs/docs/0.42/img/api/actionsheetios1.png b/docs/docs/0.42/img/api/actionsheetios1.png
new file mode 100644
index 0000000..9f7f489
Binary files /dev/null and b/docs/docs/0.42/img/api/actionsheetios1.png differ
diff --git a/docs/docs/0.42/img/api/actionsheetios2.png b/docs/docs/0.42/img/api/actionsheetios2.png
new file mode 100644
index 0000000..4cf739f
Binary files /dev/null and b/docs/docs/0.42/img/api/actionsheetios2.png differ
diff --git a/docs/docs/0.42/img/api/alertios1.png b/docs/docs/0.42/img/api/alertios1.png
new file mode 100644
index 0000000..0406823
Binary files /dev/null and b/docs/docs/0.42/img/api/alertios1.png differ
diff --git a/docs/docs/0.42/img/api/alertios2.png b/docs/docs/0.42/img/api/alertios2.png
new file mode 100644
index 0000000..6c3964b
Binary files /dev/null and b/docs/docs/0.42/img/api/alertios2.png differ
diff --git a/docs/docs/0.42/img/api/cameraroll.png b/docs/docs/0.42/img/api/cameraroll.png
new file mode 100644
index 0000000..129b98b
Binary files /dev/null and b/docs/docs/0.42/img/api/cameraroll.png differ
diff --git a/docs/docs/0.42/img/api/statusbarios.png b/docs/docs/0.42/img/api/statusbarios.png
new file mode 100644
index 0000000..15e1ee7
Binary files /dev/null and b/docs/docs/0.42/img/api/statusbarios.png differ
diff --git a/docs/docs/0.42/img/api/toastandroid.png b/docs/docs/0.42/img/api/toastandroid.png
new file mode 100644
index 0000000..a4ec2a2
Binary files /dev/null and b/docs/docs/0.42/img/api/toastandroid.png differ
diff --git a/docs/docs/0.42/img/chrome_breakpoint.png b/docs/docs/0.42/img/chrome_breakpoint.png
new file mode 100644
index 0000000..d37c953
Binary files /dev/null and b/docs/docs/0.42/img/chrome_breakpoint.png differ
diff --git a/docs/docs/0.42/img/components/activityindicatorios.png b/docs/docs/0.42/img/components/activityindicatorios.png
new file mode 100644
index 0000000..57567ca
Binary files /dev/null and b/docs/docs/0.42/img/components/activityindicatorios.png differ
diff --git a/docs/docs/0.42/img/components/buttonExample.png b/docs/docs/0.42/img/components/buttonExample.png
new file mode 100644
index 0000000..40ce923
Binary files /dev/null and b/docs/docs/0.42/img/components/buttonExample.png differ
diff --git a/docs/docs/0.42/img/components/datepickerios.png b/docs/docs/0.42/img/components/datepickerios.png
new file mode 100644
index 0000000..bf34f1c
Binary files /dev/null and b/docs/docs/0.42/img/components/datepickerios.png differ
diff --git a/docs/docs/0.42/img/components/drawerlayoutandroid.png b/docs/docs/0.42/img/components/drawerlayoutandroid.png
new file mode 100644
index 0000000..f4911dd
Binary files /dev/null and b/docs/docs/0.42/img/components/drawerlayoutandroid.png differ
diff --git a/docs/docs/0.42/img/components/image.png b/docs/docs/0.42/img/components/image.png
new file mode 100644
index 0000000..1a2158d
Binary files /dev/null and b/docs/docs/0.42/img/components/image.png differ
diff --git a/docs/docs/0.42/img/components/listview1.png b/docs/docs/0.42/img/components/listview1.png
new file mode 100644
index 0000000..36a072e
Binary files /dev/null and b/docs/docs/0.42/img/components/listview1.png differ
diff --git a/docs/docs/0.42/img/components/listview2.png b/docs/docs/0.42/img/components/listview2.png
new file mode 100644
index 0000000..aceb4b5
Binary files /dev/null and b/docs/docs/0.42/img/components/listview2.png differ
diff --git a/docs/docs/0.42/img/components/listview3.png b/docs/docs/0.42/img/components/listview3.png
new file mode 100644
index 0000000..4b777a6
Binary files /dev/null and b/docs/docs/0.42/img/components/listview3.png differ
diff --git a/docs/docs/0.42/img/components/mapview.png b/docs/docs/0.42/img/components/mapview.png
new file mode 100644
index 0000000..12277f1
Binary files /dev/null and b/docs/docs/0.42/img/components/mapview.png differ
diff --git a/docs/docs/0.42/img/components/modal.png b/docs/docs/0.42/img/components/modal.png
new file mode 100644
index 0000000..9ff9dd0
Binary files /dev/null and b/docs/docs/0.42/img/components/modal.png differ
diff --git a/docs/docs/0.42/img/components/navigator1.png b/docs/docs/0.42/img/components/navigator1.png
new file mode 100644
index 0000000..1baadd9
Binary files /dev/null and b/docs/docs/0.42/img/components/navigator1.png differ
diff --git a/docs/docs/0.42/img/components/navigator2.png b/docs/docs/0.42/img/components/navigator2.png
new file mode 100644
index 0000000..4e86cb5
Binary files /dev/null and b/docs/docs/0.42/img/components/navigator2.png differ
diff --git a/docs/docs/0.42/img/components/navigatorios1.png b/docs/docs/0.42/img/components/navigatorios1.png
new file mode 100644
index 0000000..f7a8630
Binary files /dev/null and b/docs/docs/0.42/img/components/navigatorios1.png differ
diff --git a/docs/docs/0.42/img/components/navigatorios2.png b/docs/docs/0.42/img/components/navigatorios2.png
new file mode 100644
index 0000000..c4484c6
Binary files /dev/null and b/docs/docs/0.42/img/components/navigatorios2.png differ
diff --git a/docs/docs/0.42/img/components/pickerios.png b/docs/docs/0.42/img/components/pickerios.png
new file mode 100644
index 0000000..0a285dd
Binary files /dev/null and b/docs/docs/0.42/img/components/pickerios.png differ
diff --git a/docs/docs/0.42/img/components/progressbarandroid.png b/docs/docs/0.42/img/components/progressbarandroid.png
new file mode 100644
index 0000000..ce6be4c
Binary files /dev/null and b/docs/docs/0.42/img/components/progressbarandroid.png differ
diff --git a/docs/docs/0.42/img/components/progressviewios.png b/docs/docs/0.42/img/components/progressviewios.png
new file mode 100644
index 0000000..b37bf1e
Binary files /dev/null and b/docs/docs/0.42/img/components/progressviewios.png differ
diff --git a/docs/docs/0.42/img/components/scrollview.png b/docs/docs/0.42/img/components/scrollview.png
new file mode 100644
index 0000000..399b8e8
Binary files /dev/null and b/docs/docs/0.42/img/components/scrollview.png differ
diff --git a/docs/docs/0.42/img/components/segmentedcontrolios.png b/docs/docs/0.42/img/components/segmentedcontrolios.png
new file mode 100644
index 0000000..3cf27d6
Binary files /dev/null and b/docs/docs/0.42/img/components/segmentedcontrolios.png differ
diff --git a/docs/docs/0.42/img/components/sliderios.png b/docs/docs/0.42/img/components/sliderios.png
new file mode 100644
index 0000000..aba2736
Binary files /dev/null and b/docs/docs/0.42/img/components/sliderios.png differ
diff --git a/docs/docs/0.42/img/components/switchandroid.png b/docs/docs/0.42/img/components/switchandroid.png
new file mode 100644
index 0000000..c6e5342
Binary files /dev/null and b/docs/docs/0.42/img/components/switchandroid.png differ
diff --git a/docs/docs/0.42/img/components/switchios.png b/docs/docs/0.42/img/components/switchios.png
new file mode 100644
index 0000000..6dcf042
Binary files /dev/null and b/docs/docs/0.42/img/components/switchios.png differ
diff --git a/docs/docs/0.42/img/components/tabbarios.png b/docs/docs/0.42/img/components/tabbarios.png
new file mode 100644
index 0000000..1f203e8
Binary files /dev/null and b/docs/docs/0.42/img/components/tabbarios.png differ
diff --git a/docs/docs/0.42/img/components/text.png b/docs/docs/0.42/img/components/text.png
new file mode 100644
index 0000000..031593e
Binary files /dev/null and b/docs/docs/0.42/img/components/text.png differ
diff --git a/docs/docs/0.42/img/components/textinput.png b/docs/docs/0.42/img/components/textinput.png
new file mode 100644
index 0000000..57b579e
Binary files /dev/null and b/docs/docs/0.42/img/components/textinput.png differ
diff --git a/docs/docs/0.42/img/components/toolbarandroid.png b/docs/docs/0.42/img/components/toolbarandroid.png
new file mode 100644
index 0000000..6805c5a
Binary files /dev/null and b/docs/docs/0.42/img/components/toolbarandroid.png differ
diff --git a/docs/docs/0.42/img/components/touchable.png b/docs/docs/0.42/img/components/touchable.png
new file mode 100644
index 0000000..b4083e9
Binary files /dev/null and b/docs/docs/0.42/img/components/touchable.png differ
diff --git a/docs/docs/0.42/img/components/view.png b/docs/docs/0.42/img/components/view.png
new file mode 100644
index 0000000..d917353
Binary files /dev/null and b/docs/docs/0.42/img/components/view.png differ
diff --git a/docs/docs/0.42/img/components/viewpager.png b/docs/docs/0.42/img/components/viewpager.png
new file mode 100644
index 0000000..99ce67f
Binary files /dev/null and b/docs/docs/0.42/img/components/viewpager.png differ
diff --git a/docs/docs/0.42/img/components/webview.png b/docs/docs/0.42/img/components/webview.png
new file mode 100644
index 0000000..2315a19
Binary files /dev/null and b/docs/docs/0.42/img/components/webview.png differ
diff --git a/docs/docs/0.42/img/react-native-add-react-native-integration-example-high-scores.png b/docs/docs/0.42/img/react-native-add-react-native-integration-example-high-scores.png
new file mode 100644
index 0000000..6d07707
Binary files /dev/null and b/docs/docs/0.42/img/react-native-add-react-native-integration-example-high-scores.png differ
diff --git a/docs/docs/0.42/img/react-native-add-react-native-integration-example-home-screen.png b/docs/docs/0.42/img/react-native-add-react-native-integration-example-home-screen.png
new file mode 100644
index 0000000..2b1b8b2
Binary files /dev/null and b/docs/docs/0.42/img/react-native-add-react-native-integration-example-home-screen.png differ
diff --git a/docs/docs/0.42/img/react-native-add-react-native-integration-link.png b/docs/docs/0.42/img/react-native-add-react-native-integration-link.png
new file mode 100644
index 0000000..3d89eaf
Binary files /dev/null and b/docs/docs/0.42/img/react-native-add-react-native-integration-link.png differ
diff --git a/docs/docs/0.42/img/react-native-add-react-native-integration-wire-up.png b/docs/docs/0.42/img/react-native-add-react-native-integration-wire-up.png
new file mode 100644
index 0000000..43d2add
Binary files /dev/null and b/docs/docs/0.42/img/react-native-add-react-native-integration-wire-up.png differ
diff --git a/docs/docs/0.42/img/react-native-android-sdk-environment-variable-windows.png b/docs/docs/0.42/img/react-native-android-sdk-environment-variable-windows.png
new file mode 100644
index 0000000..6b3d981
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-sdk-environment-variable-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-additional-installs-linux.png b/docs/docs/0.42/img/react-native-android-studio-additional-installs-linux.png
new file mode 100644
index 0000000..3a0eda5
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-additional-installs-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-additional-installs.png b/docs/docs/0.42/img/react-native-android-studio-additional-installs.png
new file mode 100644
index 0000000..de32a09
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-additional-installs.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-linux.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-linux.png
new file mode 100644
index 0000000..10391c7
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-windows.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-windows.png
new file mode 100644
index 0000000..600ef3a
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools.png
new file mode 100644
index 0000000..a1d80be
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-build-tools.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-linux.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-linux.png
new file mode 100644
index 0000000..8c43a49
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-windows.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-windows.png
new file mode 100644
index 0000000..a5cf175
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms.png b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms.png
new file mode 100644
index 0000000..34407b1
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-android-sdk-platforms.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-avd-linux.png b/docs/docs/0.42/img/react-native-android-studio-avd-linux.png
new file mode 100644
index 0000000..de5f254
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-avd-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-avd-windows.png b/docs/docs/0.42/img/react-native-android-studio-avd-windows.png
new file mode 100644
index 0000000..ddc8f47
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-avd-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-avd.png b/docs/docs/0.42/img/react-native-android-studio-avd.png
new file mode 100644
index 0000000..74c053b
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-avd.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-configure-sdk-linux.png b/docs/docs/0.42/img/react-native-android-studio-configure-sdk-linux.png
new file mode 100644
index 0000000..8bb9d5f
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-configure-sdk-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-configure-sdk-windows.png b/docs/docs/0.42/img/react-native-android-studio-configure-sdk-windows.png
new file mode 100644
index 0000000..1adf5cb
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-configure-sdk-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-configure-sdk.png b/docs/docs/0.42/img/react-native-android-studio-configure-sdk.png
new file mode 100644
index 0000000..acfe1f3
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-configure-sdk.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-custom-install-linux.png b/docs/docs/0.42/img/react-native-android-studio-custom-install-linux.png
new file mode 100644
index 0000000..4410948
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-custom-install-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-custom-install-windows.png b/docs/docs/0.42/img/react-native-android-studio-custom-install-windows.png
new file mode 100644
index 0000000..7ed385a
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-custom-install-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-custom-install.png b/docs/docs/0.42/img/react-native-android-studio-custom-install.png
new file mode 100644
index 0000000..01ab7b2
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-custom-install.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-kvm-linux.png b/docs/docs/0.42/img/react-native-android-studio-kvm-linux.png
new file mode 100644
index 0000000..dab0810
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-kvm-linux.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-no-virtual-device-windows.png b/docs/docs/0.42/img/react-native-android-studio-no-virtual-device-windows.png
new file mode 100644
index 0000000..933a583
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-no-virtual-device-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-studio-verify-installs-windows.png b/docs/docs/0.42/img/react-native-android-studio-verify-installs-windows.png
new file mode 100644
index 0000000..8f0cf1b
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-studio-verify-installs-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-android-tools-environment-variable-windows.png b/docs/docs/0.42/img/react-native-android-tools-environment-variable-windows.png
new file mode 100644
index 0000000..5ddeb61
Binary files /dev/null and b/docs/docs/0.42/img/react-native-android-tools-environment-variable-windows.png differ
diff --git a/docs/docs/0.42/img/react-native-congratulations.png b/docs/docs/0.42/img/react-native-congratulations.png
new file mode 100644
index 0000000..92f520e
Binary files /dev/null and b/docs/docs/0.42/img/react-native-congratulations.png differ
diff --git a/docs/docs/0.42/img/react-native-existing-app-integration-ios-before.png b/docs/docs/0.42/img/react-native-existing-app-integration-ios-before.png
new file mode 100644
index 0000000..445dd79
Binary files /dev/null and b/docs/docs/0.42/img/react-native-existing-app-integration-ios-before.png differ
diff --git a/docs/docs/0.42/img/react-native-sorry-not-supported.png b/docs/docs/0.42/img/react-native-sorry-not-supported.png
new file mode 100644
index 0000000..8848f4c
Binary files /dev/null and b/docs/docs/0.42/img/react-native-sorry-not-supported.png differ
diff --git a/docs/docs/0.42/img/segmentedcontrolios.jpg b/docs/docs/0.42/img/segmentedcontrolios.jpg
new file mode 100644
index 0000000..5a01172
Binary files /dev/null and b/docs/docs/0.42/img/segmentedcontrolios.jpg differ
diff --git a/docs/docs/0.42/indexes.json b/docs/docs/0.42/indexes.json
new file mode 100644
index 0000000..d46ade8
--- /dev/null
+++ b/docs/docs/0.42/indexes.json
@@ -0,0 +1,499 @@
+{
+ "contains": [
+ {
+ "group": "入门基础",
+ "contains": [
+ {
+ "subject": "搭建开发环境",
+ "mdlink": "getting-started"
+ },
+ {
+ "subject": "编写Hello World",
+ "mdlink": "tutorial"
+ },
+ {
+ "subject": "Props(属性)",
+ "mdlink": "props"
+ },
+ {
+ "subject": "State(状态)",
+ "mdlink": "state"
+ },
+ {
+ "subject": "样式",
+ "mdlink": "style"
+ },
+ {
+ "subject": "高度与宽度",
+ "mdlink": "height-and-width"
+ },
+ {
+ "subject": "使用Flexbox布局",
+ "mdlink": "layout-with-flexbox"
+ },
+ {
+ "subject": "处理文本输入",
+ "mdlink": "handling-text-input"
+ },
+ {
+ "subject": "如何使用ScrollView",
+ "mdlink": "using-a-scrollview"
+ },
+ {
+ "subject": "如何使用ListView",
+ "mdlink": "using-a-listview"
+ },
+ {
+ "subject": "网络",
+ "mdlink": "network"
+ },
+ {
+ "subject": "其他参考资源",
+ "mdlink": "more-resources"
+ }
+ ]
+ },
+ {
+ "group": "进阶指南",
+ "contains": [
+ {
+ "subject": "嵌入到现有原生应用",
+ "mdlink": "integration-with-existing-apps"
+ },
+ {
+ "subject": "颜色",
+ "mdlink": "colors"
+ },
+ {
+ "subject": "图片",
+ "mdlink": "images"
+ },
+ {
+ "subject": "处理触摸事件",
+ "mdlink": "handling-touches"
+ },
+ {
+ "subject": "动画",
+ "mdlink": "animations"
+ },
+ {
+ "subject": "无障碍功能",
+ "mdlink": "accessibility"
+ },
+ {
+ "subject": "定时器",
+ "mdlink": "timers"
+ },
+ {
+ "subject": "直接操作",
+ "mdlink": "direct-manipulation"
+ },
+ {
+ "subject": "调试",
+ "mdlink": "debugging"
+ },
+ {
+ "subject": "自动化测试",
+ "mdlink": "testing"
+ },
+ {
+ "subject": "JavaScript环境",
+ "mdlink": "javascript-environment"
+ },
+ {
+ "subject": "导航器对比",
+ "mdlink": "navigation"
+ },
+ {
+ "subject": "性能",
+ "mdlink": "performance"
+ },
+ {
+ "subject": "升级",
+ "mdlink": "upgrading"
+ },
+ {
+ "subject": "特定平台代码",
+ "mdlink": "platform-specific-code"
+ },
+ {
+ "subject": "手势响应系统",
+ "mdlink": "gesture-responder-system"
+ }
+ ]
+ },
+ {
+ "group": "社区资源",
+ "contains": [
+ {
+ "subject": "中文视频教程",
+ "external": "/videos.html"
+ },
+ {
+ "subject": "js.coach第三方组件库",
+ "external": "https://js.coach/react-native"
+ },
+ {
+ "subject": "中文论坛组件分享区",
+ "external": "http://bbs.reactnative.cn/category/5"
+ },
+ {
+ "subject": "中文论坛问题求助区",
+ "external": "http://bbs.reactnative.cn/category/4"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(iOS)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-ios"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-ios"
+ },
+ {
+ "subject": "链接原生库",
+ "mdlink": "linking-libraries-ios"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-ios"
+ },
+ {
+ "subject": "在模拟器上运行",
+ "mdlink": "running-on-simulator-ios"
+ },
+ {
+ "subject": "在原生和React Native间通信",
+ "mdlink": "communication-ios"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(Android)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-android"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-android"
+ },
+ {
+ "subject": "Headless JS(后台任务)",
+ "mdlink": "headless-js-android"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-android"
+ },
+ {
+ "subject": "打包APK",
+ "mdlink": "signed-apk-android"
+ },
+ {
+ "subject": "调试Android UI性能",
+ "mdlink": "android-ui-performance"
+ },
+ {
+ "subject": "从源代码编译React Native",
+ "mdlink": "android-building-from-source"
+ }
+ ]
+ },
+ {
+ "group": "组件",
+ "contains": [
+ {
+ "subject": "ActivityIndicator",
+ "mdlink": "activityindicator"
+ },
+ {
+ "subject": "Button",
+ "mdlink": "button"
+ },
+ {
+ "subject": "DatePickerIOS",
+ "mdlink": "datepickerios"
+ },
+ {
+ "subject": "DrawerLayoutAndroid",
+ "mdlink": "drawerlayoutandroid"
+ },
+ {
+ "subject": "Image",
+ "mdlink": "image"
+ },
+ {
+ "subject": "KeyboardAvoidingView",
+ "mdlink": "keyboardavoidingview"
+ },
+ {
+ "subject": "ListView",
+ "mdlink": "listview"
+ },
+ {
+ "subject": "ListView.DataSource",
+ "mdlink": "listviewdatasource"
+ },
+ {
+ "subject": "MapView",
+ "mdlink": "mapview"
+ },
+ {
+ "subject": "Modal",
+ "mdlink": "modal"
+ },
+ {
+ "subject": "Navigator",
+ "mdlink": "navigator"
+ },
+ {
+ "subject": "NavigatorIOS",
+ "mdlink": "navigatorios"
+ },
+ {
+ "subject": "Picker",
+ "mdlink": "picker"
+ },
+ {
+ "subject": "PickerIOS",
+ "mdlink": "pickerios"
+ },
+ {
+ "subject": "ProgressBarAndroid",
+ "mdlink": "progressbarandroid"
+ },
+ {
+ "subject": "ProgressViewIOS",
+ "mdlink": "progressviewios"
+ },
+ {
+ "subject": "RefreshControl",
+ "mdlink": "refreshcontrol"
+ },
+ {
+ "subject": "ScrollView",
+ "mdlink": "scrollview"
+ },
+ {
+ "subject": "SegmentedControlIOS",
+ "mdlink": "segmentedcontrolios"
+ },
+ {
+ "subject": "Slider",
+ "mdlink": "slider"
+ },
+ {
+ "subject": "StatusBar",
+ "mdlink": "statusbar"
+ },
+ {
+ "subject": "Switch",
+ "mdlink": "switch"
+ },
+ {
+ "subject": "TabBarIOS",
+ "mdlink": "tabbarios"
+ },
+ {
+ "subject": "TabBarIOS.Item",
+ "mdlink": "tabbarios-item"
+ },
+ {
+ "subject": "Text",
+ "mdlink": "text"
+ },
+ {
+ "subject": "TextInput",
+ "mdlink": "textinput"
+ },
+ {
+ "subject": "ToolbarAndroid",
+ "mdlink": "toolbarandroid"
+ },
+ {
+ "subject": "TouchableHighlight",
+ "mdlink": "touchablehighlight"
+ },
+ {
+ "subject": "TouchableNativeFeedback",
+ "mdlink": "touchablenativefeedback"
+ },
+ {
+ "subject": "TouchableOpacity",
+ "mdlink": "touchableopacity"
+ },
+ {
+ "subject": "TouchableWithoutFeedback",
+ "mdlink": "touchablewithoutfeedback"
+ },
+ {
+ "subject": "View",
+ "mdlink": "view"
+ },
+ {
+ "subject": "ViewPagerAndroid",
+ "mdlink": "viewpagerandroid"
+ },
+ {
+ "subject": "WebView",
+ "mdlink": "webview"
+ }
+ ]
+ },
+ {
+ "group": "API",
+ "contains": [
+ {
+ "subject": "ActionSheetIOS",
+ "mdlink": "actionsheetios"
+ },
+ {
+ "subject": "AdSupportIOS",
+ "mdlink": "adsupportios"
+ },
+ {
+ "subject": "Alert",
+ "mdlink": "alert"
+ },
+ {
+ "subject": "AlertIOS",
+ "mdlink": "alertios"
+ },
+ {
+ "subject": "Animated",
+ "mdlink": "animated"
+ },
+ {
+ "subject": "AppRegistry",
+ "mdlink": "appregistry"
+ },
+ {
+ "subject": "AppState",
+ "mdlink": "appstate"
+ },
+ {
+ "subject": "AsyncStorage",
+ "mdlink": "asyncstorage"
+ },
+ {
+ "subject": "BackAndroid",
+ "mdlink": "backandroid"
+ },
+ {
+ "subject": "CameraRoll",
+ "mdlink": "cameraroll"
+ },
+ {
+ "subject": "Clipboard",
+ "mdlink": "clipboard"
+ },
+ {
+ "subject": "DatePickerAndroid",
+ "mdlink": "datepickerandroid"
+ },
+ {
+ "subject": "Dimensions",
+ "mdlink": "dimensions"
+ },
+ {
+ "subject": "Easing",
+ "mdlink": "easing"
+ },
+ {
+ "subject": "Geolocation",
+ "mdlink": "geolocation"
+ },
+ {
+ "subject": "ImageEditor",
+ "mdlink": "imageeditor"
+ },
+ {
+ "subject": "ImagePickerIOS",
+ "mdlink": "imagepickerios"
+ },
+ {
+ "subject": "ImageStore",
+ "mdlink": "imagestore"
+ },
+ {
+ "subject": "InteractionManager",
+ "mdlink": "interactionmanager"
+ },
+ {
+ "subject": "Keyboard",
+ "mdlink": "keyboard"
+ },
+ {
+ "subject": "LayoutAnimation",
+ "mdlink": "layoutanimation"
+ },
+ {
+ "subject": "Linking",
+ "mdlink": "linking"
+ },
+ {
+ "subject": "NativeMethodsMixin",
+ "mdlink": "nativemethodsmixin"
+ },
+ {
+ "subject": "NetInfo",
+ "mdlink": "netinfo"
+ },
+ {
+ "subject": "PanResponder",
+ "mdlink": "panresponder"
+ },
+ {
+ "subject": "PermissionsAndroid",
+ "mdlink": "permissionsandroid"
+ },
+ {
+ "subject": "PixelRatio",
+ "mdlink": "pixelratio"
+ },
+ {
+ "subject": "PushNotificationIOS",
+ "mdlink": "pushnotificationios"
+ },
+ {
+ "subject": "Share",
+ "mdlink": "share"
+ },
+ {
+ "subject": "StyleSheet",
+ "mdlink": "stylesheet"
+ },
+ {
+ "subject": "Systrace",
+ "mdlink": "systrace"
+ },
+ {
+ "subject": "TimePickerAndroid",
+ "mdlink": "timepickerandroid"
+ },
+ {
+ "subject": "ToastAndroid",
+ "mdlink": "toastandroid"
+ },
+ {
+ "subject": "Vibration",
+ "mdlink": "vibration"
+ },
+ {
+ "subject": "布局样式属性",
+ "mdlink": "layout-props"
+ },
+ {
+ "subject": "阴影样式属性",
+ "mdlink": "shadow-props"
+ }
+ ]
+ }
+ ]
+}
diff --git a/docs/docs/0.42/integration-with-existing-apps.md b/docs/docs/0.42/integration-with-existing-apps.md
new file mode 100644
index 0000000..12177c7
--- /dev/null
+++ b/docs/docs/0.42/integration-with-existing-apps.md
@@ -0,0 +1,854 @@
+
+
+
+## 核心概念
+
+如果你正准备从头开始制作一个新的应用,那么React Native会是个非常好的选择。但如果你只想给现有的原生应用中添加一两个视图或是业务流程,React Native也同样不在话下。只需简单几步,你就可以给原有应用加上新的基于React Native的特性、画面和视图等。
+
+
+
+
+把React Native组件植入到iOS应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 创建一个`Podfile`,在其中以`subspec`的形式填写所有你要植入的React Native的组件。
+3. 创建js文件,编写React Native组件的js代码。
+4. 添加一个事件处理函数,用于创建一个`RCTRootView`。这个`RCTRootView`正是用来承载你的React Native组件的,而且它必须对应你在`index.ios.js`中使用`AppRegistry`注册的模块名字。
+5. 启动React Native的Packager服务,运行应用。
+6. 根据需要添加更多React Native的组件。
+7. [调试](debugging.html)。
+8. 准备[部署发布](running-on-device-ios.html) (比如可以利用`react-native-xcode.sh`脚本)。
+9. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+把React Native组件植入到Android应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 在Android项目根目录中使用npm来安装`react-native` ,这样同时会创建一个`node_modules/`的目录。
+3. 创建js文件,编写React Native组件的js代码。
+4. 在`build.gradle`文件中添加`com.facebook.react:react-native:+`,以及一个指向`node_nodules/`目录中的`react-native`预编译库的`maven`路径。
+5. 创建一个React Native专属的`Activity`,在其中再创建`ReactRootView`。
+6. 启动React Native的Packager服务,运行应用。
+7. 根据需要添加更多React Native的组件。
+8. 在真机上[运行](running-on-device-android.html)、[调试](debugging.html)。
+9. [打包](signed-apk-android.html)。
+10. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+## 开发环境准备
+
+
+
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在安卓平台上所需的一切依赖软件(比如`npm`)。
+
+
+
+
+### 基础环境
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在iOS平台上所需的一切依赖软件(比如`npm`)。
+
+### CocoaPods
+
+[CocoaPods](http://cocoapods.org)是针对iOS和Mac开发的包管理工具。我们用它来把React Native框架的代码下载下来并添加到你当前的项目中。
+
+```bash
+$ sudo gem install cocoapods
+```
+
+> 从技术上来讲,我们完全可以跳过CocoaPods,但是这样一来我们就需要手工来完成很多配置项。CocoaPods可以帮我们完成这些繁琐的工作。
+
+
+## 示例App
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/iOS-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。 下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/swift-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+
+
+## 依赖包
+
+React Native的植入过程同时需要React和React Native两个node依赖包。
+
+### `package.json`
+
+我们把具体的依赖包记录在`package.json`文件中。如果项目根目录中没有这个文件,那就自己创建一个。
+
+> 对于一个典型的React Native项目来说,一般`package.json`和`index.ios.js`等文件会放在项目的根目录下。而iOS相关的原生代码会放在一个名为`ios/`的子目录中,这里也同时放着你的Xcode项目文件(`.xcodeproj`)。
+
+下面是一个最简单的`package.json`的内容示例。
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+```bash
+{
+ "name": "swift-2048",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+### 安装依赖包
+
+使用npm(node包管理器,Node package manager)来安装React和React Native模块。这些模块会被安装到项目根目录下的`node_modules/`目录中。
+在包含有package.json文件的目录(一般也就是项目根目录)中运行下列命令来安装:
+
+```bash
+$ npm install
+```
+
+## React Native框架
+
+React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的`Podfile`中指定我们所需要使用的组件。
+
+### Subspecs
+
+在你开始把React Native植入到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是`subspec`要做的工作。在创建`Podfile`文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个`subspec`。
+
+可用的`subspec`都列在[`node_modules/react-native/React.podspec`](https://github.com/facebook/react-native/blob/master/React.podspec)中,基本都是按其功能命名的。一般来说你首先需要添加`Core`,这一`subspec`包含了必须的`AppRegistry`、`StyleSheet`、`View`以及其他的一些React Native核心库。如果你想使用React Native的`Text`库(即``组件),那就需要添加`RCTText`的`subspec`。同理,`Image`需要加入`RCTImage`,等等。
+
+#### Podfile
+
+在React和React Native模块成功安装到`node_modules`目录之后,你就可以开始创建`Podfile`以便选择所需的组件安装到应用中。
+
+创建`Podfile`的最简单的方式就是在iOS原生代码所在的目录中使用CocoaPods的`init`命令:
+
+```bash
+## 在iOS原生代码所在的目录中(也就是`.xcodeproj`文件所在的目录)执行:
+$ pod init
+```
+
+`Podfile`会创建在执行命令的目录中。你需要调整其内容以满足你的植入需求。调整后的`Podfile`的内容看起来类似下面这样:
+
+
+
+```
+# target的名字一般与你的项目名字相同
+target 'NumberTileGame' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+ # 如果你的RN版本 >= 0.42.0,请加入下面这行
+ pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"
+
+end
+```
+
+
+
+```
+source 'https://github.com/CocoaPods/Specs.git'
+
+# 对于Swift应用来说下面两句是必须的
+platform :ios, '8.0'
+use_frameworks!
+
+# target的名字一般与你的项目名字相同
+target 'swift-2048' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+ # 如果你的RN版本 >= 0.42.0,请加入下面这行
+ pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"
+
+end
+```
+
+
+
+#### Pod安装
+
+创建好了`Podfile`后,就可以开始安装React Native的pod包了。
+
+```bash
+$ pod install
+```
+
+然后你应该可以看到类似下面的输出(译注:同样由于众所周知的网络原因,pod install的过程在国内非常不顺利,请自行配备稳定的翻墙工具,或是尝试一些[镜像源](https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&ch=2&tn=98010089_dg&wd=cocoapods%20%E9%95%9C%E5%83%8F&oq=cocoapods%E9%95%9C%E5%83%8F&rsv_pq=8fe4602600052d40&rsv_t=5d9fNEvNrqwcBS3rvMCKw0Cc%2FoW6XdW%2Bm4zks2nF3BxZ6cyWtJx1g%2F39Id6cUzeRTLM&rqlang=cn&rsv_enter=0&inputT=809&rsv_sug3=9&rsv_sug1=7&rsv_sug7=100&prefixsug=cocoapods%20%E9%95%9C%E5%83%8F&rsp=0&rsv_sug4=1010)):
+
+```bash
+Analyzing dependencies
+Fetching podspec for `React` from `../node_modules/react-native`
+Downloading dependencies
+Installing React (0.26.0)
+Generating Pods project
+Integrating client project
+Sending stats
+Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.
+```
+
+
+
+> 如果你看到类似"*The `swift-2048 [Debug]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig`. This can lead to problems with the CocoaPods installation*"的警告,请查看Xcode的`Build Settings`中的`Framework Search Paths`选项,确保其中的`Debug`和`Release`都只包含`$(inherited)`。
+
+
+
+## 代码集成
+
+现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正植入到应用中了。在我们的2048示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的React Native页面。
+
+### React Native组件
+
+我们首先要写的是"High Score"(得分排行榜)的JavaScript端的代码。
+
+#### 创建一个`index.ios.js`文件
+
+首先创建一个空的`index.ios.js`文件。一般来说我们把它放置在项目根目录下。
+
+> `index.ios.js`是React Native应用在iOS上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行`require/import`导入语句。本教程中为了简单示范,把全部的代码都写到了`index.ios.js`里(当然实际开发中我们并不推荐这样做)。
+
+```bash
+# 在项目根目录执行以下命令创建文件:
+$ touch index.ios.js
+```
+
+#### 添加你自己的React Native代码
+
+在`index.ios.js`中添加你自己的组件。这里我们只是简单的添加一个``组件,然后用一个带有样式的``组件把它包起来。
+
+```js
+'use strict';
+
+import React,{Component} from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class RNHighScores extends React.Component {
+ render() {
+ var contents = this.props["scores"].map(
+ score => {score.name}:{score.value}{"\n"}
+ );
+ return (
+
+
+ 2048 High Scores!
+
+
+ {contents}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#FFFFFF',
+ },
+ highScoresTitle: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ scores: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+});
+
+// 整体js模块的名称
+AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
+```
+
+> `RNHighScores`是整体js模块(即你所有的js代码)的名称。你在iOS原生代码中添加React Native视图时会用到这个名称。
+
+## The Magic: `RCTRootView`
+
+现在我们已经在`index.ios.js`中创建了React Native组件,下一步就是把这个组件添加给一个新的或已有的`ViewController`。 The easiest path to take is to optionally create an event path to your component and then add that component to an existing `ViewController`.
+
+We will tie our React Native component with a new native view in the `ViewController` that will actually host it called `RCTRootView` .
+
+### Create an Event Path
+
+You can add a new link on the main game menu to go to the "High Score" React Native page.
+
+
+
+#### 事件处理
+
+We will now add an event handler from the menu link. A method will be added to the main `ViewController` of your application. This is where `RCTRootView` comes into play.
+
+When you build a React Native application, you use the React Native packager to create an `index.ios.bundle` that will be served by the React Native server. Inside `index.ios.bundle` will be our `RNHighScore` module. So, we need to point our `RCTRootView` to the location of the `index.ios.bundle` resource (via `NSURL`) and tie it to the module.
+
+We will, for debugging purposes, log that the event handler was invoked. Then, we will create a string with the location of our React Native code that exists inside the `index.ios.bundle`. Finally, we will create the main `RCTRootView`. Notice how we provide `RNHighScores` as the `moduleName` that we created [above](#the-react-native-component) when writing the code for our React Native component.
+
+
+
+首先导入`RCTRootView`的头文件。
+
+```
+#import "RCTRootView.h"
+```
+
+> 这里的`initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+- (IBAction)highScoreButtonPressed:(id)sender {
+ NSLog(@"High Score Button Pressed");
+ NSURL *jsCodeLocation = [NSURL
+ URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
+ RCTRootView *rootView =
+ [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
+ moduleName : @"RNHighScores"
+ initialProperties :
+ @{
+ @"scores" : @[
+ @{
+ @"name" : @"Alex",
+ @"value": @"42"
+ },
+ @{
+ @"name" : @"Joel",
+ @"value": @"10"
+ }
+ ]
+ }
+ launchOptions : nil];
+ UIViewController *vc = [[UIViewController alloc] init];
+ vc.view = rootView;
+ [self presentViewController:vc animated:YES completion:nil];
+}
+```
+
+> Note that `RCTRootView initWithURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `[RCTRootView alloc] initWithURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+首先`import`导入`React`库。
+
+```
+import React
+```
+
+> The `initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+@IBAction func highScoreButtonTapped(sender : UIButton) {
+ NSLog("Hello")
+ let jsCodeLocation = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")
+ let mockData:NSDictionary = ["scores":
+ [
+ ["name":"Alex", "value":"42"],
+ ["name":"Joel", "value":"10"]
+ ]
+ ]
+
+ let rootView = RCTRootView(
+ bundleURL: jsCodeLocation,
+ moduleName: "RNHighScores",
+ initialProperties: mockData as [NSObject : AnyObject],
+ launchOptions: nil
+ )
+ let vc = UIViewController()
+ vc.view = rootView
+ self.present(vc, animated: true, completion: nil)
+}
+```
+
+> 注意`RCTRootView bundleURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `RCTRootView bundleURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `let mainBundle = NSBundle(URLForResource: "main" withExtension:"jsbundle")`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+#### Wire Up
+
+Wire up the new link in the main menu to the newly added event handler method.
+
+
+
+> One of the easier ways to do this is to open the view in the storyboard and right click on the new link. Select something such as the `Touch Up Inside` event, drag that to the storyboard and then select the created method from the list provided.
+
+## 测试植入结果
+
+You have now done all the basic steps to integrate React Native with your current application. Now we will start the React Native packager to build the `index.ios.bundle` packager and the server running on `localhost` to serve it.
+
+### App Transport Security
+
+Apple has blocked implicit cleartext HTTP resource loading. So we need to add the following our project's `Info.plist` (or equivalent) file.
+
+```xml
+NSAppTransportSecurity
+
+ NSExceptionDomains
+
+ localhost
+
+ NSTemporaryExceptionAllowsInsecureHTTPLoads
+
+
+
+
+```
+
+### 运行Packager
+
+```bash
+# From the root of your project, where the `node_modules` directory is located.
+$ npm start
+```
+
+### 运行应用
+
+如果你使用的是Xcode,那么照常编译和运行应用即可。如果你没有使用Xcode(但是你仍然必须安装Xcode),则可以在命令行中使用以下命令来运行应用:
+
+```bash
+# 在项目的根目录中执行:
+$ react-native run-ios
+```
+
+In our sample application, you should see the link to the "High Scores" and then when you click on that you will see the rendering of your React Native component.
+
+Here is the *native* application home screen:
+
+
+
+Here is the *React Native* high score screen:
+
+
+
+> If you are getting module resolution issues when running your application please see [this GitHub issue](https://github.com/facebook/react-native/issues/4968) for information and possible resolution. [This comment](https://github.com/facebook/react-native/issues/4968#issuecomment-220941717) seemed to be the latest possible resolution.
+
+### 看一下完整的代码变更
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/iOS-2048/commit/9ae70c7cdd53eb59f5f7c7daab382b0300ed3585)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/swift-2048/commit/13272a31ee6dd46dc68b1dcf4eaf16c1a10f5229)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+## 在应用中添加JS代码
+
+在项目的根目录中运行:
+
+ $ npm init
+ $ npm install --save react react-native
+ $ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
+
+`npm init`创建了一个空的node模块(其实就是创建了一个package.json描述文件),而`npm install`则创建了node_modules目录并把react和react-native下载到了其中。至于第三步curl命令,其实质是`下载`.flowconfig配置文件,这个文件用于约束js代码的写法。这一步非必需,可跳过。下面我们打开新创建的`package.json`文件,然后在其`scripts`字段中加入:
+
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+
+现在你的`package.json`内容应该类似这样:
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+接下来在项目根目录中创建`index.android.js`文件,然后将下面的代码复制粘贴进来:
+
+```js
+'use strict';
+
+import React from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class HelloWorld extends React.Component {
+ render() {
+ return (
+
+ Hello, World
+
+ )
+ }
+}
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ hello: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+});
+
+AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
+```
+
+## 准备工作
+
+在你的app中 `build.gradle` 文件中添加 React Native 依赖:
+
+```
+ dependencies {
+ ...
+ compile "com.facebook.react:react-native:+" // From node_modules.
+ }
+```
+
+> 你想要指定构建时的 React Native 版本,请用 `npm` 已下载的本地 React Native 的版本号替换 `+` 。
+
+在项目的 `build.gradle` 文件中为 React Native 添加一个 maven 依赖的入口,必须写在 "allprojects" 代码块中:
+
+```
+allprojects {
+ repositories {
+ ...
+ maven {
+ // All of React Native (JS, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+ }
+ ...
+}
+```
+
+> 确保依赖路径的正确!以免在 Android Studio 运行Gradle同步构建时抛出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 异常。
+
+接着,在 `AndroidManifest.xml` 清单文件中声明网络权限:
+
+
+
+如果需要访问 `DevSettingsActivity` 界面,也需要在 `AndroidManifest.xml` 中声明:
+
+
+
+
+This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.
+
+## 添加原生代码
+
+想要通过原生代码调用 React Native ,就像这样,我们需要在一个 `Activity` 中创建一个 `ReactRootView` 对象,将它关联一个 React application 并设为界面的主视图。
+
+> 如果你想在安卓5.0以下的系统上运行,请用 `com.android.support:appcompat` 包中的 `AppCompatActivity` 代替 `Activity` 。
+
+
+```java
+public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
+ private ReactRootView mReactRootView;
+ private ReactInstanceManager mReactInstanceManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mReactRootView = new ReactRootView(this);
+ mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ .setBundleAssetName("index.android.bundle")
+ .setJSMainModuleName("index.android")
+ .addPackage(new MainReactPackage())
+ .setUseDeveloperSupport(BuildConfig.DEBUG)
+ .setInitialLifecycleState(LifecycleState.RESUMED)
+ .build();
+
+ // 注意这里的HelloWorld必须对应“index.android.js”中的
+ // “AppRegistry.registerComponent()”的第一个参数
+ mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
+
+ setContentView(mReactRootView);
+ }
+
+ @Override
+ public void invokeDefaultOnBackPressed() {
+ super.onBackPressed();
+ }
+}
+```
+
+> 如果你的项目名字不是叫“HelloWorld”,则需要将“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一个参数替换为对应的名字。
+
+如果你使用的是 Android Studio , 请用 `Alt + Enter` 为 MyReactActivity 类导包。当你使用了不止一个 `...facebook...` 包时,请谨慎选择要导入的类。
+
+我们需要把 `MyReactActivity` 的主题设定为 `Theme.AppCompat.Light.NoActionBar` ,因为里面有许多组件都使用了这一主题。
+
+ ```xml
+
+
+ ```
+
+> A `ReactInstanceManager` can be shared amongst multiple activities and/or fragments. You will want to make your own `ReactFragment` or `ReactActivity` and have a singleton *holder* that holds a `ReactInstanceManager`. When you need the `ReactInstanceManager` (e.g., to hook up the `ReactInstanceManager` to the lifecycle of those Activities or Fragments) use the one provided by the singleton.
+
+Next, we need to pass some activity lifecycle callbacks down to the `ReactInstanceManager`:
+
+```java
+@Override
+protected void onPause() {
+ super.onPause();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostPause(this);
+ }
+}
+
+@Override
+protected void onResume() {
+ super.onResume();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostResume(this, this);
+ }
+}
+
+@Override
+protected void onDestroy() {
+ super.onDestroy();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostDestroy();
+ }
+}
+```
+
+We also need to pass back button events to React Native:
+
+```java
+@Override
+ public void onBackPressed() {
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+}
+```
+
+This allows JavaScript to control what happens when the user presses the hardware back button (e.g. to implement navigation). When JavaScript doesn't handle a back press, your `invokeDefaultOnBackPressed` method will be called. By default this simply finishes your `Activity`.
+
+Finally, we need to hook up the dev menu. By default, this is activated by (rage) shaking the device, but this is not very useful in emulators. So we make it show when you press the hardware menu button (use `Ctrl + M` if you're using Android Studio emulator):
+
+```java
+@Override
+public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
+ mReactInstanceManager.showDevOptionsDialog();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+}
+```
+
+现在activity已就绪,可以运行一些JavaScript代码了。
+
+### 配置权限以便开发中的红屏错误能正确显示
+
+If your app is targeting the Android `API level 23` or greater, make sure you have the `overlay` permission enabled for the development build. You can check it with `Settings.canDrawOverlays(this);`. This is required in dev builds because react native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23, the user needs to approve it. This can be acheived by adding the following code to the Activity file in the onCreate() method. OVERLAY_PERMISSION_REQ_CODE is a field of the class which would be responsible for passing the result back to the Activity.
+
+```java
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:" + getPackageName()));
+ startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
+ }
+}
+```
+
+Finally, the `onActivityResult()` method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX.
+
+```java
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ // SYSTEM_ALERT_WINDOW permission not granted...
+ }
+ }
+ }
+}
+```
+
+
+## 运行你的应用
+
+运行应用首先需要启动开发服务器(Packager)。你只需在项目根目录中执行以下命令即可:
+
+ $ npm start
+
+Now build and run your Android app as normal (`./gradlew installDebug` from command-line; in Android Studio just create debug build as usual).
+
+> If you are using Android Studio for your builds and not the Gradle Wrapper directly, make sure you install [watchman](https://facebook.github.io/watchman/) before running `npm start`. It will prevent the packager from crashing due to conflicts between Android Studio and the React Native packager.
+
+Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display:
+
+
+
+## 在Android Studio中打包
+
+你也可以使用Android Studio来打包!You can use Android Studio to create your release builds too! It’s as easy as creating release builds of your previously-existing native Android app. There’s just one additional step, which you’ll have to do before every release build. You need to execute the following to create a React Native bundle, which’ll be included with your native Android app:
+
+ $ react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/
+
+Don’t forget to replace the paths with correct ones and create the assets folder if it doesn’t exist!
+
+Now just create a release build of your native app from within Android Studio as usual and you should be good to go!
+
+
+
diff --git a/docs/docs/0.42/interactionmanager.md b/docs/docs/0.42/interactionmanager.md
new file mode 100644
index 0000000..16555fb
--- /dev/null
+++ b/docs/docs/0.42/interactionmanager.md
@@ -0,0 +1,58 @@
+Interactionmanager可以将一些耗时较长的工作安排到所有互动或动画完成之后再进行。这样可以保证JavaScript动画的流畅运行。
+
+应用这样可以安排一个任务在交互和动画完成之后执行:
+
+```javascript
+InteractionManager.runAfterInteractions(() => {
+ // ...耗时较长的同步的任务...
+});
+```
+
+把这个和其他的延迟计划函数对比:
+
+- requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
+- setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
+- runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
+
+触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将`runAfterInteractions()`的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
+
+InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
+
+```javascript
+var handle = InteractionManager.createInteractionHandle();
+// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
+// 在动画完成之后
+InteractionManager.clearInteractionHandle(handle);
+// 在所有句柄都清除之后,现在开始依序执行队列中的任务
+```
+`runAfterInteractions`接受一个普通的回调函数,或是一个`PromiseTask`对象,该对象需要带有名为`gen`的方法,并返回一个`Promise`。如果提供的参数是一个`PromiseTask`, 那么即便它是异步的它也会阻塞任务队列,直到它(以及它所有的依赖任务,哪怕这些依赖任务也是异步的)执行完毕后,才会执行下一个任务。
+
+默认情况下,排队的任务会在一次setImmediate方法中依序批量执行。如果你调用了setDeadLine方法并设定了一个正整数值,则任务只会在设定的时间到达后开始执行。在此之前,任务会通过setTimeout来挂起并阻塞其他任务执行,这样可以给诸如触摸交互一类的事件留出时间,使应用可以更快地响应用户。
+
+### 方法
+
+
+
+
static runAfterInteractions(callback: Function) #
+
安排一个函数在所有的交互和动画完成之后运行。返回一个可取消的promise。
+
+
+
static createInteractionHandle() #
+
+
+
+
static clearInteractionHandle(handle: Handle) #
+
+
+
+
static setDeadline(deadline: number) #
+
如果设定了一个正整数值,则会使用setTimeout来挂起所有尚未执行的任务。在eventLoopRunningTime到达设定时间后,才开始使用一个setImmediate方法来批量执行所有任务。
+
+
+
+### 属性
+
+
+
+
addListener: CallExpression #
+
diff --git a/docs/docs/0.42/javascript-environment.md b/docs/docs/0.42/javascript-environment.md
new file mode 100644
index 0000000..d95513d
--- /dev/null
+++ b/docs/docs/0.42/javascript-environment.md
@@ -0,0 +1,75 @@
+在使用React Native时,你的JavaScript代码将会运行在两个不同的环境上:
+
+* 在iOS、Android的模拟器或是真机上,React Native使用的是[JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore),也就是Safari所使用的JavaScript引擎。但是在iOS上JavaScriptCore并没有使用即时编译技术(JIT),因为在iOS中应用无权拥有可写可执行的内存页(因而无法动态生成代码)。
+* 在使用Chrome调试时,所有的JavaScript代码都运行在Chrome中,并且通过WebSocket与原生代码通信。此时的运行环境是[V8引擎](https://code.google.com/p/v8/)。
+
+虽然两个环境非常类似,但开发者还是可能碰到一些不一致的地方。未来我们很可能会尝试一些其他的JS引擎,所以请尽量避免使用依赖于特定运行环境的代码。
+
+## JavaScript语法转换器
+
+语法转换器可以使编写代码的过程更加享受,因为开发者可以借助转换器直接使用新的JavaScirpt语法标准,而无需等待JS解释器的支持。
+
+React Native从0.5.0版本开始已经内置[Babel转换器](https://babeljs.io)。你可以查看[Babel的文档](https://babeljs.io/docs/plugins/#transform-plugins)来了解有关它可以转换的语法的详情。
+
+这里可以看到目前React Native默认开启的[语法转换特性](https://github.com/facebook/react-native/blob/master/babel-preset/configs/main.js#L16)。
+注:若想学习相关语法,译者推荐阮一峰老师的[《ECMAScript 6入门》](http://es6.ruanyifeng.com/)以及论坛的[讨论帖](http://bbs.reactnative.cn/topic/15)。
+
+ES5
+
+* 保留关键字: `promise.catch(function() { });`
+
+ES6
+
+* [箭头函数Arrow functions](http://babeljs.io/docs/learn-es2015/#arrows): ` this.setState({pressed: true})}`
+* [块级作用域Block scoping](https://babeljs.io/docs/learn-es2015/#let-const): `let greeting = 'hi';`
+* [数组的扩展运算Call spread](http://babeljs.io/docs/learn-es2015/#default-rest-spread): `Math.max(...array);`
+* [类Classes](http://babeljs.io/docs/learn-es2015/#classes): `class C extends React.Component { render() { return ; } }`
+* [常量Constants](https://babeljs.io/docs/learn-es2015/#let-const): `const answer = 42;`
+* [解构Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring): `var {isActive, style} = this.props;`
+* [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of): `for (var num of [1, 2, 3]) {}`
+* [模块Modules](http://babeljs.io/docs/learn-es2015/#modules): `import React, { Component } from 'react';`
+* [动态属性键Computed Properties](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var key = 'abc'; var obj = {[key]: 10};`
+* 对象方法的简写Object Consise Method: `var obj = { method() { return 10; } };`
+* [对象属性的简写Object Short Notation](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var name = 'vjeux'; var obj = { name };`
+* [参数的扩展运算Rest Params](https://github.com/sebmarkbage/ecmascript-rest-spread): `function(type, ...args) { }`
+* [字符串模板Template Literals](http://babeljs.io/docs/learn-es2015/#template-strings): ``var who = 'world'; var str = `Hello ${who}`;``
+
+ES7
+
+* [对象的扩展运算Object Spread](https://github.com/sebmarkbage/ecmascript-rest-spread): `var extended = { ...obj, a: 10 };`
+* [参数列表末尾允许放置逗号Function Trailing Comma](https://github.com/jeffmo/es-trailing-function-commas): `function f(a, b, c,) { }`
+* [Async函数](https://github.com/tc39/ecmascript-asyncawait): `async function doStuffAsync() { const foo = await doOtherStuffAsync(); }`;
+
+其他特性
+
+* [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): ` `
+* [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
+
+## 接口兼容(Polyfills)
+
+许多标准功能也都在支持的JavaScript运行环境上做了兼容支持。
+
+浏览器
+
+* [console.{log, warn, error, info, trace, table}](https://developer.chrome.com/devtools/docs/console-api)
+* [CommonJS require](https://nodejs.org/docs/latest/api/modules.html)
+* [XMLHttpRequest, fetch](/react-native/docs/network.html#content)
+* [{set, clear}{Timeout, Interval, Immediate}, {request, cancel}AnimationFrame](/react-native/docs/timers.html#content)
+* [navigator.geolocation](/react-native/docs/geolocation.html#content)
+
+ES6
+
+* [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+* String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)}
+* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
+* Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)}
+
+ES7
+
+* Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)}
+
+其他特性
+
+* `__DEV__`
+
+
diff --git a/docs/docs/0.42/keyboard.md b/docs/docs/0.42/keyboard.md
new file mode 100644
index 0000000..7eca107
--- /dev/null
+++ b/docs/docs/0.42/keyboard.md
@@ -0,0 +1,76 @@
+`Keyboard`组件可以用来控制键盘相关的事件。
+
+### 用法
+`Keyboard`组件可以监听原生键盘事件以做出相应回应,比如收回键盘。
+
+```js
+import React, { Component } from 'react';
+import { Keyboard, TextInput } from 'react-native';
+
+class Example extends Component {
+ componentWillMount () {
+ this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
+ this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
+ }
+
+ componentWillUnmount () {
+ this.keyboardDidShowListener.remove();
+ this.keyboardDidHideListener.remove();
+ }
+
+ _keyboardDidShow () {
+ alert('Keyboard Shown');
+ }
+
+ _keyboardDidHide () {
+ alert('Keyboard Hidden');
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+```
+### 方法
+
+
+
static addListener(nativeEvent, jsFunction) #
+
addListener用于注册一个JavaScript函数来监听处理原生键盘通知事件。
+
此方法会返回监听函数的引用。
+
@param {string} nativeEvent nativeEvent参数用来指明要监听的事件,具体有以下几种:
+
+ keyboardWillShow
+ keyboardDidShow
+ keyboardWillHide
+ keyboardDidHide
+ keyboardWillChangeFrame
+ keyboardDidChangeFrame
+
+
注意如果你把`android:windowSoftInputMode`设置为`adjustResize`或是`adjustNothing`,则在Android上只有`keyboardDidShow`和`keyboardDidHide`事件有效。
>
+
@param {function} jsFunction 事件触发时调用的js函数。
+
+
static removeAllListeners(eventType) #
+
移除某个类型事件的所有监听函数.
+
@param {string} eventType 要移除的原生事件类型
+
+
static removeSubscription(subscription) #
+
+
@param {EmitterSubscription} subscription 要移除的监听函数
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/keyboardavoidingview.md b/docs/docs/0.42/keyboardavoidingview.md
new file mode 100644
index 0000000..9b98529
--- /dev/null
+++ b/docs/docs/0.42/keyboardavoidingview.md
@@ -0,0 +1,150 @@
+本组件用于解决一个常见的尴尬问题:手机上弹出的键盘常常会挡住当前的视图。本组件可以自动根据键盘的位置,调整自身的position或底部的padding,以避免被遮挡。
+
+### 属性
+
+
+
+
behavior PropTypes.oneOf(['height', 'position', 'padding'])
+ #
+
+
+
+
contentContainerStyle
+ View#style
+ #
+
+
如果设定behavior值为'position',则会生成一个View作为内容容器。此属性用于指定此内容容器的样式。
+
+
+
keyboardVerticalOffset
+ PropTypes.number.isRequired
+ #
+
+
有时候应用离屏幕顶部还有一些距离(比如状态栏等等),利用此属性来补偿修正这段距离。
+
+
+
+### 方法
+
+
+
relativeKeyboardHeight(keyboardFrame): #
+
+
+
+
onKeyboardChange(event) #
+
+
+
+
onLayout(event)
+ #
+
+
+
+
+### 例子
+
+```js
+'use strict';
+
+const React = require('React');
+const ReactNative = require('react-native');
+const {
+ KeyboardAvoidingView,
+ Modal,
+ SegmentedControlIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+const UIExplorerBlock = require('./UIExplorerBlock');
+const UIExplorerPage = require('./UIExplorerPage');
+
+class KeyboardAvoidingViewExample extends React.Component {
+ static title = '';
+ static description = 'Base component for views that automatically adjust their height or position to move out of the way of the keyboard.';
+
+ state = {
+ behavior: 'padding',
+ modalOpen: false,
+ };
+
+ onSegmentChange = (segment: String) => {
+ this.setState({behavior: segment.toLowerCase()});
+ };
+
+ renderExample = () => {
+ return (
+
+
+
+
+
+
+ this.setState({modalOpen: false})}
+ style={styles.closeButton}>
+ Close
+
+
+
+ this.setState({modalOpen: true})}>
+ Open Example
+
+
+ );
+ };
+
+ render() {
+ return (
+
+
+ {this.renderExample()}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ outerContainer: {
+ flex: 1,
+ },
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ paddingHorizontal: 20,
+ paddingTop: 20,
+ },
+ textInput: {
+ borderRadius: 5,
+ borderWidth: 1,
+ height: 44,
+ paddingHorizontal: 10,
+ },
+ segment: {
+ marginBottom: 10,
+ },
+ closeButton: {
+ position: 'absolute',
+ top: 30,
+ left: 10,
+ }
+});
+
+module.exports = KeyboardAvoidingViewExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/known-issues.md b/docs/docs/0.42/known-issues.md
new file mode 100644
index 0000000..2fe0cd0
--- /dev/null
+++ b/docs/docs/0.42/known-issues.md
@@ -0,0 +1,78 @@
+### Chrome开发工具中的"React"选项无法使用
+目前[无法使用](https://github.com/facebook/react-devtools/issues/229)开发工具中的"React"选项来查看App的组件。这是由于脚本在开发工具插件中的运行方式改变了;它们现在在Web Worker内部运行,插件并不知道,因此无法很好的和React Native进行通讯。
+即便如此,你仍然可以使用开发工具的Console和Sources选项,而且可以使用断点来调试JavaScript。为了能够使用Console功能,你必须确认在开发工具下拉菜单中选择入口文件为 ⚙debuggerWorker.js,(默认选择为<top frame>)。
+
+
+### 缺失的Android模块和视图
+
+虽然React Native的Android版本的开发工作晚于iOS版本,但目前大多数视图都在Android上实现了,除了下面几个例外:
+
+#### 视图
+
+- Maps —— 我们推荐使用Leland Richardson的[react-native-maps](https://github.com/lelandrichardson/react-native-maps),它比我们内部实现的map功能更完善。
+
+
+#### 模块
+- Android推送通知 (请使用第三方模块,比如[react-native-jpush](https://github.com/reactnativecn/react-native-jpush))
+
+
+### 某些属性仅仅支持单个平台
+
+有些属性只能在单个平台上使用,这是由于这些特性仅有单个平台支持或者是尚未在其他平台上实现。所有这些都在JS文档中被`@platform`标注,并且左侧有一个小标记。
+
+### 平台一致性
+以下是一些本该(或将要)设计得更通用的API或组件:
+
+- ``和``功能类似。我们或许希望统一成``。
+
+- `ActivityIndicator`可以跨平台地渲染一个原生的加载(loading)指示器(目前在iOS上使用`ActivityIndicatorIOS`,而在Android上使用`ProgressBarAndroid`)
+
+- `ProgressBar`可以跨平台渲染一个水平的进度条(目前只在iOS上支持,使用`ProgressViewIOS `)
+
+
+### 使用第三方的原生模块
+
+[JS.coach](https://js.coach/react-native)上有很多非常优秀的第三方模块。
+在你的项目中集成这些模块应该并不困难,这里有一个[实际应用的例子](https://github.com/apptailor/react-native-google-signin)。
+
+### overflow样式在Android默认为hidden而且无法更改
+
+这是Android本身的渲染机制所致。我们没有实现这一特性,因为这是个大工程,而且我们还有很多其他重要的任务。
+Android的`overflow:hidden`还有另外一个问题:如果父容器有`borderRadius`圆角边框样式,那么即便开启了`overflow:hidden`也仍然无法把子视图超出圆角边框的部分裁切掉。这个问题只存在于Android上,iOS并没有这个问题(子视图的内容不会超出父容器的圆角边框)。你可以在[这里](https://rnplay.org/apps/BlGjdQ)看到问题的演示,以及在[这里](https://github.com/facebook/react-native/issues/3198)查看这个问题的报告以及后续进展。
+
+### 视图阴影
+
+`shadow`开头的[样式](view.html#style)现在可以在iOS上应用,而Android上对应的属性(props)是`elevation`。设置`elevation`属性就等价于使用原生的[`elevation API`](https://developer.android.com/training/material/shadows-clipping.html#Elevation),因而也有同样的限制(比如最明显的就是需要Android 5.0以上版本)。此外还会影响到层叠视图在空间z轴上的顺序。
+
+### Android M(6.0)的权限
+
+当前版本的React Native还不支持Android M的[权限模型](http://developer.android.com/training/permissions/requesting.html)。
+
+### Android纯布局(Layout-only)节点
+
+Android版本的React Native有一个优化的特性:有些视图,只起布局作用而没有对应的原生视图,那么只有它们的布局属性会被传递给子视图。这个优化对于深层次的视图的稳定性很重要因此默认开启。要关闭这个特性,请设置`collapsable`为false:
+
+```
+
+ ...
+
+```
+
+### PNG图片的内存问题
+React Native Android 依靠[Fresco](https://github.com/facebook/fresco)载入和显示图片。目前我们关闭了下采样(downsampling)(这一特性还不稳定),因此有可能载入较大的PNG图片时会出现内存问题。
+
+### react-native init时卡住
+
+尝试运行`react-native init`时加上`--verbose`参数,点这里[#2797](https://github.com/facebook/react-native/issues/2797)查看一般可能的原因。
+译注:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请将npm仓库源替换为国内镜像:
+
+```
+npm config set registry https://registry.npm.taobao.org
+npm config set disturl https://npm.taobao.org/dist
+```
+另,执行init时切记不要在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题,请使用chown修复)。
+又,react-native.cn中文网提供了完整的[绿色纯净新项目包](http://bbs.reactnative.cn/topic/11)。完整打包全部iOS和Android的第三方依赖,只要环境配置正确,无需科学上网漫长等待,解压后即可直接运行。
+
+### 文本框的边界(border)
+
+文本框默认的边界在视图的底部。这个边界有一个内衬(padding),这个padding由系统提供的背景图片所设定,并且无法改变。解决这个问题有两个方案,一是可以不指定高度,这样系统会自动处理,在恰当的位置显示边界;或者干脆通过设定[underlineColorAndroid](textinput.html#underlinecolorandroid)为透明来隐藏边界。
diff --git a/docs/docs/0.42/layout-props.md b/docs/docs/0.42/layout-props.md
new file mode 100644
index 0000000..4998bc6
--- /dev/null
+++ b/docs/docs/0.42/layout-props.md
@@ -0,0 +1,236 @@
+
+
alignItems enum('flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
alignSelf enum('auto', 'flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
borderBottomWidth number #
+
+
+
+
borderLeftWidth number #
+
+
+
borderRightWidth number #
+
+
+
+
borderTopWidth number #
+
+
+
borderWidth number
+ #
+
+
+
+
flex number
+ #
+
在React Native中flex的表现和CSS有些区别。
+ flex在RN中只能为整数值,其具体表现请参考yoga引擎库的文档,其网址是https://github.com/facebook/yoga
+
当flex取正整数值时, is a positive number, it makes the component flexible
+ and it will be sized proportional to its flex value. So a
+ component with flex set to 2 will take twice the space as a
+ component with flex set to 1.
+
When flex is 0, the component is sized according to width
+ and height and it is inflexible.
+
When flex is -1, the component is normally sized according
+ width and height. However, if there's not enough space,
+ the component will shrink to its minWidth and minHeight.
+
flexGrow, flexShrink, and flexBasis work the same as in CSS.
+
+
+
flexDirection enum('row', 'row-reverse', 'column', 'column-reverse') #
+
+
flexDirection controls which directions children of a container go.
+ row goes left to right, column goes top to bottom, and you may
+ be able to guess what the other two do. It works like flex-direction
+ in CSS, except the default is column.访问https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction 来进一步了解。
+
+
+
+
flexWrap enum('wrap', 'nowrap')
+ #
+
+
+
+
justifyContent enum('flex-start', 'flex-end', 'center', 'space-between', 'space-around') #
+
+
+
+
+
marginBottom number #
+
+
+
marginHorizontal number #
+
+
Setting marginHorizontal has the same effect as setting
+ both marginLeft and marginRight.
+
+
marginLeft number
+ #
+
+
+
marginRight number
+ #
+
+
+
+
marginVertical number #
+
Setting marginVertical has the same effect as setting both
+ marginTop and marginBottom.
+
+
+
+
+
+
overflow enum('visible', 'hidden', 'scroll')
+ #
+
overflow controls how a children are measured and displayed.
+ overflow: hidden causes views to be clipped while overflow: scroll
+ causes views to be measured independently of their parents main axis.It works likeoverflow` in
+ CSS (default: visible).访问https://developer.mozilla.org/en/docs/Web/CSS/overflow 来进一步了解。
+
+
+
paddingBottom number #
+
+
+
paddingHorizontal number #
+
+
Setting paddingHorizontal is like setting both of
+ paddingLeft and paddingRight.
+
+
paddingLeft number
+ #
+
+
+
paddingRight number #
+
+
+
paddingTop number
+ #
+
+
+
paddingVertical number #
+
Setting paddingVertical is like setting both of
+ paddingTop and paddingBottom.
+
+
position enum('absolute', 'relative')
+ #
+
position in React Native is similar to regular CSS, but
+ everything is set to relative by default, so absolute
+ positioning is always just relative to the parent.
+
If you want to position a child using specific numbers of logical
+ pixels relative to its parent, set the child to have absolute
+ position.
+
If you want to position a child relative to something
+ that is not its parent, just don't use styles for that. Use the
+ component tree.
+
访问https://facebook.github.io/yoga/docs/absolute-position/ 来进一步了解position在React Native和CSS中的差异。
+
+
+
+
+
zIndex number #
+
zIndex controls which components display on top of others.
+ Normally, you don't use zIndex. Components render according to
+ their order in the document tree, so later components draw over
+ earlier ones. zIndex may be useful if you have animations or custom
+ modal interfaces where you don't want this behavior.
+
It works like the CSS z-index property - components with a larger
+ zIndex will render on top. Think of the z-direction like it's
+ pointing from the phone into your eyeball.访问https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
+来进一步了解。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/layout-with-flexbox.md b/docs/docs/0.42/layout-with-flexbox.md
new file mode 100644
index 0000000..9b1130f
--- /dev/null
+++ b/docs/docs/0.42/layout-with-flexbox.md
@@ -0,0 +1,97 @@
+我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
+
+一般来说,使用`flexDirection`、`alignItems`和 `justifyContent`三个样式属性就已经能满足大多数布局需求。译注:这里有一份[简易布局图解](http://weibo.com/1712131295/CoRnElNkZ?ref=collection&type=comment),可以给你一个大概的印象。
+
+> React Native中的Flexbox的工作原理和web上的CSS基本一致,当然也存在少许差异。首先是默认值不同:`flexDirection`的默认值是`column`而不是`row`,而`flex`也只能指定一个数字值。
+
+#### Flex Direction
+
+在组件的`style`中指定`flexDirection`可以决定布局的**主轴**。子元素是应该沿着**水平轴(`row`)**方向排列,还是沿着**竖直轴(`column`)**方向排列呢?默认值是**竖直轴(`column`)**方向。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDirectionBasics extends Component {
+ render() {
+ return (
+ // 尝试把`flexDirection`改为`column`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
+```
+
+#### Justify Content
+
+在组件的style中指定`justifyContent`可以决定其子元素沿着**主轴**的**排列方式**。子元素是应该靠近主轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`、`space-around`以及`space-between`。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class JustifyContentBasics extends Component {
+ render() {
+ return (
+ // 尝试把`justifyContent`改为`center`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
+```
+
+#### Align Items
+
+在组件的style中指定`alignItems`可以决定其子元素沿着**次轴**(与主轴垂直的轴,比如若主轴方向为`row`,则次轴方向为`column`)的**排列方式**。子元素是应该靠近次轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`以及`stretch`。
+
+> 注意:要使`stretch`选项生效的话,子元素在次轴方向上不能有固定的尺寸。以下面的代码为例:只有将子元素样式中的`width: 50`去掉之后,`alignItems: 'stretch'`才能生效。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class AlignItemsBasics extends Component {
+ render() {
+ return (
+ // 尝试把`alignItems`改为`flex-start`看看
+ // 尝试把`justifyContent`改为`flex-end`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
+```
+
+#### 深入学习
+
+以上我们已经介绍了一些基础知识,但要运用好布局,我们还需要很多其他的样式。对于布局有影响的完整样式列表记录在[这篇文档中](layout-props.html)。
+
+现在我们已经差不多可以开始真正的开发工作了。哦,忘了还有个常用的知识点:[如何使用TextInput组件来处理用户输入](handling-text-input.html)。
diff --git a/docs/docs/0.42/layoutanimation.md b/docs/docs/0.42/layoutanimation.md
new file mode 100644
index 0000000..e309eb6
--- /dev/null
+++ b/docs/docs/0.42/layoutanimation.md
@@ -0,0 +1,49 @@
+当布局变化时,自动将视图运动到它们新的位置上。
+
+
+一个常用的调用此API的办法是调用`LayoutAnimation.configureNext`,然后调用`setState`。
+
+
+注意:目前如果要在**Android**上使用LayoutAnimation,那么还需要在`UIManager`中明确启用:
+```javascript
+UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
+```
+
+
+### 方法
+
+
+
+
static configureNext(config: Config, onAnimationDidEnd?: Function) #
+
+
计划下一次布局要发生的动画。
+
@param config 表示动画相应的属性
+
+ duration 动画持续时间,单位是毫秒
+ create, 配置创建新视图时的动画。(参阅 Anim 类型)
+ update, 配置被更新的视图的动画。(参阅 Anim 类型)
+
+
@param onAnimationDidEnd 当动画结束的时候被调用。只在iOS设备上支持。
+
@param onError 当动画产生错误的时候被调用。只在iOS设备上支持。
+
+
+
+
static create(duration: number, type, creationProp) #
+
+
用来创建configureNext所需的config参数的辅助函数。
+
+
+
+
+### 属性
+
+
+
+
Properties: CallExpression #
+
configChecker: CallExpression #
+
Presets: ObjectExpression #
+
easeInEaseOut: CallExpression #
+
+
+
+
diff --git a/docs/docs/0.42/linking-libraries-ios.md b/docs/docs/0.42/linking-libraries-ios.md
new file mode 100644
index 0000000..ac7a243
--- /dev/null
+++ b/docs/docs/0.42/linking-libraries-ios.md
@@ -0,0 +1,62 @@
+并不是所有的APP都需要使用全部的原生功能,包含支持全部特性的代码会增大应用的体积。但我们仍然希望能让你简单地根据自己的需求添加需要的特性。
+
+在这种思想下,我们把许多特性都发布成为互不相关的静态库。
+
+大部分的库只需要拖进两个文件就可以使用了,偶尔你还需要几步额外的工作,但不会再有更多的事情要做了。
+
+_我们随着React Native发布的所有库都在仓库中的`Libraries`文件夹下。其中有一些是纯Javascript代码,你只需要去`require`它们就可以使用了。另外有一些库基于一些原生代码实现,你必须把这些文件添加到你的应用,否则应用会在你使用这些库的时候产生报错。_
+
+## 添加包含原生代码的库需要几个步骤:
+
+### 自动链接
+
+#### 第一步
+安装一个带原生依赖的库:
+
+```bash
+$ npm install 某个带有原生依赖的库 --save
+```
+
+**注意:** 这一步中`--save`或`--save-dev`参数是非常重要的。React Native需要根据`package.json`文件中的`dependencies`和`devDependencies`记录来链接库。
+
+#### 第二步
+
+链接原生依赖:
+
+```bash
+$ react-native link
+```
+
+完成了!现在所有的原生依赖都成功地链接到你的iOS/Android项目了。
+
+### 手动链接
+
+#### 第一步
+
+如果该库包含原生代码,那么在它的文件夹下一定有一个`.xcodeproj`文件。
+把这个文件拖到你的XCode工程下(通常拖到XCode的`Libraries`分组里)
+
+
+
+#### 第二步
+
+点击你的主工程文件,选择`Build Phases`,然后把刚才所添加进去的`.xcodeproj`下的`Products`文件夹中的静态库文件(.a文件),拖到`Link Binary With Libraries`组内。
+
+
+
+#### 第三步
+
+不是所有的库都需要进行这个步骤,你需要考虑的问题在于:
+
+_我需要在编译的期间了解库的内容吗?_
+
+这个问题的意思是,你是需要在原生代码中使用这个库,还是只需要通过JavaScript访问?如果你只需要通过JavaScript访问这个库,你就可以跳过这步了。
+
+这一步骤对于我们随React Native发布的大部分库来说都不是必要的,但有两个例外是`PushNotificationIOS`和`LinkingIOS`。
+
+以`PushNotificationIOS`为例,你需要在`AppDelegate`每收到一条推送通知之后,调用库中的一个方法。
+
+这种情况下我们需要能够访问到库的头文件。为了能够顺利打包,你需要打开你的工程文件,选择`Build Settings`,然后搜索`Header Search Paths`,然后添加库所在的目录(如果它还有像`React`这样的子目录需要包含,注意要选中`recursive`选项)
+
+
+
diff --git a/docs/docs/0.42/linking.md b/docs/docs/0.42/linking.md
new file mode 100644
index 0000000..785dab3
--- /dev/null
+++ b/docs/docs/0.42/linking.md
@@ -0,0 +1,123 @@
+`Linking`提供了一个通用的接口来与传入和传出的App链接进行交互。
+
+### 基本用法
+
+#### 处理链接
+
+如果你的应用被其注册过的外部url调起,则可以在任何组件内这样获取和处理它:
+
+```javascript
+componentDidMount() {
+ Linking.getInitialURL().then(url) => {
+ if (url) {
+ console.log('Initial url is: ' + url);
+ }
+ }).catch(err => console.error('An error occurred', err));
+}
+```
+注:要了解更多如何在Android上支持深度链接的说明,请参阅[Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters)。
+
+如果要在现有的MainActivity中监听传入的intent,那么需要在`AndroidManifest.xml`中将MainActivity的`launchMode`设置为`singleTask`。相关解释可参考[``](http://developer.android.com/guide/topics/manifest/activity-element.html)文档。
+
+```xml
+
+```
+
+对于iOS来说,如果要在App启动后也监听传入的App链接,那么首先需要在项目中链接`RCTLinking`,具体步骤请参考[使用链接库](linking-libraries-ios.html)这篇文档,然后需要在`AppDelegate.m`中增加以下代码:
+
+```objective-c
+#import
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+ {
+ return [RCTLinkingManager application:application openURL:url
+ sourceApplication:sourceApplication annotation:annotation];
+ }
+
+// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+ {
+ return [RCTLinkingManager application:application
+ continueUserActivity:userActivity
+ restorationHandler:restorationHandler];
+ }
+```
+
+然后你的React组件就可以监听`Linking`的相关事件:
+
+```javascript
+componentDidMount() {
+ Linking.addEventListener('url', this._handleOpenURL);
+},
+componentWillUnmount() {
+ Linking.removeEventListener('url', this._handleOpenURL);
+},
+_handleOpenURL(event) {
+ console.log(event.url);
+}
+```
+
+
+#### 打开外部链接
+
+要启动一个链接相对应的应用(打开浏览器、邮箱或者其它的应用),只需调用:
+
+```javascript
+Linking.openURL(url).catch(err => console.error('An error occurred', err));
+```
+如果想在打开链接前先检查是否安装了对应的应用,则调用以下方法:
+
+```javascript
+Linking.canOpenURL(url).then(supported => {
+ if (!supported) {
+ console.log('Can\'t handle url: ' + url);
+ } else {
+ return Linking.openURL(url);
+ }
+}).catch(err => console.error('An error occurred', err));
+```
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听Linking变化的事件。type参数应填`url`,并提供一个处理函数。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
删除一个事件处理函数。type参数应填`url`。
+
+
+
+
static openURL(url: string) #
+
+
尝试使用设备上已经安装的应用打开指定的url。
+
你还可以使用其他类型的URL,比如一个地理位置(形如"geo:37.484847,-122.148386"或是一个通讯录名片,只要是可以通过{@code Intent.ACTION_VIEW}打开的即可。
+
注:如果系统不知道如何处理给定的URL,则此方法会调用失败。如果你传入的URL不是一个http链接,则最好先通过{@code canOpenURL}方法检查一下。
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
+
+
+
static canOpenURL(url: string, callback: Function) #
+
+
判断设备上是否有已经安装的应用可以处理指定的URL。回调函数的参数只有一个:bool supported
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
注:对于iOS 9以上版本,你还需要在Info.plist中添加LSApplicationQueriesSchemes字段。
+
+
+
+
static getInitialURL() #
+
+
+
diff --git a/docs/docs/0.42/listview.md b/docs/docs/0.42/listview.md
new file mode 100644
index 0000000..0476e75
--- /dev/null
+++ b/docs/docs/0.42/listview.md
@@ -0,0 +1,309 @@
+ListView - 一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个`ListView.DataSource`数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个`ListView`组件,并且定义它的`renderRow`回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)。
+
+最简单的例子:
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows(['row 1', 'row 2']),
+ };
+}
+render() {
+ return (
+ {rowData} }
+ />
+ );
+}
+```
+
+ListView还支持一些高级特性,譬如给每段/组(section)数据添加一个带有粘性的头部(类似iPhone的通讯录,其首字母会在滑动过程中吸附在屏幕上方);在列表头部和尾部增加单独的内容;在到达列表尾部的时候调用回调函数(`onEndReached`),还有在视野内可见的数据变化时调用回调函数(`onChangeVisibleRows`),以及一些性能方面的优化。
+
+有一些性能优化使得ListView可以滚动的更加平滑,尤其是在动态加载可能很大(或者概念上无限长的)数据集的时候:
+
+* 只更新变化的行 - 提供给数据源的rowHasChanged函数可以告诉ListView它是否需要重绘一行数据(即:数据是否发生了变化)参见ListViewDataSource
+* 限制频率的行渲染 - 默认情况下,每次消息循环只有一行会被渲染(可以用`pageSize`属性配置)。这把较大的工作分散成小的碎片,以降低因为渲染而导致丢帧的可能性。
+
+### 截图
+
+
+
+
+
+
+### 属性
+
+
+
+
+
+
译注:这意味着ListView可以使用所有ScrollView的属性。
+
+
+
+
dataSource ListViewDataSource #
+
+
+
+
initialListSize number #
+
+
指定在组件刚挂载的时候渲染多少行数据。用这个属性来确保首屏显示合适数量的数据,而不是花费太多帧逐步显示出来。
+
+
+
+
onChangeVisibleRows function #
+
+
(visibleRows, changedRows) => void
+
当可见的行的集合变化的时候调用此回调函数。visibleRows 以 { sectionID: { rowID: true }}的格式包含了所有可见行,而changedRows 以{ sectionID: { rowID: true | false }}的格式包含了所有刚刚改变了可见性的行,其中如果值为true表示一个行变得可见,而为false表示行刚刚离开可视区域而变得不可见。
+
+
+
+
onEndReached function #
+
+
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。
+
+
+
+
onEndReachedThreshold number #
+
+
调用onEndReached之前的临界值,单位是像素。
+
+
+
+
+
removeClippedSubviews bool #
+
+
用于提升大列表的滚动性能。需要给行容器添加样式overflow:'hidden'。(Android已默认添加此样式)。此属性默认开启。
+
+
+
+
renderFooter function #
+
+
() => renderable
+
页头与页脚会在每次渲染过程中都重新渲染(如果提供了这些属性)。如果它们重绘的性能开销很大,把他们包装到一个StaticContainer或者其它恰当的结构中。页脚会永远在列表的最底部,而页头会在最顶部。
+
+
+
+
renderHeader function #
+
+
+
renderRow function #
+
+
(rowData, sectionID, rowID, highlightRow) => renderable
+
从数据源(Data source)中接受一条数据,以及它和它所在section的ID。返回一个可渲染的组件来为这行数据进行渲染。默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。
+
如果某一行正在被高亮(通过调用highlightRow函数),ListView会得到相应的通知。当一行被高亮时,其两侧的分割线会被隐藏。行的高亮状态可以通过调用highlightRow(null)来重置。
+
+
+
+
renderScrollComponent function #
+
+
(props) => renderable
+
指定一个函数,在其中返回一个可以滚动的组件。ListView将会在该组件内部进行渲染。默认情况下会返回一个包含指定属性的ScrollView。
+
+
+
+
renderSectionHeader function #
+
+
(sectionData, sectionID) => renderable
+
如果提供了此函数,会为每个小节(section)渲染一个粘性的标题。
+
粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。
+
+
+
+
renderSeparator function #
+
+
(sectionID, rowID, adjacentRowHighlighted) => renderable
+
如果提供了此属性,一个可渲染的组件会被渲染在每一行下面,除了小节标题的前面的最后一行。在其上方的小节ID和行ID,以及邻近的行是否被高亮会作为参数传递进来。
+
+
+
+
scrollRenderAheadDistance number #
+
+
当一个行接近屏幕范围多少像素之内的时候,就开始渲染这一行。
+
+
+
+
ios stickyHeaderIndices [number] #
+
+
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。举个例子,传递stickyHeaderIndices={[0]}会让第一个成员固定在滚动视图顶端。这个属性不能和horizontal={true}一起使用。
+
+
+
+
+### 方法
+
+
+
+
scrollTo(...args)
+ #
+
+
+
scrollToEnd(options?) #
+
+
滚动到视图底部(水平方向的视图则滚动到最右边)。
加上动画参数 scrollToEnd({animated: true})则启用平滑滚动动画,或是调用
+scrollToEnd({animated: false})来立即跳转。如果不使用参数,则animated选项默认启用。
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ ListView,
+ TouchableHighlight,
+ StyleSheet,
+ RecyclerViewBackedScrollView,
+ Text,
+ View,
+} = ReactNative;
+
+var UIExplorerPage = require('./UIExplorerPage');
+
+var ListViewSimpleExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Performant, scrollable list of data.'
+ },
+
+ getInitialState: function() {
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ return {
+ dataSource: ds.cloneWithRows(this._genRows({})),
+ };
+ },
+
+ _pressData: ({}: {[key: number]: boolean}),
+
+ componentWillMount: function() {
+ this._pressData = {};
+ },
+
+ render: function() {
+ return (
+ '}
+ noSpacer={true}
+ noScroll={true}>
+ }
+ renderSeparator={this._renderSeperator}
+ />
+
+ );
+ },
+
+ _renderRow: function(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
+ var rowHash = Math.abs(hashCode(rowData));
+ var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
+ return (
+ {
+ this._pressRow(rowID);
+ highlightRow(sectionID, rowID);
+ }}>
+
+
+
+
+ {rowData + ' - ' + LOREM_IPSUM.substr(0, rowHash % 301 + 10)}
+
+
+
+
+ );
+ },
+
+ _genRows: function(pressData: {[key: number]: boolean}): Array {
+ var dataBlob = [];
+ for (var ii = 0; ii < 100; ii++) {
+ var pressedText = pressData[ii] ? ' (pressed)' : '';
+ dataBlob.push('Row ' + ii + pressedText);
+ }
+ return dataBlob;
+ },
+
+ _pressRow: function(rowID: number) {
+ this._pressData[rowID] = !this._pressData[rowID];
+ this.setState({dataSource: this.state.dataSource.cloneWithRows(
+ this._genRows(this._pressData)
+ )});
+ },
+
+ _renderSeperator: function(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
+ return (
+
+ );
+ }
+});
+
+var THUMB_URLS = [
+ require('./Thumbnails/like.png'),
+ require('./Thumbnails/dislike.png'),
+ require('./Thumbnails/call.png'),
+ require('./Thumbnails/fist.png'),
+ require('./Thumbnails/bandaged.png'),
+ require('./Thumbnails/flowers.png'),
+ require('./Thumbnails/heart.png'),
+ require('./Thumbnails/liking.png'),
+ require('./Thumbnails/party.png'),
+ require('./Thumbnails/poke.png'),
+ require('./Thumbnails/superlike.png'),
+ require('./Thumbnails/victory.png'),
+ ];
+var LOREM_IPSUM = 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';
+
+/* eslint no-bitwise: 0 */
+var hashCode = function(str) {
+ var hash = 15;
+ for (var ii = str.length - 1; ii >= 0; ii--) {
+ hash = ((hash << 5) - hash) + str.charCodeAt(ii);
+ }
+ return hash;
+};
+
+var styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ padding: 10,
+ backgroundColor: '#F6F6F6',
+ },
+ thumb: {
+ width: 64,
+ height: 64,
+ },
+ text: {
+ flex: 1,
+ },
+});
+
+module.exports = ListViewSimpleExample;
+```
diff --git a/docs/docs/0.42/listviewdatasource.md b/docs/docs/0.42/listviewdatasource.md
new file mode 100644
index 0000000..7aa981e
--- /dev/null
+++ b/docs/docs/0.42/listviewdatasource.md
@@ -0,0 +1,106 @@
+`ListViewDataSource`为`ListView`组件提供高性能的数据处理和访问。我们需要调用方法从原始输入数据中抽取数据来创建`ListViewDataSource`对象,并用其进行数据变更的比较。原始输入数据可以是简单的字符串数组,也可以是复杂嵌套的对象——分不同区(section)各自包含若干行(row)数据。
+
+要更新datasource中的数据,请(每次都重新)调用`cloneWithRows`方法(如果用到了section,则对应`cloneWithRowsAndSections`方法)。数据源中的数据本身是不可修改的,所以请勿直接尝试修改。clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。
+
+在下面这个例子中,一个组件在分块接受数据,这些数据由`_onDataArrived`方法处理——将新数据拼接(concat)到旧数据尾部,同时使用clone方法更新DataSource。我们使用concat方法来修改`this._data`以创建新数组,注意不能使用push方法拼接数组。实现`_rowHasChanged`方法需要透彻了解行数据的结构,以便提供高效的比对策略。
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ ds,
+ };
+ this._data = [];
+}
+
+_onDataArrived = (newData) => {
+ this._data = this._data.concat(newData);
+ this.setState({
+ ds: this.state.ds.cloneWithRows(this._data)
+ });
+};
+```
+
+
+### 方法
+
+
constructor(params)
+ #
+
你可以在构造函数中针对section标题和行数据提供自定义的提取方法和hasChanged比对方法。如果不提供,则会使用默认的defaultGetRowData和defaultGetSectionHeaderData方法来提取行数据和section标题。
+
默认的提取函数可以处理下列形式的数据:
+
{ sectionID_1: { rowID_1: rowData1, ... }, ... }
+
或者:
+
{ sectionID_1: [ rowData1, rowData2, ... ], ... }
+
或者:
+
[ [ rowData1, rowData2, ... ], ... ]
+
构造函数可以接受下列四种参数(都是可选):
+
+ getRowData(dataBlob, sectionID, rowID);
+ getSectionHeaderData(dataBlob, sectionID);
+ rowHasChanged(prevRowData, nextRowData);
+ sectionHeaderHasChanged(prevSectionData, nextSectionData);
+
+
+
+
cloneWithRows(dataBlob, rowIdentities) #
+
+
根据指定的dataBlob和
+ rowIdentities为ListViewDataSource复制填充数据。dataBlob即原始数据。需要在初始化时定义抽取函数(否则使用默认的抽取函数)。
+
rowIdentities是一个二维数组,包含了行数据对应的id标识符,例如[['a1', 'a2'], ['b1', 'b2', 'b3'], ...]。如果没有指定此数组,则默认取行数据的key。
+
注:此方法实际并没有 复制数据。它只是重新创建一个datasource,然后将你指定的dataBlob传递给构造函数中指定的提取函数,因而会抛弃先前的数据。如果你希望保留先前的数据,则必须先自行进行新老数据的合并处理,然后再将合并后的结果作为dataBlob传递给此方法调用。
+
+
cloneWithRowsAndSections(dataBlob, sectionIdentities, rowIdentities) #
+
+
此方法作用基本等同cloneWithRows,区别在于可以额外指定sectionIdentities 。如果你不需要section,则直接使用cloneWithRows即可。
+
sectionIdentities同理是包含了section标识符的数组。例如['s1', 's2', ...]。如果没有指定此数组,则默认取section的key。
+
注:此方法会返回新的对象!
+
+
+
getRowAndSectionCount() #
+
rowShouldUpdate(sectionIndex, rowIndex) #
+
+
+
+
getRowData(sectionIndex, rowIndex)
+ #
+
返回渲染行所需的数据(指定如何从原始dataBlob中提取数据)。
+
+
getRowIDForFlatIndex(index) #
+
给定索引值,求其对应rowID。如果查找不到则返回null。
+
+
getSectionIDForFlatIndex(index) #
+
给定索引值,求其对应sectionID。如果查找不到则返回null。
+
+
getSectionLengths() #
+
+
+
+
sectionHeaderShouldUpdate(sectionIndex) #
+
+
返回值用于说明section标题是否需要重新渲染。
+
+
getSectionHeaderData(sectionIndex) #
+
+
+
+
diff --git a/docs/docs/0.42/mapview.md b/docs/docs/0.42/mapview.md
new file mode 100644
index 0000000..75ad320
--- /dev/null
+++ b/docs/docs/0.42/mapview.md
@@ -0,0 +1,567 @@
+官方建议使用[react-native-maps](https://github.com/airbnb/react-native-maps)代替此地图组件。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
ios annotations [{latitude: number, longitude: number, animateDrop: bool, title: string, subtitle: string, hasLeftCallout: bool, hasRightCallout: bool, onLeftCalloutPress: function, onRightCalloutPress: function, id: string}] #
+
+
+
+
ios legalLabelInsets {top: number, left: number, bottom: number, right: number} #
+
+
地图上标签的合法范围。默认在地图底部左侧。参见EdgeInsetsPropType.js了解更多信息。
+
+
+
+
ios mapType enum('standard', 'satellite', 'hybrid') #
+
+
要显示的地图类型。
+
+ standard: 标准道路地图(默认)。
+ satellite: 卫星视图。
+ hybrid: 卫星视图并附带道路和感兴趣的点标记。
+
+
+
+
+
ios maxDelta number #
+
+
+
+
ios minDelta number #
+
+
+
+
ios overlays [{coordinates: [{latitude: number, longitude: number}], lineWidth: number, strokeColor: ColorPropType, fillColor: ColorPropType, id: string}] #
+
+
+
onAnnotationPress function #
+
+
当用户点击地图上的标注之后会调用此回调函数一次。
+
+
+
+
onRegionChange function #
+
+
+
+
onRegionChangeComplete function #
+
+
当用户停止拖拽地图之后,调用此回调函数一次。
+
+
+
+
pitchEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的抬起角度会使地图平面倾斜。当此属性设为false,镜头的抬起角度会忽略,地图永远都显示为俯视角度。
+
+
+
+
region {latitude: number, longitude: number, latitudeDelta: number, longitudeDelta: number} #
+
+
地图显示的区域。
+
区域使用中心的坐标和要显示的范围来定义。
+
+
+
+
rotateEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的朝向角度会用于基于中心点旋转地图平面。当此属性设置为false时,朝向角度会被忽略,并且地图永远都显示为顶部方向为正北方。
+
+
+
+
scrollEnabled bool #
+
+
如果此属性设为false,用户不能改变地图所显示的区域。默认值为true。
+
+
+
+
showsUserLocation bool #
+
+
如果此属性为true,应用会请求用户当前的位置并且聚焦到该位置。默认值是false。
+
注意 :你需要在Info.plist中增加NSLocationWhenInUseUsageDescription字段。否则它会没有任何提示而直接失败 !
+
+
+
+
+
zoomEnabled bool #
+
+
如果此属性为false,用户则不能旋转/缩放地图。默认值为true。
+
+
+
+
+
ios showsCompass bool #
+
+
如果此属性为false,地图上不会显示指南针。默认值为true。
+
+
+
+
ios showsPointsOfInterest bool #
+
+
如果此属性为false,感兴趣的点不会在地图上显示。默认为true。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var { PropTypes } = React;
+var {
+ Image,
+ MapView,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ View,
+} = ReactNative;
+
+var regionText = {
+ latitude: '0',
+ longitude: '0',
+ latitudeDelta: '0',
+ longitudeDelta: '0',
+};
+
+var MapRegionInput = React.createClass({
+
+ propTypes: {
+ region: PropTypes.shape({
+ latitude: PropTypes.number.isRequired,
+ longitude: PropTypes.number.isRequired,
+ latitudeDelta: PropTypes.number,
+ longitudeDelta: PropTypes.number,
+ }),
+ onChange: PropTypes.func.isRequired,
+ },
+
+ getInitialState() {
+ return {
+ region: {
+ latitude: 0,
+ longitude: 0,
+ }
+ };
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ this.setState({
+ region: nextProps.region || this.getInitialState().region
+ });
+ },
+
+ render: function() {
+ var region = this.state.region || this.getInitialState().region;
+ return (
+
+
+
+ {'Latitude'}
+
+
+
+
+
+ {'Longitude'}
+
+
+
+
+
+ {'Latitude delta'}
+
+
+
+
+
+ {'Longitude delta'}
+
+
+
+
+
+ {'Change'}
+
+
+
+ );
+ },
+
+ _onChangeLatitude: function(e) {
+ regionText.latitude = e.nativeEvent.text;
+ },
+
+ _onChangeLongitude: function(e) {
+ regionText.longitude = e.nativeEvent.text;
+ },
+
+ _onChangeLatitudeDelta: function(e) {
+ regionText.latitudeDelta = e.nativeEvent.text;
+ },
+
+ _onChangeLongitudeDelta: function(e) {
+ regionText.longitudeDelta = e.nativeEvent.text;
+ },
+
+ _change: function() {
+ this.setState({
+ region: {
+ latitude: parseFloat(regionText.latitude),
+ longitude: parseFloat(regionText.longitude),
+ latitudeDelta: parseFloat(regionText.latitudeDelta),
+ longitudeDelta: parseFloat(regionText.longitudeDelta),
+ },
+ });
+ this.props.onChange(this.state.region);
+ },
+
+});
+
+var MapViewExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ mapRegion: undefined,
+ mapRegionInput: undefined,
+ annotations: [],
+ };
+ },
+
+ render() {
+ return (
+
+
+
+
+ );
+ },
+
+ _getAnnotations(region) {
+ return [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ title: 'You Are Here',
+ }];
+ },
+
+ _onRegionChange(region) {
+ this.setState({
+ mapRegionInput: region,
+ });
+ },
+
+ _onRegionChangeComplete(region) {
+ if (this.state.isFirstLoad) {
+ this.setState({
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ isFirstLoad: false,
+ });
+ }
+ },
+
+ _onRegionInputChanged(region) {
+ this.setState({
+ mapRegion: region,
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ });
+ },
+
+});
+
+var AnnotationExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ this.setState({
+ isFirstLoad: false,
+ annotations: [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ ...this.props.annotation,
+ }],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var DraggableAnnotationExample = React.createClass({
+
+ createAnnotation(longitude, latitude) {
+ return {
+ longitude,
+ latitude,
+ draggable: true,
+ onDragStateChange: (event) => {
+ if (event.state === 'idle') {
+ this.setState({
+ annotations: [this.createAnnotation(event.longitude, event.latitude)],
+ });
+ }
+ console.log('Drag state: ' + event.state);
+ },
+ };
+ },
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ //When the MapView loads for the first time, we can create the annotation at the
+ //region that was loaded.
+ this.setState({
+ isFirstLoad: false,
+ annotations: [this.createAnnotation(region.longitude, region.latitude)],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var styles = StyleSheet.create({
+ map: {
+ height: 150,
+ margin: 10,
+ borderWidth: 1,
+ borderColor: '#000000',
+ },
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ textInput: {
+ width: 150,
+ height: 20,
+ borderWidth: 0.5,
+ borderColor: '#aaaaaa',
+ fontSize: 13,
+ padding: 4,
+ },
+ changeButton: {
+ alignSelf: 'center',
+ marginTop: 5,
+ padding: 3,
+ borderWidth: 0.5,
+ borderColor: '#777777',
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Base component to display maps';
+exports.examples = [
+ {
+ title: 'Map',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'showsUserLocation + followUserLocation',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Callout example',
+ render() {
+ return {
+ alert('You Are Here');
+ }}>
+
+
+ ),
+ }}/>;
+ }
+ },
+ {
+ title: 'Annotation focus example',
+ render() {
+ return {
+ alert('Annotation gets focus');
+ },
+ onBlur: () => {
+ alert('Annotation lost focus');
+ }
+ }}/>;
+ }
+ },
+ {
+ title: 'Draggable pin',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin color',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin image',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin view',
+ render() {
+ return
+
+ Thumbs Up!
+
+
+ ,
+ }}/>;
+ }
+ },
+ {
+ title: 'Custom overlay',
+ render() {
+ return ;
+ }
+ },
+];
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/modal.md b/docs/docs/0.42/modal.md
new file mode 100644
index 0000000..d99b00a
--- /dev/null
+++ b/docs/docs/0.42/modal.md
@@ -0,0 +1,298 @@
+Modal组件可以用来覆盖包含React Native根视图的原生视图(如UIViewController,Activity)。
+
+在嵌入React Native的混合应用中可以使用Modal。Modal可以使你应用中RN编写的那部分内容覆盖在原生视图上显示。
+
+```js
+import React, { Component } from 'react';
+import { Modal, Text, TouchableHighlight, View } from 'react-native';
+
+class ModalExample extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {modalVisible: false};
+ }
+
+ setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ }
+
+ render() {
+ return (
+
+ {alert("Modal has been closed.")}}
+ >
+
+
+ Hello World!
+
+ {
+ this.setModalVisible(!this.state.modalVisible)
+ }}>
+ Hide Modal
+
+
+
+
+
+
+ {
+ this.setModalVisible(true)
+ }}>
+ Show Modal
+
+
+
+ );
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
animationType PropTypes.oneOf(['none', 'slide', 'fade']) #
+
+
The animationType prop controls how the modal animates.
+
+ slide slides in from the bottom
+ fade fades into view
+ none appears without an animation
+
+
+
+
onRequestClose Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func #
+
+
The onRequestClose prop allows passing a function that will be called once the modal has been dismissed.
+
On the Android platform, this is a required function.
+
+
+
onShow function #
+
+
The onShow prop allows passing a function that will be called once the modal has been shown.
+
+
+
transparent bool
+ #
+
+
The transparent prop determines whether your modal will fill the entire view. Setting this to true will render the modal over a transparent background.
+
+
+
visible bool #
+
The visible prop determines whether your modal is visible.
+
+
+
ios onOrientationChange PropTypes.func
+ #
+
+
The onOrientationChange callback is called when the orientation changes while the modal is being displayed.
+ The orientation provided is only 'portrait' or 'landscape'. This callback is also called on initial render, regardless of the current orientation.
+
+
+
+
ios supportedOrientations PropTypes.arrayOf(PropTypes.oneOf(['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right']))
+ #
+
+
+
The supportedOrientations prop allows the modal to be rotated to any of the specified orientations. On iOS, the modal is still restricted by what's specified in your app's Info.plist's UISupportedInterfaceOrientations field.
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Modal,
+ StyleSheet,
+ Switch,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Component for presenting modal views.';
+
+var Button = React.createClass({
+ getInitialState() {
+ return {
+ active: false,
+ };
+ },
+
+ _onHighlight() {
+ this.setState({active: true});
+ },
+
+ _onUnhighlight() {
+ this.setState({active: false});
+ },
+
+ render() {
+ var colorStyle = {
+ color: this.state.active ? '#fff' : '#000',
+ };
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var ModalExample = React.createClass({
+ getInitialState() {
+ return {
+ animationType: 'none',
+ modalVisible: false,
+ transparent: false,
+ };
+ },
+
+ _setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ },
+
+ _setAnimationType(type) {
+ this.setState({animationType: type});
+ },
+
+ _toggleTransparent() {
+ this.setState({transparent: !this.state.transparent});
+ },
+
+ render() {
+ var modalBackgroundStyle = {
+ backgroundColor: this.state.transparent ? 'rgba(0, 0, 0, 0.5)' : '#f5fcff',
+ };
+ var innerContainerTransparentStyle = this.state.transparent
+ ? {backgroundColor: '#fff', padding: 20}
+ : null;
+ var activeButtonStyle = {
+ backgroundColor: '#ddd'
+ };
+
+ return (
+
+ {this._setModalVisible(false)}}
+ >
+
+
+ This modal was presented {this.state.animationType === 'none' ? 'without' : 'with'} animation.
+
+ Close
+
+
+
+
+
+ Animation Type
+
+ none
+
+
+ slide
+
+
+ fade
+
+
+
+
+ Transparent
+
+
+
+
+ Present
+
+
+ );
+ },
+});
+
+exports.examples = [
+ {
+ title: 'Modal Presentation',
+ description: 'Modals can be presented with or without animation',
+ render: () => ,
+ },
+];
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ padding: 20,
+ },
+ innerContainer: {
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+ row: {
+ alignItems: 'center',
+ flex: 1,
+ flexDirection: 'row',
+ marginBottom: 20,
+ },
+ rowTitle: {
+ flex: 1,
+ fontWeight: 'bold',
+ },
+ button: {
+ borderRadius: 5,
+ flex: 1,
+ height: 44,
+ alignSelf: 'stretch',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ },
+ buttonText: {
+ fontSize: 18,
+ margin: 5,
+ textAlign: 'center',
+ },
+ modalButton: {
+ marginTop: 10,
+ },
+});
+```
diff --git a/docs/docs/0.42/more-resources.md b/docs/docs/0.42/more-resources.md
new file mode 100644
index 0000000..6735969
--- /dev/null
+++ b/docs/docs/0.42/more-resources.md
@@ -0,0 +1,43 @@
+如果你耐心的读完并理解了本网站上的所有文档,那么你应该已经可以编写一个像样的React Native应用了。但是React Native并不全是某一家公司的作品——它汇聚了成千上万开源社区开发者的智慧结晶。如果你想深入研究React Native,那么建议不要错过下面这些参考资源。
+
+## 常用的第三方库
+
+如果你正在使用React Native,那你应该已经对[React](https://facebook.github.io/react/)有一定的了解了。React是基础中的基础所以我其实不太好意思提这个——但是,如果不幸你属于“但是”,那么请一定先了解下React,它也非常适合编写现代化的网站。
+
+开发实践中的一个常见问题就是如何管理应用的“状态(state)”。这方面目前最流行的库非[Redux](http://redux.js.org/)莫属了。不要被Redux中经常出现的类似"reducer"这样的概念术语给吓住了——它其实是个很简单的库,网上也有很多优秀的[视频教程(英文)](https://egghead.io/courses/getting-started-with-redux) 。。
+
+如果你在寻找具有某个特定功能的第三方库,那么可以看看别人[精心整理的资源列表](https://github.com/jondot/awesome-react-native)。这里还有个类似的[中文资源列表](https://github.com/reactnativecn/react-native-guide)。
+
+## 示例应用
+
+在[React Native Playground](https://rnplay.org/apps/picks)网站上有很多示例的代码。这个网站有个很酷的特性:它直接对接了真实设备,可以实时在网页上显示运行效果。当然,对于国内用户来说,可能访问很困难。
+
+另外就是Facebook的F8开发大会有一个对应的app,这个app现在已经[开源](https://github.com/fbsamples/f8app),其开发者还详细地撰写了[相关教程](http://f8-app.liaohuqiu.net/#content)。如果你想学习一个更实际更有深度的例子,那你应该看看这个。
+
+## 开发工具
+
+[Nuclide](https://nuclide.io/)是Facebook内部所使用的React Native开发工具。它最大的特点是自带调试功能,并且非常好地支持flow语法规则。(译注:然而我们还是推荐webstorm或是sublime text)。
+
+[Ignite](https://github.com/infinitered/ignite)是一套整合了Redux以及一些常见UI组件的脚手架。它带有一个命令行可以生成app、组件或是容器。如果你喜欢它的选择搭配,那么不妨一试。
+
+[CodePush](https://microsoft.github.io/code-push/)是由微软提供的热更新服务。热更新可以使你绕过AppStore的审核机制,直接修改已经上架的应用。对于国内用户,我们也推荐由本网站提供的[Pushy](http://update.reactnative.cn)热更新服务,相比CodePush来说,提供了全中文的文档和技术支持,服务器部署在国内速度更快,还提供了全自动的差量更新方式,大幅节约更新流量,欢迎朋友们试用和反馈意见!
+
+[Exponent](http://docs.getexponent.com/versions/v6.0.0/index.html)是一套开发环境,还带有一个已上架的空应用容器。这样你可以在没有原生开发平台(Xcode或是Android Studio)的情况下直接编写React Native应用(当然这样你只能写js部分代码而没法写原生代码)。
+
+[Deco](https://www.decosoftware.com/)是一个专为React Native设计的集成开发环境。它可以自动创建新项目、搜索开源组件并插入到项目中。你还可以实时地可视化地调整应用的界面。不过目前还只支持mac。
+
+## React Native的交流社区
+
+以下这些都是英文的交流区,我也就不翻译了……
+
+The [React Native Community](https://www.facebook.com/groups/react.native.community) Facebook group has thousands of developers, and it's pretty active. Come there to show off your project, or ask how other people solved similar problems.
+
+[Reactiflux](https://discord.gg/0ZcbPKXt5bZjGY5n) is a Discord chat where a lot of React-related discussion happens, including React Native. Discord is just like Slack except it works better for open source projects with a zillion contributors. Check out the #react-native channel.
+
+The [React Twitter account](https://twitter.com/reactjs) covers both React and React Native. Following that account is a pretty good way to find out what's happening in the world of React.
+
+There are a lot of [React Native Meetups](http://www.meetup.com/topics/react-native/) that happen around the world. Often there is React Native content in React meetups as well.
+
+Sometimes we have React conferences. We posted the [videos from React.js Conf 2016](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY), and we'll probably have more conferences in the future, too. Stay tuned.
+
+欢迎朋友们在下方评论区分享中文教程和资源。
\ No newline at end of file
diff --git a/docs/docs/0.42/native-component-android.md b/docs/docs/0.42/native-component-android.md
new file mode 100644
index 0000000..714423f
--- /dev/null
+++ b/docs/docs/0.42/native-component-android.md
@@ -0,0 +1,172 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对Android编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`ImageView`组件的具体实现。
+
+## ImageView样例
+
+在这个例子里,我们来看看为了让JavaScript中可以使用ImageView,需要做哪些准备工作。
+
+原生视图需要被一个`ViewManager`的派生类(或者更常见的,`SimpleViewManage`的派生类)创建和管理。一个`SimpleViewManager`可以用于这个场景,是因为它能够包含更多公共的属性,譬如背景颜色、透明度、Flexbox布局等等。
+
+这些子类本质上都是单例——React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`NativeViewHierarchyManager`,NativeViewHierarchyManager则会反过来委托它们在需要的时候去设置和更新视图的属性。`ViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+1. 创建一个ViewManager的子类。
+2. 实现`createViewInstance`方法。
+3. 导出视图的属性设置器:使用`@ReactProp`(或`@ReactPropGroup`)注解。
+4. 把这个视图管理类注册到应用程序包的`createViewManagers`里。
+5. 实现JavaScript模块。
+
+## 1. 创建`ViewManager`的子类
+
+在这个例子里我们创建一个视图管理类`ReactImageManager`,它继承自`SimpleViewManager`。`ReactImageView`是这个视图管理类所管理的对象类型,这应当是一个自定义的原生视图。`getName`方法返回的名字会用于在JavaScript端引用这个原生视图类型。
+
+```java
+...
+
+public class ReactImageManager extends SimpleViewManager {
+
+ public static final String REACT_CLASS = "RCTImageView";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+```
+
+## 2. 实现方法`createViewInstance`
+
+视图在`createViewInstance`中创建,且应当把自己初始化为默认的状态。所有属性的设置都通过后续的`updateView`来进行。
+
+```java
+ @Override
+ public ReactImageView createViewInstance(ThemedReactContext context) {
+ return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext);
+ }
+```
+
+## 3. 通过`@ReactProp`(或`@ReactPropGroup`)注解来导出属性的设置方法。
+
+要导出给JavaScript使用的属性,需要申明带有`@ReactProp`(或`@ReactPropGroup`)注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为`void`,而且访问控制必须被声明为`public`。JavaScript所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:`boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`。
+
+`@ReactProp`注解必须包含一个字符串类型的参数`name`。这个参数指定了对应属性在JavaScript端的名字。
+
+除了`name`,`@ReactProp`注解还接受这些可选的参数:`defaultBoolean`, `defaultInt`, `defaultFloat`。这些参数必须是对应的基础类型的值(也就是`boolean`, `int`, `float`),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。注意这个"默认"值只对基本类型生效,对于其他的类型而言,当对应的属性删除时,`null`会作为默认值提供给方法。
+
+使用`@ReactPropGroup`来注解的设置方法和`@ReactProp`不同。请参见`@ReactPropGroup`注解类源代码中的文档来获取更多详情。
+
+**重要!** 在ReactJS里,修改一个属性会引发一次对设置方法的调用。有一种修改情况是,移除掉之前设置的属性。在这种情况下设置方法也一样会被调用,并且“默认”值会被作为参数提供(对于基础类型来说可以通过`defaultBoolean`、`defaultFloat`等`@ReactProp`的属性提供,而对于复杂类型来说参数则会设置为`null`)
+
+```java
+ @ReactProp(name = "src")
+ public void setSrc(ReactImageView view, @Nullable String src) {
+ view.setSource(src);
+ }
+
+ @ReactProp(name = "borderRadius", defaultFloat = 0f)
+ public void setBorderRadius(ReactImageView view, float borderRadius) {
+ view.setBorderRadius(borderRadius);
+ }
+
+ @ReactProp(name = ViewProps.RESIZE_MODE)
+ public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
+ view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
+ }
+```
+
+## 4. 注册`ViewManager`
+
+在Java中的最后一步就是把视图控制器注册到应用中。这和[原生模块](NativeModulesAndroid.md)的注册方法类似,唯一的区别是我们把它放到`createViewManagers`方法的返回值里。
+
+```java
+ @Override
+ public List createViewManagers(
+ ReactApplicationContext reactContext) {
+ return Arrays.asList(
+ new ReactImageManager()
+ );
+ }
+```
+
+## 5. 实现对应的JavaScript模块
+
+整个过程的最后一步就是创建JavaScript模块并且定义Java和JavaScript之间的接口层。大部分过程都由React底层的Java和JavaScript代码来完成,你所需要做的就是通过`propTypes`来描述属性的类型。
+
+```js
+// ImageView.js
+
+import { PropTypes } from 'react';
+import { requireNativeComponent, View } from 'react-native';
+
+var iface = {
+ name: 'ImageView',
+ propTypes: {
+ src: PropTypes.string,
+ borderRadius: PropTypes.number,
+ resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
+ ...View.propTypes // 包含默认的View的属性
+ },
+};
+
+module.exports = requireNativeComponent('RCTImageView', iface);
+```
+
+`requireNativeComponent`通常接受两个参数,第一个参数是原生视图的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的`name`,用来在调试信息中显示;组件接口还必须声明`propTypes`字段,用来对应到原生视图上。这个`propTypes`还可以用来检查用户使用View的方式是否正确。
+
+注意,如果你还需要一个JavaScript组件来做一些除了指定`name`和`propTypes`以外的事情,譬如事件处理,你可以把原生组件用一个普通React组件封装。在这种情况下,`requireNativeComponent`的第二个参数变为用于封装的组件。这个在后文的`MyCustomView`例子里面用到。
+
+_译注_:和原生模块不同,原生视图的前缀RCT不会被自动去掉。
+
+# 事件
+
+现在我们已经知道了怎么导出一个原生视图组件,并且我们可以在JS里很方便的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动?当一个原生事件发生的时候,它应该也能触发JavaScript端视图上的事件,这两个视图会依据getId()而关联在一起。
+
+```java
+class MyCustomView extends View {
+ ...
+ public void onReceiveNativeEvent() {
+ WritableMap event = Arguments.createMap();
+ event.putString("message", "MyMessage");
+ ReactContext reactContext = (ReactContext)getContext();
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
+ getId(),
+ "topChange",
+ event);
+ }
+}
+```
+
+这个事件名`topChange`在JavaScript端映射到`onChange`回调属性上(这个映射关系在`UIManagerModuleConstants.java`文件里)。这个回调会被原生事件执行,然后我们通常会在封装组件里构造一个类似的API:
+
+```js
+// MyCustomView.js
+
+class MyCustomView extends React.Component {
+ constructor() {
+ this._onChange = this._onChange.bind(this);
+ }
+ _onChange(event: Event) {
+ if (!this.props.onChangeMessage) {
+ return;
+ }
+ this.props.onChangeMessage(event.nativeEvent.message);
+ }
+ render() {
+ return ;
+ }
+}
+MyCustomView.propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onChangeMessage: React.PropTypes.func,
+ ...
+};
+
+var RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`, MyCustomView, {
+ nativeOnly: {onChange: true}
+});
+```
+
+注意上面用到了`nativeOnly`。有时候有一些特殊的属性,想从原生组件中导出,但是又不希望它们成为对应React封装组件的属性。举个例子,`Switch`组件可能在原生组件上有一个`onChange`事件,然后在封装类中导出`onValueChange`回调属性。这个属性在调用的时候会带上Switch的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上`nativeOnly`选项。
diff --git a/docs/docs/0.42/native-component-ios.md b/docs/docs/0.42/native-component-ios.md
new file mode 100644
index 0000000..811b8e2
--- /dev/null
+++ b/docs/docs/0.42/native-component-ios.md
@@ -0,0 +1,362 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对iOS编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`MapView`组件的具体实现。
+
+## iOS MapView样例
+
+假设我们要把地图组件植入到我们的App中——我们用到的是[`MKMapView`](https://developer.apple.com/library/prerelease/mac/documentation/MapKit/Reference/MKMapView_Class/index.html),而现在只需要让它可以被Javascript重用。
+
+原生视图都需要被一个`RCTViewManager`的子类来创建和管理。这些管理器在功能上有些类似“视图控制器”,但它们本质上都是单例 - React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`RCTUIManager`,`RCTUIManager`则会反过来委托它们在需要的时候去设置和更新视图的属性。`RCTViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+- 首先创建一个子类
+- 添加`RCT_EXPORT_MODULE()`标记宏
+- 实现`-(UIView *)view`方法
+
+```objective-c
+// RNTMapManager.m
+#import
+
+#import
+
+@interface RNTMapManager : RCTViewManager
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+- (UIView *)view
+{
+ return [[MKMapView alloc] init];
+}
+
+@end
+```
+
+接下来你需要一些Javascript代码来让这个视图变成一个可用的React组件:
+
+```javascript
+// MapView.js
+
+var { requireNativeComponent } = require('react-native');
+
+// requireNativeComponent 自动把这个组件提供给 "RNTMapManager"
+module.exports = requireNativeComponent('RNTMap', null);
+```
+
+现在我们就已经实现了一个完整功能的地图组件了,诸如捏放和其它的手势都已经完整支持。但是现在我们还不能真正的从Javascript端控制它。(╯﹏╰)
+
+## 属性
+
+我们能让这个组件变得更强大的第一件事情就是要能够封装一些原生属性供Javascript使用。举例来说,我们希望能够禁用手指捏放操作,然后指定一个初始的地图可见区域。禁用捏放操作只需要一个布尔值类型的属性就行了,所以我们添加这么一行:
+
+```objective-c
+// RNTMapManager.m
+RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
+```
+
+注意我们现在把类型声明为`BOOL`类型——React Native用`RCTConvert`来在JavaScript和原生代码之间完成类型转换。如果转换无法完成,会产生一个“红屏”的报错提示,这样你就能立即知道代码中出现了问题。如果一切进展顺利,上面这个宏就已经包含了导出属性的全部实现。
+
+现在要想禁用捏放操作,我们只需要在JS里设置对应的属性:
+
+```javascript
+// MyApp.js
+
+```
+
+但这样并不能很好的说明这个组件的用法——用户要想知道我们的组件有哪些属性可以用,以及可以取什么样的值,他不得不一路翻到Objective-C的代码。要解决这个问题,我们可以创建一个封装组件,并且通过`PropTypes`来说明这个组件的接口。
+
+```javascript
+// MapView.js
+import React, { Component, PropTypes } from 'react';
+import { requireNativeComponent } from 'react-native';
+
+var RNTMap = requireNativeComponent('RNTMap', MapView);
+
+export default class MapView extends Component {
+ static propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: PropTypes.bool,
+ };
+ render() {
+ return ;
+ }
+}
+```
+
+_译注_:使用了封装组件之后,你还需要注意到module.exports导出的不再是requireNativeComponent的返回值,而是所创建的包装组件。
+
+现在我们有了一个封装好的组件,还有了一些注释文档,用户使用起来也更方便了。注意我们现在把`requireNativeComponent`的第二个参数从null变成了用于封装的组件`MapView`。这使得React Native的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。
+
+现在,让我们添加一个更复杂些的`region`属性。我们首先添加原生代码:
+
+```objective-c
+// RNTMapManager.m
+RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RNTMap)
+{
+ [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
+}
+```
+
+这段代码比刚才的一个简单的`BOOL`要复杂的多了。现在我们多了一个需要做类型转换的`MKCoordinateRegion`类型,还添加了一部分自定义的代码,这样当我们在JS里改变地图的可视区域的时候,视角会平滑地移动过去。在我们提供的函数体内,`json`代表了JS中传递的尚未解析的原始值。函数里还有一个`view`变量,使得我们可以访问到对应的视图实例。最后,还有一个`defaultView`对象,这样当JS给我们发送null的时候,可以把视图的这个属性重置回默认值。
+
+你可以为视图编写任何你所需要的转换函数——下面就是`MKCoordinateRegion`的转换实现,它通过两个RCTConvert的扩展来完成:
+
+```objective-c
+@implementation RCTConvert(CoreLocation)
+
+RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue);
+RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue);
+
++ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json
+{
+ json = [self NSDictionary:json];
+ return (CLLocationCoordinate2D){
+ [self CLLocationDegrees:json[@"latitude"]],
+ [self CLLocationDegrees:json[@"longitude"]]
+ };
+}
+
+@end
+
+@implementation RCTConvert(MapKit)
+
++ (MKCoordinateSpan)MKCoordinateSpan:(id)json
+{
+ json = [self NSDictionary:json];
+ return (MKCoordinateSpan){
+ [self CLLocationDegrees:json[@"latitudeDelta"]],
+ [self CLLocationDegrees:json[@"longitudeDelta"]]
+ };
+}
+
++ (MKCoordinateRegion)MKCoordinateRegion:(id)json
+{
+ return (MKCoordinateRegion){
+ [self CLLocationCoordinate2D:json],
+ [self MKCoordinateSpan:json]
+ };
+}
+```
+
+这些转换函数被设计为可以安全的处理任何JS扔过来的JSON:当有任何缺少的键或者其它问题发生的时候,显示一个“红屏”的错误提示。
+
+为了完成`region`属性的支持,我们还需要在`propTypes`里添加相应的说明(否则我们会立刻收到一个错误提示),然后就可以像使用其他属性一样使用了:
+
+```javascript
+// MapView.js
+
+MapView.propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: React.PropTypes.bool,
+
+ /**
+ * 地图要显示的区域。
+ *
+ * 区域由中心点坐标和区域范围坐标来定义。
+ *
+ */
+ region: React.PropTypes.shape({
+ /**
+ * 地图中心点的坐标。
+ */
+ latitude: React.PropTypes.number.isRequired,
+ longitude: React.PropTypes.number.isRequired,
+
+ /**
+ * 最小/最大经、纬度间的距离。
+ */
+ latitudeDelta: React.PropTypes.number.isRequired,
+ longitudeDelta: React.PropTypes.number.isRequired,
+ }),
+};
+
+// MyApp.js
+
+ render() {
+ var region = {
+ latitude: 37.48,
+ longitude: -122.16,
+ latitudeDelta: 0.1,
+ longitudeDelta: 0.1,
+ };
+ return ;
+ }
+
+```
+
+现在你可以看到region属性的整个结构已经加上了文档说明——将来可能我们会自动生成一些类似的代码,但目前还没有这样的手段。
+
+有时候你的原生组件有一些特殊的属性希望导出,但并不希望它成为公开的接口。举个例子,`Switch`组件可能会有一个`onChange`属性用来传递原始的原生事件,然后导出一个`onValueChange`属性,这个属性在调用的时候会带上`Switch`的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上额外的`nativeOnly`参数,像这样:
+
+```javascript
+var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
+ nativeOnly: { onChange: true }
+});
+```
+
+## 事件
+
+现在我们已经有了一个原生地图组件,并且从JS可以很容易的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动来改变可视区域?关键的步骤是在`RNTMapManager`中声明一个事件处理函数的属性(onChange),来委托我们提供的所有视图,然后把事件传递给JavaScript。最终的代码看起来类似这样(比起完整的实现有所简化):
+
+```objective-c
+// RNTMap.h
+
+#import
+
+#import
+
+@interface RNTMap: MKMapView
+
+@property (nonatomic, copy) RCTBubblingEventBlock onChange;
+
+@end
+```
+
+```objective-c
+// RNTMap.m
+
+#import "RNTMap.h"
+
+@implementation RNTMap
+
+@end
+```
+
+```objective-c
+#import "RNTMapManager.h"
+
+#import
+
+#import "RNTMap.h"
+#import
+
+@interface RNTMapManager()
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
+
+- (UIView *)view
+{
+ RNTMap *map = [RNTMap new];
+ map.delegate = self;
+ return map;
+}
+
+#pragma mark MKMapViewDelegate
+
+- (void)mapView:(RNTMap *)mapView regionDidChangeAnimated:(BOOL)animated
+{
+ if (!mapView.onChange) {
+ return;
+ }
+
+ MKCoordinateRegion region = mapView.region;
+ mapView.onChange(@{
+ @"region": @{
+ @"latitude": @(region.center.latitude),
+ @"longitude": @(region.center.longitude),
+ @"latitudeDelta": @(region.span.latitudeDelta),
+ @"longitudeDelta": @(region.span.longitudeDelta),
+ }
+ });
+}
+```
+
+如你所见,我们刚才通过继承`MKMapView`添加了事件处理函数,然后我们将`onChange`暴露出来,委托`RNTMapManager`代理其创建的所有视图。最后在委托方法`-mapView:regionDidChangeAnimated:`中,根据对应的视图调用事件处理函数并传递区域数据。调用`onChange`事件会触发JavaScript端的同名回调函数。这个回调会被原生事件执行,然后我们通常都会在封装组件里做一些处理,来使得API更简明:
+
+
+```javascript
+// MapView.js
+
+class MapView extends React.Component {
+ constructor() {
+ this._onChange = this._onChange.bind(this);
+ }
+ _onChange(event: Event) {
+ if (!this.props.onRegionChange) {
+ return;
+ }
+ this.props.onRegionChange(event.nativeEvent.region);
+ }
+ render() {
+ return ;
+ }
+}
+MapView.propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onRegionChange: React.PropTypes.func,
+ ...
+};
+```
+
+## 样式
+
+因为我们所有的视图都是`UIView`的子类,大部分的样式属性应该直接就可以生效。但有一部分组件会希望使用自己定义的默认样式,例如`UIDatePicker`希望自己的大小是固定的。这个默认属性对于布局算法的正常工作来说很重要,但我们也希望在使用这个组件的时候可以覆盖这些默认的样式。`DatePickerIOS`实现这个功能的办法是通过封装一个拥有弹性样式的额外视图,然后在内层的视图上应用一个固定样式(通过原生传递来的常数生成):
+
+```javascript
+// DatePickerIOS.ios.js
+
+var RCTDatePickerIOSConsts = require('react-native').UIManager.RCTDatePicker.Constants;
+...
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ rkDatePickerIOS: {
+ height: RCTDatePickerIOSConsts.ComponentHeight,
+ width: RCTDatePickerIOSConsts.ComponentWidth,
+ },
+});
+```
+
+常量`RCTDatePickerIOSConsts`在原生代码中导出,从一个组件的实际布局上获取到:
+
+```objective-c
+// RCTDatePickerManager.m
+
+- (NSDictionary *)constantsToExport
+{
+ UIDatePicker *dp = [[UIDatePicker alloc] init];
+ [dp layoutIfNeeded];
+
+ return @{
+ @"ComponentHeight": @(CGRectGetHeight(dp.frame)),
+ @"ComponentWidth": @(CGRectGetWidth(dp.frame)),
+ @"DatePickerModes": @{
+ @"time": @(UIDatePickerModeTime),
+ @"date": @(UIDatePickerModeDate),
+ @"datetime": @(UIDatePickerModeDateAndTime),
+ }
+ };
+}
+```
+
+本向导覆盖了包装原生组件所需了解的许多方面,不过你可能还有很多知识需要了解,譬如特殊的方式来插入和布局子视图。如果你想更深入了解,可以阅读`RNTMapManager`和其它的组件的[源代码](https://github.com/facebook/react-native/blob/master/React/Views)。
+
diff --git a/docs/docs/0.42/native-modules-android.md b/docs/docs/0.42/native-modules-android.md
new file mode 100644
index 0000000..7f1c9b0
--- /dev/null
+++ b/docs/docs/0.42/native-modules-android.md
@@ -0,0 +1,431 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块包装;或者你需要复用一些Java代码,而不是用Javascript重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+## Toast模块
+
+本向导会用[Toast](http://developer.android.com/reference/android/widget/Toast.html)作为例子。假设我们希望可以从Javascript发起一个Toast消息(Android中的一种会在屏幕下方弹出、保持一段时间的消息通知)
+
+我们首先来创建一个原生模块。一个原生模块是一个继承了`ReactContextBaseJavaModule`的Java类,它可以实现一些JavaScript所需的功能。我们这里的目标是可以在JavaScript里写`ToastAndroid.show('Awesome', ToastAndroid.SHORT);`,来调起一个Toast通知。
+
+```java
+package com.facebook.react.modules.toast;
+
+import android.widget.Toast;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+import java.util.Map;
+
+public class ToastModule extends ReactContextBaseJavaModule {
+
+ private static final String DURATION_SHORT_KEY = "SHORT";
+ private static final String DURATION_LONG_KEY = "LONG";
+
+ public ToastModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+}
+```
+
+`ReactContextBaseJavaModule`要求派生类实现`getName`方法。这个函数用于返回一个字符串名字,这个名字在JavaScript端标记这个模块。这里我们把这个模块叫做`ToastAndroid`,这样就可以在JavaScript中通过`React.NativeModules.ToastAndroid`访问到这个模块。**译注:RN已经内置了一个名为ToastAndroid的模块,所以如果你在练习时完全照抄,那么运行时会报错名字冲突!所以请在这里选择另外一个名字!**
+
+```java
+ @Override
+ public String getName() {
+ return "ToastAndroid";
+ }
+```
+
+_译注_:模块名前的RCT前缀会被自动移除。所以如果返回的字符串为"RCTToastAndroid",在JavaScript端依然通过`React.NativeModules.ToastAndroid`访问到这个模块。
+
+一个可选的方法`getContants`返回了需要导出给JavaScript使用的常量。它并不一定需要实现,但在定义一些可以被JavaScript同步访问到的预定义的值时非常有用。
+
+```java
+ @Override
+ public Map getConstants() {
+ final Map constants = new HashMap<>();
+ constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
+ constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
+ return constants;
+ }
+```
+
+要导出一个方法给JavaScript使用,Java方法需要使用注解`@ReactMethod`。方法的返回类型必须为`void`。React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件(参见下文的描述)。
+
+```java
+ @ReactMethod
+ public void show(String message, int duration) {
+ Toast.makeText(getReactApplicationContext(), message, duration).show();
+ }
+```
+
+### 参数类型
+
+下面的参数类型在`@ReactMethod`注明的方法中,会被直接映射到它们对应的JavaScript类型。
+
+```
+Boolean -> Bool
+Integer -> Number
+Double -> Number
+Float -> Number
+String -> String
+Callback -> function
+ReadableMap -> Object
+ReadableArray -> Array
+```
+参阅[ReadableMap](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java)和[ReadableArray](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java)。
+
+### 注册模块
+
+在Java这边要做的最后一件事就是注册这个模块。我们需要在应用的Package类的`createNativeModules`方法中添加这个模块。如果模块没有被注册,它也无法在JavaScript中被访问到。
+
+```java
+package com.facebook.react.modules.toast;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AnExampleReactPackage implements ReactPackage {
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createNativeModules(
+ ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new ToastModule(reactContext));
+
+ return modules;
+ }
+```
+
+这个package需要在`MainApplication.java`文件的`getPackages`方法中提供。这个文件位于你的react-native应用文件夹的android目录中。具体路径是: `android/app/src/main/java/com/your-app-name/MainApplication.java`.
+
+```java
+protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new AnExampleReactPackage()); // <-- 添加这一行,类名替换成你的Package类的名字.
+}
+```
+
+为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从`NativeModules`中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。
+
+```javascript
+'use strict';
+
+/**
+ * This exposes the native ToastAndroid module as a JS module. This has a function 'show'
+ * which takes the following parameters:
+ *
+ * 1. String message: A string with the text to toast
+ * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or ToastAndroid.LONG
+ */
+import { NativeModules } from 'react-native';
+
+// 下一句中的ToastAndroid即对应上文
+// public String getName()中返回的字符串
+// 练习时请务必选择另外的名字!
+
+export default NativeModules.ToastAndroid;
+```
+
+现在,在别处的JavaScript代码中可以这样调用你的方法:
+
+```javascript
+import ToastAndroid from './ToastAndroid';
+ToastAndroid.show('Awesome', ToastAndroid.SHORT);
+```
+
+## 更多特性
+
+### 回调函数
+
+原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
+
+```java
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Callback errorCallback,
+ Callback successCallback) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+ float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+ float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+ float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+ float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+ successCallback.invoke(relativeX, relativeY, width, height);
+ } catch (IllegalViewOperationException e) {
+ errorCallback.invoke(e.getMessage());
+ }
+ }
+
+...
+```
+
+这个函数可以在JavaScript里这样使用:
+
+```js
+UIManager.measureLayout(
+ 100,
+ 100,
+ (msg) => {
+ console.log(msg);
+ },
+ (x, y, width, height) => {
+ console.log(x + ':' + y + ':' + width + ':' + height);
+ }
+);
+```
+
+原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。
+
+请务必注意callback并非在对应的原生函数返回后立即被执行——注意跨语言通讯是异步的,这个执行过程会通过消息循环来进行。
+
+## Promises
+
+__译注__:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。
+
+原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的`async/await`语法则效果更佳。如果桥接原生方法的最后一个参数是一个`Promise`,则对应的JS方法就会返回一个Promise对象。
+
+我们把上面的代码用promise来代替回调进行重构:
+
+```java
+import com.facebook.react.bridge.Promise;
+
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Promise promise) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+
+ WritableMap map = Arguments.createMap();
+
+ map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0]));
+ map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1]));
+ map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2]));
+ map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3]));
+
+ promise.resolve(map);
+ } catch (IllegalViewOperationException e) {
+ promise.reject(e.getMessage());
+ }
+ }
+
+...
+```
+
+现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了`async`的异步函数内使用`await`关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
+
+```js
+async function measureLayout() {
+ try {
+ var {
+ relativeX,
+ relativeY,
+ width,
+ height,
+ } = await UIManager.measureLayout(100, 100);
+
+ console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+measureLayout();
+```
+
+### 多线程
+
+原生模块不应对自己被调用时所处的线程做任何假设,当前的状况有可能会在将来的版本中改变。如果一个过程要阻塞执行一段时间,这个工作应当分配到一个内部管理的工作线程,然后从那边可以调用任意的回调函数。_译注_:我们通常用AsyncTask来完成这项工作。
+
+### 发送事件到JavaScript
+
+原生模块可以在没有被调用的情况下往JavaScript发送事件通知。最简单的办法就是通过`RCTDeviceEventEmitter`,这可以通过`ReactContext`来获得对应的引用,像这样:
+
+```java
+...
+private void sendEvent(ReactContext reactContext,
+ String eventName,
+ @Nullable WritableMap params) {
+ reactContext
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit(eventName, params);
+}
+...
+WritableMap params = Arguments.createMap();
+...
+sendEvent(reactContext, "keyboardWillShow", params);
+```
+
+JavaScript模块可以通过使用`DeviceEventEmitter`模块来监听事件:
+
+```js
+import { DeviceEventEmitter } from 'react-native';
+...
+componentWillMount: function() {
+ DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) {
+ // handle event.
+ });
+}
+...
+```
+
+### 从`startActivityForResult`中获取结果
+
+如果你使用`startActivityForResult`调起了一个activity并想从其中获取返回结果,那么你需要监听`onActivityResult`事件。具体的做法是继承`BaseActivityEventListener`或是实现`ActivityEventListener`。我们推荐前一种做法,因为它相对来说不太会受到API变更的影响。然后你需要在模块的构造函数中注册这一监听事件。
+
+```java
+reactContext.addActivityEventListener(mActivityResultListener);
+```
+
+现在你可以通过重写下面的方法来实现对`onActivityResult`的监听:
+
+```java
+@Override
+public void onActivityResult(
+ final Activity activity,
+ final int requestCode,
+ final int resultCode,
+ final Intent intent) {
+ // 在这里实现你自己的逻辑
+}
+```
+
+下面我们写一个简单的图片选择器来实践一下。这个图片选择器会把`pickImage`方法暴露给JavaScript,而这个方法在调用时就会把图片的路径返回到JS端。
+
+```java
+public class ImagePickerModule extends ReactContextBaseJavaModule {
+
+ private static final int IMAGE_PICKER_REQUEST = 467081;
+ private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
+ private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
+ private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
+ private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";
+
+ private Promise mPickerPromise;
+
+ private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
+
+ @Override
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
+ if (requestCode == IMAGE_PICKER_REQUEST) {
+ if (mPickerPromise != null) {
+ if (resultCode == Activity.RESULT_CANCELED) {
+ mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
+ } else if (resultCode == Activity.RESULT_OK) {
+ Uri uri = intent.getData();
+
+ if (uri == null) {
+ mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
+ } else {
+ mPickerPromise.resolve(uri.toString());
+ }
+ }
+
+ mPickerPromise = null;
+ }
+ }
+ }
+ };
+
+ public ImagePickerModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+
+ // Add the listener for `onActivityResult`
+ reactContext.addActivityEventListener(mActivityEventListener);
+ }
+
+ @Override
+ public String getName() {
+ return "ImagePickerModule";
+ }
+
+ @ReactMethod
+ public void pickImage(final Promise promise) {
+ Activity currentActivity = getCurrentActivity();
+
+ if (currentActivity == null) {
+ promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
+ return;
+ }
+
+ // Store the promise to resolve/reject when picker returns data
+ mPickerPromise = promise;
+
+ try {
+ final Intent galleryIntent = new Intent(Intent.ACTION_PICK);
+
+ galleryIntent.setType("image/*");
+
+ final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");
+
+ currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST);
+ } catch (Exception e) {
+ mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
+ mPickerPromise = null;
+ }
+ }
+}
+```
+
+### 监听生命周期事件
+
+监听activity的生命周期事件(比如`onResume`, `onPause`等等)和我们在前面实现 `ActivityEventListener`的做法类似。模块必须实现`LifecycleEventListener`,然后需要在构造函数中注册一个监听函数:
+
+```java
+reactContext.addLifecycleEventListener(this);
+```
+
+现在你可以通过实现下列方法来监听activity的生命周期事件了:
+
+```java
+@Override
+public void onHostResume() {
+ // Activity `onResume`
+}
+
+@Override
+public void onHostPause() {
+ // Activity `onPause`
+}
+
+@Override
+public void onHostDestroy() {
+ // Activity `onDestroy`
+}
+```
diff --git a/docs/docs/0.42/native-modules-ios.md b/docs/docs/0.42/native-modules-ios.md
new file mode 100644
index 0000000..0ffa289
--- /dev/null
+++ b/docs/docs/0.42/native-modules-ios.md
@@ -0,0 +1,453 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块封装;或者你需要复用Objective-C、Swift或C++代码,而不是用JavaScript重新实现一遍;又或者你需要实现某些高性能、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+本文是关于如何封装原生模块的高级向导,我们假设您已经具备Objective-C或者Swift,以及iOS核心库(Foundation、UIKit)的相关知识。
+
+## iOS 日历模块演示
+
+本向导将会用[iOS日历API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html)作为示例。我们的目标就是在Javascript中可以访问到iOS的日历功能。
+
+在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
+
+```objective-c
+// CalendarManager.h
+#import
+#import
+
+@interface CalendarManager : NSObject
+@end
+```
+
+为了实现`RCTBridgeModule`协议,你的类需要包含`RCT_EXPORT_MODULE()`宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。
+
+```objective-c
+// CalendarManager.m
+@implementation CalendarManager
+
+RCT_EXPORT_MODULE();
+
+@end
+```
+
+你必须明确的声明要给Javascript导出的方法,否则React Native不会导出任何方法。声明通过`RCT_EXPORT_METHOD()`宏来实现:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
+{
+ RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
+}
+```
+
+现在从Javascript里可以这样调用这个方法:
+
+```javascript
+import { NativeModules } from 'react-native';
+var CalendarManager = NativeModules.CalendarManager;
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
+```
+
+> **注意**: Javascript方法名
+>
+> 导出到Javascript的方法名是Objective-C的方法名的第一个部分。React Native还定义了一个`RCT_REMAP_METHOD()`宏,它可以指定Javascript方法名。当许多方法的第一部分相同的时候用它来避免在Javascript端的名字冲突。
+
+桥接到Javascript的方法返回值类型必须是`void`。React Native的桥接操作是异步的,所以要返回结果给Javascript,你必须通过回调或者触发事件来进行。(参见本文档后面的部分)
+
+## 参数类型
+
+`RCT_EXPORT_METHOD` 支持所有标准JSON类型,包括:
+
+- string (`NSString`)
+- number (`NSInteger`, `float`, `double`, `CGFloat`, `NSNumber`)
+- boolean (`BOOL`, `NSNumber`)
+- array (`NSArray`) 包含本列表中任意类型
+- object (`NSDictionary`) 包含string类型的键和本列表中任意类型的值
+- function (`RCTResponseSenderBlock`)
+
+除此以外,任何`RCTConvert`类支持的的类型也都可以使用(参见[`RCTConvert`](https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h)了解更多信息)。`RCTConvert`还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。
+
+在我们的`CalendarManager`例子里,我们需要把事件的时间交给原生方法。我们不能在桥接通道里传递Date对象,所以需要把日期转化成字符串或数字来传递。我们可以这么实现原生函数:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)secondsSinceUnixEpoch)
+{
+ NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
+}
+```
+
+或者这样:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString)
+{
+ NSDate *date = [RCTConvert NSDate:ISO8601DateString];
+}
+```
+
+不过我们可以依靠自动类型转换的特性,跳过手动的类型转换,而直接这么写:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSDate *)date)
+{
+ // Date is ready to use!
+}
+```
+
+在Javascript既可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.getTime()); // 把日期以unix时间戳形式传递
+```
+
+也可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.toISOString()); // 把日期以ISO-8601的字符串形式传递
+```
+
+两个值都会被转换为正确的`NSDate`类型。但如果提供一个不合法的值,譬如一个`Array`,则会产生一个“红屏”报错信息。
+
+随着`CalendarManager.addEvent`方法变得越来越复杂,参数的个数越来越多,其中有一些可能是可选的参数。在这种情况下我们应该考虑修改我们的API,用一个dictionary来存放所有的事件参数,像这样:
+
+```objective-c
+#import
+
+RCT_EXPORT_METHOD(addEvent:(NSString *)name details:(NSDictionary *)details)
+{
+ NSString *location = [RCTConvert NSString:details[@"location"]];
+ NSDate *time = [RCTConvert NSDate:details[@"time"]];
+ ...
+}
+```
+
+然后在JS里这样调用:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', {
+ location: '4 Privet Drive, Surrey',
+ time: date.toTime(),
+ description: '...'
+})
+```
+
+> **注意**: 关于数组和映射
+>
+> Objective-C并没有提供确保这些结构体内部值的类型的方式。你的原生模块可能希望收到一个字符串数组,但如果JavaScript在调用的时候提供了一个混合number和string的数组,你会收到一个`NSArray`,里面既有`NSNumber`也有`NSString`。对于数组来说,`RCTConvert`提供了一些类型化的集合,譬如`NSStringArray`或者`UIColorArray`,你可以用在你的函数声明中。对于映射而言,开发者有责任自己调用`RCTConvert`的辅助方法来检测和转换值的类型。
+
+## 回调函数
+
+> **警告**
+>
+> 本章节内容目前还处在实验阶段,因为我们还并没有太多的实践经验来处理回调函数。
+
+原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
+
+```objective-c
+RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback)
+{
+ NSArray *events = ...
+ callback(@[[NSNull null], events]);
+}
+```
+
+`RCTResponseSenderBlock`只接受一个参数——传递给JavaScript回调函数的参数数组。在上面这个例子里我们用Node.js的常用习惯:第一个参数是一个错误对象(没有发生错误的时候为null),而剩下的部分是函数的返回值。
+
+```javascript
+CalendarManager.findEvents((error, events) => {
+ if (error) {
+ console.error(error);
+ } else {
+ this.setState({events: events});
+ }
+})
+```
+
+原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。这在封装那些通过“委托函数”来获得返回值的iOS API时最为常见。[`RCTAlertManager`](https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m)中就属于这种情况。
+
+如果你想传递一个更接近`Error`类型的对象给Javascript,可以用[`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h)提供的`RCTMakeError`函数。现在它仅仅是发送了一个和Error结构一样的dictionary给Javascript,但我们考虑在将来版本里让它产生一个真正的`Error`对象。
+
+> **注意**
+>
+> 如果你传递了回调函数,那么在原生端就必须执行它(如果传递了两个,比如onSuccess和onFail,那么执行其中一个即可),否则会导致内存泄漏。
+
+## Promises
+
+__译注__:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。
+
+原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的`async/await`语法则效果更佳。如果桥接原生方法的最后两个参数是`RCTPromiseResolveBlock`和`RCTPromiseRejectBlock`,则对应的JS方法就会返回一个Promise对象。
+
+我们把上面的代码用promise来代替回调进行重构:
+
+```objective-c
+RCT_REMAP_METHOD(findEvents,
+ resolver:(RCTPromiseResolveBlock)resolve
+ rejecter:(RCTPromiseRejectBlock)reject)
+{
+ NSArray *events = ...
+ if (events) {
+ resolve(events);
+ } else {
+ reject(error);
+ }
+}
+```
+
+现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了`async`的异步函数内使用`await`关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
+
+```js
+async function updateEvents() {
+ try {
+ var events = await CalendarManager.findEvents();
+
+ this.setState({ events });
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+updateEvents();
+```
+
+## 多线程
+
+原生模块不应对自己被调用时所处的线程做任何假设。React Native在一个独立的串行GCD队列中调用原生模块的方法,但这属于实现的细节,并且可能会在将来的版本中改变。通过实现方法`- (dispatch_queue_t)methodQueue`,原生模块可以指定自己想在哪个队列中被执行。具体来说,如果模块需要调用一些必须在主线程才能使用的API,那应当这样指定:
+
+```objective-c
+- (dispatch_queue_t)methodQueue
+{
+ return dispatch_get_main_queue();
+}
+```
+
+类似的,如果一个操作需要花费很长时间,原生模块不应该阻塞住,而是应当声明一个用于执行操作的独立队列。举个例子,`RCTAsyncLocalStorage`模块创建了自己的一个queue,这样它在做一些较慢的磁盘操作的时候就不会阻塞住React本身的消息队列:
+
+```objective-c
+- (dispatch_queue_t)methodQueue
+{
+ return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
+}
+```
+
+指定的`methodQueue`会被你模块里的所有方法共享。如果你的方法中“只有一个”是耗时较长的(或者是由于某种原因必须在不同的队列中运行的),你可以在函数体内用`dispatch_async`方法来在另一个队列执行,而不影响其他方法:
+
+```objective-c
+RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
+{
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ // 在这里执行长时间的操作
+ ...
+ // 你可以在任何线程/队列中执行回调函数
+ callback(@[...]);
+ });
+}
+```
+
+> **注意**: 在模块之间共享分发队列
+>
+> `methodQueue`方法会在模块被初始化的时候被执行一次,然后会被React Native的桥接机制保存下来,所以你不需要自己保存队列的引用,除非你希望在模块的其它地方使用它。但是,如果你希望在若干个模块中共享同一个队列,则需要自己保存并返回相同的队列实例;仅仅是返回相同名字的队列是不行的。
+
+## 依赖注入
+bridge会自动注册实现了`RCTBridgeModule`协议的模块,但是你可能也希望能够初始化自定义的模块实例(这样可以注入依赖)。
+
+要实现这个功能,你需要实现`RTCBridgeDelegate`协议,初始化`RTCBridge`,并且在初始化方法里指定代理。然后用初始化好的`RTCBridge`实例初始化一个`RTCRootView`。
+
+```objective-c
+id moduleInitialiser = [[classThatImplementsRTCBridgeDelegate alloc] init];
+
+RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];
+
+RCTRootView *rootView = [[RCTRootView alloc]
+ initWithBridge:bridge
+ moduleName:kModuleName
+ initialProperties:nil];
+```
+
+## 导出常量
+
+原生模块可以导出一些常量,这些常量在JavaScript端随时都可以访问。用这种方法来传递一些静态数据,可以避免通过bridge进行一次来回交互。
+
+```objective-c
+- (NSDictionary *)constantsToExport
+{
+ return @{ @"firstDayOfTheWeek": @"Monday" };
+}
+```
+
+Javascript端可以随时同步地访问这个数据:
+
+```javascript
+console.log(CalendarManager.firstDayOfTheWeek);
+```
+
+但是注意这个常量仅仅在初始化的时候导出了一次,所以即使你在运行期间改变`constantToExport`返回的值,也不会影响到JavaScript环境下所得到的结果。
+
+### 枚举常量
+
+用`NS_ENUM`定义的枚举类型必须要先扩展对应的RCTConvert方法才可以作为函数参数传递。
+
+假设我们要导出如下的`NS_ENUM`定义:
+
+```objc
+typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
+ UIStatusBarAnimationNone,
+ UIStatusBarAnimationFade,
+ UIStatusBarAnimationSlide,
+};
+```
+
+你需要这样来扩展RCTConvert类:
+
+```objc
+@implementation RCTConvert (StatusBarAnimation)
+ RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone),
+ @"statusBarAnimationFade" : @(UIStatusBarAnimationFade),
+ @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)}),
+ UIStatusBarAnimationNone, integerValue)
+@end
+```
+
+接着你可以这样定义方法并且导出enum值作为常量:
+
+```objc
+- (NSDictionary *)constantsToExport
+{
+ return @{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone),
+ @"statusBarAnimationFade" : @(UIStatusBarAnimationFade),
+ @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide) }
+};
+
+RCT_EXPORT_METHOD(updateStatusBarAnimation:(UIStatusBarAnimation)animation
+ completion:(RCTResponseSenderBlock)callback)
+```
+
+你的枚举现在会用上面提供的选择器进行转换(上面的例子中是`integerValue`),然后再传递给你导出的函数。
+
+## 给Javascript发送事件
+
+即使没有被JavaScript调用,原生模块也可以给JavaScript发送事件通知。最好的方法是继承`RCTEventEmitter`,实现`suppportEvents`方法并调用`self sendEventWithName:`。
+
+```objective-c
+// CalendarManager.h
+#import
+#import
+
+@interface CalendarManager : RCTEventEmitter
+
+@end
+```
+```objective-c
+// CalendarManager.m
+#import "CalendarManager.h"
+
+@implementation CalendarManager
+
+RCT_EXPORT_MODULE();
+
+- (NSArray *)supportedEvents
+{
+ return @[@"EventReminder"];
+}
+
+- (void)calendarEventReminderReceived:(NSNotification *)notification
+{
+ NSString *eventName = notification.userInfo[@"name"];
+ [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
+}
+
+@end
+```
+JavaScript代码可以创建一个包含你的模块的`NativeEventEmitter`实例来订阅这些事件。
+
+```javascript
+import { NativeEventEmitter, NativeModules } from 'react-native';
+const { CalendarManager } = NativeModules;
+
+const calendarManagerEmitter = new NativeEventEmitter(CalendarManager);
+
+const subscription = calendarManagerEmitter.addListener(
+ 'EventReminder',
+ (reminder) => console.log(reminder.name)
+);
+...
+// 别忘了取消订阅,通常在componentWillUnmount生命周期方法中实现。
+subscription.remove();
+```
+更多给JavaScript发送事件的例子请看[`RCTLocationObserver`](https://github.com/facebook/react-native/blob/master/Libraries/Geolocation/RCTLocationObserver.m)。
+
+
+## 优化无监听处理的事件
+
+如果你发送了一个事件却没有任何监听处理,则会因此收到一个资源警告。要优化因此带来的额外开销,你可以在你的`RCTEventEmitter`子类中覆盖`startObserving`和`stopObserving`方法。
+
+```objective-c
+@implementation CalendarManager
+{
+ bool hasListeners;
+}
+
+// 在添加第一个监听函数时触发
+-(void)startObserving {
+ hasListeners = YES;
+ // Set up any upstream listeners or background tasks as necessary
+}
+
+// Will be called when this module's last listener is removed, or on dealloc.
+-(void)stopObserving {
+ hasListeners = NO;
+ // Remove upstream listeners, stop unnecessary background tasks
+}
+
+- (void)calendarEventReminderReceived:(NSNotification *)notification
+{
+ NSString *eventName = notification.userInfo[@"name"];
+ if (hasListeners) { // Only send events if anyone is listening
+ [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
+ }
+}
+```
+
+## 从Swift导出
+
+Swift不支持宏,所以从Swift向React Native导出类和函数需要多做一些设置,但是大致与Objective-C是相同的。
+
+假设我们已经有了一个一样的`CalendarManager`,不过是用Swift实现的类:
+
+```swift
+// CalendarManager.swift
+
+@objc(CalendarManager)
+class CalendarManager: NSObject {
+
+ @objc func addEvent(name: String, location: String, date: NSNumber) -> Void {
+ // Date is ready to use!
+ }
+
+}
+```
+
+> **注意**: 你必须使用@objc标记来确保类和函数对Objective-C公开。
+
+接着,创建一个私有的实现文件,并将必要的信息注册到React Native中。
+
+```objc
+// CalendarManagerBridge.m
+#import
+
+@interface RCT_EXTERN_MODULE(CalendarManager, NSObject)
+
+RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)
+
+@end
+```
+
+请注意,一旦你[在IOS中混用2种语言](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html), 那就还需要一个额外的桥接头文件,称作“bridging header”,用来导出Objective-C文件给Swift。如果你是通过Xcode菜单中的`File>New File`来创建的Swift文件,Xcode会自动为你创建这个头文件。在这个头文件中,你需要引入`RCTBridgeModule.h`。
+
+```objc
+// CalendarManager-Bridging-Header.h
+#import
+```
+
+同样的,你也可以使用`RCT_EXTERN_REMAP_MODULE`和`RCT_EXTERN_REMAP_METHOD`来改变导出模块和方法的JavaScript调用名称。
+了解更多信息,请参阅[`RCTBridgeModule`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridgeModule.h).
+
+
diff --git a/docs/docs/0.42/nativemethodsmixin.md b/docs/docs/0.42/nativemethodsmixin.md
new file mode 100644
index 0000000..f9fab4f
--- /dev/null
+++ b/docs/docs/0.42/nativemethodsmixin.md
@@ -0,0 +1,48 @@
+`NativeMethodsMixin`提供了一些用于直接访问底层原生组件的方法。这在你需要聚焦(focus)一个视图或者计算它在屏幕上显示的尺寸之类的情况下可能会需要。
+
+这些方法在大部分React Native提供的默认的组件中都可以使用。注意,它们不能在一些复合组件(并非直接由原生视图构成)中使用,这可能包括你自己在应用中定义的绝大部分组件。想了解更多信息,可以参阅[直接操作](direct-manipulation.html)。
+
+### 方法
+
+
+
+
static measure(callback: MeasureOnSuccessCallback) #
+
+
计算指定视图在屏幕上显示的位置和尺寸,通过一个异步回调返回计算的结果。如果成功,回调函数会被调用,并带有以下参数::
+
+ x
+ y
+ width
+ height
+ pageX
+ pageY
+
+
注意这些信息直到原生渲染完成之前都不能使用。如果你希望尽快获取视图的位置和尺寸信息,考虑使用onLayout属性 来替代。
+
+
+
+
static measureLayout(relativeToNativeNode: number, onSuccess: MeasureLayoutOnSuccessCallback, onFail: () => void) #
+
+
与measure() 函数类似,不过计算的是相对指定祖先节点relativeToNativeNode的位置和尺寸。这意味着返回的x, y是相对于指定祖先视图的。
+
要找到一个组件的原生节点的ID,一般做法是调用React.findNodeHandle(component)。
+
+
+
+
static setNativeProps(nativeProps: Object) #
+
+
这个函数直接发送属性到原生代码。这些属性不会参与后续的对比过程——这意味着如果你不在下一次render中包含这些属性,这些属性还会保持有效(参见直接操作 )。
+
+
+
+
static focus() #
+
+
请求聚焦指定的输入框或者视图。具体的效果要取决于平台和视图的类型。
+
+
+
+
static blur() #
+
+
移除指定的输入框或者视图的焦点。这是focus()的相反操作。。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/navigation.md b/docs/docs/0.42/navigation.md
new file mode 100644
index 0000000..73a91eb
--- /dev/null
+++ b/docs/docs/0.42/navigation.md
@@ -0,0 +1,132 @@
+本文档总结对比了React Native中现有的几个导航组件。如果你刚开始接触,那么直接选择`React Navigation`就好。如果你只针对iOS平台开发,并且想和系统原生外观一致,那么可以选择`NavigatorIOS`。你还可能在很多地方听说过`Navigator`,这个老组件会逐步被`React Navigation`替代,但是它经历了长期的实践,bug很少,目前仍然可用。过去还有一个实验性的导航器组件`NavigationExperimental`,这个组件已经完全弃用。
+
+## React Navigation
+
+社区今后主推的方案是一个单独的导航库`react-navigation`,它的使用十分简单。
+
+首先是在你的应用中安装此库:
+
+```
+npm install --save react-navigation
+```
+
+然后你就可以快速创建一个有两个页面(Main和Profile)的应用了:
+
+```
+import {
+ StackNavigator,
+} from 'react-navigation';
+
+const App = StackNavigator({
+ Main: {screen: MainScreen},
+ Profile: {screen: ProfileScreen},
+});
+```
+
+其中每一个screen组件都可以单独设置导航选项,例如导航头的标题。还可以使用`navigation`属性中的方法去跳转到别的页面:
+
+```
+class MainScreen extends React.Component {
+ static navigationOptions = {
+ title: 'Welcome',
+ };
+ render() {
+ const { navigate } = this.props.navigation;
+ return (
+
+ navigate('Profile', { name: 'Jane' });
+ }
+ />
+ );
+ }
+}
+```
+
+React Navigation的路由写法使其非常容易扩展导航逻辑,或是整合到redux中。由于路由可以嵌套使用,因而开发者可以根据不同页面编写不同的导航逻辑,且彼此互不影响。
+
+React Navigation中的视图是原生组件,同时用到了运行在原生线程上的`Animated`动画库,因而性能表现十分流畅。此外其动画形式和手势都非常便于定制。
+
+要想详细了解React Navigation,可以阅读这一篇英文的[入门文档](https://reactnavigation.org/docs/intro/)。
+
+## Navigator
+
+和React Navigation类似,`Navigator`使用纯JavaScript实现了一个导航栈,因此可以跨平台工作,同时也便于定制。但Navigator早在2015年就发布了,因此它没有能够享受到如今流畅的原生动画支持。
+
+
+
+`Navigator`可以在`renderScene`方法中根据当前路由渲染不同的组件。默认情况下新的场景会从屏幕右侧滑进来,但你也可以通过`configureScene`方法来管理这一行为。你还可以通过`navigationBar`属性来配置一个跨场景的导航栏。(译注:但我们不推荐使用跨场景的navigationBar,它的代码逻辑维护起来很困难!建议自己在场景中用`View`实现自定义的导航栏。)
+
+点击这里阅读[Navigator的API文档](navigator.html)。
+
+
+## NavigatorIOS
+
+如果你只针对iOS平台开发,那么可以考虑使用[NavigatorIOS](navigatorios.html)。它是基于 [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/)封装的,所以看起来很像。
+
+
+
+```javascript
+
+```
+
+用法类似`Navigator`,`NavigatorIOS`也使用路由对象来描述场景,但有一些重要区别。其中要渲染的组件在路由对象的`component`字段中指定,要给目标组件传递的参数则写在`passProps`中。被渲染的component都会自动接受到一个名为`navigator`的属性,你可以直接调用此对象(this.props.navigator)的`push`和`pop`方法。
+
+由于`NavigatorIOS`使用的是原生的UIKit导航,所以它会自动渲染一个带有返回按钮和标题的导航栏。
+
+```javascript
+import React, { Component, PropTypes } from 'react';
+import { NavigatorIOS, Text, TouchableHighlight, View } from 'react-native';
+
+export default class NavigatorIOSApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ navigator: PropTypes.object.isRequired,
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this._onForward = this._onForward.bind(this);
+ }
+
+ _onForward() {
+ this.props.navigator.push({
+ title: 'Scene ' + nextIndex,
+ });
+ }
+
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ )
+ }
+}
+```
+
+点击这里阅读[NavigatorIOS的API文档](navigatorios.html)。
\ No newline at end of file
diff --git a/docs/docs/0.42/navigator-comparison.md b/docs/docs/0.42/navigator-comparison.md
new file mode 100644
index 0000000..8dec225
--- /dev/null
+++ b/docs/docs/0.42/navigator-comparison.md
@@ -0,0 +1,26 @@
+对于新手来讲[Navigator](navigator.html)和[NavigatorIOS](navigatorios.html)是一个很容易弄混的问题。
+
+`Navigator`和`NavigatorIOS`都可以用来管理应用中“场景”的导航(也可以称作屏幕)。导航器建立了一个路由栈,用来弹出,推入或者替换路由状态。它们和html5中的[history API](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)很类似。主要的区别在于`NavigatorIOS`使用了iOS中的[UINavigationController](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/)类,而`Navigator`则完全用js重写了一个类似功能的React组件。因此`Navigator`可以兼容iOS和Android,而`NavigatorIOS`只能用于iOS。下面是两者具体的不同点:
+
+# Navigator
+- 扩展性的API设计使得它完全可以通过js定制。
+- React Native团队正在积极开发。
+- 使用JavaScript编写。
+- iOS和Android都可以使用。
+- 包含一个简单的导航栏`Navigator.NavigationBar`,类似`NavigatorIOS`的导航栏。同时也包含一个面包屑导航叫做`Navigator.BreadcrumbNavigationBar`。参考`UIExplorer demo`来学习如何使用它们。
+ - 目前的动画效果不错并且还在改进中,但是还是没有苹果实现的`NavigatorIOS`精确。
+- 你可以通过向`navigationBar`传递属性来提供你自己的导航栏。
+
+
+# NavigatorIOS
+
+- 轻量、受限的API设置,使其相对`Navigator`来说不太方便定制。
+- 由开源社区主导开发 —— React Native的官方团队并不在自己的应用中使用。
+ - 这样的结果是导致目前有一些积压的bug,而且没有人负责处理。
+- 封装了UIKit,因此和其他原生应用表现完全一致。依赖Objective-C和JavaScript。
+ - 因此你只能使用苹果开发好的动画和行为。
+- 只支持iOS。
+- 默认包含一个导航栏:这个导航栏不是React Native视图组件,因此只能稍微修改样式。
+
+对于大多数正式的App开发,我们建议使用`Navigator` —— 使用`NavigatorIOS`实现复杂的需求很容易碰到麻烦。
+
diff --git a/docs/docs/0.42/navigator.md b/docs/docs/0.42/navigator.md
new file mode 100644
index 0000000..672829c
--- /dev/null
+++ b/docs/docs/0.42/navigator.md
@@ -0,0 +1,127 @@
+使用导航器可以让你在应用的不同场景(页面)间进行切换。导航器通过路由对象来分辨不同的场景。利用`renderScene`方法,导航栏可以根据指定的路由来渲染场景。
+
+可以通过`configureScene`属性获取指定路由对象的配置信息,从而改变场景的动画或者手势。查看`Navigator.SceneConfigs`来获取默认的动画和更多的场景配置选项。
+
+__译注__:本文档的说明较为简略,使用上有一定的难度。论坛中有一篇更为详细的[教程](http://bbs.reactnative.cn/topic/20),推荐阅读。
+
+### 截图
+
+
+
+
+### 基本用法
+```javascript
+
+ {
+ var nextIndex = route.index + 1;
+ navigator.push({
+ name: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+```
+
+### 导航方法
+如果你得到了一个navigator对象的引用(__译注__:再次推荐仔细阅读此[教程](http://bbs.reactnative.cn/topic/20),理解如何在renderScene方法中传递navigator对象,否则直接调用会报undefined错误),则可以调用许多方法来进行导航:
+
+* getCurrentRoutes() - 获取当前栈里的路由,也就是push进来,没有pop掉的那些。
+* jumpBack() - 跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。
+* jumpForward() - 上一个方法不是调到之前的路由了么,用这个跳回来就好了。
+* jumpTo(route) - 跳转到已有的场景并且不卸载。
+* push(route) - 跳转到新的场景,并且将场景入栈,你可以稍后跳转过去
+* pop() - 跳转回去并且卸载掉当前场景
+* replace(route) - 用一个新的路由替换掉当前场景
+* replaceAtIndex(route, index) - 替换掉指定序列的路由场景
+* replacePrevious(route) - 替换掉之前的场景
+* resetTo(route) - 跳转到新的场景,并且重置整个路由栈
+* immediatelyResetRouteStack(routeStack) - 用新的路由数组来重置路由栈
+* popToRoute(route) - pop到路由指定的场景,在整个路由栈中,处于指定场景之后的场景将会被卸载。
+* popToTop() - pop到栈中的第一个场景,卸载掉所有的其他场景。
+
+### 属性
+
+
+
+
configureScene function #
+
+
可选的函数,用来配置场景动画和手势。会带有两个参数调用,一个是当前的路由,一个是当前的路由栈。然后它应当返回一个场景配置对象
+
(route, routeStack) => Navigator.SceneConfigs.FloatFromRight
+
+
+ Navigator.SceneConfigs.PushFromRight (默认)
+ Navigator.SceneConfigs.FloatFromRight
+ Navigator.SceneConfigs.FloatFromLeft
+ Navigator.SceneConfigs.FloatFromBottom
+ Navigator.SceneConfigs.FloatFromBottomAndroid
+ Navigator.SceneConfigs.FadeAndroid
+ Navigator.SceneConfigs.HorizontalSwipeJump
+ Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
+ Navigator.SceneConfigs.VerticalUpSwipeJump
+ Navigator.SceneConfigs.VerticalDownSwipeJump
+
+
+
+
+
initialRoute object #
+
+
定义启动时加载的路由。路由是导航栏用来识别渲染场景的一个对象。initialRoute必须是initialRouteStack中的一个路由。initialRoute默认为initialRouteStack中最后一项。
+
+
+
+
initialRouteStack [object] #
+
+
提供一个路由集合用来初始化。如果没有设置初始路由的话则必须设置该属性。如果没有提供该属性,它将被默认设置成一个只含有initialRoute的数组。
+
+
+
+
navigationBar node #
+
+
可选参数,提供一个在场景切换的时候保持的导航栏。
+
+
+
+
navigator object #
+
+
可选参数,提供从父导航器获得的导航器对象。
+
+
+
+
onDidFocus function #
+
+
每当导航切换完成或初始化之后,调用此回调,参数为新场景的路由。
+
+
+
+
onWillFocus function #
+
+
+
+
renderScene function #
+
+
必要参数。用来渲染指定路由的场景。调用的参数是路由和导航器。
+
(route, navigator) =>
+ <MySceneComponent title ={route.title} navigator ={navigator} />
+
+
+
+
+
diff --git a/docs/docs/0.42/navigatorios.md b/docs/docs/0.42/navigatorios.md
new file mode 100644
index 0000000..cc888be
--- /dev/null
+++ b/docs/docs/0.42/navigatorios.md
@@ -0,0 +1,650 @@
+`NavigatorIOS` is a wrapper around `UINavigationController`, enabling you to implement a navigation stack. It works exactly the same as it would on a native app using `UINavigationController`, providing the same animations and behavior from UIKIt.
+
+As the name implies, it is only available on iOS. Take a look at Navigator for a similar solution for your cross-platform needs, or check out [react-native-navigation](https://github.com/wix/react-native-navigation), a component that aims to provide native navigation on both iOS and Android.
+
+To set up the navigator, provide the `initialRoute` prop with a route object. A route object is used to describe each scene that your app navigates to. `initialRoute` represents the first route in your navigator.
+
+```js
+import React, { Component, PropTypes } from 'react';
+import { NavigatorIOS, Text } from 'react-native';
+
+export default class NavigatorIOSApp extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ navigator: PropTypes.object.isRequired,
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this._onForward = this._onForward.bind(this);
+ this._onBack = this._onBack.bind(this);
+ }
+
+ _onForward() {
+ this.props.navigator.push({
+ title: 'Scene ' + nextIndex,
+ });
+ }
+
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ )
+ }
+}
+```
+
+In this code, the navigator renders the component specified in `initialRoute`, which in this case is `MyScene`. This component will receive a `route` prop and a `navigator` prop representing the navigator. The navigator's navigation bar will render the title for the current scene, "My Initial Scene".
+
+You can optionally pass in a `passProps` property to your `initialRoute`. `NavigatorIOS` passes this in as props to the rendered component:
+
+```js
+initialRoute={{
+ component: MyScene,
+ title: 'My Initial Scene',
+ passProps: { myProp: 'foo' }
+}}
+```
+
+You can then access the props passed in via `{this.props.myProp}`.
+
+### 处理导航
+
+To trigger navigation functionality such as pushing or popping a view, you have access to a navigator object. The object is passed in as a prop to any component that is rendered by NavigatorIOS. You can then call the relevant methods to perform the navigation action you need:
+
+```js
+class MyView extends Component {
+ _handleBackPress() {
+ this.props.navigator.pop();
+ }
+
+ _handleNextPress(nextRoute) {
+ this.props.navigator.push(nextRoute);
+ }
+
+ render() {
+ const nextRoute = {
+ component: MyView,
+ title: 'Bar That',
+ passProps: { myProp: 'bar' }
+ };
+ return(
+ this._handleNextPress(nextRoute)}>
+
+ See you on the other nav {this.props.myProp}!
+
+
+ );
+ }
+}
+You can also trigger navigator functionality from the NavigatorIOS component:
+
+class NavvyIOS extends Component {
+ _handleNavigationRequest() {
+ this.refs.nav.push({
+ component: MyView,
+ title: 'Genius',
+ passProps: { myProp: 'genius' },
+ });
+ }
+
+ render() {
+ return (
+ this._handleNavigationRequest(),
+ }}
+ style={{flex: 1}}
+ />
+ );
+ }
+}
+```
+
+The code above adds a `_handleNavigationRequest` private method that is invoked from the `NavigatorIOS` component when the right navigation bar item is pressed. To get access to the navigator functionality, a reference to it is saved in the `ref` prop and later referenced to push a new scene into the navigation stack.
+
+### 导航栏的配置
+
+Props passed to `NavigatorIOS` will set the default configuration for the navigation bar. Props passed as properties to a route object will set the configuration for that route's navigation bar, overriding any props passed to the `NavigatorIOS `component.
+
+```js
+_handleNavigationRequest() {
+ this.refs.nav.push({
+ //...
+ passProps: { myProp: 'genius' },
+ barTintColor: '#996699',
+ });
+}
+
+render() {
+ return (
+
+ );
+}
+```
+
+In the example above the navigation bar color is changed when the new route is pushed.
+
+### 截图
+
+
+
+
+### 属性
+
+
+
+
barTintColor string #
+
+
+
+
initialRoute {component: function, title: string, passProps: object, backButtonIcon: Image.propTypes.source, backButtonTitle: string, leftButtonIcon: Image.propTypes.source, leftButtonTitle: string, onLeftButtonPress: function, rightButtonIcon: Image.propTypes.source, rightButtonTitle: string, onRightButtonPress: function, wrapperStyle: [object Object]} #
+
+
NavigatorIOS使用"路由"对象来包含要渲染的子视图、它们的属性、以及导航条配置。"push"和任何其它的导航函数的参数都是这样的路由对象。
+
+
+
+
+
+
导航器中的组件的默认属性。一个常见的用途是设置所有页面的背景颜色。
+
+
+
+
navigationBarHidden bool #
+
+
+
+
shadowHidden bool #
+
+
+
+
+
titleTextColor string #
+
+
+
+
+
interactivePopGestureEnabled bool #
+
+
决定是否启用滑动返回手势。不指定此属性时,手势会根据navigationBar的显隐情况决定是否启用(显示时启用手势,隐藏时禁用手势)。指定此属性后,手势与navigationBar的显隐情况无关。
+
+
+
+
+### 方法
+
+
+
push(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Navigate forward to a new route
+
+
popN(n: number) #
+
Go back N pages at once. When N=1, behavior matches pop()
+
+
+
replaceAtIndex(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}, index: number) #
+
Replace a route in the navigation stack.
+
index specifies the route in the stack that should be replaced.
+ If it's negative, it counts from the back.
+
+
replace(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replace the route for the current page and immediately
+ load the view for the new route.
+
+
replacePrevious(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replace the route/view for the previous page.
+
+
+
popToRoute(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Go back to the item for a particular route object
+
+
replacePreviousAndPop(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replaces the previous route/view and transitions back to it.
+
+
resetTo(route: {
+ component: Function;
+ title: string;
+ passProps?: Object;
+ backButtonTitle?: string;
+ backButtonIcon?: Object;
+ leftButtonTitle?: string;
+ leftButtonIcon?: Object;
+ onLeftButtonPress?: Function;
+ rightButtonTitle?: string;
+ rightButtonIcon?: Object;
+ onRightButtonPress?: Function;
+ wrapperStyle?: any;
+}) #
+
Replaces the top item and popToTop
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const ViewExample = require('./ViewExample');
+
+const createExamplePage = require('./createExamplePage');
+const nativeImageSource = require('nativeImageSource');
+const {
+ AlertIOS,
+ NavigatorIOS,
+ ScrollView,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+class EmptyPage extends React.Component {
+ render() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+}
+
+class NavigatorIOSExamplePage extends React.Component {
+ render() {
+ var recurseTitle = 'Recurse Navigation';
+ if (!this.props.depth || this.props.depth === 1) {
+ recurseTitle += ' - more examples here';
+ }
+ return (
+
+
+
+ {this._renderRow(recurseTitle, () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: NavigatorIOSExamplePage,
+ backButtonTitle: 'Custom Back',
+ passProps: {depth: this.props.depth ? this.props.depth + 1 : 1},
+ });
+ })}
+ {this._renderRow('Push View Example', () => {
+ this.props.navigator.push({
+ title: 'Very Long Custom View Example Title',
+ component: createExamplePage(null, ViewExample),
+ });
+ })}
+ {this._renderRow('Custom title image Example', () => {
+ this.props.navigator.push({
+ title: 'Custom title image Example',
+ titleImage: require('./relay.png'),
+ component: createExamplePage(null, ViewExample),
+ });
+ })}
+ {this._renderRow('Custom Right Button', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ rightButtonTitle: 'Cancel',
+ onRightButtonPress: () => this.props.navigator.pop(),
+ passProps: {
+ text: 'This page has a right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Right System Button', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ rightButtonSystemIcon: 'bookmarks',
+ onRightButtonPress: () => this.props.navigator.pop(),
+ passProps: {
+ text: 'This page has a right system button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Left & Right Icons', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ leftButtonTitle: 'Custom Left',
+ onLeftButtonPress: () => this.props.navigator.pop(),
+ rightButtonIcon: nativeImageSource({
+ ios: 'NavBarButtonPlus',
+ width: 17,
+ height: 17
+ }),
+ onRightButtonPress: () => {
+ AlertIOS.alert(
+ 'Bar Button Action',
+ 'Recognized a tap on the bar button icon',
+ [
+ {
+ text: 'OK',
+ onPress: () => console.log('Tapped OK'),
+ },
+ ]
+ );
+ },
+ passProps: {
+ text: 'This page has an icon for the right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Custom Left & Right System Icons', () => {
+ this.props.navigator.push({
+ title: NavigatorIOSExample.title,
+ component: EmptyPage,
+ leftButtonSystemIcon: 'cancel',
+ onLeftButtonPress: () => this.props.navigator.pop(),
+ rightButtonSystemIcon: 'search',
+ onRightButtonPress: () => {
+ AlertIOS.alert(
+ 'Bar Button Action',
+ 'Recognized a tap on the bar button icon',
+ [
+ {
+ text: 'OK',
+ onPress: () => console.log('Tapped OK'),
+ },
+ ]
+ );
+ },
+ passProps: {
+ text: 'This page has an icon for the right button in the nav bar',
+ }
+ });
+ })}
+ {this._renderRow('Pop', () => {
+ this.props.navigator.pop();
+ })}
+ {this._renderRow('Pop to top', () => {
+ this.props.navigator.popToTop();
+ })}
+ {this._renderReplace()}
+ {this._renderReplacePrevious()}
+ {this._renderReplacePreviousAndPop()}
+ {this._renderRow('Exit NavigatorIOS Example', this.props.onExampleExit)}
+
+
+
+ );
+ }
+
+ _renderReplace = () => {
+ if (!this.props.depth) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace here', () => {
+ var prevRoute = this.props.route;
+ this.props.navigator.replace({
+ title: 'New Navigation',
+ component: EmptyPage,
+ rightButtonTitle: 'Undo',
+ onRightButtonPress: () => this.props.navigator.replace(prevRoute),
+ passProps: {
+ text: 'The component is replaced, but there is currently no ' +
+ 'way to change the right button or title of the current route',
+ }
+ });
+ });
+ };
+
+ _renderReplacePrevious = () => {
+ if (!this.props.depth || this.props.depth < 2) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace previous', () => {
+ this.props.navigator.replacePrevious({
+ title: 'Replaced',
+ component: EmptyPage,
+ passProps: {
+ text: 'This is a replaced "previous" page',
+ },
+ wrapperStyle: styles.customWrapperStyle,
+ });
+ });
+ };
+
+ _renderReplacePreviousAndPop = () => {
+ if (!this.props.depth || this.props.depth < 2) {
+ // this is to avoid replacing the top of the stack
+ return null;
+ }
+ return this._renderRow('Replace previous and pop', () => {
+ this.props.navigator.replacePreviousAndPop({
+ title: 'Replaced and Popped',
+ component: EmptyPage,
+ passProps: {
+ text: 'This is a replaced "previous" page',
+ },
+ wrapperStyle: styles.customWrapperStyle,
+ });
+ });
+ };
+
+ _renderRow = (title: string, onPress: Function) => {
+ return (
+
+
+
+
+ {title}
+
+
+
+
+
+ );
+ };
+}
+
+class NavigatorIOSExample extends React.Component {
+ static title = '';
+ static description = 'iOS navigation capabilities';
+ static external = true;
+
+ render() {
+ const {onExampleExit} = this.props;
+ return (
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ customWrapperStyle: {
+ backgroundColor: '#bbdddd',
+ },
+ emptyPage: {
+ flex: 1,
+ paddingTop: 64,
+ },
+ emptyPageText: {
+ margin: 10,
+ },
+ list: {
+ backgroundColor: '#eeeeee',
+ marginTop: 10,
+ },
+ group: {
+ backgroundColor: 'white',
+ },
+ groupSpace: {
+ height: 15,
+ },
+ line: {
+ backgroundColor: '#bbbbbb',
+ height: StyleSheet.hairlineWidth,
+ },
+ row: {
+ backgroundColor: 'white',
+ justifyContent: 'center',
+ paddingHorizontal: 15,
+ paddingVertical: 15,
+ },
+ separator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: '#bbbbbb',
+ marginLeft: 15,
+ },
+ rowNote: {
+ fontSize: 17,
+ },
+ rowText: {
+ fontSize: 17,
+ fontWeight: '500',
+ },
+});
+
+module.exports = NavigatorIOSExample;
+```
diff --git a/docs/docs/0.42/navigators.md b/docs/docs/0.42/navigators.md
new file mode 100644
index 0000000..eb389f8
--- /dev/null
+++ b/docs/docs/0.42/navigators.md
@@ -0,0 +1,167 @@
+---
+id: navigators
+title: Using Navigators
+layout: docs
+category: The Basics
+permalink: docs/using-navigators.html
+next: more-resources
+---
+
+Mobile apps rarely consist of just one screen. As soon as you add a second screen to your app, you will have to take into consideration how the user will navigate from one screen to the other.
+
+You can use navigators to transition between multiple screens. These transitions can be typical side-to-side animations down a master/detail stack, or vertical modal popups.
+
+## Navigator
+
+React Native has several built-in navigation components, but for your first app you will probably want to use `Navigator`. It provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize.
+
+
+
+### Working with Scenes
+
+At this point you should feel comfortable rendering all sorts of components in your app, be it a simple `View` with `Text` inside, or a `ScrollView` with a list of `Image`s. Together, these components make up a scene (another word for screen) in your app.
+
+A scene is nothing other than a React component that is typically rendered full screen. This is in contrast to a `Text`, an `Image`, or even a custom `SpinningBeachball` component that is meant to be rendered as part of a screen. You may have already used one without realizing it - the ["HelloWorldApp"](docs/tutorial.html), the ["FlexDirectionBasics"](docs/flexbox.html), and the ["ListViewBasics"](docs/using-a-listview.html) components covered earlier in the tutorial are all examples of scenes.
+
+For simplicity's sake, let's define a simple scene that displays a bit of text. We will come back to this scene later as we add navigation to our app. Create a new file called "MyScene.js" with the following contents:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+export default class MyScene extends Component {
+ getDefaultProps() {
+ return {
+ title: 'MyScene'
+ };
+ }
+
+ render() {
+ return (
+
+ Hi! My name is {this.props.title}.
+
+ )
+ }
+}
+```
+
+Notice the `export default` in front of the component declaration. This will _export_ the component, and in turn allow other components to _import_ it later on, like so:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+import MyScene from './MyScene';
+
+class YoDawgApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp);
+```
+
+We now have a simple app that renders your scene and nothing else. In this case, `MyScene` is a simple example of a [reusable React component](https://facebook.github.io/react/docs/reusable-components.html).
+
+### Using Navigator
+
+Enough about scenes, let's start navigating. We will start by rendering a `Navigator`, and then let the `Navigator` render the scene for you by passing in your own render function to its `renderScene` prop.
+
+```javascript
+render() {
+ return (
+ {
+
+ }}
+ />
+ );
+}
+```
+
+Something you will encounter a lot when dealing with navigation is the concept of routes. A route is an object that contains information about a scene. It is used to provide all the context that the navigator's `renderScene` function needs to render a scene. It can have any number of keys to help distinguish your scene, and I happened to pick a single `title` key for the above example.
+
+#### Pushing scenes onto the stack
+
+In order to transition to a new scene, you will need to learn about `push` and `pop`. These two methods are provided by the `navigator` object that is passed to your `renderScene` function above. They can be used, as you may have realized, to push and pop routes into your navigation stack.
+
+```javascript
+navigator.push({
+ title: 'Next Scene',
+ index: 1,
+});
+
+navigator.pop();
+```
+
+A more complete example that demonstrates the pushing and popping of routes could therefore look something like this:
+
+```javascript
+import React, { Component, PropTypes } from 'react';
+import { Navigator, Text, TouchableHighlight, View } from 'react-native';
+
+export default class SimpleNavigationApp extends Component {
+ render() {
+ return (
+
+ {
+ const nextIndex = route.index + 1;
+ navigator.push({
+ title: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+
+ // Function to call to go back to the previous scene
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+ )
+ }
+}
+
+class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ onForward: PropTypes.func.isRequired,
+ onBack: PropTypes.func.isRequired,
+ }
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ Tap me to load the next scene
+
+
+ Tap me to go back
+
+
+ )
+ }
+}
+```
+
+In this example, the `MyScene` component is passed the title of the current route via the `title` prop. It displays two tappable components that call the `onForward` and `onBack` functions passed through its props, which in turn will call `navigator.push()` and `navigator.pop()` as needed.
+
+Check out the [Navigator API reference](docs/navigator.html) for more `Navigator` code samples, or read through the [Navigation guide](docs/navigation.html) for other examples of what you can do with navigators.
+
+## High Five!
+
+If you've gotten here by reading linearly through the tutorial, then you are a pretty impressive human being. Congratulations. Next, you might want to check out [all the cool stuff the community does with React Native](/react-native/docs/more-resources.html).
diff --git a/docs/docs/0.42/netinfo.md b/docs/docs/0.42/netinfo.md
new file mode 100644
index 0000000..e286111
--- /dev/null
+++ b/docs/docs/0.42/netinfo.md
@@ -0,0 +1,286 @@
+NetInfo模块可以获知设备联网或离线的状态信息。
+
+```javascript
+NetInfo.fetch().done((reach) => {
+ console.log('Initial: ' + reach);
+});
+function handleFirstConnectivityChange(reach) {
+ console.log('First change: ' + reach);
+ NetInfo.removeEventListener(
+ 'change',
+ handleFirstConnectivityChange
+ );
+}
+NetInfo.addEventListener(
+ 'change',
+ handleFirstConnectivityChange
+);
+```
+
+### IOS
+以异步的方式判断设备是否联网,以及是否使用了移动数据网络。
+
+- `none` - 设备处于离线状态。
+- `wifi` - 设备处于联网状态且通过wifi链接,或者是一个iOS的模拟器。
+- `cell` - 设备是通过Edge、3G、WiMax或是LTE网络联网的。
+- `unknown` - 发生错误,网络状况不可知
+
+### Android
+请求网络信息需要先在应用的`AndroidManifest.xml`文件中添加如下权限字段:
+```
+
+```
+Android的联网类型:
+- `NONE` - 设备处于离线状态
+- `BLUETOOTH` - 蓝牙数据连接
+- `DUMMY` - 模拟数据连接
+- `ETHERNET` - 以太网数据连接
+- `MOBILE` - 移动网络数据连接
+- `MOBILE_DUN` - 拨号移动网络数据连接
+- `MOBILE_HIPRI` - 高优先级移动网络数据连接
+- `MOBILE_MMS` - 彩信移动网络数据连接
+- `MOBILE_SUPL` - 安全用户面定位(SUPL)数据连接
+- `VPN` - 虚拟网络连接。需要Android5.0以上
+- `WIFI` - WIFI数据连接
+- `WIMAX` - WiMAX数据连接
+- `UNKNOWN` - 未知数据连接
+
+其他的连接状态已被Android API隐藏,但可以在需要时使用。
+
+### isConnectionExpensive
+此方法仅Android可用。用于判断当前活动的连接是否计费。如果当前连接是通过移动数据网络,或者通过基于移动数据网络所创建的wifi热点,都有可能被判定为计费的数据连接。
+
+```javascript
+NetInfo.isConnectionExpensive((isConnectionExpensive) => {
+ console.log('Connection is ' + (isConnectionExpensive ? 'Expensive' : 'Not Expensive'));
+});
+```
+
+### isConnected
+此方法所有平台皆可使用。以异步方式获取一个布尔值,用于判断当前设备是否联网。
+
+```javascript
+NetInfo.isConnected.fetch().done((isConnected) => {
+ console.log('First, is ' + (isConnected ? 'online' : 'offline'));
+});
+function handleFirstConnectivityChange(isConnected) {
+ console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
+ NetInfo.isConnected.removeEventListener(
+ 'change',
+ handleFirstConnectivityChange
+ );
+}
+NetInfo.isConnected.addEventListener(
+ 'change',
+ handleFirstConnectivityChange
+);
+```
+
+
+### 方法
+
+
+
+
static addEventListener(eventName, handler) #
+
在网络状况/类型发生变化时调用此监听函数。回调的参数为上面列出的网络状况/类型。
+
+
+
+
static removeEventListener(eventName, handler) #
+
+
+
static fetch() #
+
返回一个promise,用于获取当前的网络状况/类型。
+
+
+
static isConnectionExpensive() #
+
+
+
+### 属性
+
+
+
isConnected: ObjectExpression
+ #
+
此属性为一个对象,也可调用上面列出的方法。但其监听函数接受的参数为一个布尔值,仅仅能表明当前网络是否联通。如果你只关心设备是否连上网了(不关心网络类型),那么使用此属性即可。
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ NetInfo,
+ Text,
+ View,
+ TouchableWithoutFeedback,
+} = ReactNative;
+
+const ConnectionInfoSubscription = React.createClass({
+ getInitialState() {
+ return {
+ connectionInfoHistory: [],
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.addEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.removeEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ _handleConnectionInfoChange: function(connectionInfo) {
+ const connectionInfoHistory = this.state.connectionInfoHistory.slice();
+ connectionInfoHistory.push(connectionInfo);
+ this.setState({
+ connectionInfoHistory,
+ });
+ },
+ render() {
+ return (
+
+ {JSON.stringify(this.state.connectionInfoHistory)}
+
+ );
+ }
+});
+
+const ConnectionInfoCurrent = React.createClass({
+ getInitialState() {
+ return {
+ connectionInfo: null,
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.addEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ NetInfo.fetch().done(
+ (connectionInfo) => { this.setState({connectionInfo}); }
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.removeEventListener(
+ 'change',
+ this._handleConnectionInfoChange
+ );
+ },
+ _handleConnectionInfoChange: function(connectionInfo) {
+ this.setState({
+ connectionInfo,
+ });
+ },
+ render() {
+ return (
+
+ {this.state.connectionInfo}
+
+ );
+ }
+});
+
+const IsConnected = React.createClass({
+ getInitialState() {
+ return {
+ isConnected: null,
+ };
+ },
+ componentDidMount: function() {
+ NetInfo.isConnected.addEventListener(
+ 'change',
+ this._handleConnectivityChange
+ );
+ NetInfo.isConnected.fetch().done(
+ (isConnected) => { this.setState({isConnected}); }
+ );
+ },
+ componentWillUnmount: function() {
+ NetInfo.isConnected.removeEventListener(
+ 'change',
+ this._handleConnectivityChange
+ );
+ },
+ _handleConnectivityChange: function(isConnected) {
+ this.setState({
+ isConnected,
+ });
+ },
+ render() {
+ return (
+
+ {this.state.isConnected ? 'Online' : 'Offline'}
+
+ );
+ }
+});
+
+const IsConnectionExpensive = React.createClass({
+ getInitialState() {
+ return {
+ isConnectionExpensive: (null : ?boolean),
+ };
+ },
+ _checkIfExpensive() {
+ NetInfo.isConnectionExpensive().then(
+ isConnectionExpensive => { this.setState({isConnectionExpensive}); }
+ );
+ },
+ render() {
+ return (
+
+
+
+ Click to see if connection is expensive:
+ {this.state.isConnectionExpensive === true ? 'Expensive' :
+ this.state.isConnectionExpensive === false ? 'Not expensive'
+ : 'Unknown'}
+
+
+
+
+ );
+ }
+});
+
+exports.title = 'NetInfo';
+exports.description = 'Monitor network status';
+exports.examples = [
+ {
+ title: 'NetInfo.isConnected',
+ description: 'Asynchronously load and observe connectivity',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'NetInfo.update',
+ description: 'Asynchronously load and observe connectionInfo',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'NetInfo.updateHistory',
+ description: 'Observed updates to connectionInfo',
+ render(): ReactElement { return ; }
+ },
+ {
+ platform: 'android',
+ title: 'NetInfo.isConnectionExpensive (Android)',
+ description: 'Asynchronously check isConnectionExpensive',
+ render(): ReactElement { return ; }
+ },
+];
+```
diff --git a/docs/docs/0.42/network.md b/docs/docs/0.42/network.md
new file mode 100644
index 0000000..a440c5f
--- /dev/null
+++ b/docs/docs/0.42/network.md
@@ -0,0 +1,138 @@
+很多移动应用都需要从远程地址中获取数据或资源。你可能需要给某个REST API发起POST请求以提交用户数据,又或者可能仅仅需要从某个服务器上获取一些静态内容——以下就是你会用到的东西。新手可以对照这个[简短的视频教程](http://v.youku.com/v_show/id_XMTUyNTEwMTA5Ng==.html)加深理解。
+
+## 使用Fetch
+
+React Native提供了和web标准一致的[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API),用于满足开发者访问网络的需求。如果你之前使用过`XMLHttpRequest`(即俗称的ajax)或是其他的网络API,那么Fetch用起来将会相当容易上手。这篇文档只会列出Fetch的基本用法,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索`fetch api`关键字以了解更多信息。
+
+#### 发起网络请求
+
+要从任意地址获取内容的话,只需简单地将网址作为参数传递给fetch方法即可(fetch这个词本身也就是`获取`的意思):
+
+```js
+fetch('https://mywebsite.com/mydata.json')
+```
+
+Fetch还有可选的第二个参数,可以用来定制HTTP请求一些参数。你可以指定header参数,或是指定使用POST方法,又或是提交数据等等:
+
+```js
+fetch('https://mywebsite.com/endpoint/', {
+ method: 'POST',
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ firstParam: 'yourValue',
+ secondParam: 'yourOtherValue',
+ })
+})
+```
+
+译注:如果你的服务器无法识别上面POST的数据格式,那么可以尝试传统的form格式,示例如下:
+
+```js
+fetch('https://mywebsite.com/endpoint/', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: 'key1=value1&key2=value2'
+})
+```
+
+可以参考[Fetch请求文档](https://developer.mozilla.org/en-US/docs/Web/API/Request)来查看所有可用的参数。
+
+#### 处理服务器的响应数据
+
+上面的例子演示了如何发起请求。很多情况下,你还需要处理服务器回复的数据。
+
+网络请求天然是一种异步操作(译注:同样的还有[asyncstorage](asyncstorage.html),请不要再问怎样把异步变成同步!无论在语法层面怎么折腾,它们的异步本质是无法变更的。异步的意思是你应该趁这个时间去做点别的事情,比如显示loading,而不是让界面卡住傻等)。Fetch 方法会返回一个[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise),这种模式可以简化异步风格的代码(译注:同样的,如果你不了解promise,建议使用搜索引擎补课):
+
+ ```js
+ getMoviesFromApiAsync() {
+ return fetch('https://facebook.github.io/react-native/movies.json')
+ .then((response) => response.json())
+ .then((responseJson) => {
+ return responseJson.movies;
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+ }
+ ```
+
+你也可以在React Native应用中使用ES7标准中的`async`/`await` 语法:
+
+ ```js
+ // 注意这个方法前面有async关键字
+ async getMoviesFromApi() {
+ try {
+ // 注意这里的await语句,其所在的函数必须有async关键字声明
+ let response = await fetch('https://facebook.github.io/react-native/movies.json');
+ let responseJson = await response.json();
+ return responseJson.movies;
+ } catch(error) {
+ console.error(error);
+ }
+ }
+ ```
+
+别忘了catch住`fetch`可能抛出的异常,否则出错时你可能看不到任何提示。
+
+> 默认情况下,iOS会阻止所有非https的请求。如果你请求的接口是http协议,那么首先需要添加一个App Transport Security的例外,详细可参考[这篇帖子](https://segmentfault.com/a/1190000002933776)。
+
+
+### 使用其他的网络库
+
+React Native中已经内置了[XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)(也就是俗称的ajax)。一些基于XMLHttpRequest封装的第三方库也可以使用,例如[frisbee](https://github.com/niftylettuce/frisbee)或是[axios](https://github.com/mzabriskie/axios)等。但注意不能使用jQuery,因为jQuery中还使用了很多浏览器中才有而RN中没有的东西(所以也不是所有web中的ajax库都可以直接使用)。
+
+```js
+var request = new XMLHttpRequest();
+request.onreadystatechange = (e) => {
+ if (request.readyState !== 4) {
+ return;
+ }
+
+ if (request.status === 200) {
+ console.log('success', request.responseText);
+ } else {
+ console.warn('error');
+ }
+};
+
+request.open('GET', 'https://mywebsite.com/endpoint/');
+request.send();
+```
+
+> 需要注意的是,安全机制与网页环境有所不同:在应用中你可以访问任何网站,没有[跨域](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)的限制。
+
+## WebSocket支持
+
+React Native还支持[WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket),这种协议可以在单个TCP连接上提供全双工的通信信道。
+
+```js
+var ws = new WebSocket('ws://host.com/path');
+
+ws.onopen = () => {
+ // 打开一个连接
+
+ ws.send('something'); // 发送一个消息
+};
+
+ws.onmessage = (e) => {
+ // 接收到了一个消息
+ console.log(e.data);
+};
+
+ws.onerror = (e) => {
+ // 发生了一个错误
+ console.log(e.message);
+};
+
+ws.onclose = (e) => {
+ // 连接被关闭了
+ console.log(e.code, e.reason);
+};
+```
+
+现在你的应用已经可以从各种渠道获取数据了,那么接下来面临的问题多半就是如何在不同的页面间组织和串联内容了。要管理页面的跳转,你需要学习使用[导航器](using-navigators.html)。
diff --git a/docs/docs/0.42/panresponder.md b/docs/docs/0.42/panresponder.md
new file mode 100644
index 0000000..f4afb4d
--- /dev/null
+++ b/docs/docs/0.42/panresponder.md
@@ -0,0 +1,236 @@
+`PanResponder`类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
+
+它提供了一个对[触摸响应系统](gesture-responder-system.html)响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的`gestureState`对象。
+
+```javascript
+onPanResponderMove: (event, gestureState) => {}
+```
+
+原生事件是指由以下字段组成的合成触摸事件:
+
+- `nativeEvent`
+ + `changedTouches` - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
+ + `identifier` - 触摸点的ID
+ + `locationX` - 触摸点相对于父元素的横坐标
+ + `locationY` - 触摸点相对于父元素的纵坐标
+ + `pageX` - 触摸点相对于根元素的横坐标
+ + `pageY` - 触摸点相对于根元素的纵坐标
+ + `target` - 触摸点所在的元素ID
+ + `timestamp` - 触摸事件的时间戳,可用于移动速度的计算
+ + `touches` - 当前屏幕上的所有触摸点的集合
+
+一个`gestureState`对象有如下的字段:
+
+* `stateID` - 触摸状态的ID。在屏幕上有至少一个触摸点的情况下,这个ID会一直有效。
+* `moveX` - 最近一次移动时的屏幕横坐标
+* `moveY` - 最近一次移动时的屏幕纵坐标
+* `x0` - 当响应器产生时的屏幕坐标
+* `y0` - 当响应器产生时的屏幕坐标
+* `dx` - 从触摸操作开始时的累计横向路程
+* `dy` - 从触摸操作开始时的累计纵向路程
+* `vx` - 当前的横向移动速度
+* `vy` - 当前的纵向移动速度
+* `numberActiveTouches` - 当前在屏幕上的有效触摸点的数量
+
+### 基本用法
+
+```javascript
+ componentWillMount: function() {
+ this._panResponder = PanResponder.create({
+ // 要求成为响应者:
+ onStartShouldSetPanResponder: (evt, gestureState) => true,
+ onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
+ onMoveShouldSetPanResponder: (evt, gestureState) => true,
+ onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
+
+ onPanResponderGrant: (evt, gestureState) => {
+ // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
+
+ // gestureState.{x,y}0 现在会被设置为0
+ },
+ onPanResponderMove: (evt, gestureState) => {
+ // 最近一次的移动距离为gestureState.move{X,Y}
+
+ // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
+ },
+ onPanResponderTerminationRequest: (evt, gestureState) => true,
+ onPanResponderRelease: (evt, gestureState) => {
+ // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
+ // 一般来说这意味着一个手势操作已经成功完成。
+ },
+ onPanResponderTerminate: (evt, gestureState) => {
+ // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
+ },
+ onShouldBlockNativeResponder: (evt, gestureState) => {
+ // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
+ // 默认返回true。目前暂时只支持android。
+ return true;
+ },
+ });
+ },
+
+ render: function() {
+ return (
+
+ );
+ },
+```
+
+### 可运行的例子
+
+要想看看可以直接使用的例子,请参阅[UIExplorer中的PanResponder](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/PanResponderExample.js)
+
+### 方法
+
+
+
+
static create(config: object) #
+
+
@param {object} 配置所有响应器回调的加强版本,不仅仅包括原本的ResponderSyntheticEvent,还包括PanResponder手势状态的回调。你只要简单的把onResponder*回调中的Responder替换为PanResponder。举例来说,这个config对象可能看起来像这样:
+
+ onMoveShouldSetPanResponder: (e, gestureState) => {...}
+ onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
+ onStartShouldSetPanResponder: (e, gestureState) => {...}
+ onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
+ onPanResponderReject: (e, gestureState) => {...}
+ onPanResponderGrant: (e, gestureState) => {...}
+ onPanResponderStart: (e, gestureState) => {...}
+ onPanResponderEnd: (e, gestureState) => {...}
+ onPanResponderRelease: (e, gestureState) => {...}
+ onPanResponderMove: (e, gestureState) => {...}
+ onPanResponderTerminate: (e, gestureState) => {...}
+ onPanResponderTerminationRequest: (e, gestureState) => {...}
+
+ onShouldBlockNativeResponder: (e, gestureState) => {...}
+ 通常来说,对那些有对应捕获事件的事件来说,我们在捕获阶段更新gestureState一次,然后在冒泡阶段直接使用即可。
+ 注意onStartShould* 回调。他们只会在此节点冒泡/捕获的开始/结束事件中提供已经更新过的gestureState。一旦这个节点成为了事件的响应者,则所有的开始/结束事件都会被手势正确处理,并且gestureState也会被正确更新。(numberActiveTouches)有可能没有包含所有的触摸点,除非你就是触摸事件的响应者。
+
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ PanResponder,
+ StyleSheet,
+ View,
+ processColor,
+} = ReactNative;
+
+var CIRCLE_SIZE = 80;
+
+var PanResponderExample = React.createClass({
+
+ statics: {
+ title: 'PanResponder Sample',
+ description: 'Shows the use of PanResponder to provide basic gesture handling.',
+ },
+
+ _panResponder: {},
+ _previousLeft: 0,
+ _previousTop: 0,
+ _circleStyles: {},
+ circle: (null : ?{ setNativeProps(props: Object): void }),
+
+ componentWillMount: function() {
+ this._panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
+ onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
+ onPanResponderGrant: this._handlePanResponderGrant,
+ onPanResponderMove: this._handlePanResponderMove,
+ onPanResponderRelease: this._handlePanResponderEnd,
+ onPanResponderTerminate: this._handlePanResponderEnd,
+ });
+ this._previousLeft = 20;
+ this._previousTop = 84;
+ this._circleStyles = {
+ style: {
+ left: this._previousLeft,
+ top: this._previousTop,
+ backgroundColor: 'green',
+ }
+ };
+ },
+
+ componentDidMount: function() {
+ this._updateNativeStyles();
+ },
+
+ render: function() {
+ return (
+
+ {
+ this.circle = circle;
+ }}
+ style={styles.circle}
+ {...this._panResponder.panHandlers}
+ />
+
+ );
+ },
+
+ _highlight: function() {
+ this._circleStyles.style.backgroundColor = 'blue';
+ this._updateNativeStyles();
+ },
+
+ _unHighlight: function() {
+ this._circleStyles.style.backgroundColor = 'green';
+ this._updateNativeStyles();
+ },
+
+ _updateNativeStyles: function() {
+ this.circle && this.circle.setNativeProps(this._circleStyles);
+ },
+
+ _handleStartShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
+ // Should we become active when the user presses down on the circle?
+ return true;
+ },
+
+ _handleMoveShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
+ // Should we become active when the user moves a touch over the circle?
+ return true;
+ },
+
+ _handlePanResponderGrant: function(e: Object, gestureState: Object) {
+ this._highlight();
+ },
+ _handlePanResponderMove: function(e: Object, gestureState: Object) {
+ this._circleStyles.style.left = this._previousLeft + gestureState.dx;
+ this._circleStyles.style.top = this._previousTop + gestureState.dy;
+ this._updateNativeStyles();
+ },
+ _handlePanResponderEnd: function(e: Object, gestureState: Object) {
+ this._unHighlight();
+ this._previousLeft += gestureState.dx;
+ this._previousTop += gestureState.dy;
+ },
+});
+
+var styles = StyleSheet.create({
+ circle: {
+ width: CIRCLE_SIZE,
+ height: CIRCLE_SIZE,
+ borderRadius: CIRCLE_SIZE / 2,
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ },
+ container: {
+ flex: 1,
+ paddingTop: 64,
+ },
+});
+
+module.exports = PanResponderExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/performance.md b/docs/docs/0.42/performance.md
new file mode 100644
index 0000000..4485d3c
--- /dev/null
+++ b/docs/docs/0.42/performance.md
@@ -0,0 +1,131 @@
+使用React Native替代基于WebView的框架来开发App的一个强有力的理由,就是为了使App可以达到每秒60帧(足够流畅),并且能有类似原生App的外观和手感。因此我们也尽可能地优化React Native去实现这一目标,使开发者能集中精力处理App的业务逻辑,而不用费心考虑性能。但是,总还是有一些地方有所欠缺,以及在某些场合React Native还不能够替你决定如何进行优化(用原生代码写也无法避免),因此人工的干预依然是必要的。
+本文的目的是教给你一些基本的知识,来帮你排查性能方面的问题,以及探讨这些问题产生的原因和推荐的解决方法。
+
+## 关于“帧”你所需要知道的
+
+老一辈人常常把电影称为“移动的画”,是因为视频中逼真的动态效果其实是一种幻觉,这种幻觉是由一组静态的图片以一个稳定的速度快速变化所产生的。我们把这组图片中的每一张图片叫做一帧,而每秒钟显示的帧数直接的影响了视频(或者说用户界面)的流畅度和真实感。iOS设备提供了每秒60的帧率,这就留给了开发者和UI系统大约16.67ms来完成生成一张静态图片(帧)所需要的所有工作。如果在这分派的16.67ms之内没有能够完成这些工作,就会引发‘丢帧’的后果,使界面表现的不够流畅。
+
+下面要讲的事情可能更为复杂:请先调出你应用的开发菜单,打开`Show FPS Monitor`. 你会注意到有两个不同的帧率.
+
+### JavaScript 帧率
+
+对大多数React Native应用来说,业务逻辑是运行在JavaScript线程上的。这是React应用所在的线程,也是发生API调用,以及处理触摸事件等操作的线程。更新数据到原生支持的视图是批量进行的,并且在事件循环每进行一次的时候被发送到原生端,这一步通常会在一帧时间结束之前处理完(如果一切顺利的话)。如果JavaScript线程有一帧没有及时响应,就被认为发生了一次丢帧。 例如,你在一个复杂应用的根组件上调用了`this.setState`,从而导致一次开销很大的子组件树的重绘,可想而知,这可能会花费200ms也就是整整12帧的丢失。此时,任何由JavaScript控制的动画都会卡住。只要卡顿超过100ms,用户就会明显的感觉到。
+
+这种情况经常发生在Navigator的切换过程中:当你push一个新的路由时,JavaScript需要绘制新场景所需的所有组件,以发送正确的命令给原生端去创建视图。由于切换是由JavaScript线程所控制,因此经常会占用若干帧的时间,引起一些卡顿。有的时候,组件会在`componentDidMount`函数中做一些额外的事情,这甚至可能会导致页面切换过程中多达一秒的卡顿。
+
+另一个例子是触摸事件的响应:如果你正在JavaScript线程处理一个跨越多个帧的工作,你可能会注意到TouchableOpacity的响应被延迟了。这是因为JavaScript线程太忙了,不能够处理主线程发送过来的原始触摸事件。结果TouchableOpacity就不能及时响应这些事件并命令主线程的页面去调整透明度了。
+
+### 主线程 (也即UI线程) 帧率
+
+很多人会注意到,`NavigatorIOS`的性能要比Navigator好的多。原因就是它的切换动画是完全在主线程上执行的,因此不会被JavaScript线程上的掉帧所影响。([阅读关于为何你仍然需要使用Navigator](using-navigators.html))
+
+同样,当JavaScript线程卡住的时候,你仍然可以欢快的上下滚动ScrollView,因为ScrollView运行在主线程之上(尽管滚动事件会被分发到JS线程,但是接收这些事件对于滚动这个动作来说并不必要)。
+
+## 性能问题的常见原因
+
+### console.log语句
+
+在运行打好了离线包的应用时,控制台打印语句可能会极大地拖累JavaScript线程。注意有些第三方调试库也可能包含控制台打印语句,比如[redux-logger](https://github.com/evgenyrodionov/redux-logger),所以在发布应用前请务必仔细检查,确保全部移除。
+
+
+> 这里有个小技巧可以在发布时屏蔽掉所有的`console.*`调用。React Native中有一个全局变量`__DEV__`用于指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的console实现。
+
+```js
+if (!__DEV__) {
+ global.console = {
+ info: () => {},
+ log: () => {},
+ warn: () => {},
+ error: () => {},
+ };
+}
+```
+
+这样在打包发布时,所有的控制台语句就会被自动替换为空函数,而在调试时它们仍然会被正常调用。
+
+### 开发模式 (dev=true)
+
+JavaScript线程的性能在开发模式下是很糟糕的。这是不可避免的,因为有许多工作需要在运行的时候去做,譬如使你获得良好的警告和错误信息,又比如验证属性类型(propTypes)以及产生各种其他的警告。
+
+### 缓慢的导航器(Navigator)切换
+
+如之前说,`Navigator`的动画是由JavaScript线程所控制的。想象一下“从右边推入”这个场景的切换:每一帧中,新的场景从右向左移动,从屏幕右边缘开始(不妨认为是320单位宽的的x轴偏移),最终移动到x轴偏移为0的屏幕位置。切换过程中的每一帧,JavaScript线程都需要发送一个新的x轴偏移量给主线程。如果JavaScript线程卡住了,它就无法处理这项事情,因而这一帧就无法更新,动画就被卡住了。
+
+长远的解决方法,其中一部分是要允许基于JavaScript的动画从主线程分离。同样是上面的例子,我们可以在切换动画开始的时候计算出一个列表,其中包含所有的新的场景需要的x轴偏移量,然后一次发送到主线程以某种优化的方式执行。由于JavaScript线程已经从更新x轴偏移量给主线程这个职责中解脱了出来,因此JavaScript线程中的掉帧就不是什么大问题了 —— 用户将基本上不会意识到这个问题,因为用户的注意力会被流畅的切换动作所吸引。
+
+新的[React Navigation](https://reactnavigation.org/)库的一大目标就是为了解决这个问题。React Navigation中的视图是原生组件,同时用到了运行在原生线程上的`Animated`动画库,因而性能表现十分流畅。
+
+### ListView初始化渲染太慢以及列表过长时滚动性能太差
+这是一个频繁出现的问题。因为iOS配备了UITableView,通过重用底层的UIViews实现了非常高性能的体验(相比之下ListView的性能没有那么好)。用React Native实现相同效果的工作仍正在进行中,但是在此之前,我们有一些可用的方法来稍加改进性能以满足我们的需求。
+
+#### initialListSize
+
+这个属性定义了在首次渲染中绘制的行数。如果我们关注于快速的显示出页面,可以设置`initialListSize`为1,然后我们会发现其他行在接下来的帧中被快速绘制到屏幕上。而每帧所显示的行数由`pageSize`所决定。
+
+#### pageSize
+
+在初始渲染也就是`initialListSize`被使用之后,ListView将利用`pageSize`来决定每一帧所渲染的行数。默认值为1 —— 但是如果你的页面很小,而且渲染的开销不大的话,你会希望这个值更大一些。稍加调整,你会发现它所起到的作用。
+
+#### scrollRenderAheadDistance
+
+“在将要进入屏幕区域之前的某个位置,开始绘制一行,距离按像素计算。”
+
+如果我们有一个2000个元素的列表,并且立刻全部渲染出来的话,无论是内存还是计算资源都会显得很匮乏。还很可能导致非常可怕的阻塞。因此`scrollRenderAheadDistance`允许我们来指定一个超过视野范围之外所需要渲染的行数。
+
+#### removeClippedSubviews
+
+“当这一选项设置为true的时候,超出屏幕的子视图(同时`overflow`值为`hidden`)会从它们原生的父视图中移除。这个属性可以在列表很长的时候提高滚动的性能。默认为false。(0.14版本后默认为true)”
+
+这是一个应用在长列表上极其重要的优化。Android上,`overflow`值总是`hidden`的,所以你不必担心没有设置它。而在iOS上,你需要确保在行容器上设置了`overflow: hidden`。
+
+### 我的组件渲染太慢,我不需要立即显示全部
+
+这在初次浏览ListView时很常见,适当的使用它是获得稳定性能的关键。就像之前所提到的,它可以提供一些手段在不同帧中来分开渲染页面,稍加改进就可以满足你的需求。此外要记住的是,ListView也可以横向滚动。
+
+### 在重绘一个几乎没有什么变化的页面时,JS帧率严重降低
+
+如果你正在使用一个ListView,你必须提供一个`rowHasChanged`函数,它通过快速的算出某一行是否需要重绘,来减少很多不必要的工作。如果你使用了不可变的数据结构,这项工作就只需检查其引用是否相等。
+
+同样的,你可以实现`shouldComponentUpdate`函数来指明在什么样的确切条件下,你希望这个组件得到重绘。如果你编写的是纯粹的组件(返回值完全由props和state所决定),你可以利用`PureRenderMixin`来为你做这个工作。再强调一次,不可变的数据结构在提速方面非常有用 —— 当你不得不对一个长列表对象做一个深度的比较,它会使重绘你的整个组件更加快速,而且代码量更少。
+
+### 由于在JavaScript线程中同时做很多事情,导致JS线程掉帧
+
+“导航切换极慢”是该问题的常见表现。在其他情形下,这种问题也可能会出现。使用`InteractionManager`是一个好的方法,但是如果在动画中,为了用户体验的开销而延迟其他工作并不太能接受,那么你可以考虑一下使用`LayoutAnimation`。
+
+`Animated`的接口一般会在JavaScript线程中计算出所需要的每一个关键帧,而`LayoutAnimation`则利用了`Core Animation`,使动画不会被JS线程和主线程的掉帧所影响。
+
+举一个需要使用这项功能的例子:比如需要给一个模态框做动画(从下往上划动,并在半透明遮罩中淡入),而这个模态框正在初始化,并且可能响应着几个网络请求,渲染着页面的内容,并且还在更新着打开这个模态框的父页面。了解更多有关如何使用LayoutAnimation的信息,请查看[动画指南](/docs/animations.html)。
+
+注意:
+
+ - `LayoutAnimation`只工作在“一次性”的动画上("静态"动画) -- 如果动画可能会被中途取消,你还是需要使用`Animated`。
+
+### 在屏幕上移动视图(滚动,切换,旋转)时,UI线程掉帧
+
+当具有透明背景的文本位于一张图片上时,或者在每帧重绘视图时需要用到透明合成的任何其他情况下,这种现象尤为明显。设置`shouldRasterizeIOS`或者`renderToHardwareTextureAndroid`属性可以显著改善这一现象。
+注意不要过度使用该特性,否则你的内存使用量将会飞涨。在使用时,要评估你的性能和内存使用情况。如果你没有需要移动这个视图的需求,请关闭这一属性。
+
+### 使用动画改变图片的尺寸时,UI线程掉帧
+
+在iOS上,每次调整Image组件的宽度或者高度,都需要重新裁剪和缩放原始图片。这个操作开销会非常大,尤其是大的图片。比起直接修改尺寸,更好的方案是使用`transform: [{scale}]`的样式属性来改变尺寸。比如当你点击一个图片,要将它放大到全屏的时候,就可以使用这个属性。
+
+### Touchable系列组件不能很好的响应
+
+有些时候,如果我们有一项操作与点击事件所带来的透明度改变或者高亮效果发生在同一帧中,那么有可能在`onPress`函数结束之前我们都看不到这些效果。比如在`onPress`执行了一个`setState`的操作,这个操作需要大量计算工作并且导致了掉帧。对此的一个解决方案是将`onPress`处理函数中的操作封装到`requestAnimationFrame`中:
+
+
+```javascript
+handleOnPress() {
+ // 谨记在使用requestAnimationFrame、setTimeout以及setInterval时
+ // 要使用TimerMixin(其作用是在组件unmount时,清除所有定时器)
+ this.requestAnimationFrame(() => {
+ this.doExpensiveAction();
+ });
+}
+```
+
+## 分析
+
+你可以利用内置的分析器来同时获取JavaScript线程和主线程中代码执行情况的详细信息。
+
+对于iOS来说,Instruments是一个宝贵的工具库,Android的话,你可以使用systrace,参见[调试Android UI性能](/docs/android-ui-performance.html#content)。
diff --git a/docs/docs/0.42/permissionsandroid.md b/docs/docs/0.42/permissionsandroid.md
new file mode 100644
index 0000000..218d85a
--- /dev/null
+++ b/docs/docs/0.42/permissionsandroid.md
@@ -0,0 +1,61 @@
+`PermissionsAndroid`可以访问Android M(也就是6.0)开始提供的权限模型。有一些权限写在`AndroidManifest.xml`就可以在安装时自动获得。但有一些“危险”的权限则需要弹出提示框供用户选择。本API即用于后一种情形。
+
+在低于Android 6.0的设备上,权限只要写在`AndroidManifest.xml`里就会自动获得,此情形下`check`和`request` 方法将始终返回true。
+
+如果用户之前拒绝过你的某项权限请求,那么系统会建议你显示一个为什么需要这个权限的“详细解释”(rationale参数)。如果用户之前拒绝过,那么当你再次申请的时候,弹出的就可能不是原先的申请信息,而是`rationale`参数里提供的进一步解释。
+
+### 例子
+
+```js
+async function requestCameraPermission() {
+ try {
+ const granted = await PermissionsAndroid.request(
+ PermissionsAndroid.PERMISSIONS.CAMERA,
+ {
+ 'title': '申请摄像头权限',
+ 'message': '一个很牛逼的应用想借用你的摄像头,' +
+ '然后你就可以拍出酷炫的皂片啦。'
+ }
+ )
+ if (granted === PermissionsAndroid.RESULTS.GRANTED) {
+ console.log("现在你获得摄像头权限了")
+ } else {
+ console.log("用户并不屌你")
+ }
+ } catch (err) {
+ console.warn(err)
+ }
+}
+```
+### 方法
+
+
+
+
+ constructor
+ ()
+ #
+
+
+
+
check(permission)
+ #
+
+
返回一个promise,最终值为用户是否授权过的布尔值。
+
+
+
request(permission, rationale?)
+ #
+
+
+
+
+
requestMultiple(permissions)
+ #
+
在一个弹出框中向用户请求多个权限。返回值为一个object,key为各权限名称,对应值为用户授权与否。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/picker.md b/docs/docs/0.42/picker.md
new file mode 100644
index 0000000..d8d6f07
--- /dev/null
+++ b/docs/docs/0.42/picker.md
@@ -0,0 +1,56 @@
+本组件可以在iOS和Android上渲染原生的选择器(Picker)。用例:
+```js
+ this.setState({language: lang})}>
+
+
+
+```
+
+### 属性
+
+
+
+
onValueChange function #
+
某一项被选中时执行此回调。调用时带有如下参数:
+
+ itemValue: 被选中项的value属性
+ itemPosition: 被选中项在picker中的索引位置
+
+
+
+
+
style pickerStyleType
+ #
+
+
android enabled
+ bool #
+
+
+
android mode
+ enum('dialog', 'dropdown') #
+
在Android上,可以指定在用户点击选择器时,以怎样的形式呈现选项:
+
+ dialog(对话框形式): 显示一个模态对话框。默认选项。
+ dropdown(下拉框形式): 以选择器所在位置为锚点展开一个下拉框。
+
+
+
+
android prompt
+ string #
+
设置选择器的提示字符串。在Android的对话框模式中用作对话框的标题。
+
+
ios itemStyle
+ itemStylePropType #
+
+
+
diff --git a/docs/docs/0.42/pickerios.md b/docs/docs/0.42/pickerios.md
new file mode 100644
index 0000000..8af8904
--- /dev/null
+++ b/docs/docs/0.42/pickerios.md
@@ -0,0 +1,154 @@
+### 截图
+
+
+### 属性
+
+
+
itemStyle itemStylePropType #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ PickerIOS,
+ Text,
+ View,
+} = ReactNative;
+
+var PickerItemIOS = PickerIOS.Item;
+
+var CAR_MAKES_AND_MODELS = {
+ amc: {
+ name: 'AMC',
+ models: ['AMX', 'Concord', 'Eagle', 'Gremlin', 'Matador', 'Pacer'],
+ },
+ alfa: {
+ name: 'Alfa-Romeo',
+ models: ['159', '4C', 'Alfasud', 'Brera', 'GTV6', 'Giulia', 'MiTo', 'Spider'],
+ },
+ aston: {
+ name: 'Aston Martin',
+ models: ['DB5', 'DB9', 'DBS', 'Rapide', 'Vanquish', 'Vantage'],
+ },
+ audi: {
+ name: 'Audi',
+ models: ['90', '4000', '5000', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'Q5', 'Q7'],
+ },
+ austin: {
+ name: 'Austin',
+ models: ['America', 'Maestro', 'Maxi', 'Mini', 'Montego', 'Princess'],
+ },
+ borgward: {
+ name: 'Borgward',
+ models: ['Hansa', 'Isabella', 'P100'],
+ },
+ buick: {
+ name: 'Buick',
+ models: ['Electra', 'LaCrosse', 'LeSabre', 'Park Avenue', 'Regal',
+ 'Roadmaster', 'Skylark'],
+ },
+ cadillac: {
+ name: 'Cadillac',
+ models: ['Catera', 'Cimarron', 'Eldorado', 'Fleetwood', 'Sedan de Ville'],
+ },
+ chevrolet: {
+ name: 'Chevrolet',
+ models: ['Astro', 'Aveo', 'Bel Air', 'Captiva', 'Cavalier', 'Chevelle',
+ 'Corvair', 'Corvette', 'Cruze', 'Nova', 'SS', 'Vega', 'Volt'],
+ },
+};
+
+var PickerExample = React.createClass({
+ getInitialState: function() {
+ return {
+ carMake: 'cadillac',
+ modelIndex: 3,
+ };
+ },
+
+ render: function() {
+ var make = CAR_MAKES_AND_MODELS[this.state.carMake];
+ var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
+ return (
+
+ Please choose a make for your car:
+ this.setState({carMake, modelIndex: 0})}>
+ {Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
+
+ ))}
+
+ Please choose a model of {make.name}:
+ this.setState({modelIndex})}>
+ {CAR_MAKES_AND_MODELS[this.state.carMake].models.map((modelName, modelIndex) => (
+
+ ))}
+
+ You selected: {selectionString}
+
+ );
+ },
+});
+
+var PickerStyleExample = React.createClass({
+ getInitialState: function() {
+ return {
+ carMake: 'cadillac',
+ modelIndex: 0,
+ };
+ },
+
+ render: function() {
+ var make = CAR_MAKES_AND_MODELS[this.state.carMake];
+ var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
+ return (
+ this.setState({carMake, modelIndex: 0})}>
+ {Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
+
+ ))}
+
+ );
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Render lists of selectable options with UIPickerView.';
+exports.examples = [
+{
+ title: '',
+ render: function(): ReactElement {
+ return ;
+ },
+},
+{
+ title: ' with custom styling',
+ render: function(): ReactElement {
+ return ;
+ },
+}];
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/pixelratio.md b/docs/docs/0.42/pixelratio.md
new file mode 100644
index 0000000..485755c
--- /dev/null
+++ b/docs/docs/0.42/pixelratio.md
@@ -0,0 +1,67 @@
+PixelRatio类提供了访问设备的像素密度的方法。
+
+使用PixelRatio有如下几种常用情形:
+
+### 根据像素密度获取指定大小的图片
+
+如果应用运行在一个高像素密度的设备上,显示的图片也应当分辨率更高。一个取得缩略图的好规则就是将显示尺寸乘以像素密度比:
+
+```javascript
+var image = getImage({
+ width: PixelRatio.getPixelSizeForLayoutSize(200),
+ height: PixelRatio.getPixelSizeForLayoutSize(100),
+});
+
+```
+__译注__: 这段代码的意思是,如果你要在屏幕上摆放一个宽200高100的图片,那么首先要准备多个分辨率尺寸的图。`PixelRatio.getPixelSizeForLayoutSize(200)`方法会根据当前设备的pixelratio返回对应值,比如当前设备的pixelratio为2,则返回 200 * 2 = 400,最后生成的参数为{ width: 400, height: 200 },然后开发者自己实现getImage方法,根据这一参数,返回最符合此尺寸的图片地址。
+
+### 方法
+
+
+
+
static get() #
+
+
返回设备的像素密度,例如:
+
+ PixelRatio.get() === 1mdpi Android 设备 (160 dpi)
+ PixelRatio.get() === 1.5hdpi Android 设备 (240 dpi)
+ PixelRatio.get() === 2iPhone 4, 4S iPhone 5, 5c, 5s iPhone 6 xhdpi Android 设备 (320 dpi)
+ PixelRatio.get() === 3iPhone 6 plus xxhdpi Android 设备 (480 dpi)
+ PixelRatio.get() === 3.5
+
+
+
+
+
static getFontScale() #
+
+
返回字体大小缩放比例。这个比例可以用于计算绝对的字体大小,所以很多深度依赖字体大小的组件需要用此函数的结果进行计算。
+
如果没有设置字体大小,它会直接返回设备的像素密度。
+
目前这个函数仅仅在Android设备上实现了,它会体现用户选项里的“设置 > 显示 > 字体大小”。在iOS设备上它会直接返回默认的像素密度。
+
+
+
+
static getPixelSizeForLayoutSize(layoutSize: number) #
+
+
将一个布局尺寸(dp)转换为像素尺寸(px)。
+
一定会返回一个整数数值。
+
+
+
+
static startDetecting() #
+
+
+
+
+### 描述
+
+## 像素网格对齐
+
+在iOS设备上,你可以给元素指定任意精度的坐标和尺寸,例如29.674825。不过最终的物理屏幕上只会显示固定的坐标数。譬如iPhone4的分辨率是640x960,而iPhone6是750*1334。iOS会试图尽可能忠实地显示你指定的坐标,所以它采用了一种把一个像素分散到多个像素里的做法来欺骗眼睛。但这个作用的负面影响是显示出来的元素看起来会有一些模糊。
+
+在实践中,我们发现开发者们并不想要这个特性,反而需要去做一些额外的工作来确保坐标与像素坐标对齐,来避免元素显得模糊。在React Native中,我们会自动对齐坐标到像素坐标。
+
+我们做这个对齐的时候必须十分小心。如果你同时使用已经对齐的值和没有对齐的值,就会很容易产生一些因为近似导致的累积错误。即使这样的累积错误只发生一次,后果也可能会很严重,因为很可能会导致一个像素宽的边框最终突然消失或者显示为两倍的宽度。
+
+在React Native中,所有JS中的东西,包括布局引擎,都使用任意精度的数值。我们只在主线程最后设置原生组件的位置和坐标的时候才去做对齐工作。而且,对齐是相对于屏幕进行的,而非相对于父元素进行,进一步避免近似误差的累积。
diff --git a/docs/docs/0.42/platform-specific-code.md b/docs/docs/0.42/platform-specific-code.md
new file mode 100644
index 0000000..7414dad
--- /dev/null
+++ b/docs/docs/0.42/platform-specific-code.md
@@ -0,0 +1,93 @@
+在制作跨平台的App时,多半会碰到针对不同平台编写不同代码的需求。最直接的方案就是把组件放置到不同的文件夹下:
+
+```sh
+/common/components/
+/android/components/
+/ios/components/
+```
+
+另一个选择是根据平台不同在组件的文件命名上加以区分,如下:
+
+```sh
+BigButtonIOS.js
+BigButtonAndroid.js
+```
+
+但除此以外React Native还提供了另外两种简单区分平台的方案:
+
+## 特定平台扩展名
+React Native会检测某个文件是否具有`.ios.`或是`.android.`的扩展名,然后根据当前运行的平台加载正确对应的文件。
+
+假设你的项目中有如下两个文件:
+
+```sh
+BigButton.ios.js
+BigButton.android.js
+```
+
+这样命名组件后你就可以在其他组件中直接引用,而无需关心当前运行的平台是哪个。
+
+```javascript
+import BigButton from './components/BigButton';
+```
+
+React Native会根据运行平台的不同引入正确对应的组件。
+
+还有个实用的方法是Platform.select(),它可以以Platform.OS为key,从传入的对象中返回对应平台的值,见下面的示例:
+
+```javascript
+import { Platform, StyleSheet } from 'react-native';
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ ...Platform.select({
+ ios: {
+ backgroundColor: 'red',
+ },
+ android: {
+ backgroundColor: 'blue',
+ },
+ }),
+ },
+});
+```
+
+上面的代码会根据平台的不同返回不同的container样式——iOS上背景色为红色,而android为蓝色。
+
+这一方法可以接受任何合法类型的参数,因此你也可以直接用它针对不同平台返回不同的组件,像下面这样:
+
+
+```javascript
+var Component = Platform.select({
+ ios: () => require('ComponentIOS'),
+ android: () => require('ComponentAndroid'),
+})();
+
+ ;
+```
+
+
+## 平台模块
+React Native提供了一个检测当前运行平台的模块。如果组件只有一小部分代码需要依据平台定制,那么这个模块就可以派上用场。
+
+```javascript
+import { Platform, StyleSheet } from 'react-native';
+
+var styles = StyleSheet.create({
+ height: (Platform.OS === 'ios') ? 200 : 100,
+});
+```
+
+`Platform.OS`在iOS上会返回`ios`,而在Android设备或模拟器上则会返回`android`。
+
+### 检测Android版本
+在Android上,平台模块还可以用来检测当前所运行的Android平台的版本:
+
+```javascript
+import { Platform } from 'react-native';
+
+if(Platform.Version === 21){
+ console.log('Running on Lollipop!');
+}
+```
diff --git a/docs/docs/0.42/progressbarandroid.md b/docs/docs/0.42/progressbarandroid.md
new file mode 100644
index 0000000..e434d7c
--- /dev/null
+++ b/docs/docs/0.42/progressbarandroid.md
@@ -0,0 +1,165 @@
+封装了Android平台上的`ProgressBar`的React组件。这个组件可以用来表示应用正在加载或者有些事情正在进行中。
+
+例子:
+
+```javascript
+render: function() {
+ var progressBar =
+
+
+ ;
+
+ return (
+
+ );
+},
+```
+### 截图
+
+
+### 属性
+
+
+
+
+
+
indeterminate indeterminateType #
+
+
决定进度条是否要显示一个不确定的进度。注意这个在styleAttr是Horizontal的时候必须是false。
+
+
+
+
+
styleAttr STYLE_ATTRIBUTES #
+
+
进度条的样式。可取值有:
+
+ Horizontal
+ Small
+ Large
+ Inverse
+ SmallInverse
+ LargeInverse
+
+
+
+
+
+
+### 样例
+
+```javascript
+'use strict';
+
+var ProgressBar = require('ProgressBarAndroid');
+var React = require('React');
+var UIExplorerBlock = require('UIExplorerBlock');
+var UIExplorerPage = require('UIExplorerPage');
+
+var TimerMixin = require('react-timer-mixin');
+
+var MovingBar = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState: function() {
+ return {
+ progress: 0
+ };
+ },
+
+ componentDidMount: function() {
+ this.setInterval(
+ () => {
+ var progress = (this.state.progress + 0.02) % 1;
+ this.setState({progress: progress});
+ }, 50
+ );
+ },
+
+ render: function() {
+ return ;
+ },
+});
+
+var ProgressBarAndroidExample = React.createClass({
+
+ statics: {
+ title: '',
+ description: 'Visual indicator of progress of some operation. ' +
+ 'Shows either a cyclic animation or a horizontal bar.',
+ },
+
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+module.exports = ProgressBarAndroidExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/progressviewios.md b/docs/docs/0.42/progressviewios.md
new file mode 100644
index 0000000..4c571ba
--- /dev/null
+++ b/docs/docs/0.42/progressviewios.md
@@ -0,0 +1,123 @@
+使用`ProgressViewIOS`来在iOS上渲染一个UIProgressView。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
progressImage Image.propTypes.source #
+
+
+
+
progressTintColor string #
+
+
+
+
progressViewStyle enum('default', 'bar') #
+
+
+
+
trackImage Image.propTypes.source #
+
+
一个可拉伸的图片,用于显示进度条后面的轨道。
+
+
+
+
trackTintColor string #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ProgressViewIOS,
+ StyleSheet,
+ View,
+} = ReactNative;
+var TimerMixin = require('react-timer-mixin');
+
+var ProgressViewExample = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState() {
+ return {
+ progress: 0,
+ };
+ },
+
+ componentDidMount() {
+ this.updateProgress();
+ },
+
+ updateProgress() {
+ var progress = this.state.progress + 0.01;
+ this.setState({ progress });
+ this.requestAnimationFrame(() => this.updateProgress());
+ },
+
+ getProgress(offset) {
+ var progress = this.state.progress + offset;
+ return Math.sin(progress % Math.PI) % 1;
+ },
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = 'ProgressViewIOS';
+exports.description = 'ProgressViewIOS';
+exports.examples = [{
+ title: 'ProgressViewIOS',
+ render() {
+ return (
+
+ );
+ }
+}];
+
+var styles = StyleSheet.create({
+ container: {
+ marginTop: -20,
+ backgroundColor: 'transparent',
+ },
+ progressView: {
+ marginTop: 20,
+ }
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/props.md b/docs/docs/0.42/props.md
new file mode 100644
index 0000000..0f9b238
--- /dev/null
+++ b/docs/docs/0.42/props.md
@@ -0,0 +1,60 @@
+大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为`props`(属性)。
+
+以常见的基础组件`Image`为例,在创建一个图片时,可以传入一个名为`source`的prop来指定要显示的图片的地址,以及使用名为`style`的prop来控制其尺寸。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Image } from 'react-native';
+
+class Bananas extends Component {
+ render() {
+ let pic = {
+ uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
+ };
+ return (
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('Bananas', () => Bananas);
+```
+
+译注:在iOS上使用http链接的图片地址可能不会显示,参见[这篇说明修改](https://segmentfault.com/a/1190000002933776)。
+
+请注意`{pic}`外围有一层括号,我们需要用括号来把`pic`这个变量嵌入到JSX语句中。括号的意思是括号内部为一个js变量或表达式,需要执行后取值。因此我们可以把任意合法的JavaScript表达式通过括号嵌入到JSX语句中。
+
+自定义的组件也可以使用`props`。通过在不同的场景使用不同的属性定制,可以尽量提高自定义组件的复用范畴。只需在`render`函数中引用`this.props`,然后按需处理即可。下面是一个例子:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+class Greeting extends Component {
+ render() {
+ return (
+ Hello {this.props.name}!
+ );
+ }
+}
+
+class LotsOfGreetings extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('LotsOfGreetings', () => LotsOfGreetings);
+```
+
+我们在`Greeting`组件中将`name`作为一个属性来定制,这样可以复用这一组件来制作各种不同的“问候语”。上面的例子把`Greeting`组件写在JSX语句中,用法和内置组件并无二致——这正是React体系的魅力所在——如果你想搭建一套自己的基础UI框架,那就放手做吧!
+
+上面的例子出现了一样新的名为[`View`](view.html)的组件。[`View`](view.html) 常用作其他组件的容器,来帮助控制布局和样式。
+
+仅仅使用`props`和基础的[`Text`](text.html)、[`Image`](image.html)以及[`View`](view.html)组件,你就已经足以编写各式各样的UI组件了。要学习如何动态修改你的界面,那就需要进一步[学习State(状态)的概念](state.html)。
diff --git a/docs/docs/0.42/pushnotificationios.md b/docs/docs/0.42/pushnotificationios.md
new file mode 100644
index 0000000..a8adf39
--- /dev/null
+++ b/docs/docs/0.42/pushnotificationios.md
@@ -0,0 +1,372 @@
+本模块帮助你处理应用的推送通知,包括权限控制以及应用图标上的角标数(未读消息数)。
+
+要使用推送通知功能,首先[在苹果后台配置推送通知服务](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6)并且准备好服务端的系统。设置的过程可以参考[Parse的教程](https://parse.com/tutorials/ios-push-notifications)
+
+首先请[手动链接](linking-libraries-ios.html)PushNotificationIOS的库(以下操作如果不熟悉,请自行补习Xcode的使用教程):
+- 将`node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj`文件拖到Xcode界面中
+- 在Xcode的`Link Binary With Libraries`中添加`libRCTPushNotification.a`
+- 在`Header Search Paths`中添加: `$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS`
+- 将搜索选项设为`recursive`
+
+然后你需要在AppDelegate中启用推送通知的支持以及注册相应的事件。
+
+在`AppDelegate.m`开头:
+
+```objective-c
+#import "RCTPushNotificationManager.h"
+```
+
+然后在AppDelegate实现中添加如下的代码:
+
+```objective-c
+ // Required to register for notifications
+ - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
+ {
+ [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
+ }
+ // Required for the register event.
+ - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
+ {
+ [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+ }
+ // Required for the notification event.
+ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
+ {
+ [RCTPushNotificationManager didReceiveRemoteNotification:notification];
+ }
+ // Required for the localNotification event.
+ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+ {
+ [RCTPushNotificationManager didReceiveLocalNotification:notification];
+ }
+```
+
+### 方法
+
+
+
+
static presentLocalNotification(details: Object) #
+
+
立即产生一个本地通知
+
details参数是一个对象,包含:
+
+ alertBody : 要在通知提示中显示的消息。
+ alertAction : 在交互式通知提示下显示的"action"。默认为"view"。
+ soundName : 通知触发时播放的声音名字(可选)。
+ category : 可选的通知类型,但对于交互式通知为必填。
+ userInfo : 提供一个可选的object,可以在其中提供额外的数据。
+ applicationIconBadgeNumber : 指定显示在应用右上角的数字角标(可选)。默认值为0,即不显示角标。
+
+
+
+
+
static scheduleLocalNotification(details: Object) #
+
+
计划一个本地通知,在将来进行提示。
+
details参数是一个对象,包含:
+
+ fireDate : 系统发送这个提示的日期和时间。
+ alertBody : 要在通知提示中显示的消息。
+ alertAction : 在交互式通知提示下显示的"action"。默认为"view"。
+ soundName : 通知触发时播放的声音名字(可选)。
+ category : 可选的通知类型,但对于交互式通知为必填。
+ userInfo : 提供一个可选的object,可以在其中提供额外的数据。
+ applicationIconBadgeNumber : 指定显示在应用右上角的数字角标(可选)。默认值为0,即不显示角标。
+
+
+
+
+
static cancelAllLocalNotifications() #
+
+
+
+
static setApplicationIconBadgeNumber(number: number) #
+
+
设置要在手机主屏幕应用图标上显示的角标数(未读消息数)。
+
+
+
+
static getApplicationIconBadgeNumber(callback: Function) #
+
+
获取目前在手机主屏幕应用图标上显示的角标数(未读消息数)。
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听器,监听远程或本地推送的通知事件,不论应用在前台还是在后台运行
+
事件类型有:
+
+ notification : 当收到来自远程的推送通知时调用handler函数,第一个参数是一个PushNotificationIOS实例。
+ localNotification : 当收到来自本地的推送通知时调用handler函数,第一个参数是一个PushNotificationIOS实例。
+ register: 当用户注册远程通知的时候调用handler函数。参数是一个十六进制的字符串,表示了设备标识(deviceToken)。
+
+
+
+
+
static requestPermissions(permissions?: {
+ alert?: boolean,
+ badge?: boolean,
+ sound?: boolean
+ }) #
+
+
向iOS系统请求通知权限,给用户展示一个对话框。默认情况下,它会请求所有的权限。不过你可以通过传递一个映射(map)到permissions参数来请求指定的权限子集。可以请求的权限类型有:
+
+ alert
+ badge
+ sound
+
+
如果提供了一个映射(map)作为参数,只有值为真值的权限才会被请求。
+
+
+
+
static abandonPermissions() #
+
+
注销所有从苹果推送通知服务收到的远程消息。
+
你应该只会在极少的情况下需要调用此函数,譬如一个新版本的App要取消所有远程推送通知的支持。如果是用户希望关闭推送通知,他可以打开系统设置的推送通知一栏来暂时屏蔽。应用通过此方法注销后,可以随时重新注册。
+
+
+
+
static checkPermissions(callback: Function) #
+
+
检查哪些推送通知权限被开启。 callback函数会被调用,参数为permissions 对象:
+
+ alert :boolean
+ badge :boolean
+ sound :boolean
+
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
移除注册事件监听器。在componentWillUnmount中调用此函数以避免内存泄露。
+
+
+
+
static popInitialNotification() #
+
+
如果用户通过点击推送通知来冷启动应用(即:之前应用不在运行状态),此函数会返回一个初始的通知。
+
第一次调用popInitialNotification会返回初始的通知对象,或者返回null。后续的调用全部会返回null.
+
+
+
+
constructor(nativeNotif: Object) #
+
你应该永远不需要自己实例化PushNotificationIOS对象。监听notification事件和调用popInitialNotification应当足够了。
+
+
+
+
getMessage() #
+
+
getAlert方法的别名。获取推送通知的主消息内容。
+
+
+
+
+
+
getBadgeCount() #
+
+
从aps对象中获取推送通知的角标数(未读消息数)。
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ AlertIOS,
+ PushNotificationIOS,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+var Button = React.createClass({
+ render: function() {
+ return (
+
+
+ {this.props.label}
+
+
+ );
+ }
+});
+
+class NotificationExample extends React.Component {
+ componentWillMount() {
+ // Add listener for push notifications
+ PushNotificationIOS.addEventListener('notification', this._onNotification);
+ // Add listener for local notifications
+ PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification);
+ }
+
+ componentWillUnmount() {
+ // Remove listener for push notifications
+ PushNotificationIOS.removeEventListener('notification', this._onNotification);
+ // Remove listener for local notifications
+ PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification);
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ _sendNotification() {
+ require('RCTDeviceEventEmitter').emit('remoteNotificationReceived', {
+ aps: {
+ alert: 'Sample notification',
+ badge: '+1',
+ sound: 'default',
+ category: 'REACT_NATIVE'
+ },
+ });
+ }
+
+ _sendLocalNotification() {
+ require('RCTDeviceEventEmitter').emit('localNotificationReceived', {
+ aps: {
+ alert: 'Sample local notification',
+ badge: '+1',
+ sound: 'default',
+ category: 'REACT_NATIVE'
+ },
+ });
+ }
+
+ _onNotification(notification) {
+ AlertIOS.alert(
+ 'Push Notification Received',
+ 'Alert message: ' + notification.getMessage(),
+ [{
+ text: 'Dismiss',
+ onPress: null,
+ }]
+ );
+ }
+
+ _onLocalNotification(notification){
+ AlertIOS.alert(
+ 'Local Notification Received',
+ 'Alert message: ' + notification.getMessage(),
+ [{
+ text: 'Dismiss',
+ onPress: null,
+ }]
+ );
+ }
+}
+
+class NotificationPermissionExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {permissions: null};
+ }
+
+ render() {
+ return (
+
+
+
+ {JSON.stringify(this.state.permissions)}
+
+
+ );
+ }
+
+ _showPermissions() {
+ PushNotificationIOS.checkPermissions((permissions) => {
+ this.setState({permissions});
+ });
+ }
+}
+
+var styles = StyleSheet.create({
+ button: {
+ padding: 10,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ buttonLabel: {
+ color: 'blue',
+ },
+});
+
+exports.title = 'PushNotificationIOS';
+exports.description = 'Apple PushNotification and badge value';
+exports.examples = [
+{
+ title: 'Badge Number',
+ render(): ReactElement {
+ PushNotificationIOS.requestPermissions();
+
+ return (
+
+ PushNotificationIOS.setApplicationIconBadgeNumber(42)}
+ label="Set app's icon badge to 42"
+ />
+ PushNotificationIOS.setApplicationIconBadgeNumber(0)}
+ label="Clear app's icon badge"
+ />
+
+ );
+ },
+},
+{
+ title: 'Push Notifications',
+ render(): ReactElement {
+ return ;
+ }
+},
+{
+ title: 'Notifications Permissions',
+ render(): ReactElement {
+ return ;
+ }
+}];
+```
diff --git a/docs/docs/0.42/refreshcontrol.md b/docs/docs/0.42/refreshcontrol.md
new file mode 100644
index 0000000..b56dfea
--- /dev/null
+++ b/docs/docs/0.42/refreshcontrol.md
@@ -0,0 +1,159 @@
+这一组件可以用在ScrollView或ListView内部,为其添加下拉刷新的功能。当ScrollView处于竖直方向的起点位置(scrollY: 0),此时下拉会触发一个`onRefresh`事件。
+
+### 属性
+
+
onRefresh function
+#
+
+
+
+
android colors
+[ColorPropType] #
+
+
+
android enabled
+bool #
+
+
+
android progressBackgroundColor
+ColorPropType #
+
+
+
android size
+RefreshLayoutConsts.SIZE.DEFAULT #
+
指定刷新指示器的大小,具体数值可参阅RefreshControl.SIZE.
+
+
android progressViewOffset
+React.PropTypes.number #
+
指定刷新指示器的垂直起始位置(top offset)。
+
+
ios tintColor
+ColorPropType #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ ScrollView,
+ StyleSheet,
+ RefreshControl,
+ Text,
+ TouchableWithoutFeedback,
+ View,
+} = ReactNative;
+
+const styles = StyleSheet.create({
+ row: {
+ borderColor: 'grey',
+ borderWidth: 1,
+ padding: 20,
+ backgroundColor: '#3a5795',
+ margin: 5,
+ },
+ text: {
+ alignSelf: 'center',
+ color: '#fff',
+ },
+ scrollview: {
+ flex: 1,
+ },
+});
+
+const Row = React.createClass({
+ _onClick: function() {
+ this.props.onClick(this.props.data);
+ },
+ render: function() {
+ return (
+
+
+
+ {this.props.data.text + ' (' + this.props.data.clicks + ' clicks)'}
+
+
+
+ );
+ },
+});
+
+const RefreshControlExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Adds pull-to-refresh support to a scrollview.'
+ },
+
+ getInitialState() {
+ return {
+ isRefreshing: false,
+ loaded: 0,
+ rowData: Array.from(new Array(20)).map(
+ (val, i) => ({text: 'Initial row ' + i, clicks: 0})),
+ };
+ },
+
+ _onClick(row) {
+ row.clicks++;
+ this.setState({
+ rowData: this.state.rowData,
+ });
+ },
+
+ render() {
+ const rows = this.state.rowData.map((row, ii) => {
+ return ;
+ });
+ return (
+
+ }>
+ {rows}
+
+ );
+ },
+
+ _onRefresh() {
+ this.setState({isRefreshing: true});
+ setTimeout(() => {
+ // prepend 10 items
+ const rowData = Array.from(new Array(10))
+ .map((val, i) => ({
+ text: 'Loaded row ' + (+this.state.loaded + i),
+ clicks: 0,
+ }))
+ .concat(this.state.rowData);
+
+ this.setState({
+ loaded: this.state.loaded + 10,
+ isRefreshing: false,
+ rowData: rowData,
+ });
+ }, 5000);
+ },
+});
+
+module.exports = RefreshControlExample;
+```
diff --git a/docs/docs/0.42/running-on-device-android.md b/docs/docs/0.42/running-on-device-android.md
new file mode 100644
index 0000000..5bc930b
--- /dev/null
+++ b/docs/docs/0.42/running-on-device-android.md
@@ -0,0 +1,51 @@
+## 前提条件:USB调试
+
+你需要开启USB调试才能在你的设备上安装你的APP。首先,确定[你已经打开设备的USB调试开关](https://www.baidu.com/s?wd=%E5%AE%89%E5%8D%93%E6%89%93%E5%BC%80usb%E8%B0%83%E8%AF%95)
+
+确保你的设备已经**成功连接**。可以输入`adb devices`来查看:
+
+ $ adb devices
+ List of devices attached
+ emulator-5554 offline # Google模拟器
+ 14ed2fcc device # 真实设备
+
+在右边那列看到**device**说明你的设备已经被正确连接了。注意,你只应当**连接仅仅一个设备**。
+
+__译注__:如果你连接了多个设备(包含模拟器在内),后续的一些操作可能会失败。拔掉不需要的设备,或者关掉模拟器,确保adb devices的输出只有一个是连接状态。
+
+现在你可以运行`react-native run-android`来在设备上安装并启动应用了。
+
+__译注__:在真机上运行时可能会遇到白屏的情况,请找到并开启`悬浮窗权限`。比如miui系统的设置[在此处](http://jingyan.baidu.com/article/f25ef25466c0fc482d1b824d.html)。
+
+> 提示
+>
+> 你还可以运行`react-native run-android --variant=release`来安装release版的应用。当然你需要[先配置好签名](signed-apk-android.html),且此时无法再开启开发者菜单。注意在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
+## 从设备上访问开发服务器。
+
+在启用开发服务器的情况下,你可以快速的迭代修改应用,然后在设备上查看结果。按照下面描述的任意一种方法来使你的运行在电脑上的开发服务器可以从设备上访问到。
+
+> 注意
+>
+> 大部分现代的安卓设备已经没有了硬件"Menu"按键,这是我们用来调出开发者菜单的。在这种情况下你可以通过摇晃设备来打开开发者菜单(重新加载、调试,等等……)
+
+### (Android 5.0及以上)使用adb reverse命令
+
+> 注意,这个选项只能在5.0以上版本(API 21+)的安卓设备上使用。
+
+首先把你的设备通过USB数据线连接到电脑上,并开启USB调试(关于如何开启USB调试,参见上面的章节)。
+
+1. 运行`adb reverse tcp:8081 tcp:8081`
+2. 不需要更多配置,你就可以使用`Reload JS`和其它的开发选项了。
+
+### (Android 5.0以下)通过Wi-Fi连接你的本地开发服务器
+
+1. 首先确保你的电脑和手机设备在**同一个Wi-Fi环境**下。
+2. 在设备上运行你的React Native应用。和打开其它App一样操作。
+3. 你应该会看到一个“红屏”错误提示。这是正常的,下面的步骤会解决这个报错。
+4. 摇晃设备,或者运行`adb shell input keyevent 82`,可以打开**开发者菜单**。
+5. 点击进入`Dev Settings`。
+6. 点击`Debug server host for device`。
+7. 输入你电脑的IP地址和端口号(譬如10.0.1.1:8081)。**在Mac上**,你可以在系统设置/网络里找查询你的IP地址。**在Windows上**,打开命令提示符并输入`ipconfig`来查询你的IP地址。**在Linux上**你可以在终端中输入`ifconfig`来查询你的IP地址。
+8. 回到**开发者菜单**然后选择`Reload JS`。
+
diff --git a/docs/docs/0.42/running-on-device-ios.md b/docs/docs/0.42/running-on-device-ios.md
new file mode 100644
index 0000000..f9d3894
--- /dev/null
+++ b/docs/docs/0.42/running-on-device-ios.md
@@ -0,0 +1,22 @@
+
+在真机上测试iOS应用需要一台Mac电脑,同时还需要注册一个Apple ID。如果你需要把应用发布到App Store,那么你还需要去苹果开发者网站购买一个开发者账户(在自己手机上测试则不用)。本文档只探讨React Native相关的发布问题。
+
+## 在真机上访问开发服务器(packager)
+
+你可以在真机上访问开发服务器以快速测试和迭代。首先需要确保设备已使用usb连接至电脑,同时和电脑处在同一wifi网络内,然后在Xcode中选择你的设备作为编译目标(左上角运行按钮的右边),然后点击运行按钮即可。
+如果你需要在真机上启用调试功能,则需要打开[RCTWebSocketExecutor.m](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m)文件,然后将其中的"localhost"改为你的电脑的IP地址,最后启用开发者菜单中的"Debug JS Remotely"选项。
+
+> 提示
+摇晃设备就可以打开开发者菜单。
+
+## 发布应用
+
+当你使用React Native做好一个漂亮的应用之后,一定跃跃欲试想要在App Store上发布了吧。发布的流程和其他iOS原生应用完全一样,除了以下一些注意事项。
+在App Store上发布应用首先需要编译一个“发布版本”(release)的应用。具体的做法是在Xcode中选择Product -> Scheme -> Edit Scheme (cmd + <),然后选择Run选项卡,将Build Configuration设置为release。
+Release版本的应用会自动禁用开发者菜单,同时也会将js文件和静态图片打包压缩后内置到包中,这样应用可以在本地读取而无需访问开发服务器(同时这样一来你也无法再调试,需要调试请将Buiid Configuration再改为debug)。
+由于发布版本已经内置了js文件,因而也无法再通过开发服务器来实时更新。面向用户的热更新,请使用专门的[热更新服务](http://update.reactnative.cn)。
+编译完成后,你就可以打包提交到TestFlight进行内测,或是提交到App Store进行发布。相关流程较为复杂,不熟悉原生应用发布流程的同学请自行搜索学习。
+
+### App Transport Security
+
+**App Transport Security**(简称ATS)是iOS 9中新增的一项安全特性。在默认设置下,只允许HTTPS的请求,而所有HTTP的请求都会被拒绝。详情可参考[这篇帖子](https://segmentfault.com/a/1190000002933776)。
\ No newline at end of file
diff --git a/docs/docs/0.42/running-on-simulator-ios.md b/docs/docs/0.42/running-on-simulator-ios.md
new file mode 100644
index 0000000..068c979
--- /dev/null
+++ b/docs/docs/0.42/running-on-simulator-ios.md
@@ -0,0 +1,9 @@
+## 启动模拟器
+
+当你完成了初始化React Native新项目后,就可以在项目目录下运行`react-native run-ios`来启动模拟器。如果一切配置都没有问题,应该很快就能看到你的应用在iOS模拟器上运行起来。
+
+## 指定模拟的设备类型
+
+你可以使用`--simulator`参数,在其后加上要使用的设备名称来指定要模拟的设备类型(目前默认为"iPhone 6")。如果你要模拟iPhone 4s,那么这样运行命令即可:`react-native run-ios --simulator "iPhone 4s"`。
+
+你可以在终端中运行`xcrun simctl list devices`来查看具体可用的设备名称。
diff --git a/docs/docs/0.42/sample-application-movies.md b/docs/docs/0.42/sample-application-movies.md
new file mode 100644
index 0000000..1a99bb3
--- /dev/null
+++ b/docs/docs/0.42/sample-application-movies.md
@@ -0,0 +1,504 @@
+## 简介
+
+在本示例教程中,我们将编写一个简单的应用,可以从电影数据库中取得最近正在上映的25部电影,并在一个`ListView`中展示出来。
+
+## 准备工作
+
+React Native需要一些基础的配置工作,你可以参考[开始使用React Native](getting-started.html)来进行。
+
+在所有依赖的软件都已经安装完毕后,只需要输入两条命令就可以创建一个React Native工程。
+
+1. `npm install -g react-native-cli`
+
+ react-native-cli是一个终端命令,它可以完成其余的设置工作。它可以通过npm安装。刚才这条命令会往你的终端安装一个叫做`react-native`的命令。这个安装过程你只需要进行一次。
+
+2. `react-native init SampleAppMovies`
+
+ 这个命令会初始化一个工程、下载React Native的所有源代码和依赖包,最后在`SampleAppMovies/iOS/SampleAppMovies.xcodeproj`和`SampleAppMovies/android/app`下分别创建一个新的XCode工程和一个gradle工程。
+
+__译注__:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请先将npm仓库源替换为国内镜像:
+
+```bash
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+另,执行init时切记`不要`在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题。如果你这样做了,请使用chown命令修复)。
+
+## 开发
+
+想开发iOS版本,你现在可以在XCode中打开刚刚创建的工程(`SampleAppMovies/iOS/SampleAppMovies.xcodeproj`),然后只要按下`⌘+R`就可以构建并运行。这个操作会同时打开一个用于实现动态代码加载的Node服务(React Packager)。所以每当你修改代码,你只需要在模拟器中按下`⌘+R`,而无需重新在XCode中编译。
+
+想开发Android版本,先连接你的设备或启动模拟器,然后在`SampleAppMovies`目录下运行`react-native run-android`,就会构建工程并自动安装到你的模拟器或者设备,同时启动用于实现动态代码加载的Node服务。当你修改代码之后,你需要打开摇一摇菜单(摇一下设备,或者按下设备的Menu键,或者在模拟器上按下F2或Page Up,Genymotion按下⌘+M),然后在菜单中点击“Reload JS”。
+
+### Hello World
+
+`react-native init`命令会创建一个指定名字的应用,我们刚才输入的命令就创建了一个名为SampleAppMovies的应用。这是一个简单的Hello World应用。对于iOS版本,你可以编辑`index.ios.js`来做一些改动,然后在模拟器中按⌘+R来看到修改的结果。对Android版本,你可以编辑`index.android.js`来做一些改动,然后在摇一摇菜单中点击“Reload JS”来看到修改的结果。
+
+### 模拟数据
+
+__译注__:本文的示例代码改用了ES6语法,可能和其他文档写法不一致。但React Native从0.18之后,新建项目默认已经采用了ES6语法,故我们推荐不熟悉ES6与ES5区别的朋友先读读[这篇文章](http://bbs.reactnative.cn/topic/15),另外还可以看看[阮一峰老师的书](http://es6.ruanyifeng.com/)。
+
+在我们真正从Rotten Tomatoes(_译注:一个国外的电影社区_)抓取数据之前,我们先制造一些模拟数据来练一练手。在Facebook我们通常在JS文件的开头,紧跟着import语句之后声明一个常量,不过这不重要,你可以把它放在`index.ios.js`和`index.android.js`的任意位置:
+
+```javascript
+var MOCKED_MOVIES_DATA = [
+ {title: '标题', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
+];
+```
+
+译注:在iOS上使用http链接的图片地址可能不会显示,参见[这篇说明修改](https://segmentfault.com/a/1190000002933776)。
+
+### 展现一个电影
+
+我们接下来要展现一个电影,绘制它的标题、年份、以及缩略图(_译注:这个过程我们通常会叫做“渲染/render”,后面我们都会用“渲染”这个词_)。渲染缩略图需要用到Image组件,所以把Image添加到对React的import列表中。
+
+```javascript
+import React, {
+ Component,
+} from 'react';
+import {
+ AppRegistry,
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+```
+
+然后修改一下render函数,这样我们可以把上面创建的模拟数据渲染出来。
+
+```javascript
+ render() {
+ var movie = MOCKED_MOVIES_DATA[0];
+ return (
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+```
+
+按下`⌘+R`或者`Reload JS`,现在你应该能看到文字"Title"和"2015",但现在Image组件没渲染任何东西,这是因为我们还没有为图片指定我们想要渲染的宽和高。这通过样式来实现。当我们修改样式的时候,我们也应该清理掉我们不再使用的样式。
+
+```javascript
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ thumbnail: {
+ width: 53,
+ height: 81,
+ },
+});
+```
+
+然后把它应用到Image组件上:
+
+```javascript
+
+```
+
+按下`⌘+R`或者`Reload JS`,现在图片应该可以被渲染出来了。
+
+| | |
+|--|--|
+| ||
+
+### 添加样式
+
+现在我们已经成功的把我们的数据渲染出来了,下面让我们把它弄的更好看一些。我想把文字放在图片的右边,然后把标题弄的大一些,并且水平居中:
+
+```
++---------------------------------+
+|+-------++----------------------+|
+|| || 标题 ||
+|| 图片 || ||
+|| || 年份 ||
+|+-------++----------------------+|
++---------------------------------+
+```
+
+所以我们需要增加一个container来实现一个水平布局内嵌套一个垂直布局。
+
+```javascript
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+```
+
+和之前相比并没有太多变化,我们增加了一个container来包装文字,然后把它移到了Image的后面(因为他们最终在图片的右边)。然后我们来看看样式要怎么改:
+
+```javascript
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+```
+
+我们用Flexbox来布局。如果你想了解更多,可以读读[这篇文章](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)。
+
+在上面的代码片段中,我们用了一句`flexDirection: 'row'`来让我们的主容器的成员从左到右横向布局,而非默认的从上到下纵向布局。
+
+现在我们往`style`对象里增加另一个样式:
+
+```javascript
+ rightContainer: {
+ flex: 1,
+ },
+```
+
+这句话的作用是让`rightContainer`在父容器中占据Image之外剩下的全部空间。如果你还不是很理解的话,你可以往`rightContainer`里增加一个`backgroundColor`看一看,然后再去掉`flex:1`对比一下。你会发现去掉这一句后,容器会变成能容纳它孩子的最小大小。
+
+给文字添加样式就简单的多了:
+
+```javascript
+ title: {
+ fontSize: 20,
+ marginBottom: 8,
+ textAlign: 'center',
+ },
+ year: {
+ textAlign: 'center',
+ },
+```
+
+再按一次`⌘+R`或者`Reload JS`来看看最新的结果。
+
+| | |
+|--|--|
+| ||
+
+### 拉取真正的数据
+
+从Rotten Tomatoes的API拉取数据和学习React Native并没有什么直接关系,所以你也可以直接跳过本节。
+
+把下面的常量放到文件的最开头(通常在import下面)来创建我们请求数据所需的地址常量REQUEST_URL
+
+```javascript
+/**
+ * 为了避免骚扰,我们用了一个样例数据来替代Rotten Tomatoes的API
+ * 请求,这个样例数据放在React Native的Github库中。
+ * 当然,由于众所周知的原因,这个地址可能国内访问也比较困难。
+ */
+var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
+```
+
+首先在应用中创建一个初始的null状态,这样可以通过`this.state.movies == null`来判断我们的数据是不是已经被抓取到了。我们在服务器响应返回的时候执行`this.setState({movies: moviesData})`来改变这个状态。把下面这段代码放到我们的React类的render函数之前(下面注释中的“绑定操作”你可以看看这个[短视频教程](http://v.youku.com/v_show/id_XMTgyNzM0NjQzMg==.html)):
+
+```javascript
+ constructor(props) {
+ super(props); //这一句不能省略,照抄即可
+ this.state = {
+ movies: null, //这里放你自己定义的state变量及初始值
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+```
+
+组件加载完毕之后,就可以向服务器请求数据。`componentDidMount`是React组件的一个生命周期方法,它会在组件刚加载完成的时候调用一次,以后不会再被调用。React中的各种生命周期方法请[参阅此文档](http://facebook.github.io/react/docs/component-specs.html)。
+
+```javascript
+ componentDidMount() {
+ this.fetchData();
+ }
+```
+
+现在我们来为组件添加`fetchData`函数。你所需要做的就是在Promise调用链结束后执行`this.setState({movies:data})`。在React的工作机制下,`setState`实际上会触发一次`重新渲染`的流程,此时render函数被触发,发现this.state.movies不再是`null`。
+
+```javascript
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ movies: responseData.movies,
+ });
+ });
+ }
+```
+
+现在我们来修改render函数。在电影数据加载完毕之前,先渲染一个“加载中”的视图;而如果电影数据已经加载完毕了,则渲染第一个电影数据。
+
+
+```javascript
+ render() {
+ if (!this.state.movies) {
+ return this.renderLoadingView();
+ }
+
+ var movie = this.state.movies[0];
+ return this.renderMovie(movie);
+ }
+
+ renderLoadingView() {
+ return (
+
+
+ 正在加载电影数据……
+
+
+ );
+ }
+
+ renderMovie(movie) {
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+```
+
+现在再按一次`⌘+R`或者`Reload JS`,你会首先看到“正在加载电影数据……”,然后在响应数据到达之后,看到第一个电影的信息。
+
+| | |
+|--|--|
+| ||
+
+## ListView
+
+现在我们来让我们的应用能够渲染所有的数据而不是仅仅第一部电影。我们要用到的就是ListView组件。
+
+为什么建议把内容放到ListView里?比起直接渲染出所有的元素,或是放到一个ScrollView里有什么优势?这是因为尽管React很高效,渲染一个可能很大的元素列表还是会很慢。`ListView`会安排视图的渲染,只显示当前在屏幕上的那些元素。而那些已经渲染好了但移动到了屏幕之外的元素,则会从原生视图结构中移除(以提高性能)。
+
+首先要做的事情:在文件最开头,从React中引入`ListView`。
+
+```javascript
+import React, {
+ Component,
+} from 'react';
+import {
+ AppRegistry,
+ Image,
+ ListView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+```
+
+现在来修改render函数。当我们已经有了数据之后,渲染一个包含多个电影信息的ListView,而不仅仅是单个的电影。
+
+```javascript
+ render() {
+ if (!this.state.loaded) {
+ return this.renderLoadingView();
+ }
+
+ return (
+
+ );
+ }
+```
+
+`dataSource`接口用来在ListView的整个更新过程中判断哪些数据行发生了变化。
+
+你会注意到我们现在用到了`this.state`中的`dataSource`。下一步就是在`constructor`生成的初始状态中添加一个空白的`dataSource`。另外,我们现在要把数据存储在`dataSource`中了,所以不再另外用`this.state.movies`来保存数据。我们可以在state里用一个布尔型的属性(`this.state.loaded`)来判断数据加载是否已经完成了。
+
+```javascript
+ constructor(props) {
+ super(props);
+ this.state = {
+ dataSource: new ListView.DataSource({
+ rowHasChanged: (row1, row2) => row1 !== row2,
+ }),
+ loaded: false,
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+```
+
+同时我们也要修改`fetchData`方法来把数据更新到dataSource里:
+
+```javascript
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
+ loaded: true,
+ });
+ });
+ }
+```
+
+最后,我们再在`styles`对象里给`ListView`添加一些样式。
+
+```javascript
+ listView: {
+ paddingTop: 20,
+ backgroundColor: '#F5FCFF',
+ },
+```
+
+现在可以体现最终的结果了:
+
+| | |
+|--|--|
+| ||
+
+为了实现一个完整功能的应用,接下来其实还有一些工作要做,譬如:添加导航器,搜索,加载更多,等等等等。可以在[Movies示例](https://github.com/facebook/react-native/tree/master/Examples/Movies)中看看我们是怎么做的。
+
+### 最终的代码
+
+```javascript
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+
+import React, {
+ Component,
+} from 'react';
+
+import {
+ AppRegistry,
+ Image,
+ ListView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+
+var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
+
+class SampleAppMovies extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ dataSource: new ListView.DataSource({
+ rowHasChanged: (row1, row2) => row1 !== row2,
+ }),
+ loaded: false,
+ };
+ // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向会变为空
+ // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
+ this.fetchData = this.fetchData.bind(this);
+ }
+
+ componentDidMount() {
+ this.fetchData();
+ }
+
+ fetchData() {
+ fetch(REQUEST_URL)
+ .then((response) => response.json())
+ .then((responseData) => {
+ // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
+ this.setState({
+ dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
+ loaded: true,
+ });
+ });
+ }
+
+ render() {
+ if (!this.state.loaded) {
+ return this.renderLoadingView();
+ }
+
+ return (
+
+ );
+ }
+
+ renderLoadingView() {
+ return (
+
+
+ Loading movies...
+
+
+ );
+ }
+
+ renderMovie(movie) {
+ return (
+
+
+
+ {movie.title}
+ {movie.year}
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ rightContainer: {
+ flex: 1,
+ },
+ title: {
+ fontSize: 20,
+ marginBottom: 8,
+ textAlign: 'center',
+ },
+ year: {
+ textAlign: 'center',
+ },
+ thumbnail: {
+ width: 53,
+ height: 81,
+ },
+ listView: {
+ paddingTop: 20,
+ backgroundColor: '#F5FCFF',
+ },
+});
+
+AppRegistry.registerComponent('SampleAppMovies', () => SampleAppMovies);
+```
diff --git a/docs/docs/0.42/scrollview.md b/docs/docs/0.42/scrollview.md
new file mode 100644
index 0000000..05ed38b
--- /dev/null
+++ b/docs/docs/0.42/scrollview.md
@@ -0,0 +1,542 @@
+一个包装了平台的ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。
+
+记住ScrollView必须有一个确定的高度才能正常工作,因为它实际上所做的就是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作)。要给一个ScrollView确定一个高度的话,要么直接给它设置高度(不建议),要么确定所有的父容器都已经绑定了高度。在视图栈的任意一个位置忘记使用`{flex:1}`都会导致错误,你可以使用元素查看器来查找问题的原因。
+
+ScrollView内部的其他响应者尚无法阻止ScrollView本身成为响应者。
+
+`ScrollView`和`ListView/FlatList`应该如何选择?ScrollView会简单粗暴地把所有子元素一次性全部渲染出来。其原理浅显易懂,使用上自然也最简单。然而这样简单的渲染逻辑自然带来了性能上的不足。想象一下你有一个特别长的列表需要显示,可能有好几屏的高度。创建和渲染那些屏幕以外的JS组件和原生视图,显然对于渲染性能和内存占用都是一种极大的拖累和浪费。
+
+这就是为什么我们还有专门的`ListView`组件。`ListView`会惰性渲染子元素,只在它们将要出现在屏幕中时开始渲染。这种惰性渲染逻辑要复杂很多,因而API在使用上也更为繁琐。除非你要渲染的数据特别少,否则你都应该尽量使用`ListView`,哪怕它们用起来更麻烦。
+
+`FlatList`是0.43版本开始新出的改进版的`ListView`,性能更优,但可能不够稳定,尚待时间考验。
+
+### 属性
+
+
+
+
+
contentContainerStyle StyleSheetPropType(ViewStylePropTypes) #
+
+
这些样式会应用到一个内层的内容容器上,所有的子视图都会包裹在内容容器内。例子:
+
return (
+ <ScrollView contentContainerStyle ={styles.contentContainer} >
+ </ScrollView >
+ ) ;
+ ...
+ var styles = StyleSheet.create({
+ contentContainer: {
+ paddingVertical: 20
+ }
+ });
+
+
+
+
+
horizontal bool #
+
+
当此属性为true的时候,所有的子视图会在水平方向上排成一行,而不是默认的在垂直方向上排成一列。默认值为false。
+
+
+
+
keyboardDismissMode enum('none', "interactive", 'on-drag') #
+
+
用户拖拽滚动视图的时候,是否要隐藏软键盘。
+
+
+
+
+
keyboardShouldPersistTaps enum('always', 'never', 'handled', false, true) #
+
如果当前界面有软键盘,那么点击scrollview后是否收起键盘,取决于本属性的设置。(译注:很多人反应TextInput无法自动失去焦点/需要点击多次切换到其他组件等等问题,其关键都是需要将TextInput放到ScrollView中再设置本属性)
+
+ 'never'(默认值),点击TextInput以外的子组件会使当前的软键盘收起。此时子元素不会收到点击事件。
+ 'always',键盘不会自动收起,ScrollView也不会捕捉点击事件,但子组件可以捕获。
+ 'handled',当点击事件被子组件捕获时,键盘不会自动收起。这样切换TextInput时键盘可以保持状态。多数带有TextInput的情况下你应该选择此项。
+ false,已过期,请使用'never'代替。
+ true,已过期,请使用'always'代替。
+
+
+
+
onContentSizeChange function #
+
此函数会在ScrollView内部可滚动内容的视图发生变化时调用。
+
调用参数为内容视图的宽和高: (contentWidth,
+ contentHeight)
+
此方法是通过绑定在内容容器上的onLayout来实现的。
+
+
+
onMomentumScrollStart?: function #
+
+
+
+
onMomentumScrollEnd?: function #
+
+
+
+
onScroll function #
+
+
在滚动的过程中,每帧最多调用一次此回调函数。调用的频率可以用scrollEventThrottle属性来控制。
+
+
+
refreshControl element #
+
+
+
+
removeClippedSubviews bool #
+
+
(实验特性):当此属性为true时,屏幕之外的子视图(子视图的overflow样式需要设为hidden)会被移除。这个可以提升大列表的滚动性能。默认值为true。
+
+
+
+
showsHorizontalScrollIndicator bool #
+
+
当此属性为true的时候,显示一个水平方向的滚动条。
+
+
+
+
showsVerticalScrollIndicator bool #
+
+
当此属性为true的时候,显示一个垂直方向的滚动条。
+
+
+
+
style style #
+
+
+
+
+
+
backfaceVisibility enum('visible', 'hidden')
+
+
+
backgroundColor string
+
+
+
borderColor string
+
+
+
borderTopColor string
+
+
+
borderRightColor string
+
+
+
borderBottomColor string
+
+
+
borderLeftColor string
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius number
+
+
+
borderTopRightRadius number
+
+
+
borderBottomLeftRadius number
+
+
+
borderBottomRightRadius number
+
+
+
borderStyle enum('solid', 'dotted', 'dashed')
+
+
+
borderWidth number
+
+
+
borderTopWidth number
+
+
+
borderRightWidth number
+
+
+
borderBottomWidth number
+
+
+
borderLeftWidth number
+
+
+
opacity number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
shadowColor string
+
+
+
shadowOffset {width: number, height: number}
+
+
+
shadowOpacity number
+
+
+
shadowRadius number
+
+
+
+
+
+
+ android endFillColor
+ color
+ #
+
+
+
有时候滚动视图会占据比实际内容更多的空间。这种情况下可以使用此属性,指定以某种颜色来填充多余的空间,以避免设置背景和创建不必要的绘制开销。一般情况下并不需要这种高级优化技巧。
+
+
+
+
android overScrollMode enum('auto', 'always', 'never') #
+
覆盖默认的overScroll模式
+
可选的值有:
+
+ 'auto' - 默认值,允许用户在内容超出视图高度之后可以滚动视图。
+
+ 'always' - 无论内容尺寸,用户始终可以滚动视图。
+ 'never' - 始终不允许用户滚动视图。
+
+
+
+
+
android scrollPerfTag
+ string #
+
Tag used to log scroll performance on this scroll view. Will force
+ momentum events to be turned on (see sendMomentumEvents). This doesn't do
+ anything out of the box and you need to implement a custom native
+ FpsListener for it to be useful.
+
+
+
+
ios alwaysBounceHorizontal bool #
+
+
当此属性为true时,水平方向即使内容比滚动视图本身还要小,也可以弹性地拉动一截。当horizontal={true}时默认值为true,否则为false。
+
+
+
+
ios alwaysBounceVertical bool #
+
+
当此属性为true时,垂直方向即使内容比滚动视图本身还要小,也可以弹性地拉动一截。当horizontal={true}时默认值为false,否则为true。
+
+
+
+
ios automaticallyAdjustContentInsets bool #
+
+
当滚动视图放在一个导航条或者工具条后面的时候,iOS系统是否要自动调整内容的范围。默认值为true。(译注:如果你的ScrollView或ListView的头部出现莫名其妙的空白,尝试将此属性置为false)
+
+
+
+
ios bounces bool #
+
+
当值为true时,如果内容范围比滚动视图本身大,在到达内容末尾的时候,可以弹性地拉动一截。如果为false,尾部的所有弹性都会被禁用,即使alwaysBounce属性为true。默认值为true。
+
+
+
+
ios bouncesZoom bool #
+
+
当值为true时,使用手势缩放内容可以超过min/max的限制,然后在手指抬起之后弹回min/max的缩放比例。否则的话,缩放不能超过限制。
+
+
+
+
ios canCancelContentTouches bool #
+
+
当值为false时,一旦有子节点响应触摸操作,即使手指开始移动也不会拖动滚动视图。默认值为true(在以上情况下可以拖动滚动视图。)
+
+
+
+
ios centerContent bool #
+
+
当值为true时,如果滚动视图的内容比视图本身小,则会自动把内容居中放置。当内容比滚动视图大的时候,此属性没有作用。默认值为false。
+
+
+
+
ios contentInset {top: number, left: number, bottom: number, right: number} #
+
+
内容范围相对滚动视图边缘的坐标。默认为{0, 0, 0, 0}。
+
+
+
+
ios contentOffset PointPropType #
+
+
用来手动设置初始的滚动坐标。默认值为{x: 0, y: 0}。
+
+
+
+
ios decelerationRate number #
+
+
一个浮点数,用于决定当用户抬起手指之后,滚动视图减速停下的速度。常见的选项有:
+
+ Normal: 0.998 (默认值)
+ Fast: 0.9
+
+
+
+
+
ios directionalLockEnabled bool #
+
+
当值为真时,滚动视图在拖拽的时候会锁定只有垂直或水平方向可以滚动。默认值为false。
+
+
+
+
ios indicatorStyle
+ enum('default', 'black', 'white') #
+
+
设置滚动条的样式。
+
+ default,默认值,等同black.
+ black,黑色滚动条。
+ white,白色滚动条。
+
+
+
+
+
ios maximumZoomScale number #
+
+
+
+
ios minimumZoomScale number #
+
+
+
+
ios onRefreshStart function #
+
+
已过期
+
请使用refreshControl 属性代替。
+
+
+
+
+
+
pagingEnabled bool #
+
+
当值为true时,滚动条会停在滚动视图的尺寸的整数倍位置。这个可以用在水平分页上。默认值为false。
+
+
+
+
scrollEnabled bool #
+
+
当值为false的时候,内容不能滚动,默认值为true。
+
+
+
+
ios scrollEventThrottle number #
+
+
这个属性控制在滚动过程中,scroll事件被调用的频率(单位是每秒事件数量)。更大的数值能够更及时的跟踪滚动位置,不过可能会带来性能问题,因为更多的信息会通过bridge传递。默认值为0,意味着每次视图被滚动,scroll事件只会被调用一次。
+
+
+
+
ios scrollIndicatorInsets {top: number, left: number, bottom: number, right: number} #
+
+
决定滚动条距离视图边缘的坐标。这个值应该和contentInset一样。默认值为{0, 0, 0, 0}。
+
+
+
+
ios scrollsToTop bool #
+
+
当此值为true时,点击状态栏的时候视图会滚动到顶部。默认值为true。
+
+
+
+
ios snapToAlignment enum('start', "center", 'end') #
+
+
当设置了snapToInterval,snapToAlignment会定义停驻点与滚动视图之间的关系。
+
+
+
+
+
ios snapToInterval number #
+
+
当设置了此属性时,会让滚动视图滚动停止后,停止在snapToInterval的倍数的位置。这可以在一些子视图比滚动视图本身小的时候用于实现分页显示。与snapToAlignment组合使用。
+
+
+
+
stickyHeaderIndices [number] #
+
+
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。举个例子,传递stickyHeaderIndices={[0]}会让第一个成员固定在滚动视图顶端。这个属性不能和horizontal={true}一起使用。
+
+
+
+
ios zoomScale number #
+
+
滚动视图内容初始的缩放比例。默认值为1.0。
+
+
+
+
+
+### 方法
+
+
scrollTo(y: number | { x?: number, y?: number, animated?: boolean }, x: number, animated: boolean)
+ #
+
滚动到指定的x, y偏移处。第三个参数为是否启用平滑滚动动画。
+
使用示例:
+
scrollTo({x: 0, y: 0, animated: true})
+
+
scrollToEnd(options?) #
+
+
滚动到视图底部(水平方向的视图则滚动到最右边)。
加上动画参数 scrollToEnd({animated: true})则启用平滑滚动动画,或是调用
+scrollToEnd({animated: false})来立即跳转。如果不使用参数,则animated选项默认启用。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ScrollView,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+ Image
+} = ReactNative;
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Component that enables scrolling through child components';
+exports.examples = [
+{
+ title: '',
+ description: 'To make content scrollable, wrap it within a component',
+ render: function() {
+ var _scrollView: ScrollView;
+ return (
+
+ { _scrollView = scrollView; }}
+ automaticallyAdjustContentInsets={false}
+ onScroll={() => { console.log('onScroll!'); }}
+ scrollEventThrottle={200}
+ style={styles.scrollView}>
+ {THUMBS.map(createThumbRow)}
+
+ { _scrollView.scrollTo({y: 0}); }}>
+ Scroll to top
+
+ { _scrollView.scrollToEnd({animated: true}); }}>
+ Scroll to bottom
+
+
+ );
+ }
+}, {
+ title: ' (horizontal = true)',
+ description: 'You can display \'s child components horizontally rather than vertically',
+ render: function() {
+ var _scrollView: ScrollView;
+ return (
+
+ { _scrollView = scrollView; }}
+ automaticallyAdjustContentInsets={false}
+ horizontal={true}
+ style={[styles.scrollView, styles.horizontalScrollView]}>
+ {THUMBS.map(createThumbRow)}
+
+ { _scrollView.scrollTo({x: 0}); }}>
+ Scroll to start
+
+ { _scrollView.scrollToEnd({animated: true}); }}>
+ Scroll to end
+
+
+ );
+ }
+}];
+
+class Thumb extends React.Component {
+ shouldComponentUpdate(nextProps, nextState) {
+ return false;
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+var THUMBS = ['https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851549_767334479959628_274486868_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851561_767334496626293_1958532586_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851579_767334503292959_179092627_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851589_767334513292958_1747022277_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851563_767334559959620_1193692107_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851593_767334566626286_1953955109_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851591_767334523292957_797560749_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851567_767334529959623_843148472_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851548_767334489959627_794462220_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851575_767334539959622_441598241_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/t39.1997/p128x128/851573_767334549959621_534583464_n.png', 'https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-prn1/t39.1997/p128x128/851583_767334573292952_1519550680_n.png'];
+THUMBS = THUMBS.concat(THUMBS); // double length of THUMBS
+var createThumbRow = (uri, i) => ;
+
+var styles = StyleSheet.create({
+ scrollView: {
+ backgroundColor: '#6A85B1',
+ height: 300,
+ },
+ horizontalScrollView: {
+ height: 120,
+ },
+ containerPage: {
+ height: 50,
+ width: 50,
+ backgroundColor: '#527FE4',
+ padding: 5,
+ },
+ text: {
+ fontSize: 20,
+ color: '#888888',
+ left: 80,
+ top: 20,
+ height: 40,
+ },
+ button: {
+ margin: 7,
+ padding: 5,
+ alignItems: 'center',
+ backgroundColor: '#eaeaea',
+ borderRadius: 3,
+ },
+ buttonContents: {
+ flexDirection: 'row',
+ width: 64,
+ height: 64,
+ },
+ img: {
+ width: 64,
+ height: 64,
+ }
+});
+```
diff --git a/docs/docs/0.42/segmentedcontrolios.md b/docs/docs/0.42/segmentedcontrolios.md
new file mode 100644
index 0000000..bd5c6ba
--- /dev/null
+++ b/docs/docs/0.42/segmentedcontrolios.md
@@ -0,0 +1,214 @@
+使用`SegmentedControlIOS`来在iOS设备上渲染一个`UISegmentedControl`组件。这是一个分段显示多个选项的组件。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
enabled bool #
+
+
如果为false,用户不能与此控件交互。默认为true。
+
+
+
+
momentary bool #
+
+
如果为true,选中的段不会一直保持特效。但onValueChange回调还是会正常工作。
+
+
+
+
onChange function #
+
+
当用户点击某一段的时候调用。参数是一个事件对象。
+
+
+
+
onValueChange function #
+
+
当用户点击某一段的时候调用。参数是被选中段的值。
+
+
+
+
selectedIndex number #
+
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ SegmentedControlIOS,
+ Text,
+ View,
+ StyleSheet
+} = ReactNative;
+
+var BasicSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+});
+
+var PreSelectedSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+});
+
+var MomentarySegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+});
+
+var DisabledSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+ );
+ },
+});
+
+var ColorSegmentedControlExample = React.createClass({
+ render() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+var EventSegmentedControlExample = React.createClass({
+ getInitialState() {
+ return {
+ values: ['One', 'Two', 'Three'],
+ value: 'Not selected',
+ selectedIndex: undefined
+ };
+ },
+
+ render() {
+ return (
+
+
+ Value: {this.state.value}
+
+
+ Index: {this.state.selectedIndex}
+
+
+
+ );
+ },
+
+ _onChange(event) {
+ this.setState({
+ selectedIndex: event.nativeEvent.selectedSegmentIndex,
+ });
+ },
+
+ _onValueChange(value) {
+ this.setState({
+ value: value,
+ });
+ }
+});
+
+var styles = StyleSheet.create({
+ text: {
+ fontSize: 14,
+ textAlign: 'center',
+ fontWeight: '500',
+ margin: 10,
+ },
+});
+
+exports.title = '';
+exports.displayName = 'SegmentedControlExample';
+exports.description = 'Native segmented control';
+exports.examples = [
+ {
+ title: 'Segmented controls can have values',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can have a pre-selected value',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can be momentary',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Segmented controls can be disabled',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Custom colors can be provided',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Change events can be detected',
+ render(): ReactElement { return ; }
+ }
+];
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/shadow-props.md b/docs/docs/0.42/shadow-props.md
new file mode 100644
index 0000000..fa31388
--- /dev/null
+++ b/docs/docs/0.42/shadow-props.md
@@ -0,0 +1,22 @@
+### 属性
+
+
+
ios shadowColor
+ color #
+
+
+
+
ios shadowOffset
+ {width: number, height: number} #
+
+
+
+
ios shadowOpacity
+ number #
+
+
+
ios shadowRadius
+ number #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/share.md b/docs/docs/0.42/share.md
new file mode 100644
index 0000000..4deadda
--- /dev/null
+++ b/docs/docs/0.42/share.md
@@ -0,0 +1,160 @@
+### 方法
+
+
+
static share(content, options) #
+
打开一个对话框来共享文本内容。
+
在iOS中,返回一个Promise,它将被调用一个包含action的对象,activityType。 如果用户关闭对话框,则Promise仍将被解析,而ActionDisissedAction和所有其他键未被定义。
+
在Android中,返回一个Promise,它始终使用Share.sharedAction操作来解决。
+
+
Content #
+
+
+ message - 要分享的消息
+ title - 消息的标题
+
+
iOS #
+
+
至少需要一个URL和消息.
+
Options #
+ iOS #
+
+ excludedActivityTypes
+ tintColor
+
+
Android #
+
+
+
+
+
static sharedAction() #
+
+
+
+
static dismissedAction() #
+
该对话框已被拒绝.
+ @platform ios
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ Share,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Share';
+exports.description = 'Share data with other Apps.';
+exports.examples = [{
+ title: 'Share Text Content',
+ render() {
+ return ;
+ }
+}];
+
+class ShareMessageExample extends React.Component {
+ _shareMessage: Function;
+ _shareText: Function;
+ _showResult: Function;
+ state: any;
+
+ constructor(props) {
+ super(props);
+
+ this._shareMessage = this._shareMessage.bind(this);
+ this._shareText = this._shareText.bind(this);
+ this._showResult = this._showResult.bind(this);
+
+ this.state = {
+ result: ''
+ };
+ }
+
+ render() {
+ return (
+
+
+
+ Click to share message
+
+
+
+
+ Click to share message, URL and title
+
+
+ {this.state.result}
+
+ );
+ }
+
+ _shareMessage() {
+ Share.share({
+ message: 'React Native | A framework for building native apps using React'
+ })
+ .then(this._showResult)
+ .catch((error) => this.setState({result: 'error: ' + error.message}));
+ }
+
+ _shareText() {
+ Share.share({
+ message: 'A framework for building native apps using React',
+ url: 'http://facebook.github.io/react-native/',
+ title: 'React Native'
+ }, {
+ dialogTitle: 'Share React Native website',
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ],
+ tintColor: 'green'
+ })
+ .then(this._showResult)
+ .catch((error) => this.setState({result: 'error: ' + error.message}));
+ }
+
+ _showResult(result) {
+ if (result.action === Share.sharedAction) {
+ if (result.activityType) {
+ this.setState({result: 'shared with an activityType: ' + result.activityType});
+ } else {
+ this.setState({result: 'shared'});
+ }
+ } else if (result.action === Share.dismissedAction) {
+ this.setState({result: 'dismissed'});
+ }
+ }
+
+}
+
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
diff --git a/docs/docs/0.42/signed-apk-android.md b/docs/docs/0.42/signed-apk-android.md
new file mode 100644
index 0000000..32e7036
--- /dev/null
+++ b/docs/docs/0.42/signed-apk-android.md
@@ -0,0 +1,107 @@
+Android要求所有应用都有一个数字签名才会被允许安装在用户手机上,所以在把应用发布到类似[Google Play store](https://play.google.com/store)这样的应用市场之前,你需要先生成一个签名的APK包。Android开发者官网上的[如何给你的应用签名](https://developer.android.com/tools/publishing/app-signing.html)文档描述了签名的细节。本指南旨在提供一个简化的签名和打包js的操作步骤,不会涉及太多理论。
+
+### 生成一个签名密钥
+
+你可以用`keytool`命令生成一个私有密钥。在Windows上`keytool`命令放在JDK的bin目录中(比如`C:\Program Files\Java\jdkx.x.x_x\bin`),你可能需要在命令行中先进入那个目录才能执行此命令。
+
+ $ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
+
+这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息。最后它会生成一个叫做`my-release-key.keystore`的密钥库文件。
+
+在运行上面这条语句之后,密钥库里应该已经生成了一个单独的密钥,有效期为10000天。--alias参数后面的别名是你将来为应用签名时所需要用到的,所以记得记录这个别名。
+
+**注意:请记得妥善地保管好你的密钥库文件,不要上传到版本库或者其它的地方。**
+
+### 设置gradle变量
+
+1. 把`my-release-key.keystore`文件放到你工程中的`android/app`文件夹下。
+2. 编辑`~/.gradle/gradle.properties`(没有这个文件你就创建一个),添加如下的代码(注意把其中的`****`替换为相应密码)
+
+**注意:~表示用户目录,比如windows上可能是`C:\Users\用户名`,而mac上可能是`/Users/用户名`。**
+
+```
+MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
+MYAPP_RELEASE_KEY_ALIAS=my-key-alias
+MYAPP_RELEASE_STORE_PASSWORD=*****
+MYAPP_RELEASE_KEY_PASSWORD=*****
+```
+
+上面的这些会作为全局的gradle变量,我们在后面的步骤中可以用来给应用签名。
+
+
+> __关于密钥库的注意事项:__
+
+> 一旦你在Play Store发布了你的应用,如果想修改签名,就必须用一个不同的包名来重新发布你的应用(这样也会丢失所有的下载数和评分)。所以请务必备份好你的密钥库和密码。
+
+提示:如果你不想以明文方式保存密码,同时你使用的是macOS系统,那么你也可以把密码[保存到钥匙串(Keychain)中](https://pilloxa.gitlab.io/posts/safer-passwords-in-gradle/)。这样一来你就可以省略掉上面配置中的后两行(即MYAPP_RELEASE_STORE_PASSWORD和MYAPP_RELEASE_KEY_PASSWORD)。
+
+
+### 添加签名到项目的gradle配置文件
+
+编辑你项目目录下的`android/app/build.gradle`,添加如下的签名配置:
+
+```gradle
+...
+android {
+ ...
+ defaultConfig { ... }
+ signingConfigs {
+ release {
+ storeFile file(MYAPP_RELEASE_STORE_FILE)
+ storePassword MYAPP_RELEASE_STORE_PASSWORD
+ keyAlias MYAPP_RELEASE_KEY_ALIAS
+ keyPassword MYAPP_RELEASE_KEY_PASSWORD
+ }
+ }
+ buildTypes {
+ release {
+ ...
+ signingConfig signingConfigs.release
+ }
+ }
+}
+...
+```
+
+### 生成发行APK包
+
+只需在终端中运行以下命令:
+
+```sh
+$ cd android && ./gradlew assembleRelease
+```
+
+译注:cd android表示进入android目录(如果你已经在android目录中了那就不用输入了)。`./gradlew assembleRelease`在macOS和Linux系统中表示执行当前目录下的名为gradlew的脚本文件,运行参数为assembleRelease,注意这个`./`不可省略;而在windows命令行下则需要去掉`./`。
+
+Gradle的`assembleRelease`参数会把所有用到的JavaScript代码都打包到一起,然后内置到APK包中。如果你想调整下这个行为(比如js代码以及静态资源打包的默认文件名或是目录结构等),可以看看`android/app/build.gradle`文件,然后琢磨下应该怎么修改以满足你的需求。
+
+生成的APK文件位于`android/app/build/outputs/apk/app-release.apk`,它已经可以用来发布了。
+
+
+### 测试应用的发行版本
+
+在把发行版本提交到Play Store之前,你应该做一次最终测试。输入以下命令可以在设备上安装发行版本:
+
+```sh
+$ cd android && ./gradlew installRelease
+```
+
+注意`installRelease`参数只能在你完成了上面的签名配置之后才可以使用。
+你现在可以关掉运行中的packager了,因为你所有的代码和框架依赖已经都被打包到apk包中,可以离线运行了。
+
+> 在debug和release版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。
+
+### 启用Proguard代码混淆来缩小APK文件的大小(可选)
+
+Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少APK的大小。
+
+**重要**:启用Proguard之后,你必须再次全面地测试你的应用。Proguard有时候需要为你引入的每个原生库做一些额外的配置。参见`app/proguard-rules.pro`文件。
+
+要启用Proguard,设置`minifyEnabled`选项为`true`:
+
+```gradle
+/**
+ * 在release发行版中启用Proguard来减小 to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = true
+```
diff --git a/docs/docs/0.42/slider.md b/docs/docs/0.42/slider.md
new file mode 100644
index 0000000..4f4474e
--- /dev/null
+++ b/docs/docs/0.42/slider.md
@@ -0,0 +1,251 @@
+用于选择一个范围值的组件。
+
+### 属性
+
+
+
+
+
disabled bool #
+
+
如果为true,用户就不能移动滑块。默认为false。
+
+
+
+
ios maximumTrackImage Image.propTypes.source #
+
指定一个滑块右侧轨道背景图。仅支持静态图片。图片最左边的像素会被平铺直至填满轨道。
+
+
maximumTrackTintColor string #
+
+
滑块右侧轨道的颜色。默认为一个蓝色的渐变色。
+
+
+
+
ios maximumValue number #
+
+
滑块的最大值(当滑块滑到最右端时表示的值)。默认为1。
+
+
+
+
ios minimumTrackImage Image.propTypes.source #
+
指定一个滑块左侧轨道背景图。仅支持静态图片。图片最右边的像素会被平铺直至填满轨道。
+
+
minimumTrackTintColor string #
+
+
滑块左侧轨道的颜色。默认为一个蓝色的渐变色。
+
+
+
+
ios minimumValue number #
+
+
滑块的最小值(当滑块滑到最左侧时表示的值)。默认为0。
+
+
+
+
onSlidingComplete function #
+
+
+
+
onValueChange function #
+
+
+
+
step number #
+
+
滑块的最小步长。这个值应该在0到(maximumValue - minimumValue)之间。默认值为0。
+
+
+
+
+
thumbImage Image.propTypes.source #
+
+
+
+
android thumbTintColor ColorPropType #
+
+
Color of the foreground switch grip.
+
+
+
+
trackImage Image.propTypes.source #
+
+
给轨道设置一张背景图。只支持静态图片。图片最中央的像素会被平铺直至填满轨道。
+
+
+
+
value number #
+
+
滑块的初始值。这个值应该在最小值和最大值之间。默认值是0。
+
这不是一个受约束的组件。 也就是说,如果你不更新值,在用户操作后,这个组件也不会还原到初始值。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Slider,
+ Text,
+ StyleSheet,
+ View,
+} = ReactNative;
+
+var SliderExample = React.createClass({
+ getDefaultProps() {
+ return {
+ value: 0,
+ }
+ },
+
+ getInitialState() {
+ return {
+ value: this.props.value,
+ };
+ },
+
+ render() {
+ return (
+
+
+ {this.state.value && +this.state.value.toFixed(3)}
+
+ this.setState({value: value})} />
+
+ );
+ }
+});
+
+var SlidingCompleteExample = React.createClass({
+ getInitialState() {
+ return {
+ slideCompletionValue: 0,
+ slideCompletionCount: 0,
+ };
+ },
+
+ render() {
+ return (
+
+ this.setState({
+ slideCompletionValue: value,
+ slideCompletionCount: this.state.slideCompletionCount + 1})} />
+
+ Completions: {this.state.slideCompletionCount} Value: {this.state.slideCompletionValue}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ slider: {
+ height: 10,
+ margin: 10,
+ },
+ text: {
+ fontSize: 14,
+ textAlign: 'center',
+ fontWeight: '500',
+ margin: 10,
+ },
+});
+
+exports.title = '';
+exports.displayName = 'SliderExample';
+exports.description = 'Slider input for numeric values';
+exports.examples = [
+ {
+ title: 'Default settings',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Initial value: 0.5',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'minimumValue: -1, maximumValue: 2',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'step: 0.25',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'onSlidingComplete',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Custom min/max track tint color',
+ platform: 'ios',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Custom thumb image',
+ platform: 'ios',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Custom track image',
+ platform: 'ios',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Custom min/max track image',
+ platform: 'ios',
+ render(): ReactElement {
+ return (
+
+ );
+ }
+ },
+];
+```
diff --git a/docs/docs/0.42/state.md b/docs/docs/0.42/state.md
new file mode 100644
index 0000000..f08ea2f
--- /dev/null
+++ b/docs/docs/0.42/state.md
@@ -0,0 +1,51 @@
+我们使用两种数据来控制一个组件:`props`和`state`。`props`是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用`state`。
+
+一般来说,你需要在constructor中初始化`state`(译注:这是ES6的写法,早期的很多ES5的例子使用的是getInitialState方法来初始化state,这一做法会逐渐被淘汰),然后在需要修改时调用`setState`方法。
+
+假如我们需要制作一段不停闪烁的文字。文字内容本身在组件创建时就已经指定好了,所以文字内容应该是一个`prop`。而文字的显示或隐藏的状态(快速的显隐切换就产生了闪烁的效果)则是随着时间变化的,因此这一状态应该写到`state`中。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+class Blink extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showText: true };
+
+ // 每1000毫秒对showText状态做一次取反操作
+ setInterval(() => {
+ this.setState({ showText: !this.state.showText });
+ }, 1000);
+ }
+
+ render() {
+ // 根据当前showText的值决定是否显示text内容
+ let display = this.state.showText ? this.props.text : ' ';
+ return (
+ {display}
+ );
+ }
+}
+
+class BlinkApp extends Component {
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('BlinkApp', () => BlinkApp);
+```
+
+实际开发中,我们一般不会在定时器函数(setInterval、setTimeout等)中来操作state。典型的场景是在接收到服务器返回的新数据,或者在用户输入数据之后。你也可以使用一些“状态容器”比如[Redux](http://redux.js.org/index.html)来统一管理数据流(译注:但我们不建议新手过早去学习redux)。
+
+State的工作原理和React.js完全一致,所以对于处理state的一些更深入的细节,你可以参阅[React.Component API](https://facebook.github.io/react/docs/component-api.html)。
+
+看到这里,你可能觉得我们的例子总是千篇一律的黑色文本,太特么无聊了。那么我们一起来[学习一下样式](style.html)吧。
diff --git a/docs/docs/0.42/statusbar.md b/docs/docs/0.42/statusbar.md
new file mode 100644
index 0000000..52ae9ab
--- /dev/null
+++ b/docs/docs/0.42/statusbar.md
@@ -0,0 +1,522 @@
+用于控制应用状态栏的组件。
+
+### 与Navigator搭配的用法
+`StatusBar`组件可以同时加载多个。此时属性会按照加载顺序合并(后者覆盖前者)。一个典型的用法就是在使用`Navigator`时,针对不同的路由指定不同的状态栏样式,如下:
+```js
+
+
+
+
+
+ ...
+
+ }
+ />
+
+```
+
+### 常量
+
+`currentHeight` 状态栏的当前高度。
+
+
+### 属性
+
+
+
animated bool #
+
指定状态栏的变化是否应以动画形式呈现。目前支持这几种样式:backgroundColor, barStyle和hidden。
+
+
+
android backgroundColor color
+ #
+
+
+
android translucent bool #
+
+
指定状态栏是否透明。设置为true时,应用会在状态栏之下绘制(即所谓“沉浸式”——被状态栏遮住一部分)。常和带有半透明背景色的状态栏搭配使用。
+
+
barStyle
+ enum('default', 'light-content', 'dark-content') #
+
+
+
ios networkActivityIndicatorVisible bool #
+
+
+
ios showHideTransition enum('fade', 'slide') #
+
通过hidden属性来显示或隐藏状态栏时所使用的动画效果。默认值为'fade'。
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Component for controlling the status bar';
+
+const colors = [
+ '#ff0000',
+ '#00ff00',
+ '#0000ff',
+];
+
+const barStyles = [
+ 'default',
+ 'light-content',
+];
+
+const showHideTransitions = [
+ 'fade',
+ 'slide',
+];
+
+function getValue(values: Array, index: number): T {
+ return values[index % values.length];
+}
+
+const StatusBarHiddenExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ hidden: false,
+ showHideTransition: getValue(showHideTransitions, 0),
+ };
+ },
+
+ _showHideTransitionIndex: 0,
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ _onChangeHidden() {
+ this.setState({hidden: !this.state.hidden});
+ },
+
+ _onChangeTransition() {
+ this._showHideTransitionIndex++;
+ this.setState({
+ showHideTransition: getValue(showHideTransitions, this._showHideTransitionIndex),
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+ hidden: {this.state.hidden ? 'true' : 'false'}
+
+
+
+
+ animated (ios only): {this.state.animated ? 'true' : 'false'}
+
+
+
+
+
+ showHideTransition (ios only):
+ '{getValue(showHideTransitions, this._showHideTransitionIndex)}'
+
+
+
+
+ );
+ },
+});
+
+const StatusBarStyleExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ barStyle: getValue(barStyles, this._barStyleIndex),
+ };
+ },
+
+ _barStyleIndex: 0,
+
+ _onChangeBarStyle() {
+ this._barStyleIndex++;
+ this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
+ },
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ render() {
+ return (
+
+
+
+
+ style: '{getValue(barStyles, this._barStyleIndex)}'
+
+
+
+
+ animated: {this.state.animated ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+const StatusBarNetworkActivityExample = React.createClass({
+ getInitialState() {
+ return {
+ networkActivityIndicatorVisible: false,
+ };
+ },
+
+ _onChangeNetworkIndicatorVisible() {
+ this.setState({
+ networkActivityIndicatorVisible: !this.state.networkActivityIndicatorVisible,
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+
+ networkActivityIndicatorVisible:
+ {this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
+
+
+
+
+ );
+ },
+});
+
+const StatusBarBackgroundColorExample = React.createClass({
+ getInitialState() {
+ return {
+ animated: true,
+ backgroundColor: getValue(colors, 0),
+ };
+ },
+
+ _colorIndex: 0,
+
+ _onChangeBackgroundColor() {
+ this._colorIndex++;
+ this.setState({backgroundColor: getValue(colors, this._colorIndex)});
+ },
+
+ _onChangeAnimated() {
+ this.setState({animated: !this.state.animated});
+ },
+
+ render() {
+ return (
+
+
+
+
+ backgroundColor: '{getValue(colors, this._colorIndex)}'
+
+
+
+
+ animated: {this.state.animated ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+
+const StatusBarTranslucentExample = React.createClass({
+ getInitialState() {
+ return {
+ translucent: false,
+ };
+ },
+
+ _onChangeTranslucent() {
+ this.setState({
+ translucent: !this.state.translucent,
+ });
+ },
+
+ render() {
+ return (
+
+
+
+
+ translucent: {this.state.translucent ? 'true' : 'false'}
+
+
+
+ );
+ },
+});
+
+const StatusBarStaticIOSExample = React.createClass({
+ render() {
+ return (
+
+ {
+ StatusBar.setHidden(true, 'slide');
+ }}>
+
+ setHidden(true, 'slide')
+
+
+ {
+ StatusBar.setHidden(false, 'fade');
+ }}>
+
+ setHidden(false, 'fade')
+
+
+ {
+ StatusBar.setBarStyle('default', true);
+ }}>
+
+ setBarStyle('default', true)
+
+
+ {
+ StatusBar.setBarStyle('light-content', true);
+ }}>
+
+ setBarStyle('light-content', true)
+
+
+ {
+ StatusBar.setNetworkActivityIndicatorVisible(true);
+ }}>
+
+ setNetworkActivityIndicatorVisible(true)
+
+
+ {
+ StatusBar.setNetworkActivityIndicatorVisible(false);
+ }}>
+
+ setNetworkActivityIndicatorVisible(false)
+
+
+
+ );
+ },
+});
+
+const StatusBarStaticAndroidExample = React.createClass({
+ render() {
+ return (
+
+ {
+ StatusBar.setHidden(true);
+ }}>
+
+ setHidden(true)
+
+
+ {
+ StatusBar.setHidden(false);
+ }}>
+
+ setHidden(false)
+
+
+ {
+ StatusBar.setBackgroundColor('#ff00ff', true);
+ }}>
+
+ setBackgroundColor('#ff00ff', true)
+
+
+ {
+ StatusBar.setBackgroundColor('#00ff00', true);
+ }}>
+
+ setBackgroundColor('#00ff00', true)
+
+
+ {
+ StatusBar.setTranslucent(true);
+ StatusBar.setBackgroundColor('rgba(0, 0, 0, 0.4)', true);
+ }}>
+
+ setTranslucent(true) and setBackgroundColor('rgba(0, 0, 0, 0.4)', true)
+
+
+ {
+ StatusBar.setTranslucent(false);
+ StatusBar.setBackgroundColor('black', true);
+ }}>
+
+ setTranslucent(false) and setBackgroundColor('black', true)
+
+
+
+ );
+ },
+});
+
+const examples = [{
+ title: 'StatusBar hidden',
+ render() {
+ return ;
+ },
+}, {
+ title: 'StatusBar style',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar network activity indicator',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar background color',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar background color',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar static API',
+ render() {
+ return ;
+ },
+ platform: 'ios',
+}, {
+ title: 'StatusBar static API',
+ render() {
+ return ;
+ },
+ platform: 'android',
+}, {
+ title: 'StatusBar dimensions',
+ render() {
+ return (
+
+ Height: {StatusBar.currentHeight} pts
+
+ );
+ }
+}];
+
+exports.examples = examples;
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ borderRadius: 5,
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+ title: {
+ marginTop: 16,
+ marginBottom: 8,
+ fontWeight: 'bold',
+ }
+});
+```
diff --git a/docs/docs/0.42/style.md b/docs/docs/0.42/style.md
new file mode 100644
index 0000000..09fc6d6
--- /dev/null
+++ b/docs/docs/0.42/style.md
@@ -0,0 +1,42 @@
+在React Native中,你并不需要学习什么特殊的语法来定义样式。我们仍然是使用JavaScript来写样式。所有的核心组件都接受名为`style`的属性。这些样式名基本上是遵循了web上的CSS的命名,只是按照JS的语法要求使用了驼峰命名法,例如将`background-color`改为`backgroundColor`。
+
+`style`属性可以是一个普通的JavaScript对象。这是最简单的用法,因而在示例代码中很常见。你还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
+
+实际开发中组件的样式会越来越复杂,我们建议使用`StyleSheet.create`来集中定义组件的样式。比如像下面这样:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, StyleSheet, Text, View } from 'react-native';
+
+class LotsOfStyles extends Component {
+ render() {
+ return (
+
+ just red
+ just bigblue
+ bigblue, then red
+ red, then bigblue
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ bigblue: {
+ color: 'blue',
+ fontWeight: 'bold',
+ fontSize: 30,
+ },
+ red: {
+ color: 'red',
+ },
+});
+
+AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
+```
+
+常见的做法是按顺序声明和使用`style`属性,以借鉴CSS中的“层叠”做法(即后声明的属性会覆盖先声明的同名属性)。
+
+文本的样式定义请参阅[Text组件的文档](text.html)。
+
+现在你已经了解如何调整文本样式了,下面我们要学习的是[如何控制组件的尺寸](height-and-width.html)。
diff --git a/docs/docs/0.42/stylesheet.md b/docs/docs/0.42/stylesheet.md
new file mode 100644
index 0000000..1309da6
--- /dev/null
+++ b/docs/docs/0.42/stylesheet.md
@@ -0,0 +1,124 @@
+StyleSheet提供了一种类似CSS样式表的抽象。
+
+创建一个样式表:
+
+```javascript
+var styles = StyleSheet.create({
+ container: {
+ borderRadius: 4,
+ borderWidth: 0.5,
+ borderColor: '#d6d7da',
+ },
+ title: {
+ fontSize: 19,
+ fontWeight: 'bold',
+ },
+ activeTitle: {
+ color: 'red',
+ },
+});
+```
+
+使用一个样式表:
+
+```javascript
+
+
+
+```
+
+从代码质量角度:
+
+* 从render函数中移除具体的样式内容,可以使代码更清晰易懂。
+* 给样式命名也是对render函数中的原始组件的作用的一种标记。
+
+从性能角度:
+
+* 创建一个样式表,就可以使得我们后续更容易通过ID来引用样式,而不是每次都创建一个新的对象。
+* 它还使得样式只会在JavaScript和原生之间传递一次,随后的过程都可以只传递一个ID(这个优化还未实现)。
+
+### 方法
+
+
+
static create(obj: {[key: string]: any}) #
+
+
+### 属性
+
+
+
hairlineWidth: CallExpression #
+
这一常量定义了当前平台上的最细的宽度。可以用作边框或是两个元素间的分隔线。例如:
+
{
+ borderBottomColor: '#bbb' ,
+ borderBottomWidth: StyleSheet. hairlineWidth
+ }
+
这一常量始终是一个整数的像素值(线看起来会像头发丝一样细),并会尽量符合当前平台最细的线的标准。然而,你不能把它“视为一个常量”,因为不同的平台和不同的屏幕像素密度会导致不同的结果。
+
+
absoluteFill: CallExpression
+ #
+
A very common pattern is to create overlays with position absolute and zero positioning,
+ so absoluteFill can be used for convenience and to reduce duplication of these repeated
+ styles.
+
+
absoluteFillObject: ObjectExpression #
+
Sometimes you may want absoluteFill but with a couple tweaks - absoluteFillObject
+ can be
+ used to create a customized entry in a StyleSheet, e.g.:
+
const styles = StyleSheet.create({
+ wrapper: {
+ ...StyleSheet.absoluteFillObject,
+ top: 10,
+ backgroundColor: 'transparent',
+ },
+ });
+
+
flatten: CallExpression
+ #
+
Flattens an array of style objects, into one aggregated style object.
+ Alternatively, this method can be used to lookup IDs, returned by
+ StyleSheet.register.
+
NOTE : Exercise caution as abusing this can tax you in terms of
+ optimizations.
+ IDs enable optimizations through the bridge and memory in general. Refering
+ to style objects directly will deprive you of these optimizations.
+
Example:
+
var styles = StyleSheet. create( {
+ listItem: {
+ flex: 1 ,
+ fontSize: 16 ,
+ color: 'white'
+ } ,
+ selectedListItem: {
+ color: 'green'
+ }
+ } ) ;
+
+ StyleSheet. flatten( [ styles. listItem,
+ styles. selectedListItem])
+
Alternative use:
+
StyleSheet. flatten( styles. listItem) ;
+
This method internally uses StyleSheetRegistry.getStyleByID(style)
+ to resolve style objects represented by IDs. Thus, an array of style
+ objects (instances of StyleSheet.create), are individually resolved to,
+ their respective objects, merged as one and then returned. This also explains
+ the alternative use.
+
+
+
diff --git a/docs/docs/0.42/switch.md b/docs/docs/0.42/switch.md
new file mode 100644
index 0000000..56a8040
--- /dev/null
+++ b/docs/docs/0.42/switch.md
@@ -0,0 +1,54 @@
+跨平台通用的可以在两个状态中切换的组件。
+注意这是一个“受控组件”(controlled component)。你必须使用`onValueChange`回调来更新`value`属性以响应用户的操作。如果不更新`value`属性,组件只会按一开始给定的`value`值来渲染且保持不变,看上去就像完全点不动。
+
+@keyword checkbox @keyword toggle @keyword 单选 @keyword 多选
+
+### 截图
+
+
+
+
+### 属性
+
+
+
+
+
+
onValueChange function #
+
+
当值改变的时候调用此回调函数,参数为新的值。
+
+
+
+
+
value bool #
+
+
表示此开关是否打开。默认为false(关闭状态)。
+
+
+
+
onTintColor ColorPropType #
+
+
+
+
thumbTintColor ColorPropType #
+
+
+
+
tintColor ColorPropType #
+
关闭状态时的边框颜色(iOS)或背景颜色(Android)。
+
+
+
diff --git a/docs/docs/0.42/systrace.md b/docs/docs/0.42/systrace.md
new file mode 100644
index 0000000..fecbe8c
--- /dev/null
+++ b/docs/docs/0.42/systrace.md
@@ -0,0 +1,67 @@
+### 方法
+
+
+
static setEnabled(enabled) #
+
+
static beginEvent(profileName?, args?) #
+
beginEvent/endEvent for starting and then ending a profile within the same call stack frame
+
+
+
static beginAsyncEvent(profileName?) #
+
beginAsyncEvent/endAsyncEvent for starting and then ending a profile where the end can either
+ occur on another thread or out of the current stack frame, eg await
+ the returned cookie variable should be used as input into the endAsyncEvent call to end the profile
+
+
+
static endAsyncEvent(profileName?, cookie?) #
+
static counterEvent(profileName?, value?) #
+
counterEvent registers the value to the profileName on the systrace timeline
+
+
static attachToRelayProfiler(relayProfiler) #
+
Relay profiles use await calls, so likely occur out of current stack frame
+ therefore async variant of profiling is used
+
+
static swizzleJSON() #
+
+
This is not called by default due to perf overhead but it's useful
+ if you want to find traces which spend too much time in JSON.
+
+
static measureMethods(object, objectName, methodNames) #
+
+
Measures multiple methods of a class. For example, you can do:
+ Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']);
+
@param object
+ @param objectName
+ @param methodNames Map from method names to method display names.
+
+
static measure(objName, fnName, func) #
+
Returns an profiled version of the input function. For example, you can:
+ JSON.parse = Systrace.measure('JSON', 'parse', JSON.parse);
+
@param objName
+ @param fnName
+ @param {function} func
+ @return {function} replacement function
+
+
+
diff --git a/docs/docs/0.42/tabbarios-item.md b/docs/docs/0.42/tabbarios-item.md
new file mode 100644
index 0000000..50a7df7
--- /dev/null
+++ b/docs/docs/0.42/tabbarios-item.md
@@ -0,0 +1,52 @@
+### 属性
+
+
+
+
+
badge string, number #
+
+
+
+
icon Image.propTypes.source #
+
+
给当前标签指定一个自定义的图标。如果定义了systemIcon属性, 这个属性会被忽略。
+
+
+
+
onPress function #
+
+
当此标签被选中时调用。你应该修改组件的状态来使得selected={true}。
+
+
+
+
selected bool #
+
+
这个属性决定了子视图是否可见。如果你看到一个空白的页面,很可能是没有选中任何一个标签。
+
+
+
+
selectedIcon Image.propTypes.source #
+
+
当标签被选中的时候显示的自定义图标。如果定义了systemIcon属性,这个属性会被忽略。如果定义了icon而没定义这个属性,在选中的时候图标会染上蓝色。
+
+
+
+
+
systemIcon enum('bookmarks', 'contacts', 'downloads', 'favorites', 'featured', 'history', 'more', 'most-recent', 'most-viewed', 'recents', 'search', 'top-rated') #
+
+
一些预定义的系统图标。注意如果你使用了此属性,标题和自定义图标都会被覆盖为系统定义的值。
+
+
+
+
title string #
+
+
在图标下面显示的标题文字。如果定义了systemIcon属性,这个属性会被忽略。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/tabbarios.md b/docs/docs/0.42/tabbarios.md
new file mode 100644
index 0000000..eb9cc92
--- /dev/null
+++ b/docs/docs/0.42/tabbarios.md
@@ -0,0 +1,143 @@
+#### __译注__:本组件,以及一切带IOS或Android后缀的组件,都不能跨平台运行。如果需要替代品,请到[js.coach](https://js.coach/react-native?search=tab)或[github](https://github.com/search?utf8=%E2%9C%93&q=react+native+tab)上搜索。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
barTintColor string #
+
+
+
+
+
+
unselectedItemTintColor string #
+
+
当前没有被选中的标签图标的颜色。仅在iOS 10及以上版本有效
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ TabBarIOS,
+ Text,
+ View,
+} = ReactNative;
+
+var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
+
+var TabBarExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Tab-based navigation.',
+ },
+
+ displayName: 'TabBarExample',
+
+ getInitialState: function() {
+ return {
+ selectedTab: 'redTab',
+ notifCount: 0,
+ presses: 0,
+ };
+ },
+
+ _renderContent: function(color: string, pageText: string, num?: number) {
+ return (
+
+ {pageText}
+ {num} re-renders of the {pageText}
+
+ );
+ },
+
+ render: function() {
+ return (
+
+ {
+ this.setState({
+ selectedTab: 'blueTab',
+ });
+ }}>
+ {this._renderContent('#414A8C', 'Blue Tab')}
+
+ 0 ? this.state.notifCount : undefined}
+ selected={this.state.selectedTab === 'redTab'}
+ onPress={() => {
+ this.setState({
+ selectedTab: 'redTab',
+ notifCount: this.state.notifCount + 1,
+ });
+ }}>
+ {this._renderContent('#783E33', 'Red Tab', this.state.notifCount)}
+
+ {
+ this.setState({
+ selectedTab: 'greenTab',
+ presses: this.state.presses + 1
+ });
+ }}>
+ {this._renderContent('#21551C', 'Green Tab', this.state.presses)}
+
+
+ );
+ },
+
+});
+
+var styles = StyleSheet.create({
+ tabContent: {
+ flex: 1,
+ alignItems: 'center',
+ },
+ tabText: {
+ color: 'white',
+ margin: 50,
+ },
+});
+
+module.exports = TabBarExample;
+```
diff --git a/docs/docs/0.42/testing.md b/docs/docs/0.42/testing.md
new file mode 100644
index 0000000..957d650
--- /dev/null
+++ b/docs/docs/0.42/testing.md
@@ -0,0 +1,77 @@
+## 运行测试与贡献代码
+
+React Native的官方代码仓库里有一些测试代码,你可以在贡献代码之后回归测试一下,以检测有没有引起别的问题。这些测试是通过[Travis](http://docs.travis-ci.com/)持续集成系统来运行的,并且会自动针对你提交的代码给出测试结果。
+
+当然我们的测试不可能有完整的覆盖率(尤其对于复杂的用户交互),所以很多更改也还需要仔细的人工审查。我们期待你能帮助我们提高测试覆盖率,以及提供更多的测试代码或是测试用例。
+
+## 使用Jest来测试
+
+[Jest](http://facebook.github.io/jest/)是在命令行通过node来执行的纯js测试工具。测试代码放置在`__tests__`目录下。有一些功能我们还没有完成模拟(jest中需要模拟一些接口),因而没有纳入测试,以避免测试不通过和提高测试速度,但我们正在尽最大努力去逐渐补完这些功能的模拟。你可以在react-native源代码的根目录中使用如下命令来运行现有的jest测试代码:
+
+```
+npm test
+```
+
+我们建议你在贡献代码的时候也添加自己的测试代码。你可以参考这个简单的例子[`getImageSource-test.js`](https://github.com/facebook/react-native/blob/master/Examples/Movies/__tests__/getImageSource-test.js)。
+
+注意:要运行你自己的测试代码,请首先去jest的官网阅读指导文档,然后在`package.json`中加入`jest`对象,在其中包含一些预备测试环境的脚本。下面是一个示例:
+
+```
+...
+"scripts": {
+ ...
+ "test": "jest"
+},
+...
+"jest": {
+ "scriptPreprocessor": "node_modules/react-native/jestSupport/preprocessor.js",
+ "setupEnvScriptFile": "node_modules/react-native/jestSupport/env.js",
+ "testPathIgnorePatterns": [
+ "/node_modules/",
+ "packager/react-packager/src/Activity/"
+ ],
+ "testFileExtensions": [
+ "js"
+ ],
+ "unmockedModulePathPatterns": [
+ "promise",
+ "source-map"
+ ]
+},
+...
+```
+
+注意:你可能需要先在当前的环境中安装、更新或是链接Node.js和其他的一些工具,不然测试可能无法正常运行。点这里查看最新的[测试配置文件.travis.yml](https://github.com/facebook/react-native/blob/master/.travis.yml#L11-24)。
+
+## 单元测试 (Android)
+
+React Native使用[Buck](https://github.com/facebook/buck)编译工具来运行测试。 单元测试部分直接在本地运行,不需要模拟器。运行下面的命令来执行这些测试:
+
+```bash
+$ cd react-native
+$ ./scripts/run-android-local-unit-tests.sh
+```
+
+## 集成测试 (Android)
+
+React Native使用[Buck](https://github.com/facebook/buck)编译工具来运行测试。 集成测试需要在模拟器/真机上运行,以验证模块、组件以及React Native的内核部分(比如bridge)在端对端测试中运作正常。
+
+确保你正确安装和配置了Android NDK,具体配置参见[这篇文档](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md#prerequisites),然后运行下面的命令来执行测试:
+
+```bash
+$ cd react-native
+$ npm install
+$ ./scripts/run-android-local-integration-tests.sh
+```
+
+## 集成测试 (iOS)
+
+React Native提供了一些工具来简化跨原生与JS端的组件的集成测试。这套工具的两个主要部分是`RCTTestRunner`与`RCTTestModule`。`RCTTestRunner`预设了ReactNative的环境,并且可以以`XCTestCase`的形式在Xcode中直接运行测试 (最简单的方法就是使用`runTest:module`)。而`RCTTestModule`则是以 `NativeModules.TestModule`对象导出到了JS环境中。测试代码需要以JS写成的,并且必须在测试完成后调用`TestModule.markTestCompleted()`方法,否则测试过程会超时并且失败。失败的表现一般是抛出一个JS异常。测试错误条件也是可行的,使用`runTest:module:initialProps:expectErrorRegex:`或是`runTest:module:initialProps:expectErrorBlock:`方法,它们会按提供的条件去验证抛出的错误是否符合。你可以参考[`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestHarnessTest.js)、[`IntegrationTests.m`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m)以及 [IntegrationTestsApp.js](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js)来看具体怎么做集成测试。
+
+Xcode中运行IntegrationTest和UIExplorer两个官方示例应用时,可以按下`cmd + U`键来直接在本地运行集成测试。
+
+## 快照测试 (iOS)
+
+快照测试是集成测试的一种常见类型。这类测试首先渲染一个组件,然后使用`TestModule.verifySnapshot()`比对屏幕截图与参考效果图,其原理是利用了[`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case)这个库。参考效果图是通过在`RCTTestRunner`中设置`recordMode = YES`,然后在运行测试时录制的。屏幕截图在32位和64位色深以及不同的操作系统版本上可能会有细微的差别,所以建议强制在指定的配置环境中执行测试。此外我们还强烈建议所有的网络数据和其他的潜在依赖项都应该事先模拟。你可以参考[`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/IntegrationTests/SimpleSnapshotTest.js)这个例子。
+
+如果你提交的PR(Pull Request,即提交你贡献的代码,并请求官方人员合并到仓库中)会影响到快照测试,比如给现有的快照测试添加一个新的测试用例,那么首先需要重新录制参考效果图。只需在[UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42)中设置`_runner.recordMode = YES;`,然后重新运行先前失败的测试代码,再之后将这一设置改回去,最后提交/更新你的PR,看Travis的自动测试能否通过。
diff --git a/docs/docs/0.42/text.md b/docs/docs/0.42/text.md
new file mode 100644
index 0000000..de9fbdf
--- /dev/null
+++ b/docs/docs/0.42/text.md
@@ -0,0 +1,1079 @@
+一个用于显示文本的React组件,并且它也支持嵌套、样式,以及触摸处理。在下面的例子里,嵌套的标题和正文文字会继承来自`styles.baseText`的`fontFamily`字体样式,不过标题上还附加了它自己额外的样式。标题和文本会在顶部依次堆叠,并且被代码中内嵌的换行符分隔开。
+
+```javascript
+renderText: function() {
+ return (
+
+
+ {this.state.titleText + '\n\n'}
+
+
+ {this.state.bodyText}
+
+
+ );
+},
+...
+var styles = StyleSheet.create({
+ baseText: {
+ fontFamily: 'Cochin',
+ },
+ titleText: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ },
+};
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
adjustsFontSizeToFit bool #
+
+
指定字体是否随着给定样式的限制而自动缩放。
+
+
+
+
allowFontScaling bool #
+
+
控制字体是否要根据系统的“字体大小”辅助选项来进行缩放。
+
+
+
+
ios minimumFontScale bool #
+
+
当adjustsFontSizeToFit开启时,指定最小的缩放比(即不能低于这个值)。可设定的值为0.01 - 1.0
+
+
+
+
numberOfLines number #
+
+
用来当文本过长的时候裁剪文本。包括折叠产生的换行在内,总的行数不会超过这个属性的限制。
+
+
+
+
onLayout function #
+
+
当挂载或者布局变化以后调用,参数为如下的内容:
+
{nativeEvent: {layout: {x, y, width, height}}}
+
+
+
+
onLongPress function #
+
+
+
+
+
selectable function #
+
+
决定用户是否可以长按选择文本,以便复制和粘贴。
+
+
style style #
+
+
+
+
fontFamily string
+
fontSize number
+
fontStyle enum('normal', 'italic')
+
+
+
fontWeight enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900')
+ 指定字体的粗细。大多数字体都支持'normal'和'bold'值。并非所有字体都支持所有的数字值。如果某个值不支持,则会自动选择最接近的值。
+
+
+
lineHeight number
+
+
textAlign enum('auto', 'left', 'right', 'center', 'justify')
+ 指定文本的对齐方式。其中'justify'值仅iOS支持,在Android上会变为left
+
+
+
textDecorationLine enum('none', 'underline', 'line-through', 'underline line-through')
+
+
+
textShadowOffset {width: number, height: number}
+
textShadowRadius number
+
+
android includeFontPadding bool
+ Android在默认情况下会为文字额外保留一些padding,以便留出空间摆放上标或是下标的文字。对于某些字体来说,这些额外的padding可能会导致文字难以垂直居中。如果你把textAlignVertical设置为center之后,文字看起来依然不在正中间,那么可以尝试将本属性设置为false.
+
+
+
+
android textAlignVertical enum('auto', 'top', 'bottom', 'center')
+
ios fontVariant [enum('small-caps', 'oldstyle-nums', 'lining-nums', 'tabular-nums', 'proportional-nums')]
+
+
ios letterSpacing number
+
+
ios textDecorationColor color
+
ios textDecorationStyle enum('solid', 'double', 'dotted', 'dashed')
+
ios writingDirection enum('auto', 'ltr', 'rtl')
+
+
+
+
+
ios suppressHighlighting bool #
+
+
当为true时,如果文本被按下,则没有任何视觉效果。默认情况下,文本被按下时会有一个灰色的、椭圆形的高光。
+
+
+
+
+
+## 嵌套文本
+
+在iOS当中,显示一个格式化文本的方法就是使用`NSAttributedString`:提供你想显示的文本内容,并且使用范围标注来指定一些格式。这种用法非常繁琐。在React Native中,我们决定采用和Web一致的设计,这样你可以把相同格式的文本嵌套包裹起来:
+
+```javascript
+
+ I am bold
+
+ and red
+
+
+```
+
+而实际上在框架内部,这会生成一个扁平结构的`NSAttributedString`,包含以下的信息:
+
+```javascript
+"I am bold and red"
+0-9: bold
+9-17: bold, red
+```
+
+## 容器
+
+``元素在布局上不同于其它组件:在Text内部的元素不再使用flexbox布局,而是采用文本布局。这意味着``内部的元素不再是一个个矩形,而可能会在行末进行折叠。
+
+```javascript
+
+ First part and
+ second part
+
+// Text container: all the text flows as if it was one
+// |First part |
+// |and second |
+// |part |
+
+
+ First part and
+ second part
+
+// View container: each text is its own block
+// |First part |
+// |and |
+// |second part|
+```
+
+## 样式继承限制
+
+在Web上,要想指定整个文档的字体和大小,我们只需要写:
+
+```css
+/* 这段代码是CSS, *不是*React Native */
+html {
+ font-family: 'lucida grande', tahoma, verdana, arial, sans-serif;
+ font-size: 11px;
+ color: #141823;
+}
+```
+
+当浏览器尝试渲染一个文本节点的时候,它会在树中一路向上查询,直到根节点,来找到一个具备`font-size`属性的元素。这个系统一个不好的地方在于**任何**节点都可能会有`font-size`属性,包括``标签。这个设计为了方便而设计,但实际上语义上并不太正确。
+
+在React Native中,我们把这个问题设计的更加严谨:**你必须把你的文本节点放在`
`组件内**。你不能直接在``下放置一段文本。
+
+```javascript
+// 错误的做法:会导致一个错误。下不能直接放一段文本。
+
+ 一些文本
+
+
+// 正确的做法
+
+
+ 一些文本
+
+
+```
+
+并且你也不能直接设置一整颗子树的默认样式。使用一个一致的文本和尺寸的推荐方式是创建一个包含相关样式的组件`MyAppText`,然后在你的App中反复使用它。你还可以创建更多特殊的组件譬如`MyAppHeaderText`来表达不同样式的文本。
+
+```javascript
+
+ 这个组件包含了一个默认的字体样式,用于整个应用的文本
+ 这个组件包含了用于标题的样式
+
+```
+
+React Native实际上还是有一部分样式继承的实现,不过仅限于文本标签的子树。在下面的代码里,第二部分会在加粗的同时又显示为红色:
+
+```javascript
+
+ I am bold
+
+ and red
+
+
+```
+
+我们相信这种看起来不太舒服的给文本添加样式的方法反而会帮助我们生产更好的App:
+
+- (对开发者来说) React组件在概念上被设计为强隔离性的:你应当可以在应用的任何位置放置一个组件,而且只要属性相同,其外观和表现都将完全相同。文本如果能够继承外面的样式属性,将会打破这种隔离性。
+
+- (对实现者来说) React Native的实现也被简化了。我们不需要在每个元素上都添加一个`fontFamily`字段,并且我们也不需要隐含地在显示文本的时候向上遍历树。唯一的样式继承在原生Text组件中编码,也不会影响到其它组件或者系统本身。
+
+### 例子
+
+#### iOS
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+var Entity = React.createClass({
+ render: function() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var AttributeToggler = React.createClass({
+ getInitialState: function() {
+ return {fontWeight: 'bold', fontSize: 15};
+ },
+ toggleWeight: function() {
+ this.setState({
+ fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
+ });
+ },
+ increaseSize: function() {
+ this.setState({
+ fontSize: this.state.fontSize + 1
+ });
+ },
+ render: function() {
+ var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
+ return (
+
+
+ Tap the controls below to change attributes.
+
+
+ See how it will even work on this nested text
+
+
+ Toggle Weight
+
+
+ Increase Size
+
+
+ );
+ }
+});
+
+exports.title = '';
+exports.description = 'Base component for rendering styled text.';
+exports.displayName = 'TextExample';
+exports.examples = [
+{
+ title: 'Wrap',
+ render: function() {
+ return (
+
+ The text should wrap if it goes on multiple lines. See, this is going to
+ the next line.
+
+ );
+ },
+}, {
+ title: 'Padding',
+ render: function() {
+ return (
+
+ This text is indented by 10px padding on all sides.
+
+ );
+ },
+}, {
+ title: 'Font Family',
+ render: function() {
+ return (
+
+
+ Cochin
+
+
+ Cochin bold
+
+
+ Helvetica
+
+
+ Helvetica bold
+
+
+ Verdana
+
+
+ Verdana bold
+
+
+ );
+ },
+}, {
+ title: 'Font Size',
+ render: function() {
+ return (
+
+
+ Size 23
+
+
+ Size 8
+
+
+ );
+ },
+}, {
+ title: 'Color',
+ render: function() {
+ return (
+
+
+ Red color
+
+
+ Blue color
+
+
+ );
+ },
+}, {
+ title: 'Font Weight',
+ render: function() {
+ return (
+
+
+ Move fast and be ultralight
+
+
+ Move fast and be light
+
+
+ Move fast and be normal
+
+
+ Move fast and be bold
+
+
+ Move fast and be ultrabold
+
+
+ );
+ },
+}, {
+ title: 'Font Style',
+ render: function() {
+ return (
+
+
+ Normal text
+
+
+ Italic text
+
+
+ );
+ },
+}, {
+ title: 'Text Decoration',
+ render: function() {
+ return (
+
+
+ Solid underline
+
+
+ Double underline with custom color
+
+
+ Dashed underline with custom color
+
+
+ Dotted underline with custom color
+
+
+ None textDecoration
+
+
+ Solid line-through
+
+
+ Double line-through with custom color
+
+
+ Dashed line-through with custom color
+
+
+ Dotted line-through with custom color
+
+
+ Both underline and line-through
+
+
+ );
+ },
+}, {
+ title: 'Nested',
+ description: 'Nested text components will inherit the styles of their ' +
+ 'parents (only backgroundColor is inherited from non-Text parents). ' +
+ ' only supports other and raw text (strings) as children.',
+ render: function() {
+ return (
+
+
+ (Normal text,
+
+ (and bold
+
+ (and tiny inherited bold blue)
+
+ )
+
+ )
+
+
+ (opacity
+
+ (is inherited
+
+ (and accumulated
+
+ (and also applies to the background)
+
+ )
+
+ )
+
+ )
+
+
+ Entity Name
+
+
+ );
+ },
+}, {
+ title: 'Text Align',
+ render: function() {
+ return (
+
+
+ auto (default) - english LTR
+
+
+ أحب اللغة العربية auto (default) - arabic RTL
+
+
+ left left left left left left left left left left left left left left left
+
+
+ center center center center center center center center center center center
+
+
+ right right right right right right right right right right right right right
+
+
+ justify: this text component{"'"}s contents are laid out with "textAlign: justify"
+ and as you can see all of the lines except the last one span the
+ available width of the parent container.
+
+
+ );
+ },
+}, {
+ title: 'Letter Spacing',
+ render: function() {
+ return (
+
+
+ letterSpacing = 0
+
+
+ letterSpacing = 2
+
+
+ letterSpacing = 9
+
+
+ letterSpacing = -1
+
+
+ );
+ },
+}, {
+ title: 'Spaces',
+ render: function() {
+ return (
+
+ A {'generated'} {' '} {'string'} and some spaces
+
+ );
+ },
+}, {
+ title: 'Line Height',
+ render: function() {
+ return (
+
+
+ A lot of space between the lines of this long passage that should
+ wrap once.
+
+
+ );
+ },
+}, {
+ title: 'Empty Text',
+ description: 'It\'s ok to have Text with zero or null children.',
+ render: function() {
+ return (
+
+ );
+ },
+}, {
+ title: 'Toggling Attributes',
+ render: function(): ReactElement {
+ return ;
+ },
+}, {
+ title: 'backgroundColor attribute',
+ description: 'backgroundColor is inherited from all types of views.',
+ render: function() {
+ return (
+
+ Yellow container background,
+
+ {' '}red background,
+
+ {' '}blue background,
+
+ {' '}inherited blue background,
+
+ {' '}nested green background.
+
+
+
+
+
+ );
+ },
+}, {
+ title: 'numberOfLines attribute',
+ render: function() {
+ return (
+
+
+ Maximum of one line, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after one line.
+
+
+ Maximum of two lines, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after two lines.
+
+
+ No maximum lines specified, no matter how much I write here. If I keep writing, it{"'"}ll just keep going and going.
+
+
+ );
+ },
+}, {
+ title: 'Text highlighting (tap the link to see highlight)',
+ render: function() {
+ return (
+
+ Lorem ipsum dolor sit amet, null}>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+ );
+ },
+}, {
+ title: 'allowFontScaling attribute',
+ render: function() {
+ return (
+
+
+ By default, text will respect Text Size accessibility setting on iOS.
+ It means that all font sizes will be increased or descreased depending on the value of Text Size setting in
+ {" "}Settings.app - Display & Brightness - Text Size
+
+
+ You can disable scaling for your Text component by passing {"\""}allowFontScaling={"{"}false{"}\""} prop.
+
+
+ This text will not scale.
+
+
+ );
+ },
+}, {
+ title: 'Inline images',
+ render: function() {
+ return (
+
+
+ This text contains an inline image . Neat, huh?
+
+
+ );
+ },
+}, {
+ title: 'Text shadow',
+ render: function() {
+ return (
+
+
+ Demo text shadow
+
+
+ );
+ },
+}];
+
+var styles = StyleSheet.create({
+ backgroundColorText: {
+ margin: 5,
+ marginBottom: 0,
+ backgroundColor: 'rgba(100, 100, 100, 0.3)'
+ },
+});
+```
+
+#### Android
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var Entity = React.createClass({
+ render: function() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var AttributeToggler = React.createClass({
+ getInitialState: function() {
+ return {fontWeight: 'bold', fontSize: 15};
+ },
+ toggleWeight: function() {
+ this.setState({
+ fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
+ });
+ },
+ increaseSize: function() {
+ this.setState({
+ fontSize: this.state.fontSize + 1
+ });
+ },
+ render: function() {
+ var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
+ return (
+
+
+ Tap the controls below to change attributes.
+
+
+ See how it will even work on this nested text
+
+
+ Toggle Weight
+ {' (with highlight onPress)'}
+
+
+ Increase Size (suppressHighlighting true)
+
+
+ );
+ }
+});
+
+var TextExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Base component for rendering styled text.',
+ },
+ render: function() {
+ return (
+
+
+
+ The text should wrap if it goes on multiple lines.
+ See, this is going to the next line.
+
+
+
+
+ This text is indented by 10px padding on all sides.
+
+
+
+
+ Sans-Serif
+
+
+ Sans-Serif Bold
+
+
+ Serif
+
+
+ Serif Bold
+
+
+ Monospace
+
+
+ Monospace Bold (After 5.0)
+
+
+
+
+
+
+ Roboto Regular
+
+
+ Roboto Italic
+
+
+ Roboto Bold
+
+
+ Roboto Bold Italic
+
+
+ Roboto Light
+
+
+ Roboto Light Italic
+
+
+ Roboto Thin (After 4.2)
+
+
+ Roboto Thin Italic (After 4.2)
+
+
+ Roboto Condensed
+
+
+ Roboto Condensed Italic
+
+
+ Roboto Condensed Bold
+
+
+ Roboto Condensed Bold Italic
+
+
+ Roboto Medium (After 5.0)
+
+
+ Roboto Medium Italic (After 5.0)
+
+
+
+
+
+
+
+
+ NotoSerif Regular
+
+
+ NotoSerif Bold Italic
+
+
+ NotoSerif Italic (Missing Font file)
+
+
+
+
+
+
+
+ Size 23
+
+
+ Size 8
+
+
+
+
+ Red color
+
+
+ Blue color
+
+
+
+
+ Move fast and be bold
+
+
+ Move fast and be bold
+
+
+
+
+ Move fast and be bold
+
+
+ Move fast and be bold
+
+
+
+
+ Move fast and be bold
+
+
+
+
+ Solid underline
+
+
+ None textDecoration
+
+
+ Solid line-through
+
+
+ Both underline and line-through
+
+
+ Mixed text with underline and line-through text nodes
+
+
+
+ console.log('1st')}>
+ (Normal text,
+ console.log('2nd')}>
+ (and bold
+ console.log('3rd')}>
+ (and tiny bold italic blue
+ console.log('4th')}>
+ (and tiny normal blue)
+
+ )
+
+ )
+
+ )
+
+ console.log('1st')}>
+ (Serif
+ console.log('2nd')}>
+ (Serif Bold Italic
+ console.log('3rd')}>
+ (Monospace Normal
+ console.log('4th')}>
+ (Sans-Serif Bold
+ console.log('5th')}>
+ (and Sans-Serif Normal)
+
+ )
+
+ )
+
+ )
+
+ )
+
+
+ Entity Name
+
+
+
+
+ auto (default) - english LTR
+
+
+ أحب اللغة العربية auto (default) - arabic RTL
+
+
+ left left left left left left left left left left left left left left left
+
+
+ center center center center center center center center center center center
+
+
+ right right right right right right right right right right right right right
+
+
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。
+
+
+
+
+ 星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。星际争霸是世界上最好的游戏。
+
+
+
+
+
+
+ A {'generated'} {' '} {'string'} and some spaces
+
+
+
+
+ Holisticly formulate inexpensive ideas before best-of-breed benefits. Continually expedite magnetic potentialities rather than client-focused interfaces.
+
+
+
+
+
+
+
+
+
+
+ Red background,
+
+ {' '}blue background,
+
+ {' '}inherited blue background,
+
+ {' '}nested green background.
+
+
+
+
+
+ Same alpha as background,
+
+ Inherited alpha from background,
+
+ Reapply alpha
+
+
+
+
+
+
+
+
+
+
+ Default containerBackgroundColor (inherited) + backgroundColor wash
+
+
+ {"containerBackgroundColor: 'transparent' + backgroundColor wash"}
+
+
+
+
+ Maximum of one line no matter now much I write here. If I keep writing it{"'"}ll just truncate after one line
+
+
+ Maximum of two lines no matter now much I write here. If I keep writing it{"'"}ll just truncate after two lines
+
+
+ No maximum lines specified no matter now much I write here. If I keep writing it{"'"}ll just keep going and going
+
+
+
+
+ This text contains an inline image . Neat, huh?
+
+
+
+
+ Demo text shadow
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ backgroundColorText: {
+ left: 5,
+ backgroundColor: 'rgba(100, 100, 100, 0.3)'
+ },
+});
+
+module.exports = TextExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/textinput.md b/docs/docs/0.42/textinput.md
new file mode 100644
index 0000000..89871eb
--- /dev/null
+++ b/docs/docs/0.42/textinput.md
@@ -0,0 +1,1977 @@
+TextInput是一个允许用户在应用中通过键盘输入文本的基本组件。本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。
+
+最简单的用法就是丢一个`TextInput`到应用里,然后订阅它的`onChangeText`事件来读取用户的输入。注意,从TextInput里取值这就是目前唯一的做法!即使用`onChangeText`写入state,然后从this.state中取出值。它还有一些其它的事件,譬如`onSubmitEditing`和`onFocus`。一个简单的例子如下:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, TextInput } from 'react-native';
+
+class UselessTextInput extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { text: 'Useless Placeholder' };
+ }
+
+ render() {
+ return (
+ this.setState({text})}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+// App registration and rendering
+AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
+```
+
+注意有些属性仅在`multiline`为true或者为false的时候有效。此外,当`multiline=false`时,为元素的某一个边添加边框样式(例如:`borderBottomColor`,`borderLeftWidth`等)将不会生效。为了能够实现效果你可以使用一个`View`来包裹`TextInput`:
+
+``` ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View, TextInput } from 'react-native';
+
+class UselessTextInput extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+class UselessTextInputMultiline extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'Useless Multiline Placeholder',
+ };
+ }
+
+ // 你可以试着输入一种颜色,比如red,那么这个red就会作用到View的背景色样式上
+ render() {
+ return (
+
+ this.setState({text})}
+ value={this.state.text}
+ />
+
+ );
+ }
+}
+
+// App registration and rendering
+AppRegistry.registerComponent(
+ 'AwesomeProject',
+ () => UselessTextInputMultiline
+);
+```
+
+`TextInput`在安卓上默认有一个底边框,同时会有一些padding。如果要想使其看起来和iOS上尽量一致,则需要设置`padding: 0`,同时设置`underlineColorAndroid="transparent"`来去掉底边框。
+
+又,在安卓上如果设置`multiline = {true}`,文本默认会垂直居中,可设置`textAlignVertical: top`样式来使其居顶显示。
+
+又又,在安卓上长按选择文本会导致`windowSoftInputMode`设置变为`adjustResize`,这样可能导致绝对定位的元素被键盘给顶起来。要解决这一问题你需要在AndroidManifest.xml中明确指定合适的`windowSoftInputMode`( )值,或是自己监听事件来处理布局变化。
+
+
+### 截图
+
+
+### 属性
+
+
+
+
autoCapitalize enum('none', 'sentences', 'words', 'characters') #
+
+
控制TextInput是否要自动将特定字符切换为大写:
+
+ characters: 所有的字符。
+ words: 每个单词的第一个字符。
+ sentences: 每句话的第一个字符(默认)。
+ none: 不自动切换任何字符为大写。
+
+
+
+
+
autoCorrect bool #
+
+
如果为false,会关闭拼写自动修正。默认值是true。
+
+
+
+
autoFocus bool #
+
+
如果为true,在componentDidMount后会获得焦点。默认值为false。
+
+
+
+
blurOnSubmit bool #
+
+
如果为true,文本框会在提交的时候失焦。对于单行输入框默认值为true,多行则为false。注意:对于多行输入框来说,如果将blurOnSubmit设为true,则在按下回车键时就会失去焦点同时触发onSubmitEditing事件,而不会换行。
+
+
+
+
caretHidden bool #
+
+
如果为true,则隐藏光标。默认值为false
+
+
+
+
defaultValue string #
+
+
提供一个文本框中的初始值。当用户开始输入的时候,值就可以改变。
+
在一些简单的使用情形下,如果你不想用监听消息然后更新value属性的方法来保持属性和状态同步的时候,就可以用defaultValue来代替。
+
+
+
+
editable bool #
+
+
如果为false,文本框是不可编辑的。默认值为true。
+
+
+
+
keyboardType enum("default", 'numeric', 'email-address', "ascii-capable", 'numbers-and-punctuation', 'url', 'number-pad', 'phone-pad', 'name-phone-pad', 'decimal-pad', 'twitter', 'web-search') #
+
+
决定弹出的何种软键盘的,譬如numeric(纯数字键盘)。
+
这些值在所有平台都可用:
+
+ default
+ numeric
+ email-address
+
+
+
+
+
maxLength number #
+
+
限制文本框中最多的字符数。使用这个属性而不用JS逻辑去实现,可以避免闪烁的现象。
+
+
+
+
multiline bool #
+
+
如果为true,文本框中可以输入多行文字。默认值为false。
+
+
+
+
+
onChange function #
+
+
+
+
onChangeText function #
+
+
当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。
+
+
+
+
onEndEditing function #
+
+
+
+
+
onLayout function #
+
+
当组件挂载或者布局变化的时候调用,参数为{x, y, width, height}。
+
+
+
+
onScroll function #
+
+
Invoked on content scroll with { nativeEvent: { contentOffset: { x, y } } }.
+ May also contain other properties from ScrollEvent but on Android contentSize is not provided for performance reasons.
+
+
+
+
onSelectionChange function #
+
+
Callback that is called when the text input selection is changed. This will be called with
+ { nativeEvent: { selection: { start, end } } }.
+
+
+
+
onSubmitEditing function #
+
+
此回调函数当软键盘的`确定`/`提交`按钮被按下的时候调用此函数。如果multiline={true},此属性不可用。
+
+
+
+
placeholder string #
+
+
+
+
placeholderTextColor color #
+
+
+
+
ios returnKeyType enum('done', 'go', 'next', 'search', 'send', 'none', 'previous', 'default', 'emergency-call', 'google', 'join', 'route', 'yahoo') #
+
决定“确定”按钮显示的内容。 On Android you can also use
+returnKeyLabel.
Cross platform
The following values work across platforms:
+
+ done
+ go
+ next
+ search
+ send
+
+
Android Only
The following values work on Android only:
+
+
iOS Only
The following values work on iOS only:
+
+ default
+ emergency-call
+ google
+ join
+ route
+ yahoo
+
+
+
+
+
secureTextEntry bool #
+
+
如果为true,文本框会遮住之前输入的文字,这样类似密码之类的敏感文字可以更加安全。默认值为false。
+
+
+
+
selectTextOnFocus bool #
+
+
如果为true,当获得焦点的时候,所有的文字都会被选中。
+
+
+
+
selection {start: number, end: number} #
+
+
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
+
+
+
+
selectionColor color #
+
+
设置输入框高亮时的颜色(在iOS上还包括光标)
+
+
+
+
+
+
译注:这意味着本组件继承了所有Text的样式。
+
+
+
+
value string #
+
+
文本框中的文字内容。
+
TextInput是一个受约束的(Controlled)的组件,意味着如果提供了value属性,原生值会被强制与value属性保持一致。在大部分情况下这都工作的很好,不过有些情况下会导致一些闪烁现象——一个常见的原因就是通过不改变value来阻止用户进行编辑。如果你希望阻止用户输入,可以考虑设置editable={false};如果你是希望限制输入的长度,可以考虑设置maxLength属性,这两个属性都不会导致闪烁。
+
+
+
+
android disableFullscreenUI bool #
+
+
When false, if there is a small amount of space available around a text input
+ (e.g. landscape orientation on a phone), the OS may choose to have the user edit
+ the text inside of a full screen text input mode. When true, this feature is
+ disabled and users will always edit the text directly inside of the text input.
+ Defaults to false.
+
+
+
+
android inlineImageLeft string #
+
If defined, the provided image resource will be rendered on the left.
+
+
+
android inlineImagePadding number #
+
Padding between the inline image, if any, and the text input itself.
+
+
+
android returnKeyLabel string #
+
Sets the return key to the label. Use it instead of returnKeyType.
+
+
+
android textBreakStrategy enum('simple', 'highQuality', 'balanced') #
+
Set text break strategy on Android API Level 23+, possible values are simple, highQuality, balanced
+The default value is simple.
+
+
+
ios clearButtonMode enum('never', 'while-editing', 'unless-editing', 'always') #
+
+
+
+
ios clearTextOnFocus bool #
+
+
如果为true,每次开始输入的时候都会清除文本框的内容。
+
+
+
+
ios enablesReturnKeyAutomatically bool #
+
+
如果为true,键盘会在文本框内没有文字的时候禁用确认按钮。默认值为false。
+
+
+
+
ios dataDetectorTypes enum('phoneNumber', 'link', 'address', 'calendarEvent', 'none', 'all'), [object Object] #
+
+
Determines the types of data converted to clickable URLs in the text input. Only valid if multiline={true} and editable={false}. By default no data types are detected.
You can provide one type or an array of many types.
Possible values for dataDetectorTypes are:
+
+ 'phoneNumber'
+ 'link'
+ 'address'
+ 'calendarEvent'
+ 'none''all'
+
+
+
+
+
ios keyboardAppearance enum('default', 'light', 'dark') #
+
+
+
+
ios onKeyPress function #
+
+
当一个键被按下的时候调用此回调。传递给回调函数的参数为{ nativeEvent: { key: keyValue } },其中keyValue即为被按下的键。会在onChange之前调用。
+
+
+
+
ios selectionState DocumentSelectionState #
+
+
+
+
android numberOfLines number #android
+
+
设置输入框的行数。当multiline设置为true时使用它,可以占据对应的行数。
+
+
+
+
android underlineColorAndroid string #
+
+
文本框的下划线颜色(译注:如果要去掉文本框的边框,请将此属性设为透明transparent)。
+
+
+
+
ios spellCheck bool #
+
如果设置为false,则禁用拼写检查的样式(比如错误拼写的单词下的红线)。默认值继承自autoCorrect.
+
+
+
+
+
+### 方法
+
+
+
isFocused(): boolean
+ #
+
+
+
+
+
+### 例子
+
+#### iOS
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Text,
+ TextInput,
+ View,
+ StyleSheet,
+} = ReactNative;
+
+class WithLabel extends React.Component {
+ render() {
+ return (
+
+
+ {this.props.label}
+
+ {this.props.children}
+
+ );
+ }
+}
+
+class TextEventsExample extends React.Component {
+ state = {
+ curText: '',
+ prevText: '',
+ prev2Text: '',
+ prev3Text: '',
+ };
+
+ updateText = (text) => {
+ this.setState((state) => {
+ return {
+ curText: text,
+ prevText: state.curText,
+ prev2Text: state.prevText,
+ prev3Text: state.prev2Text,
+ };
+ });
+ };
+
+ render() {
+ return (
+
+ this.updateText('onFocus')}
+ onBlur={() => this.updateText('onBlur')}
+ onChange={(event) => this.updateText(
+ 'onChange text: ' + event.nativeEvent.text
+ )}
+ onEndEditing={(event) => this.updateText(
+ 'onEndEditing text: ' + event.nativeEvent.text
+ )}
+ onSubmitEditing={(event) => this.updateText(
+ 'onSubmitEditing text: ' + event.nativeEvent.text
+ )}
+ onSelectionChange={(event) => this.updateText(
+ 'onSelectionChange range: ' +
+ event.nativeEvent.selection.start + ',' +
+ event.nativeEvent.selection.end
+ )}
+ onKeyPress={(event) => {
+ this.updateText('onKeyPress key: ' + event.nativeEvent.key);
+ }}
+ style={styles.default}
+ />
+
+ {this.state.curText}{'\n'}
+ (prev: {this.state.prevText}){'\n'}
+ (prev2: {this.state.prev2Text}){'\n'}
+ (prev3: {this.state.prev3Text})
+
+
+ );
+ }
+}
+
+class AutoExpandingTextInput extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
+ height: 0,
+ };
+ }
+ render() {
+ return (
+ {
+ this.setState({text});
+ }}
+ onContentSizeChange={(event) => {
+ this.setState({height: event.nativeEvent.contentSize.height});
+ }}
+ style={[styles.default, {height: Math.max(35, this.state.height)}]}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+class RewriteExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ var limit = 20;
+ var remainder = limit - this.state.text.length;
+ var remainderColor = remainder > 5 ? 'blue' : 'red';
+ return (
+
+ {
+ text = text.replace(/ /g, '_');
+ this.setState({text});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ {remainder}
+
+
+ );
+ }
+}
+
+class RewriteExampleInvalidCharacters extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ return (
+
+ {
+ this.setState({text: text.replace(/\s/g, '')});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ );
+ }
+}
+
+class TokenizedTextExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {text: 'Hello #World'};
+ }
+ render() {
+
+ //define delimiter
+ let delimiter = /\s+/;
+
+ //split string
+ let _text = this.state.text;
+ let token, index, parts = [];
+ while (_text) {
+ delimiter.lastIndex = 0;
+ token = delimiter.exec(_text);
+ if (token === null) {
+ break;
+ }
+ index = token.index;
+ if (token[0].length === 0) {
+ index = 1;
+ }
+ parts.push(_text.substr(0, index));
+ parts.push(token[0]);
+ index = index + token[0].length;
+ _text = _text.slice(index);
+ }
+ parts.push(_text);
+
+ //highlight hashtags
+ parts = parts.map((text) => {
+ if (/^#/.test(text)) {
+ return {text} ;
+ } else {
+ return text;
+ }
+ });
+
+ return (
+
+ {
+ this.setState({text});
+ }}>
+ {parts}
+
+
+ );
+ }
+}
+
+class BlurOnSubmitExample extends React.Component {
+ focusNextField = (nextField) => {
+ this.refs[nextField].focus();
+ };
+
+ render() {
+ return (
+
+ this.focusNextField('2')}
+ />
+ this.focusNextField('3')}
+ />
+ this.focusNextField('4')}
+ />
+ this.focusNextField('5')}
+ />
+
+
+ );
+ }
+}
+
+type SelectionExampleState = {
+ selection: {
+ start: number;
+ end?: number;
+ };
+ value: string;
+};
+
+class SelectionExample extends React.Component {
+ state: SelectionExampleState;
+
+ _textInput: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ selection: {start: 0, end: 0},
+ value: props.value
+ };
+ }
+
+ onSelectionChange({nativeEvent: {selection}}) {
+ this.setState({selection});
+ }
+
+ getRandomPosition() {
+ var length = this.state.value.length;
+ return Math.round(Math.random() * length);
+ }
+
+ select(start, end) {
+ this._textInput.focus();
+ this.setState({selection: {start, end}});
+ }
+
+ selectRandom() {
+ var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
+ this.select(...positions);
+ }
+
+ placeAt(position) {
+ this.select(position, position);
+ }
+
+ placeAtRandom() {
+ this.placeAt(this.getRandomPosition());
+ }
+
+ render() {
+ var length = this.state.value.length;
+
+ return (
+
+ this.setState({value})}
+ onSelectionChange={this.onSelectionChange.bind(this)}
+ ref={textInput => (this._textInput = textInput)}
+ selection={this.state.selection}
+ style={this.props.style}
+ value={this.state.value}
+ />
+
+
+ selection = {JSON.stringify(this.state.selection)}
+
+
+ Place at Start (0, 0)
+
+
+ Place at End ({length}, {length})
+
+
+ Place at Random
+
+
+ Select All
+
+
+ Select Random
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ page: {
+ paddingBottom: 300,
+ },
+ default: {
+ height: 26,
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ flex: 1,
+ fontSize: 13,
+ padding: 4,
+ },
+ multiline: {
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ flex: 1,
+ fontSize: 13,
+ height: 50,
+ padding: 4,
+ marginBottom: 4,
+ },
+ multilineWithFontStyles: {
+ color: 'blue',
+ fontWeight: 'bold',
+ fontSize: 18,
+ fontFamily: 'Cochin',
+ height: 60,
+ },
+ multilineChild: {
+ width: 50,
+ height: 40,
+ position: 'absolute',
+ right: 5,
+ backgroundColor: 'red',
+ },
+ eventLabel: {
+ margin: 3,
+ fontSize: 12,
+ },
+ labelContainer: {
+ flexDirection: 'row',
+ marginVertical: 2,
+ flex: 1,
+ },
+ label: {
+ width: 115,
+ alignItems: 'flex-end',
+ marginRight: 10,
+ paddingTop: 2,
+ },
+ rewriteContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ remainder: {
+ textAlign: 'right',
+ width: 24,
+ },
+ hashtag: {
+ color: 'blue',
+ fontWeight: 'bold',
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Single and multi-line text inputs.';
+exports.examples = [
+ {
+ title: 'Auto-focus',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: "Live Re-Write ( -> '_') + maxLength",
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Live Re-Write (no spaces allowed)',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Auto-capitalize',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-correct',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Keyboard types',
+ render: function() {
+ var keyboardTypes = [
+ 'default',
+ 'ascii-capable',
+ 'numbers-and-punctuation',
+ 'url',
+ 'number-pad',
+ 'phone-pad',
+ 'name-phone-pad',
+ 'email-address',
+ 'decimal-pad',
+ 'twitter',
+ 'web-search',
+ 'numeric',
+ ];
+ var examples = keyboardTypes.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Keyboard appearance',
+ render: function() {
+ var keyboardAppearance = [
+ 'default',
+ 'light',
+ 'dark',
+ ];
+ var examples = keyboardAppearance.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Return key types',
+ render: function() {
+ var returnKeyTypes = [
+ 'default',
+ 'go',
+ 'google',
+ 'join',
+ 'next',
+ 'route',
+ 'search',
+ 'send',
+ 'yahoo',
+ 'done',
+ 'emergency-call',
+ ];
+ var examples = returnKeyTypes.map((type) => {
+ return (
+
+
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Enable return key automatically',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Secure text entry',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Event handling',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Colored input text',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Colored highlight/cursor for text input',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Clear button mode',
+ render: function () {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Clear and select',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Blur on submit',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Multiline blur on submit',
+ render: function() {
+ return (
+
+ alert(event.nativeEvent.text)}
+ />
+
+ );
+ }
+ },
+ {
+ title: 'Multiline',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-expanding',
+ render: function() {
+ return (
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Attributed text',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Text selection & cursor placement',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'TextInput maxLength',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ },
+];
+```
+
+#### Android
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Text,
+ TextInput,
+ View,
+ StyleSheet,
+} = ReactNative;
+
+class TextEventsExample extends React.Component {
+ state = {
+ curText: '',
+ prevText: '',
+ prev2Text: '',
+ };
+
+ updateText = (text) => {
+ this.setState((state) => {
+ return {
+ curText: text,
+ prevText: state.curText,
+ prev2Text: state.prevText,
+ };
+ });
+ };
+
+ render() {
+ return (
+
+ this.updateText('onFocus')}
+ onBlur={() => this.updateText('onBlur')}
+ onChange={(event) => this.updateText(
+ 'onChange text: ' + event.nativeEvent.text
+ )}
+ onEndEditing={(event) => this.updateText(
+ 'onEndEditing text: ' + event.nativeEvent.text
+ )}
+ onSubmitEditing={(event) => this.updateText(
+ 'onSubmitEditing text: ' + event.nativeEvent.text
+ )}
+ style={styles.singleLine}
+ />
+
+ {this.state.curText}{'\n'}
+ (prev: {this.state.prevText}){'\n'}
+ (prev2: {this.state.prev2Text})
+
+
+ );
+ }
+}
+
+class AutoExpandingTextInput extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
+ height: 0,
+ };
+ }
+ render() {
+ return (
+ {
+ this.setState({height: event.nativeEvent.contentSize.height});
+ }}
+ onChangeText={(text) => {
+ this.setState({text});
+ }}
+ style={[styles.default, {height: Math.max(35, this.state.height)}]}
+ value={this.state.text}
+ />
+ );
+ }
+}
+
+class RewriteExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+ render() {
+ var limit = 20;
+ var remainder = limit - this.state.text.length;
+ var remainderColor = remainder > 5 ? 'blue' : 'red';
+ return (
+
+ {
+ text = text.replace(/ /g, '_');
+ this.setState({text});
+ }}
+ style={styles.default}
+ value={this.state.text}
+ />
+
+ {remainder}
+
+
+ );
+ }
+}
+
+class TokenizedTextExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: 'Hello #World'};
+ }
+ render() {
+
+ //define delimiter
+ let delimiter = /\s+/;
+
+ //split string
+ let _text = this.state.text;
+ let token, index, parts = [];
+ while (_text) {
+ delimiter.lastIndex = 0;
+ token = delimiter.exec(_text);
+ if (token === null) {
+ break;
+ }
+ index = token.index;
+ if (token[0].length === 0) {
+ index = 1;
+ }
+ parts.push(_text.substr(0, index));
+ parts.push(token[0]);
+ index = index + token[0].length;
+ _text = _text.slice(index);
+ }
+ parts.push(_text);
+
+ //highlight hashtags
+ parts = parts.map((text) => {
+ if (/^#/.test(text)) {
+ return {text} ;
+ } else {
+ return text;
+ }
+ });
+
+ return (
+
+ {
+ this.setState({text});
+ }}>
+ {parts}
+
+
+ );
+ }
+}
+
+class BlurOnSubmitExample extends React.Component {
+ focusNextField = (nextField) => {
+ this.refs[nextField].focus();
+ };
+
+ render() {
+ return (
+
+ this.focusNextField('2')}
+ />
+ this.focusNextField('3')}
+ />
+ this.focusNextField('4')}
+ />
+ this.focusNextField('5')}
+ />
+
+
+ );
+ }
+}
+
+class ToggleDefaultPaddingExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {hasPadding: false};
+ }
+ render() {
+ return (
+
+
+ this.setState({hasPadding: !this.state.hasPadding})}>
+ Toggle padding
+
+
+ );
+ }
+}
+
+type SelectionExampleState = {
+ selection: {
+ start: number;
+ end: number;
+ };
+ value: string;
+};
+
+class SelectionExample extends React.Component {
+ state: SelectionExampleState;
+
+ _textInput: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ selection: {start: 0, end: 0},
+ value: props.value
+ };
+ }
+
+ onSelectionChange({nativeEvent: {selection}}) {
+ this.setState({selection});
+ }
+
+ getRandomPosition() {
+ var length = this.state.value.length;
+ return Math.round(Math.random() * length);
+ }
+
+ select(start, end) {
+ this._textInput.focus();
+ this.setState({selection: {start, end}});
+ }
+
+ selectRandom() {
+ var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
+ this.select(...positions);
+ }
+
+ placeAt(position) {
+ this.select(position, position);
+ }
+
+ placeAtRandom() {
+ this.placeAt(this.getRandomPosition());
+ }
+
+ render() {
+ var length = this.state.value.length;
+
+ return (
+
+ this.setState({value})}
+ onSelectionChange={this.onSelectionChange.bind(this)}
+ ref={textInput => (this._textInput = textInput)}
+ selection={this.state.selection}
+ style={this.props.style}
+ value={this.state.value}
+ />
+
+
+ selection = {JSON.stringify(this.state.selection)}
+
+
+ Place at Start (0, 0)
+
+
+ Place at End ({length}, {length})
+
+
+ Place at Random
+
+
+ Select All
+
+
+ Select Random
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ multiline: {
+ height: 60,
+ fontSize: 16,
+ padding: 4,
+ marginBottom: 10,
+ },
+ eventLabel: {
+ margin: 3,
+ fontSize: 12,
+ },
+ singleLine: {
+ fontSize: 16,
+ padding: 4,
+ },
+ singleLineWithHeightTextInput: {
+ height: 30,
+ },
+ hashtag: {
+ color: 'blue',
+ fontWeight: 'bold',
+ },
+});
+
+exports.title = '';
+exports.description = 'Single and multi-line text inputs.';
+exports.examples = [
+ {
+ title: 'Auto-focus',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: "Live Re-Write ( -> '_')",
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Auto-capitalize',
+ render: function() {
+ var autoCapitalizeTypes = [
+ 'none',
+ 'sentences',
+ 'words',
+ 'characters',
+ ];
+ var examples = autoCapitalizeTypes.map((type) => {
+ return (
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Auto-correct',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Keyboard types',
+ render: function() {
+ var keyboardTypes = [
+ 'default',
+ 'email-address',
+ 'numeric',
+ 'phone-pad',
+ ];
+ var examples = keyboardTypes.map((type) => {
+ return (
+
+ );
+ });
+ return {examples} ;
+ }
+ },
+ {
+ title: 'Blur on submit',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Event handling',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Colors and text inputs',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+
+ Darker backgroundColor
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Text input, themes and heights',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'fontFamily, fontWeight and fontStyle',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Passwords',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Editable',
+ render: function() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Multiline',
+ render: function() {
+ return (
+
+
+
+
+ multiline with children, aligned bottom-right
+
+
+ );
+ }
+ },
+ {
+ title: 'Fixed number of lines',
+ platform: 'android',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Auto-expanding',
+ render: function() {
+ return (
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Attributed text',
+ render: function() {
+ return ;
+ }
+ },
+ {
+ title: 'Return key',
+ render: function() {
+ var returnKeyTypes = [
+ 'none',
+ 'go',
+ 'search',
+ 'send',
+ 'done',
+ 'previous',
+ 'next',
+ ];
+ var returnKeyLabels = [
+ 'Compile',
+ 'React Native',
+ ];
+ var examples = returnKeyTypes.map((type) => {
+ return (
+
+ );
+ });
+ var types = returnKeyLabels.map((type) => {
+ return (
+
+ );
+ });
+ return {examples}{types} ;
+ }
+ },
+ {
+ title: 'Inline Images',
+ render: function() {
+ return (
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Toggle Default Padding',
+ render: function(): React.Element { return ; },
+ },
+ {
+ title: 'Text selection & cursor placement',
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+ },
+];
+```
diff --git a/docs/docs/0.42/timepickerandroid.md b/docs/docs/0.42/timepickerandroid.md
new file mode 100644
index 0000000..8f83d20
--- /dev/null
+++ b/docs/docs/0.42/timepickerandroid.md
@@ -0,0 +1,49 @@
+本组件会打开一个标准的Android时间选择器的对话框。
+
+### 示例
+```js
+try {
+ const {action, hour, minute} = await TimePickerAndroid.open({
+ hour: 14,
+ minute: 0,
+ is24Hour: false, // 会显示为'2 PM'
+ });
+ if (action !== TimePickerAndroid.dismissedAction) {
+ // 这里开始可以处理用户选好的时分两个参数:hour (0-23), minute (0-59)
+ }
+} catch ({code, message}) {
+ console.warn('Cannot open time picker', message);
+}
+```
+
+### 方法
+
+
+
static open(options: Object) #
+
+
打开一个标准的Android时间选择器的对话框。
+
可选的options对象的key值如下:
+
+ hour (0-23) - 要显示的小时,默认为当前时间。
+ minute (0-59) - 要显示的分钟,默认为当前时间。
+ is24Hour (boolean) - 如果设为true,则选择器会使用24小时制。如果设为false,则会额外显示AM/PM的选项。如果不设定,则采取当前地区的默认设置。
+
+ 在用户选好时间后返回一个Promise,回调参数为一个对象,其中包含有action, hour (0-23),
+ minute (0-59)。如果用户取消了对话框,Promise仍然会执行,返回的action为TimePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必 先检查action的值。
+
+
+
static timeSetAction() #
+
+
+
+
static dismissedAction() #
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/timers.md b/docs/docs/0.42/timers.md
new file mode 100644
index 0000000..5ed023c
--- /dev/null
+++ b/docs/docs/0.42/timers.md
@@ -0,0 +1,87 @@
+定时器是一个应用中非常重要的部分。React Native实现了和浏览器一致的[定时器Timer](https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Timers)。
+
+## 定时器
+
+- setTimeout, clearTimeout
+- setInterval, clearInterval
+- setImmediate, clearImmediate
+- requestAnimationFrame, cancelAnimationFrame
+
+`requestAnimationFrame(fn)`和`setTimeout(fn, 0)`不同,前者会在每帧刷新之后执行一次,而后者则会尽可能快的执行(在iPhone5S上有可能每秒1000次以上)。
+
+`setImmediate`则会在当前JavaScript执行块结束的时候执行,就在将要发送批量响应数据到原生之前。注意如果你在`setImmediate`的回调函数中又执行了`setImmediate`,它会紧接着立刻执行,而不会在调用之前等待原生代码。
+
+`Promise`的实现就使用了`setImmediate`来执行异步调用。
+
+## InteractionManager
+
+原生应用感觉如此流畅的一个重要原因就是在互动和动画的过程中避免繁重的操作。在React Native里,我们目前受到限制,因为我们只有一个JavaScript执行线程。不过你可以用`InteractionManager`来确保在执行繁重工作之前所有的交互和动画都已经处理完毕。
+
+应用可以通过以下代码来安排一个任务,使其在交互结束之后执行:
+
+```javascript
+InteractionManager.runAfterInteractions(() => {
+ // ...需要长时间同步执行的任务...
+});
+```
+
+我们来把它和之前的几个任务安排方法对比一下:
+
+- requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
+- setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
+- runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
+
+触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将`runAfterInteractions()`的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
+
+InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
+
+```javascript
+var handle = InteractionManager.createInteractionHandle();
+// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
+// 在动画完成之后
+InteractionManager.clearInteractionHandle(handle);
+// 在所有句柄都清除之后,现在开始依序执行队列中的任务
+```
+
+## TimerMixin
+
+我们发现很多React Native应用发生致命错误(闪退)是与计时器有关。具体来说,是在某个组件被卸载(unmount)之后,计时器却仍然被激活。为了解决这个问题,我们引入了`TimerMixin`。如果你在组件中引入`TimerMixin`,就可以把你原本的`setTimeout(fn, 500)`改为`this.setTimeout(fn, 500)`(只需要在前面加上`this.`),然后当你的组件卸载时,所有的计时器事件也会被正确的清除。
+
+这个库并没有跟着React Native一起发布。你需要在项目文件夹下输入`npm i react-timer-mixin --save`来单独安装它。
+
+```javascript
+var TimerMixin = require('react-timer-mixin');
+
+var Component = React.createClass({
+ mixins: [TimerMixin],
+ componentDidMount: function() {
+ this.setTimeout(
+ () => { console.log('这样我就不会导致内存泄露!'); },
+ 500
+ );
+ }
+});
+```
+
+我们强烈建议您使用react-timer-mixin提供的`this.setTimeout(...)`来代替`setTimeout(...)`。这可以规避许多难以排查的BUG。
+
+__译注__:Mixin属于ES5语法,对于ES6代码来说,__无法直接使用Mixin__。如果你的项目是用ES6代码编写,同时又使用了计时器,那么你只需铭记`在unmount组件时清除(clearTimeout/clearInterval)所有用到的定时器`,那么也可以实现和TimerMixin同样的效果。例如:
+```js
+import React,{
+ Component
+} from 'react';
+
+export default class Hello extends Component {
+ componentDidMount() {
+ this.timer = setTimeout(
+ () => { console.log('把一个定时器的引用挂在this上'); },
+ 500
+ );
+ }
+ componentWillUnmount() {
+ // 如果存在this.timer,则使用clearTimeout清空。
+ // 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear
+ this.timer && clearTimeout(this.timer);
+ }
+};
+```
diff --git a/docs/docs/0.42/toastandroid.md b/docs/docs/0.42/toastandroid.md
new file mode 100644
index 0000000..f1166fd
--- /dev/null
+++ b/docs/docs/0.42/toastandroid.md
@@ -0,0 +1,115 @@
+本模块将原生的ToastAndroid模块导出为一个JS模块,用于在Android设备上显示一个悬浮的提示信息。本模块包含一个`show`方法接受以下的参数:
+
+1. String message: 一个字符串,表示将要显示的文本内容。
+2. int duration: 提示信息持续显示的时间。可以是`ToastAndroid.SHORT`或者`ToastAndroid.LONG`。
+
+还有一个名为`showWithGravity`的方法可以指定弹出的位置。可选项有:ToastAndroid.TOP, ToastAndroid.BOTTOM, ToastAndroid.CENTER.
+
+用法示例:
+```javascript
+ToastAndroid.show('A pikachu appeared nearby !', ToastAndroid.SHORT);
+ToastAndroid.showWithGravity('All Your Base Are Belong To Us', ToastAndroid.SHORT, ToastAndroid.CENTER);
+```
+
+### 截图
+
+
+### 方法
+
+
+
+
static show(message: string, duration: number) #
+
static showWithGravity(message, duration, gravity) #
+
+
+### 属性
+
+ SHORT: MemberExpression # // Toast duration constants
TOP: MemberExpression # // Toast gravity constants
BOTTOM: MemberExpression # CENTER: MemberExpression #
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ ToastAndroid,
+ TouchableWithoutFeedback,
+} = ReactNative;
+
+var UIExplorerBlock = require('UIExplorerBlock');
+var UIExplorerPage = require('UIExplorerPage');
+
+class ToastExample extends React.Component {
+ static title = 'Toast Example';
+ static description = 'Example that demonstrates the use of an Android Toast to provide feedback.';
+ state = {};
+
+ render() {
+ return (
+
+
+
+ ToastAndroid.show('This is a toast with short duration', ToastAndroid.SHORT)}>
+ Click me.
+
+
+
+
+ ToastAndroid.show('This is a toast with long duration', ToastAndroid.LONG)}>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with top gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.TOP,
+ )
+ }>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with center gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.CENTER,
+ )
+ }>
+ Click me.
+
+
+
+
+ ToastAndroid.showWithGravity(
+ 'This is a toast with bottom gravity',
+ ToastAndroid.SHORT,
+ ToastAndroid.BOTTOM,
+ )
+ }>
+ Click me.
+
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ text: {
+ color: 'black',
+ },
+});
+
+module.exports = ToastExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/toolbarandroid.md b/docs/docs/0.42/toolbarandroid.md
new file mode 100644
index 0000000..d4889a2
--- /dev/null
+++ b/docs/docs/0.42/toolbarandroid.md
@@ -0,0 +1,252 @@
+ToolbarAndroid是一个包装了仅限Android平台的`工具栏(Toolbar)`[部件][0]的React组件。一个Toolbar可以显示一个徽标,一个导航图标(譬如汉堡形状的菜单按钮),一个标题与副标题,以及一个功能列表。标题和副标题会在中间显示,徽标和导航图标会在左侧显示,而功能列表则在右侧显示。
+
+如果工具栏只有一个子节点,它会在标题和功能列表之间显示。
+
+尽管Toolbar支持在徽标、导航和功能图标上使用远程图片,这也只应该在开发(DEV)模式下使用。在发行(release)模式下,你永远都应该用图片资源来渲染这些图标。使用`require('./some_icon.png')`会自动帮你包装好,所以只要你不直接用`{uri:'http://...'}`,就没什么问题。
+
+[0]: https://developer.android.com/reference/android/support/v7/widget/Toolbar.html
+
+例子:
+
+```javascript
+render: function() {
+ return (
+
+ )
+},
+onActionSelected: function(position) {
+ if (position === 0) { // index of 'Settings'
+ showSettings();
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
actions [{title: string, icon: optionalImageSource, show: enum('always', 'ifRoom', 'never'), showWithText: bool}] #
+
+
设置功能菜单中的可用功能。他们会显示为部件右侧的图标或文字。如果放不下,则会被放进一个弹出菜单里。
+
这个属性接受一个对象数组,每个对象可以有如下的字段:
+
+ title: 必须的 , 功能的标题
+ icon: 这个功能的图标,例如require('./some_icon')
+ show: 是直接作为icon显示还是先隐藏,而在弹出菜单里显示:always总是显示,ifRoom如果放的下则显示,或者never从不显示。
+ showWithText: 值为布尔类型,指定是否在图标旁边同时还显示文字
+
+
+
+
+
contentInsetEnd number #
+
+
设置Toolbar的右边缘和屏幕右边缘的距离。
+
除了导航按钮和菜单以外,设置这一属性也会影响Toolbar的内容区域。它定义了Toolbar与屏幕边沿的最小边距,可以用来使Toolbar的内容和一些设计上的网格线对齐。
+
+
+
+
contentInsetStart number #
+
设置Toolbar的左边缘和屏幕左边缘的距离。
作用同上。
+
+
+
logo optionalImageSource #
+
+
+
+
navIcon optionalImageSource #
+
+
+
+
onActionSelected function #
+
+
当一个功能被选中的时候调用此回调。传递给此回调的唯一参数是该功能在actions数组中的位置。
+
+
+
+
onIconClicked function #
+
+
+
+
overflowIcon optionalImageSource #
+
+
+
+
rtl bool #
+
+
设置toolbar的排列顺序为从右到左。除了将这一属性设为true以外,你还需要在AndroidManifest.xml中添加:
+
android:supportsRtl="true"
+
以及在Main.Activity的onCreate方法中调用
+ setLayoutDirection(LayoutDirection.RTL)
+
+
+
+
+
+
subtitleColor string #
+
+
+
+
+
+
titleColor string #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var SwitchAndroid = require('SwitchAndroid');
+var ToolbarAndroid = require('ToolbarAndroid');
+
+var ToolbarAndroidExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Examples of using the Android toolbar.'
+ },
+ getInitialState: function() {
+ return {
+ actionText: 'Example app with toolbar component',
+ toolbarSwitch: false,
+ colorProps: {
+ titleColor: '#3b5998',
+ subtitleColor: '#6a7180',
+ },
+ };
+ },
+ render: function() {
+ return (
+
+
+ this.setState({actionText: 'Icon clicked'})}
+ style={styles.toolbar}
+ subtitle={this.state.actionText}
+ title="Toolbar" />
+ {this.state.actionText}
+
+
+
+
+ this.setState({'toolbarSwitch': value})} />
+ {'\'Tis but a switch'}
+
+
+
+
+
+
+
+
+
+
+ this.setState({colorProps: {}})}
+ title="Wow, such toolbar"
+ style={styles.toolbar}
+ subtitle="Much native"
+ {...this.state.colorProps} />
+
+ Touch the icon to reset the custom colors to the default (theme-provided) ones.
+
+
+
+
+
+
+
+
+
+ );
+ },
+ _onActionSelected: function(position) {
+ this.setState({
+ actionText: 'Selected ' + toolbarActions[position].title,
+ });
+ },
+});
+
+var toolbarActions = [
+ {title: 'Create', icon: require('image!ic_create_black_48dp'), show: 'always'},
+ {title: 'Filter'},
+ {title: 'Settings', icon: require('image!ic_settings_black_48dp'), show: 'always'},
+];
+
+var styles = StyleSheet.create({
+ toolbar: {
+ backgroundColor: '#e9eaed',
+ height: 56,
+ },
+});
+
+module.exports = ToolbarAndroidExample;
+```
diff --git a/docs/docs/0.42/touchablehighlight.md b/docs/docs/0.42/touchablehighlight.md
new file mode 100644
index 0000000..11b0838
--- /dev/null
+++ b/docs/docs/0.42/touchablehighlight.md
@@ -0,0 +1,62 @@
+本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低,同时会有一个底层的颜色透过而被用户看到,使得视图变暗或变亮。在底层实现上,实际会创建一个新的视图到视图层级中,如果使用的方法不正确,有时候会导致一些不希望出现的视觉效果。譬如没有给视图的backgroundColor显式声明一个不透明的颜色。
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+
+ );
+},
+```
+
+> **注意**:TouchableHighlight只支持一个子节点
+>
+> 如果你希望包含多个子组件,用一个View来包装它们。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
activeOpacity number #
+
+
指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在0到1之间)。
+
+
+
+
onHideUnderlay function #
+
+
+
+
onShowUnderlay function #
+
+
+
+
+
underlayColor string #
+
+
+
diff --git a/docs/docs/0.42/touchablenativefeedback.md b/docs/docs/0.42/touchablenativefeedback.md
new file mode 100644
index 0000000..89ea587
--- /dev/null
+++ b/docs/docs/0.42/touchablenativefeedback.md
@@ -0,0 +1,39 @@
+本组件用于封装视图,使其可以正确响应触摸操作(仅限Android平台)。在Android设备上,这个组件利用原生状态来渲染触摸的反馈。目前它只支持一个单独的View实例作为子节点。在底层实现上,实际会创建一个新的RCTView节点替换当前的子View,并附带一些额外的属性。
+
+原生触摸操作反馈的背景可以使用`background`属性来自定义。
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+ Button
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
background backgroundPropType #
+
+
决定在触摸反馈的时候显示什么类型的背景。它接受一个有着type属性和一些基于type属性的额外数据的对象。我们推荐使用以下的静态方法之一来创建这个对象:
+
1) TouchableNativeFeedback.SelectableBackground() - 会创建一个对象,表示安卓主题默认的对于被选中对象的背景。(?android:attr/selectableItemBackground)
+
2) TouchableNativeFeedback.SelectableBackgroundBorderless() - 会创建一个对象,表示安卓主题默认的对于被选中的无边框对象的背景。(?android:attr/selectableItemBackgroundBorderless)。只在Android API level 21+适用。
+
3) TouchableNativeFeedback.Ripple(color, borderless) - 会创建一个对象,当按钮被按下时产生一个涟漪状的背景,你可以通过color参数来指定颜色,如果参数borderless是true,那么涟漪还会渲染到视图的范围之外。(参见原生的actionbar buttons作为该效果的一个例子)。这个背景类型只在Android API level 21+适用。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/touchableopacity.md b/docs/docs/0.42/touchableopacity.md
new file mode 100644
index 0000000..2002e30
--- /dev/null
+++ b/docs/docs/0.42/touchableopacity.md
@@ -0,0 +1,33 @@
+本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低。这个过程并不会真正改变视图层级,大部分情况下很容易添加到应用中而不会带来一些奇怪的副作用。(__译注__:此组件与TouchableHighlight的区别在于并没有额外的颜色变化,更适于一般场景)
+
+例子:
+
+```javascript
+renderButton: function() {
+ return (
+
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
+
+
译注:这意味着本组件继承了所有TouchableWithoutFeedback的属性。
+
+
+
+
activeOpacity number #
+
+
指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在0到1之间)。
+
+
+
diff --git a/docs/docs/0.42/touchablewithoutfeedback.md b/docs/docs/0.42/touchablewithoutfeedback.md
new file mode 100644
index 0000000..ee2ac49
--- /dev/null
+++ b/docs/docs/0.42/touchablewithoutfeedback.md
@@ -0,0 +1,78 @@
+除非你有一个很好的理由,否则不要用这个组件。所有能够响应触屏操作的元素在触屏后都应该有一个视觉上的反馈(然而本组件没有任何视觉反馈)。这也是为什么一个"web"应用总是显得不够"原生"的主要原因之一。
+
+> **注意**:TouchableWithoutFeedback只支持一个子节点
+>
+> 如果你希望包含多个子组件,用一个View来包装它们。
+
+### 属性
+
+
+
+
accessibilityComponentType View.AccessibilityComponentType #
+
+
+
accessibilityTraits View.AccessibilityTraits, [View.AccessibilityTraits] #
+
+
+
+
delayLongPress number #
+
+
单位是毫秒,从onPressIn开始,到onLongPress被调用的延迟。
+
+
+
+
delayPressIn number #
+
+
单位是毫秒,从触摸操作开始到onPressIn被调用的延迟。
+
+
+
+
delayPressOut number #
+
+
单位是毫秒,从触摸操作结束开始到onPressOut被调用的延迟。
+
+
+
+
+ disabled bool #
+
+
+
+
+
+ hitSlop {top: number, left: number, bottom: number, right: number} #
+
+
这一属性定义了按钮的外延范围。这一范围也会使pressRetentionOffset(见下文)变得更大。
+ 注意: 触摸范围不会超过父视图的边界,也不会影响原先和本组件层叠的视图(保留原先的触摸优先级)。
+
+
+
onLayout function #
+
+
当加载或者布局改变的时候被调用,参数为:
+
{nativeEvent: {layout: {x, y, width, height}}}
+
+
+
+
onLongPress function #
+
+
+
onPress function #
+
+
当触摸操作结束时调用,但如果被取消了则不调用(譬如响应者被一个滚动操作取代)
+
+
+
+
+
onPressOut function #
+
+
+
pressRetentionOffset {top: number, left: number, bottom: number, right: number} #
+
+
在当前视图不能滚动的前提下指定这个属性,可以决定当手指移开多远距离之后,会不再激活按钮。但如果手指再次移回范围内,按钮会被再次激活。只要视图不能滚动,你可以来回多次这样的操作。确保你传入一个常量来减少内存分配。
+
+
+
diff --git a/docs/docs/0.42/transforms.md b/docs/docs/0.42/transforms.md
new file mode 100644
index 0000000..7eb6d04
--- /dev/null
+++ b/docs/docs/0.42/transforms.md
@@ -0,0 +1,14 @@
+### 属性列表
+
+
+
+
+ transform [{perspective: number}, {rotate: string}, {rotateX: string}, {rotateY: string}, {rotateZ: string}, {scale: number}, {scaleX: number}, {scaleY: number}, {translateX: number}, {translateY: number}, {skewX: string}, {skewY: string}] #
+
+
+
+
+ transformMatrix TransformMatrixPropType #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.42/troubleshooting.md b/docs/docs/0.42/troubleshooting.md
new file mode 100644
index 0000000..46c28eb
--- /dev/null
+++ b/docs/docs/0.42/troubleshooting.md
@@ -0,0 +1,122 @@
+## Cmd-R在模拟器里不能重新加载应用
+
+在菜单`Hardware > KeyboardMenu`中启用iOS模拟器的"Connect hardware keyboard"。
+
+
+
+如果你使用的键盘不是QWERTY或AZERTY布局,你可以在菜单中选择`Hardware > Shake Gesture`来打开开发者菜单,然后点击"Reload"刷新应用。
+
+## 端口已被使用
+
+可能别的进程正在使用8081端口,你可以尝试关闭它或者尝试修改packager所监听的端口。
+
+##### 关闭使用8081端口的进程
+
+```bash
+$ sudo lsof -n -i4TCP:8081 | grep LISTEN`
+```
+
+然后
+
+```bash
+$ kill -9 <上面显示的进程ID>
+```
+
+##### Windows用户
+
+```bash
+> netstat -o -p TCP
+```
+
+结果的第二列中冒号后面的部分为端口号,找到端口号为8081的行,该行最后一列的数字为进程ID
+
+```bash
+> tskill <进程ID>
+```
+
+##### 在XCode中改变端口号
+
+编辑`AppDelegate.m`来更换端口号
+
+```
+ // OPTION 1
+ // Load from development server. Start the server from the repository root:
+ //
+ // $ npm start
+ //
+ // To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
+ // iOS device are on the same Wi-Fi network.
+ jsCodeLocation = [NSURL URLWithString:@"http://localhost:9381/index.ios.bundle"];
+```
+
+## Mac系统下提示错误提示“Watchman took to long to load”
+
+某些版本的Watchman存在一个BUG,权限设置会导致它无法正常启动。最近的一个更新解决了这个问题,如果你遇到了这个错误提示,重新安装最新版本的Watchman:
+
+```bash
+brew uninstall watchman
+brew install --HEAD watchman
+```
+
+## NPM locking error
+
+如果你在执行`react-native init `的过程中遇到npm报错:"npm WARN locking Error: EACCESS",可以尝试执行:
+
+```bash
+sudo chown -R $USER ~/.npm
+sudo chown -R $USER /usr/local/lib/node_modules
+```
+
+## 在Chrome中调试卡住或者不能正常调试
+
+有可能你的某个Chrome扩展正在和调试器进行意外的交互。如果你遇到了这个问题,可以尝试禁用你的全部扩展,然后逐个启用,直到找到导致问题的扩展。
+
+## XCode构建失败
+
+检查导致构建失败的具体原因,在左侧边栏进入"Issue"页面
+
+##### 缺少React库
+
+如果你使用CocoaPods,检查你是否已经在`Podfile`中增加了React的相关声明。举例来说,如果你正在使用` `, ` `和`fetch()`三个API,你需要在`Podfile`中增加以下内容:
+
+```
+pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'RCTText',
+ 'RCTImage',
+ 'RCTNetwork',
+ 'RCTWebSocket',
+]
+```
+
+接下来,确保你执行过`pod install`命令,并且`Pods/`目录已经被创建,并且React的相关库已经被安装。CocoaPods会引导你从此使用生成的`.xcworkspace`文件,以使用刚刚安装的依赖。
+
+如果你手动添加React库,确保你已经引用了全部的相关依赖,譬如`RCTText.xcodeproj`,`RCTImage.xcodeproj`。要添加哪些依赖取决于你使用了哪些功能。接下来,每个依赖工程所产生的二进制文件要被链接到你的应用程序中。在XCode的工程设置里,找到`Linked Frameworks and Binarys`区域。更多的详细步骤参考[使用链接库](/docs/linking-libraries-ios.html#content)。
+
+##### 报错:“Argument list too long: recursive header expansion failed”
+
+在工程的`Build Settings`面板中,`User Search Header Paths`和`Header Search Paths`选项用于控制XCode在什么目录下寻找代码中`#import`所引用的头文件。对Pods来说,CocoaPods会配置一个默认的查找目录的数组。检查这个选项确保它没有被一个新配置覆盖,并且其中没有配置一个很大的目录。如果其中的某个目录很大,XCode在尝试递归搜索整个目录结构的时候可能会报出以上的错误。
+
+要想把`User Search Header Paths`和`Header Search Paths`恢复到CocoaPods所指定的默认值,首先选中Build Settings面板中的这两个字段,然后按下Delete键。这将会删除自定义的配置,然后恢复到CocoaPods所指定的默认配置。
+
+## 无法连接到开发服务器
+
+##### iOS
+
+确保你的设备和你的电脑在同一个网段下。如果你的设备正在使用2G/3G/4G上网,就没有办法访问你的电脑的本地IP。
+
+##### Android
+
+对于Android 5.0以上设备,你可以运行`adb reverse tcp:8081 tcp:8081`来使得你的设备可以访问到你的电脑。
+
+## 使用`WebSocket`的模块(譬如Firebase)抛出了异常
+
+React Native实现了一套WebSockets的接口兼容(POLYFILLS)。这些兼容组件作为react-native模块的一部分来初始化,所以如果你在`require('react-native')`之前引用了使用WebSockets的模块,就可能会产生错误。确保在你的程序中,最先`require('react-native')`
+
+像这样:
+
+```
+var ReactNative = require('react-native');
+var Firebase = require('firebase');
+```
+
+感谢Issue [#3645](https://github.com/facebook/react-native/issues/3645)发现此问题。如果你对相关内容好奇,可以阅读[InitializeJavaScriptAppEngine.js](https://github.com/facebook/react-native/blob/master/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js),WebSocket的接口兼容在这个文件中被初始化。
\ No newline at end of file
diff --git a/docs/docs/0.42/tutorial-core-components.md b/docs/docs/0.42/tutorial-core-components.md
new file mode 100644
index 0000000..23903fd
--- /dev/null
+++ b/docs/docs/0.42/tutorial-core-components.md
@@ -0,0 +1,139 @@
+组件是React Native应用的基石。一个典型的RN应用的用户界面(UI)是如何产生的?首先是声明组件(以及嵌套组件),然后组件被转换为了对应平台的原生UI组件。
+
+下面介绍的是一些React Native应用中常用的核心组件,它们既可以单独使用,也可以组合使用。
+
+## Text
+
+React Native中最基础的组件莫过于[`Text`](text.html#content)组件了。`Text` 就是用于显示文本。
+
+下面的代码演示了如何在设备上显示一个`"Hello"`。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text } from 'react-native';
+
+const App = () => {
+ return (
+ Hello World!
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## Image
+
+另一个基础的React Native组件就是[`Image`](image.html#content)组件了。类似`Text`,`Image`也就是用于显示图片。
+
+> `Image`就好比是网站中的`img`标签。
+
+最简单的渲染图片的方法就是在`source`属性中指定一个源文件。
+
+下面的代码在设备上显示了一个名为`check.png`的图片。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Image } from 'react-native';
+
+const App = () => {
+ return (
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## View
+
+[`View`](view.html#content)是React Native应用中最基础的“容器”。`View`是对不同目标平台基础视图控件的抽象封装,比如它对应iOS上的`UIView` 。
+
+> `View`就好比是网站中的`div`标签。
+
+虽然像`Text`和`Image`这样的基础组件无需包装在`View`里也可以正常显示,但这并不是我们提倡的做法。将它们包装在`View`组件里,才更好控制其样式和布局。
+
+下面的例子创建了一个`View`组件并将`Hello`这串字符对齐到了设备的顶端中部,而这如果仅仅依靠`Text`组件自身是实现不了的。(你尝试在这里只放一个`Text`组件而不用`View`包装起来,则文字只会显示在左上角):
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text, View } from 'react-native';
+
+const App = () => {
+ return (
+
+ Hello!
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## TextInput
+
+很多应用还离不开用户的直接输入。发帖或者写评论就是一个典型的例子。[`TextInput`](textinput.html#content)就是让用户输入文本的基础组件。
+
+下面的例子创建了一个简单的`TextInput`输入框,其中有空白时的占位文字`Hello`。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, TextInput, View } from 'react-native';
+
+const App = () => {
+ return (
+
+
+
+ );
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => App);
+```
+
+## ListView
+
+在很多移动应用中,列表是个非常核心的元素。[`ListView`](listview.html#content) 组件是一个特制的[`View`](view.html#content),用于显示数据可变的垂直滚动列表。
+
+`ListView`组件有两个必需的属性:`dataSource`和`renderRow`。`dataSource`即为列表内容的实际数据来源。`renderRow`则根据数据渲染实际内容。
+
+下面的例子创建了一个简单的`ListView`,并预设了一些模拟数据。它会首先初始化`datasource`,然后根据其数据来渲染`ListView` 。
+
+> 要使用`ListView`,`rowHasChanged`函数也是必须的。这里我们只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。
+
+```JavaScript
+import React from 'react';
+import { AppRegistry, Text, View, ListView} from 'react-native';
+
+class SimpleList extends React.Component {
+ // 初始化模拟数据
+ constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows(['John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie'])
+ };
+ }
+ render() {
+ return (
+
+ {rowData} }
+ />
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('MyApp', () => SimpleList);
+```
diff --git a/docs/docs/0.42/tutorial.md b/docs/docs/0.42/tutorial.md
new file mode 100644
index 0000000..2250bec
--- /dev/null
+++ b/docs/docs/0.42/tutorial.md
@@ -0,0 +1,43 @@
+React Native看起来很像React,只不过其基础组件是原生组件而非web组件。要理解React Native应用的基本结构,首先需要了解一些基本的React的概念,比如JSX语法、组件、`state`状态以及`props`属性。如果你已经了解了React,那么还需要掌握一些React Native特有的知识,比如原生组件的使用。这篇教程可以供任何基础的读者学习,不管你是否有React方面的经验。
+
+让我们开始吧!
+
+## Hello World
+
+根据历史悠久的“传统”,我们也来写一个“Hello World”:
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text } from 'react-native';
+
+class HelloWorldApp extends Component {
+ render() {
+ return (
+ Hello world!
+ );
+ }
+}
+
+// 注意,这里用引号括起来的'HelloWorldApp'必须和你init创建的项目名一致
+AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
+```
+
+你可以新建一个项目,然后用上面的代码覆盖你的`index.ios.js`或是`index.android.js` 文件,然后运行看看。
+
+## 那这段代码是什么意思呢?
+
+初看这段代码,可能觉得并不像JavaScript——没错,这是“未来”的JavaScript.
+
+首先你需要了解ES2015 (也叫作ES6)——这是一套对JavaScript的语法改进的官方标准。但是这套标准目前还没有在所有的浏览器上完整实现,所以目前而言web开发中还很少使用。React Native内置了对ES2015标准的支持,你可以放心使用而无需担心兼容性问题。上面的示例代码中的`import`、`from`、`class`、`extends`、以及`() =>`箭头函数等新语法都是ES2015中的特性。如果你不熟悉ES2015的话,可以看看[阮一峰老师的书](http://es6.ruanyifeng.com/),还有论坛的这篇[总结](http://bbs.reactnative.cn/topic/15)。
+
+示例中的这一行`Hello world! `恐怕很多人看起来也觉得陌生。这叫做JSX——是一种在JavaScript中嵌入XML结构的语法。很多传统的应用框架会设计自有的模板语法,让你在结构标记中嵌入代码。React反其道而行之,设计的JSX语法却是让你在代码中嵌入结构标记。初看起来,这种写法很像web上的HTML,只不过使用的并不是web上常见的标签如``或是`
`等,这里我们使用的是React Native的组件。上面的示例代码中,使用的是内置的``组件,它专门用来显示文本。
+
+## 组件与AppRegistry
+
+上面的代码定义了一个名为`HelloWorldApp`的新的`组件(Component)`,并且使用了名为`AppRegistry`的内置模块进行了“注册”操作。你在编写React Native应用时,肯定会写出很多新的组件。而一个App的最终界面,其实也就是各式各样的组件的组合。组件本身结构可以非常简单——唯一必须的就是在`render`方法中返回一些用于渲染结构的JSX语句。
+
+`AppRegistry`模块则是用来告知React Native哪一个组件被注册为整个应用的根容器。你无需在此深究,因为一般在整个应用里`AppRegistry.registerComponent`这个方法只会调用一次。上面的代码里已经包含了具体的用法,你只需整个复制到`index.ios.js`或是`index.android.js`文件中即可运行。
+
+## 这个示例弱爆了!
+
+……是的。如果想做些更有意思的东西,请[接着学习Props属性](props.html)。或者可以看看一个[稍微复杂些的“电影列表”例子](sample-application-movies.html)。
diff --git a/docs/docs/0.42/upgrading.md b/docs/docs/0.42/upgrading.md
new file mode 100644
index 0000000..d21a305
--- /dev/null
+++ b/docs/docs/0.42/upgrading.md
@@ -0,0 +1,103 @@
+时刻将React Native更新到最新的版本,可以获得更多API、视图、开发者工具以及其他一些好东西(译注:官方开发任务繁重,人手紧缺,几乎不会对旧版本提供维护支持,所以即便更新可能带来一些兼容上的变更,但建议开发者还是尽一切可能第一时间更新)。由于一个完整的React Native项目是由Android项目、iOS项目和JavaScript项目组成的,且都打包在一个npm包中,所以升级可能会有一些麻烦。我们会尽量简化这一流程。你可以在项目目录下使用`react-native -v`命令查看当前的版本。以下是目前所需的升级步骤:
+
+__译注__:[更新日志点这里查看](http://bbs.reactnative.cn/category/1)
+
+
+## 基于Git的自动合并更新
+
+**重要提示:** 现在你不需要运行npm install去下载新版本的React Native了,按照下面的步骤即可自动进行更新。
+
+### 1. 安装Git
+你需要安装Git,但这并不要求你自己使用Git去管理项目。只是我们的更新过程会使用到Git罢了。你可以在[这里](https://git-scm.com/downloads)下载安装Git,注意要把git的路径添加到`PATH`变量中。
+
+### 2. 安装`react-native-git-upgrade`工具模块
+
+```sh
+$ npm install -g react-native-git-upgrade
+```
+
+`react-native-git-upgrade`提供了豪华的一条龙自动合并更新流程,主要包含两个服务:
+
+* 首先它会利用Git工具计算新旧版本文件间的差异并生成补丁
+* 然后在用户的项目文件上应用补丁
+
+### 3. 运行更新命令
+
+```sh
+$ react-native-git-upgrade
+# 这样会直接把react native升级到最新版本
+
+# 或者是:
+
+$ react-native-git-upgrade X.Y.Z
+# 这样把react native升级到指定的X.Y.Z版本
+```
+
+升级过程会如丝般顺滑。当然在少数情况下,取决于具体的版本和你修改的程度,Git的合并算法也可能遭遇失败产生一些冲突,需要你人工介入。
+
+### 4. 解决冲突
+
+文件中的冲突会以分隔线隔开,并清楚的标记出处,例如下面这样:
+
+```
+13B07F951A680F5B00A75B9A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+<<<<<<< ours
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/HockeySDK.embeddedframework",
+ "$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
+ );
+=======
+ CURRENT_PROJECT_VERSION = 1;
+>>>>>>> theirs
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ "$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
+ );
+```
+
+上面代码中的"ours"表示你自己的代码,而"theirs"表示React Native的官方代码。然后你可以根据实际情况判断,选择某一方晋级,另一方出局(
+
+## 老式升级方案
+
+如果上面的自动升级流程有问题,那么你可以尝试一下下面的老的升级方案。
+
+## 1. 更新`react-native`的node依赖包
+
+请去下面的网址查看`react-native`的npm包的最新版本,或使用`npm info react-native`命令查看。
+
+* [https://www.npmjs.com/package/react-native](https://www.npmjs.com/package/react-native)
+
+打开项目目录下的`package.json`文件,然后在`dependencies`模块下找到`react-native`,将当前版本号改到最新,然后在命令行中运行(译注:如果提示权限错误,就在命令前加上sudo):
+
+```sh
+$ npm install
+```
+
+译注:从0.24版本开始,react-native还需要额外安装react模块,且对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react模块版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm install react@某.某.某版本 --save`。
+
+## 2. 升级项目模板文件
+
+新版本的npm包通常还会包含一些动态生成的文件,这些文件是在运行`react-native init`创建新项目时生成的,比如iOS和Android的项目文件。为了使老项目的项目文件也能得到更新(不重新init),你需要在命令行中运行:
+
+```sh
+$ react-native upgrade
+```
+
+这一命令会检查最新的项目模板,然后进行如下操作:
+
+* 如果是新添加的文件,则直接创建。
+* 如果文件和当前版本的文件相同,则跳过。
+* 如果文件和当前版本的文件不同,则会提示你一些选项:查看两者的不同,选择保留你的版本或是用新的模板覆盖。你可以按下`h`键来查看所有可以使用的命令。
+
+__译注__:如果你有修改原生代码,那么在使用upgrade升级前,`先备份,再覆盖`。覆盖完成后,使用比对工具找出差异,将你之前修改的代码逐步搬运到新文件中。
+
+# 手动升级
+
+有时候React Native的项目结构改动较大,此时还需要手动做一些修改,例如从0.13到0.14版本,或是0.28到0.29版本。所以在升级时请先阅读一下[更新日志](http://bbs.reactnative.cn/category/1/),以确定是否需要做一些额外的手动修改。
diff --git a/docs/docs/0.42/using-a-listview.md b/docs/docs/0.42/using-a-listview.md
new file mode 100644
index 0000000..fe365b4
--- /dev/null
+++ b/docs/docs/0.42/using-a-listview.md
@@ -0,0 +1,43 @@
+`ListView`组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。
+
+`ListView`更适于长列表数据,且元素个数可以增删。和[`ScrollView`](using-a-scrollview.html)不同的是,`ListView`并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
+
+`ListView`组件必须的两个属性是`dataSource`和`renderRow`。`dataSource`是列表的数据源,而`renderRow`则逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。
+
+下面的例子创建了一个简单的`ListView`,并预设了一些模拟数据。首先是初始化`ListView`所需的`dataSource`,其中的每一项(行)数据之后都在`renderRow`中被渲染成了`Text`组件,最后构成整个`ListView`。
+
+> `rowHasChanged`函数也是`ListView`的必需属性。这里我们只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, ListView, Text, View } from 'react-native';
+
+class ListViewBasics extends Component {
+ // 初始化模拟数据
+ constructor(props) {
+ super(props);
+ const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows([
+ 'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
+ ])
+ };
+ }
+ render() {
+ return (
+
+ {rowData} }
+ />
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('ListViewBasics', () => ListViewBasics);
+```
+
+`ListView`的一个常用场景就是从服务器端取回列表数据然后显示,要实现这一过程,你可能还需要学习[React Native的网络相关用法](network.html).
diff --git a/docs/docs/0.42/using-a-scrollview.md b/docs/docs/0.42/using-a-scrollview.md
new file mode 100644
index 0000000..31c0a76
--- /dev/null
+++ b/docs/docs/0.42/using-a-scrollview.md
@@ -0,0 +1,58 @@
+[`ScrollView`](scrollview.html)是一个通用的可滚动的容器,你可以在其中放入多个组件和视图,而且这些组件并不需要是同类型的。ScrollView不仅可以垂直滚动,还能水平滚动(通过`horizontal`属性来设置)。
+
+下面的示例代码创建了一个垂直滚动的`ScrollView`,其中还混杂了图片和文字组件。
+
+注:下面的这个`./img/favicon.png`并不实际存在,请自己准备图片素材,并改为相对应的正确路径,具体请参考[图片文档](images.html)。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import{ AppRegistry, ScrollView, Image, Text, View } from 'react-native'
+
+class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
+ render() {
+ return(
+
+ Scroll me plz
+
+
+
+
+
+ If you like
+
+
+
+
+
+ Scrolling down
+
+
+
+
+
+ What's the best
+
+
+
+
+
+ Framework around?
+
+
+
+
+
+ React Native
+
+ );
+ }
+}
+
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent(
+ 'IScrolledDownAndWhatHappenedNextShockedMe',
+ () => IScrolledDownAndWhatHappenedNextShockedMe);
+```
+
+`ScrollView`适合用来显示数量不多的滚动元素。放置在`ScollView`中的所有组件都会被渲染,哪怕有些组件因为内容太长被挤出了屏幕外。如果你需要显示较长的滚动列表,那么应该使用功能差不多但性能更好的`ListView`组件。下面我们来看看[如何使用ListView](using-a-listview.html)。
diff --git a/docs/docs/0.42/using-navigators.md b/docs/docs/0.42/using-navigators.md
new file mode 100644
index 0000000..361d5c4
--- /dev/null
+++ b/docs/docs/0.42/using-navigators.md
@@ -0,0 +1,170 @@
+移动应用很少只包含一个页面。从你添加第二个页面开始,就得考虑如何管理多个页面间的跳转了。
+
+导航器正是为此而生。它可以管理多个页面间的跳转,也包含了一些常见的过渡动画,包括水平翻页、垂直弹出等等。
+
+## Navigator
+
+React Native目前有几个内置的导航器组件,一般来说我们首推`Navigator`。它使用纯JavaScript实现了一个导航栈,因此可以跨平台工作,同时也便于定制。
+
+
+
+### 场景(Scene)的概念与使用
+
+无论是`View`中包含`Text`,还是一个排满了图片的`ScrollView`,渲染各种组件现在对你来说应该已经得心应手了。这些摆放在一个屏幕中的组件,就共同构成了一个“场景(Scene)”。
+
+场景简单来说其实就是一个全屏的React组件。与之相对的是单个的`Text`、`Image`又或者是你自定义的什么组件,仅仅占据页面中的一部分。你其实已经不知不觉地接触到了场景——在前面的教程中,[“编写HelloWorld”](tutorial.html)、[“使用Flexbox布局”](layout-with-flexbox.html)、[“如何使用ListView”](using-a-listview.html)中的组件都是完整的场景示例。
+
+下面我们来定义一个仅显示一些文本的简单场景。创建一个名为“MyScene.js”的文件,然后粘贴如下代码:
+
+```javascript
+import React, { Component } from 'react';
+import { View, Text } from 'react-native';
+
+export default class MyScene extends Component {
+ static defaultProps = {
+ title: 'MyScene'
+ };
+
+ render() {
+ return (
+
+ Hi! My name is {this.props.title}.
+
+ )
+ }
+}
+```
+
+注意组件声明前面的`export default`关键字。它的意思是**导出(export)**当前组件,以允许其他组件**引入(import)**和使用当前组件,就像下面这样(下面的代码你可以写在index.ios.js或是index.android.js中):
+
+```javascript
+import React, { Component } from 'react';
+import { AppRegistry } from 'react-native';
+
+// ./MyScene表示的是当前目录下的MyScene.js文件,也就是我们刚刚创建的文件
+// 注意即便当前文件和MyScene.js在同一个目录中,"./"两个符号也是不能省略的!
+// 但是.js后缀是可以省略的
+
+import MyScene from './MyScene';
+
+class YoDawgApp extends Component {
+ render() {
+ return (
+
+ )
+ }
+}
+
+AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp);
+```
+
+我们现在已经创建了只有单个场景的App。其中的`MyScene`同时也是一个[可复用的React组件](https://facebook.github.io/react/docs/reusable-components.html)的例子。
+
+### 使用Navigator
+
+场景已经说的够多了,下面我们开始尝试导航跳转。首先要做的是渲染一个`Navigator`组件,然后通过此组件的`renderScene`属性方法来渲染其他场景。
+
+```javascript
+render() {
+ return (
+ {
+ return
+ }}
+ />
+ );
+}
+```
+
+使用导航器经常会碰到“路由(route)”的概念。“路由”抽象自现实生活中的路牌,在RN中专指包含了场景信息的对象。`renderScene`方法是完全根据路由提供的信息来渲染场景的。你可以在路由中任意自定义参数以区分标记不同的场景,我们在这里仅仅使用`title`作为演示。
+
+#### 将场景推入导航栈
+
+要过渡到新的场景,你需要了解`push`和`pop`方法。这两个方法由`navigator`对象提供,而这个对象就是上面的`renderScene`方法中传递的第二个参数。 我们使用这两个方法来把路由对象推入或弹出导航栈。
+
+```javascript
+navigator.push({
+ title: 'Next Scene',
+ index: 1,
+});
+
+navigator.pop();
+```
+
+下面是一个更完整的示例:
+
+```javascript
+import React, { Component } from 'react';
+import { AppRegistry, Navigator, Text, View } from 'react-native';
+
+import MyScene from './MyScene';
+
+class SimpleNavigationApp extends Component {
+ render() {
+ return (
+
+ {
+ const nextIndex = route.index + 1;
+ navigator.push({
+ title: 'Scene ' + nextIndex,
+ index: nextIndex,
+ });
+ }}
+
+ // Function to call to go back to the previous scene
+ onBack={() => {
+ if (route.index > 0) {
+ navigator.pop();
+ }
+ }}
+ />
+ }
+ />
+ )
+ }
+}
+
+AppRegistry.registerComponent('SimpleNavigationApp', () => SimpleNavigationApp);
+```
+
+对应的MyScene.js代码如下:
+```js
+import React, { Component, PropTypes } from 'react';
+import { View, Text, TouchableHighlight } from 'react-native';
+
+export default class MyScene extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ onForward: PropTypes.func.isRequired,
+ onBack: PropTypes.func.isRequired,
+ }
+ render() {
+ return (
+
+ Current Scene: { this.props.title }
+
+ 点我进入下一场景
+
+
+ 点我返回上一场景
+
+
+ )
+ }
+}
+```
+
+在这个例子中,`MyScene`通过`title`属性接受了路由对象中的title值。它还包含了两个可点击的组件`TouchableHighlight`,会在点击时分别调用通过props传入的`onForward`和`onBack`方法,而这两个方法各自调用了`navigator.push()`和`navigator.pop()`,从而实现了场景的变化。
+
+查看[Navigator API文档](navigator.html)来了解更多`Navigator`的信息。同时推荐你阅读[导航器对比](navigation.html)和论坛中的一个[详细教程](http://bbs.reactnative.cn/topic/20/)来加深理解。
+
+## 恭喜!
+
+如果你一字不漏地看完了本教程,恭喜你获得成就:毅力+1!我们暂时没有更多的东西可以教你了,你可以看看一些[社区的参考资源](more-resources.html)。
diff --git a/docs/docs/0.42/vibration.md b/docs/docs/0.42/vibration.md
new file mode 100644
index 0000000..3f710f3
--- /dev/null
+++ b/docs/docs/0.42/vibration.md
@@ -0,0 +1,145 @@
+本模块导出函数`Vibration.vibrate()`用于控制设备震动。震动触发是异步的,也就是说这个函数会立即返回而非等待震动结束。
+
+在不支持震动的设备上(如iOS模拟器),调用此方法没有任何效果。
+
+注意对于android来说需要在`AndroidManifest.xml`中添加` `权限。
+
+### 方法
+
+
+
+
static vibrate(pattern, repeat) #
+
+
+
pattern参数为一个不定长的数组。在Andriod上,数组第一个元素表示开始震动前的等待时间,然后是震动持续时长和等待时长的交替,例如[0, 500, 1000, 500]表示立刻开始震动500ms,然后等待1000ms,再震动500ms;但在iOS上震动时长是固定的,所以从数组第二个元素开始都是表示震动的间隔时长。
+
repeat参数为布尔类型,表示是否持续循环震动。为true时只有调用cancel才会停止。
+
+
+
+
static cancel() #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ Vibration,
+ Platform,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Vibration';
+exports.description = 'Vibration API';
+
+var pattern, patternLiteral, patternDescription;
+if (Platform.OS === 'android') {
+ pattern = [0, 500, 200, 500];
+ patternLiteral = '[0, 500, 200, 500]';
+ patternDescription = `${patternLiteral}
+arg 0: duration to wait before turning the vibrator on.
+arg with odd: vibration length.
+arg with even: duration to wait before next vibration.
+`;
+} else {
+ pattern = [0, 1000, 2000, 3000];
+ patternLiteral = '[0, 1000, 2000, 3000]';
+ patternDescription = `${patternLiteral}
+vibration length on iOS is fixed.
+pattern controls durations BETWEEN each vibration only.
+
+arg 0: duration to wait before turning the vibrator on.
+subsequent args: duration to wait before next vibrattion.
+`;
+}
+
+exports.examples = [
+ {
+ title: 'Pattern Descriptions',
+ render() {
+ return (
+
+ {patternDescription}
+
+ );
+ },
+ },
+ {
+ title: 'Vibration.vibrate()',
+ render() {
+ return (
+ Vibration.vibrate()}>
+
+ Vibrate
+
+
+ );
+ },
+ },
+ {
+ title: `Vibration.vibrate(${patternLiteral})`,
+ render() {
+ return (
+ Vibration.vibrate(pattern)}>
+
+ Vibrate once
+
+
+ );
+ },
+ },
+ {
+ title: `Vibration.vibrate(${patternLiteral}, true)`,
+ render() {
+ return (
+ Vibration.vibrate(pattern, true)}>
+
+ Vibrate until cancel
+
+
+ );
+ },
+ },
+ {
+ title: 'Vibration.cancel()',
+ render() {
+ return (
+ Vibration.cancel()}>
+
+ Cancel
+
+
+ );
+ },
+ },
+];
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/vibrationios.md b/docs/docs/0.42/vibrationios.md
new file mode 100644
index 0000000..4eeb22d
--- /dev/null
+++ b/docs/docs/0.42/vibrationios.md
@@ -0,0 +1,57 @@
+注意:`VibrationIOS`已经过期。请使用[`Vibration`](vibration.html)代替。
+本模块导出函数`VibrationIOS.vibrate()`用于控制设备震动。在iOS设备上,调用这个函数会触发一个一秒钟的震动。震动触发是异步的,也就是说这个函数会立即返回而非等待震动结束。
+
+在不支持震动的设备上(如iOS模拟器),调用此方法没有任何效果。
+
+震动模式设置现在还不支持。
+
+### 方法
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ VibrationIOS
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'VibrationIOS';
+exports.description = 'Vibration API for iOS';
+exports.examples = [{
+ title: 'VibrationIOS.vibrate()',
+ render() {
+ return (
+ VibrationIOS.vibrate()}>
+
+ Vibrate
+
+
+ );
+ },
+}];
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/view.md b/docs/docs/0.42/view.md
new file mode 100644
index 0000000..276e733
--- /dev/null
+++ b/docs/docs/0.42/view.md
@@ -0,0 +1,268 @@
+作为创建UI时最基础的组件,`View`是一个支持Flexbox布局、样式、一些触摸处理、和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图。不论在什么平台上,`View`都会直接对应一个平台的原生视图,无论它是`UIView`、``还是`android.view.View`。下面的例子创建了一个`View`,包含了两个有颜色的方块和一个自定义的组件,并且设置了一个内边距:
+
+```javascript
+
+
+
+
+
+```
+
+`View`的设计初衷是和`StyleSheet`搭配使用,这样可以使代码更清晰并且获得更高的性能。尽管内联样式也同样可以使用。
+
+### 截图
+
+
+### 属性
+
+
+
+
accessibilityLabel string #
+
+
设置当用户与此元素交互时,“读屏器”(对视力障碍人士的辅助功能)阅读的文字。默认情况下,这个文字会通过遍历所有的子元素并累加所有的文本标签来构建。
+
+
+
+
accessible bool #
+
+
当此属性为true时,表示此视图时一个启用了无障碍功能的元素。默认情况下,所有可触摸操作的元素都是无障碍功能元素。
+
+
+
+
onAccessibilityTap function #
+
+
当accessible为true时,如果用户对一个已选中的无障碍元素做了一个双击手势时,系统会调用此函数。(译注:此事件是针对残障人士,并非是一个普通的点击事件。如果要为View添加普通点击事件,请直接使用Touchable系列组件替代View,然后添加onPress函数 )。
+
+
+
+
onLayout function #
+
+
当组件挂载或者布局变化的时候调用,参数为:
+
{nativeEvent: { layout: {x, y, width, height}}}
+
这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。
+
+
+
+
onMagicTap function #
+
+
当accessible为true时,如果用户做了一个双指轻触(Magic tap)手势,系统会调用此函数。
+
+
+
+
onMoveShouldSetResponder function #
+
+
+
onMoveShouldSetResponderCapture function #
+
+
+
onResponderGrant function #
+
+
对于大部分的触摸处理,你只需要用TouchableHighlight或TouchableOpacity包装你的组件。阅读Touchable.js、ScrollResponder.js和ResponderEventPlugin.js来了解更多信息。
+
+
+
+
onResponderMove function #
+
+
+
onResponderReject function #
+
+
+
onResponderRelease function #
+
+
+
onResponderTerminate function #
+
+
+
onResponderTerminationRequest function #
+
+
+
onStartShouldSetResponder function #
+
+
+
onStartShouldSetResponderCapture function #
+
+
+
pointerEvents enum('box-none', 'none', 'box-only', 'auto') #
+
+
用于控制当前视图是否可以作为触控事件的目标。
+
+
+
+
+
removeClippedSubviews bool #
+
+
这是一个特殊的性能相关的属性,由RCTView导出。在制作滑动控件时,如果控件有很多不在屏幕内的子视图,会非常有用。
+
要让此属性生效,首先要求视图有很多超出范围的子视图,并且子视图和容器视图(或它的某个祖先视图)都应该有样式overflow: hidden。
+
+
+
+
style style #
+
+
+
+
+
backfaceVisibility enum('visible', 'hidden')
+
+
+
backgroundColor string
+
+
+
borderColor string
+
+
+
borderTopColor string
+
+
+
borderRightColor string
+
+
+
borderBottomColor string
+
+
+
borderLeftColor string
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius number
+
+
+
borderTopRightRadius number
+
+
+
borderBottomLeftRadius number
+
+
+
borderBottomRightRadius number
+
+
+
borderStyle enum('solid', 'dotted', 'dashed')
+
+
+
borderWidth number
+
+
+
borderTopWidth number
+
+
+
borderRightWidth number
+
+
+
borderBottomWidth number
+
+
+
borderLeftWidth number
+
+
+
opacity number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
+ android
+ elevation number
+
(限Android)使用Android原生的
+elevation API 来设置视图的高度(elevation)。这样可以为视图添加一个投影,并且会影响视图层叠的顺序。此属性仅支持Android5.0及以上版本。
+
+
+
+
+
+
+
+
android accessibilityComponentType AccessibilityComponentType #
+
+
使无障碍服务对这个UI组件与原生组件一致处理。仅对Android平台有效。
+
+
+
+
android accessibilityLiveRegion enum('none', 'polite', 'assertive') #
+
+
+
+
ios accessibilityTraits AccessibilityTraits, [AccessibilityTraits] #
+
+
为读屏器提供更多属性。除非在元素里指定,默认情况下不提供任何属性。
+
+
+
+
android collapsable bool #
+
+
如果一个View只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除。 把此属性设为false可以禁用这个优化,以确保对应视图在原生结构中存在。
+
+
+
+
android importantForAccessibility enum('auto', 'yes', 'no', 'no-hide-descendants') #
+
+
+
+
android needsOffscreenAlphaCompositing bool #
+
+
决定这个视图是否要先离屏渲染再进行半透明度处理,来确保颜色和混合效果正确。默认值(false)会在渲染组件和它的所有子节点的时候直接应用透明通道,而不会先离屏渲染整个组件再将它附加一个透明通道后渲染到屏幕上。有时候当你给视图设置了一个透明度,且其中有较多元素层叠在一起的时候,默认的设置就会导致看起来不太正常(会比正常显得更加不透明)。
+
为了正确的透明表现而进行离屏渲染会带来极大的开销,而且对于非原生开发者来说很难调试。这就是为啥它被默认关闭。如果你需要在一个动画中启用这个属性,考虑与renderToHardwareTextureAndroid组合使用,前提是视图的内容 不会发生变化(即:它不需要每帧重绘一次)。如果开启了renderToHardwareTextureAndroid,则视图只会离屏渲染一次之后保存为一个硬件纹理,然后以正确的透明度绘制到屏幕上,这样就不会导致GPU频繁切换渲染目标(GPU切换渲染目标会带来极大的开销)。
+
+
+
+
android renderToHardwareTextureAndroid bool #
+
+
决定这个视图是否要把它自己(以及所有的子视图)渲染到一个GPU上的硬件纹理中。
+
在Android上,这对于只修改不透明度、旋转、位移、或缩放的动画和交互十分有用:在这些情况下,视图不必每次都重新绘制,显示列表也不需要重新执行。纹理可以被重用于不同的参数。负面作用是这会大量消耗显存,所以当交互/动画结束后应该把此属性设置回false。
+
+
+
+
ios shouldRasterizeIOS bool #
+
+
决定这个视图是否需要在被混合之前绘制到一个位图上。
+
在iOS上,这对于不会修改组件的尺寸和孩子的动画和交互十分有用。举例来说,当我们移动一个静态视图的位置的时候,预渲染允许渲染器重用一个缓存了静态视图的位图,并快速合成。
+
预渲染会产生一个离屏的渲染过程,并且位图会消耗内存。所以使用此属性需要进行充分的测试和评估。
+
+
+
diff --git a/docs/docs/0.42/viewpagerandroid.md b/docs/docs/0.42/viewpagerandroid.md
new file mode 100644
index 0000000..30c607c
--- /dev/null
+++ b/docs/docs/0.42/viewpagerandroid.md
@@ -0,0 +1,358 @@
+一个允许在子视图之间左右翻页的容器。每一个`ViewPagerAndroid`的子容器会被视作一个单独的页,并且会被拉伸填满`ViewPagerAndroid`。
+
+注意所有的子视图都必须是纯View,而不能是自定义的复合容器。你可以给每个子视图设置样式属性譬如`padding`或`backgroundColor`。
+
+例子:
+
+```javascript
+render: function() {
+ return (
+
+
+ First page
+
+
+ Second page
+
+
+ );
+}
+
+...
+
+var styles = {
+ ...
+ pageStyle: {
+ alignItems: 'center',
+ padding: 20,
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
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 #
+
+
页面滑动状态变化时调用此回调函数。页面滑动状态可能为以下三种之一:
+
+
+
+
+
onPageSelected function #
+
+
这个回调会在页面切换完成后(当用户在页面间滑动)调用。
+
回调参数中的event.nativeEvent对象会包含如下的字段:
+
+
+
+
scrollEnabled bool
+ #
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ StyleSheet,
+ Text,
+ TouchableWithoutFeedback,
+ TouchableOpacity,
+ View,
+ ViewPagerAndroid,
+} = ReactNative;
+
+import type { ViewPagerScrollState } from 'ViewPagerAndroid';
+
+var PAGES = 5;
+var BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
+var IMAGE_URIS = [
+ 'http://apod.nasa.gov/apod/image/1410/20141008tleBaldridge001h990.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/volcanicpillar_vetter_960.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/m27_snyder_960.jpg',
+ 'http://apod.nasa.gov/apod/image/1409/PupAmulti_rot0.jpg',
+ 'http://apod.nasa.gov/apod/image/1510/lunareclipse_27Sep_beletskycrop4.jpg',
+];
+
+var LikeCount = React.createClass({
+ getInitialState: function() {
+ return {
+ likes: 7,
+ };
+ },
+ onClick: function() {
+ this.setState({likes: this.state.likes + 1});
+ },
+ render: function() {
+ var thumbsUp = '\uD83D\uDC4D';
+ return (
+
+
+
+ {thumbsUp + ' Like'}
+
+
+
+ {this.state.likes + ' likes'}
+
+
+ );
+ },
+});
+
+var Button = React.createClass({
+ _handlePress: function() {
+ if (this.props.enabled && this.props.onPress) {
+ this.props.onPress();
+ }
+ },
+ render: function() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+});
+
+var ProgressBar = React.createClass({
+ render: function() {
+ var fractionalPosition = (this.props.progress.position + this.props.progress.offset);
+ var progressBarSize = (fractionalPosition / (PAGES - 1)) * this.props.size;
+ return (
+
+
+
+ );
+ }
+});
+
+var ViewPagerAndroidExample = React.createClass({
+ statics: {
+ title: '
',
+ description: 'Container that allows to flip left and right between child views.'
+ },
+ getInitialState: function() {
+ return {
+ page: 0,
+ animationsAreEnabled: true,
+ scrollEnabled: true,
+ progress: {
+ position: 0,
+ offset: 0,
+ },
+ };
+ },
+
+ onPageSelected: function(e) {
+ this.setState({page: e.nativeEvent.position});
+ },
+
+ onPageScroll: function(e) {
+ this.setState({progress: e.nativeEvent});
+ },
+
+ onPageScrollStateChanged: function(state : ViewPagerScrollState) {
+ this.setState({scrollState: state});
+ },
+
+ move: function(delta) {
+ var page = this.state.page + delta;
+ this.go(page);
+ },
+
+ go: function(page) {
+ if (this.state.animationsAreEnabled) {
+ this.viewPager.setPage(page);
+ } else {
+ this.viewPager.setPageWithoutAnimation(page);
+ }
+
+ this.setState({page});
+ },
+
+ render: function() {
+ var pages = [];
+ for (var i = 0; i < PAGES; i++) {
+ var pageStyle = {
+ backgroundColor: BGCOLOR[i % BGCOLOR.length],
+ alignItems: 'center',
+ padding: 20,
+ };
+ pages.push(
+
+
+
+
+ );
+ }
+ var { page, animationsAreEnabled } = this.state;
+ return (
+
+ { this.viewPager = viewPager; }}>
+ {pages}
+
+
+ this.setState({scrollEnabled: !this.state.scrollEnabled})}
+ />
+
+
+ { animationsAreEnabled ?
+ this.setState({animationsAreEnabled: false})}
+ /> :
+ this.setState({animationsAreEnabled: true})}
+ /> }
+ ScrollState[ {this.state.scrollState} ]
+
+
+ 0} onPress={() => this.go(0)}/>
+ 0} onPress={() => this.move(-1)}/>
+ Page {page + 1} / {PAGES}
+
+ this.move(1)}/>
+ this.go(PAGES - 1)}/>
+
+
+ );
+ },
+});
+
+var styles = StyleSheet.create({
+ buttons: {
+ flexDirection: 'row',
+ height: 30,
+ backgroundColor: 'black',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ button: {
+ flex: 1,
+ width: 0,
+ margin: 5,
+ borderColor: 'gray',
+ borderWidth: 1,
+ backgroundColor: 'gray',
+ },
+ buttonDisabled: {
+ backgroundColor: 'black',
+ opacity: 0.5,
+ },
+ buttonText: {
+ color: 'white',
+ },
+ scrollStateText: {
+ color: '#99d1b7',
+ },
+ container: {
+ flex: 1,
+ backgroundColor: 'white',
+ },
+ image: {
+ width: 300,
+ height: 200,
+ padding: 20,
+ },
+ likeButton: {
+ backgroundColor: 'rgba(0, 0, 0, 0.1)',
+ borderColor: '#333333',
+ borderWidth: 1,
+ borderRadius: 5,
+ flex: 1,
+ margin: 8,
+ padding: 8,
+ },
+ likeContainer: {
+ flexDirection: 'row',
+ },
+ likesText: {
+ flex: 1,
+ fontSize: 18,
+ alignSelf: 'center',
+ },
+ progressBarContainer: {
+ height: 10,
+ margin: 10,
+ borderColor: '#eeeeee',
+ borderWidth: 2,
+ },
+ progressBar: {
+ alignSelf: 'flex-start',
+ flex: 1,
+ backgroundColor: '#eeeeee',
+ },
+ viewPager: {
+ flex: 1,
+ },
+});
+
+module.exports = ViewPagerAndroidExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.42/webview.md b/docs/docs/0.42/webview.md
new file mode 100644
index 0000000..0ede453
--- /dev/null
+++ b/docs/docs/0.42/webview.md
@@ -0,0 +1,579 @@
+创建一个原生的WebView,可以用于访问一个网页。
+
+### 截图
+
+
+### 属性
+
+
+
+
ios allowsInlineMediaPlayback bool #
+
指定HTML5视频是在网页当前位置播放还是使用原生的全屏播放器播放。
+ 默认值为false。
+
注意 : 要让视频在网页中播放,不光要将这个属性设为true,HTML中的视频元素本身也需要包含webkit-playsinline属性。
+
+
+
automaticallyAdjustContentInsets bool #
+
+
+
+
contentInset {top: number, left: number, bottom: number, right: number} #
+
+
+
ios dataDetectorTypes enum('phoneNumber', 'link', 'address', 'calendarEvent', 'none', 'all'), [object Object] #
+
探测网页中某些特殊数据类型,自动生成可点击的链接,默认情况下仅允许探测电话号码。
你可以指定探测下述类型中的一种,或者使用数组来指定多个类型。
+
dataDetectorTypes的可选值:
+
+ 'phoneNumber'
+ 'link'
+ 'address'
+ 'calendarEvent'
+ 'none'
+ 'all'
+
+
+
+
ios decelerationRate
+ ScrollView.propTypes.decelerationRate #
+
指定一个浮点数,用于设置在用户停止触摸之后,此视图应以多快的速度停止滚动。也可以指定预设的字符串值,如"normal"和"fast",分别对应UIScrollViewDecelerationRateNormal 和UIScrollViewDecelerationRateFast。
+
+ Normal(正常速度): 0.998
+ Fast(较快速度): 0.9 (iOS WebView的默认值)
+
+
+
+
android domStorageEnabled bool #
+
+
仅限Android平台。指定是否开启DOM本地存储。
+
+
+
+
injectedJavaScript string #
+
+
+
+
mediaPlaybackRequiresUserAction bool #
+
+
设置页面中的HTML5音视频是否需要在用户点击后再开始播放。默认值为true.
+
+
+
+
+
+
onLoadStart function
+ #
+
+
+
onMessage function
+ #
+
+
在webview内部的网页中调用window.postMessage方法时可以触发此属性对应的函数,从而实现网页和RN之间的数据交换。
+ 设置此属性的同时会在webview中注入一个postMessage的全局函数并覆盖可能已经存在的同名实现。
+
网页端的window.postMessage只发送一个参数data,此参数封装在RN端的event对象中,即event.nativeEvent.data。data
+ 只能是一个字符串。
+
+
+
+
android javaScriptEnabled bool #
+
+
仅限Android平台。iOS平台JavaScript是默认开启的。
+
+
+
+
onNavigationStateChange function #
+
+
+
ios onShouldStartLoadWithRequest function #
+
+
允许为webview发起的请求运行一个自定义的处理函数。返回true或false表示是否要继续执行响应的请求。
+
+
+
+
renderError function #
+
+
+
+
renderLoading function #
+
+
+
source {uri: string, method: string, headers: object, body: string}, {html: string, baseUrl: string}, number
+ #
+
在WebView中载入一段静态的html代码或是一个url(还可以附带一些header选项)。
+
+
+
scalesPageToFit bool #
+
+
设置是否要把网页缩放到适应视图的大小,以及是否允许用户改变缩放比例。
+
+
+
+
ios scrollEnabled bool #
+
+
+
startInLoadingState bool #
+
+
强制WebView在第一次加载时先显示loading视图。默认为true。
+
+
+
+
+
+
+
+ android userAgent
+ string #
+
+
为WebView设置user-agent字符串标识。这一字符串也可以在原生端用WebViewConfig来设置,但js端的设置会覆盖原生端的设置。
+
+
+
+### 例子
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableWithoutFeedback,
+ TouchableOpacity,
+ View,
+ WebView
+} = ReactNative;
+
+var HEADER = '#3b5998';
+var BGWASH = 'rgba(255,255,255,0.8)';
+var DISABLED_WASH = 'rgba(255,255,255,0.25)';
+
+var TEXT_INPUT_REF = 'urlInput';
+var WEBVIEW_REF = 'webview';
+var DEFAULT_URL = 'https://m.facebook.com';
+
+class WebViewExample extends React.Component {
+ state = {
+ url: DEFAULT_URL,
+ status: 'No Page Loaded',
+ backButtonEnabled: false,
+ forwardButtonEnabled: false,
+ loading: true,
+ scalesPageToFit: true,
+ };
+
+ inputText = '';
+
+ handleTextInputChange = (event) => {
+ var url = event.nativeEvent.text;
+ if (!/^[a-zA-Z-_]+:/.test(url)) {
+ url = 'http://' + url;
+ }
+ this.inputText = url;
+ };
+
+ render() {
+ this.inputText = this.state.url;
+
+ return (
+
+
+
+
+ {'<'}
+
+
+
+
+ {'>'}
+
+
+
+
+
+
+ Go!
+
+
+
+
+
+
+ {this.state.status}
+
+
+ );
+ }
+
+ goBack = () => {
+ this.refs[WEBVIEW_REF].goBack();
+ };
+
+ goForward = () => {
+ this.refs[WEBVIEW_REF].goForward();
+ };
+
+ reload = () => {
+ this.refs[WEBVIEW_REF].reload();
+ };
+
+ onShouldStartLoadWithRequest = (event) => {
+ // Implement any custom loading logic here, don't forget to return!
+ return true;
+ };
+
+ onNavigationStateChange = (navState) => {
+ this.setState({
+ backButtonEnabled: navState.canGoBack,
+ forwardButtonEnabled: navState.canGoForward,
+ url: navState.url,
+ status: navState.title,
+ loading: navState.loading,
+ scalesPageToFit: true
+ });
+ };
+
+ onSubmitEditing = (event) => {
+ this.pressGoButton();
+ };
+
+ pressGoButton = () => {
+ var url = this.inputText.toLowerCase();
+ if (url === this.state.url) {
+ this.reload();
+ } else {
+ this.setState({
+ url: url,
+ });
+ }
+ // dismiss keyboard
+ this.refs[TEXT_INPUT_REF].blur();
+ };
+}
+
+class Button extends React.Component {
+ _handlePress = () => {
+ if (this.props.enabled !== false && this.props.onPress) {
+ this.props.onPress();
+ }
+ };
+
+ render() {
+ return (
+
+
+ {this.props.text}
+
+
+ );
+ }
+}
+
+class ScaledWebView extends React.Component {
+ state = {
+ scalingEnabled: true,
+ };
+
+ render() {
+ return (
+
+
+
+ { this.state.scalingEnabled ?
+ this.setState({scalingEnabled: false})}
+ /> :
+ this.setState({scalingEnabled: true})}
+ /> }
+
+
+ );
+ }
+}
+
+class MessagingTest extends React.Component {
+ webview = null
+
+ state = {
+ messagesReceivedFromWebView: 0,
+ message: '',
+ }
+
+ onMessage = e => this.setState({
+ messagesReceivedFromWebView: this.state.messagesReceivedFromWebView + 1,
+ message: e.nativeEvent.data,
+ })
+
+ postMessage = () => {
+ if (this.webview) {
+ this.webview.postMessage('"Hello" from React Native!');
+ }
+ }
+
+ render(): ReactElement {
+ const {messagesReceivedFromWebView, message} = this.state;
+
+ return (
+
+
+ Messages received from web view: {messagesReceivedFromWebView}
+ {message || '(No message)'}
+
+
+
+
+
+ { this.webview = webview; }}
+ style={{
+ backgroundColor: BGWASH,
+ height: 100,
+ }}
+ source={require('./messagingtest.html')}
+ onMessage={this.onMessage}
+ />
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: HEADER,
+ },
+ addressBarRow: {
+ flexDirection: 'row',
+ padding: 8,
+ },
+ webView: {
+ backgroundColor: BGWASH,
+ height: 350,
+ },
+ addressBarTextInput: {
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ borderWidth: 1,
+ height: 24,
+ paddingLeft: 10,
+ paddingTop: 3,
+ paddingBottom: 3,
+ flex: 1,
+ fontSize: 14,
+ },
+ navButton: {
+ width: 20,
+ padding: 3,
+ marginRight: 3,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ },
+ disabledButton: {
+ width: 20,
+ padding: 3,
+ marginRight: 3,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: DISABLED_WASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ },
+ goButton: {
+ height: 24,
+ padding: 3,
+ marginLeft: 8,
+ alignItems: 'center',
+ backgroundColor: BGWASH,
+ borderColor: 'transparent',
+ borderRadius: 3,
+ alignSelf: 'stretch',
+ },
+ statusBar: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingLeft: 5,
+ height: 22,
+ },
+ statusBarText: {
+ color: 'white',
+ fontSize: 13,
+ },
+ spinner: {
+ width: 20,
+ marginRight: 6,
+ },
+ buttons: {
+ flexDirection: 'row',
+ height: 30,
+ backgroundColor: 'black',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ button: {
+ flex: 0.5,
+ width: 0,
+ margin: 5,
+ borderColor: 'gray',
+ borderWidth: 1,
+ backgroundColor: 'gray',
+ },
+});
+
+const HTML = `
+\n
+
+
+ Hello Static World
+
+
+
+
+
+ Hello Static World
+
+
+`;
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Base component to display web content';
+exports.examples = [
+ {
+ title: 'Simple Browser',
+ render(): React.Element { return ; }
+ },
+ {
+ title: 'Scale Page to Fit',
+ render(): React.Element { return ; }
+ },
+ {
+ title: 'Bundled HTML',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Static HTML',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'POST Test',
+ render(): React.Element {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Mesaging Test',
+ render(): ReactElement { return ; }
+ }
+];
+```
diff --git a/docs/docs/0.43/accessibility.md b/docs/docs/0.43/accessibility.md
new file mode 100644
index 0000000..2ed438c
--- /dev/null
+++ b/docs/docs/0.43/accessibility.md
@@ -0,0 +1,161 @@
+## iOS与Android原生App的无障碍功能(accessibility)
+__译注__:accessibility一词常见多种译法:可访问性、无障碍性、辅助功能等等,其中文意思都不太能准确表达其功能的本质——即为残障人士提供便利。本文主要采用“无障碍功能”和“辅助技术/服务”的说法。如果你或你的公司暂时没有资源和精力去服务这些用户,那么你可以跳过本文。但是,`译者个人希望借本文档,呼吁有能力有资源的商业公司/组织/个人,重视残障人士使用智能手机的权利`。
+
+iOS和Android都提供了便于残障人士无障碍使用App的API。此外,两个平台都提供了整套的辅助技术,比如都有针对视力受损人士的读屏软件(iOS的VoiceOver和Android的TalkBack)。同样地,在React Native中我们也封装了对应的API,使开发者能够在App中集成无障碍功能。注意:iOS与Android在具体方法上会有所区别,因此React Native的实现也会因平台而异。
+
+## 使App能够无障碍使用
+
+### 无障碍功能属性
+
+#### accessible (iOS, Android)
+
+设置为`true`时表示当前视图是一个“无障碍元素”(accessibility element)。无障碍元素会将其所有子组件视为一整个可以选中的组件。默认情况下,所有可点击的组件(Touchable系列组件)都是无障碍元素。
+
+在Android上,React Native视图的‘accessible={true}’属性会被转译为原生视图对应的‘focusable={true}’属性。
+
+```javascript
+
+ text one
+ text two
+
+```
+
+在上面这个例子中,当父视图开启无障碍属性后,我们就无法单独选中'text one'和'text two',而只能选中整个父视图。
+
+
+
+#### 无障碍标签accessibilityLabel (iOS, Android)
+
+当一个视图启用无障碍属性后,最好再加上一个accessibilityLabel(无障碍标签),这样可以让使用VoiceOver的人们清楚地知道自己选中了什么。VoiceOver会读出选中元素的无障碍标签。
+
+设定`accessibilityLabel`属性并赋予一个字符串内容即可在视图中启用无障碍标签:
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+在上面这段示例代码中,如果不在TouchableOpacity上设置无障碍标签,那么其默认值就会是"Press me!"(即Text子组件的文本值)。此时无障碍标签是通过自动取所有Text子节点的值,然后用空格连起来生成。
+
+#### 无障碍元素特性accessibilityTraits (iOS)
+
+无障碍元素特性可以使VoiceOver的用户知道自己选中的是什么类型的元素。是文本标签?是按钮?还是头部?`accessibilityTraits`回答了这一问题。
+
+设定`accessibilityTraits`属性并赋予以下一个或多个(以数组的形式)特性字符串即可启用无障碍元素特性:
+
+* **none** 无特性元素。
+* **button** 具有按钮特性。
+* **link** 具有链接特性。
+* **header** 作为内容区域的头部(比如导航栏的标题)。
+* **search** 用作搜索框的文本框。
+* **image** 具有图片特性。可以和按钮或链接等连用。
+* **selected** 元素被选中时使用。比如表格中被选中的一行或是[segmented control](segmentedcontrolios.html)中被选中的一个按钮。
+* **plays** 在元素被点击后播放音效时使用。
+* **key** 元素作为虚拟键盘的一个键使用。
+* **text** 具有不可修改的文本的特性。
+* **summary** 在App冷启动(指完全退出后台后再进入)时提供当前的简要总结信息的元素。比如当天气应用冷启动时,显示当前天气情况的元素就会被标记为**summary**。
+* **disabled** 在元素被禁用,不接受用户输入时使用。
+* **frequentUpdates** 有些元素会频繁更新其标签或值,但我们又不希望太频繁地接受到通知,那么就使用这一特性标记。这一特性标记会使无障碍功能的客户端隔一段时间后再去检查变化(避免频繁打扰用户)。秒表就是个典型的例子。
+* **startsMedia** 在元素启动一个多媒体会话时使用(比如播放电影或是录音),此时不应该被VoiceOver这样的辅助技术打断。
+* **adjustable** 元素具有可调整的特性(比如一个滑块)。
+* **allowsDirectInteraction** 在元素可以接受VoiceOver用户的直接触摸交互时使用(比如展示钢琴键盘的视图)。
+* **pageTurn** 用于通知VoiceOver当前页面已经阅读完毕,可以滚动到下一个页面了。
+
+#### 无障碍元素的点击事件onAccessibilityTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户双击某个已经选中的无障碍元素时调用。
+
+#### MagicTap双指双击事件onMagicTap (iOS)
+
+使用这一属性来绑定一个自定义的事件处理函数,这一函数会在当用户执行"magic tap"操作(即使用两个指头来双击)时调用。magic tap的事件处理函数应该做与当前组件相关性最高的操作,比如在电话应用中,magic tap的操作就应该接通电话,或是挂断已经接通的电话。如果当前选中的元素并没有`onMagicTap`函数,则系统会自动遍历视图层,直到找到一个可以响应此操作的。
+
+#### 无障碍组件类型accessibilityComponentType (Android)
+
+在某些情况下,我们也希望告知用户他选中的组件的类型(比如是个按钮)。如果我们使用的是原生按钮,这一行为会自动进行。但既然我们主要是使用javascript,则还需要为Android的TalkBack技术提供更多信息。要实现这一点,就必须为所有UI组件指定`accessibilityComponentType`属性。比如可以指定`button`,`radiobutton_checked`以及`radiobutton_unchecked`等值。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+上面这个例子里,TouchableWithoutFeedback在TalkBack中被声明为一个原生按钮。
+
+#### 无障碍的动态区域accessibilityLiveRegion (Android)
+
+组件发生动态变化时,我们希望TalkBack能够提醒用户。这一行为可以通过设置`accessibilityLiveRegion`属性来实现。具体值可以设置为`none`,`polite`以及`assertive`:
+
+* **none** 辅助服务不应该提醒用户当前视图的变化。
+* **polite** 辅助服务应该提醒用户当前视图的变化。
+* **assertive** 辅助服务应该立即打断当前的语音会话,提醒用户当前视图的变化。
+
+```javascript
+
+
+ Click me
+
+
+
+ Clicked {this.state.count} times
+
+```
+
+上面这个例子中,_addOne方法会改变state.count这个变量。那么只要用户点击了 TouchableWithoutFeedback,TalkBack就会读出Text组件中的值,因为它设置了`accessibilityLiveRegion=”polite”`属性。
+
+#### 无障碍功能优先级importantForAccessibility (Android)
+
+如果有两个UI组件同时层叠覆盖在父视图之上,那么默认的无障碍功能的焦点位置就可能难以预料。`importantForAccessibility`属性解决了这一问题,它可以控制某个视图是否触发无障碍功能事件,以及是否将其报告给辅助服务。具体值可以设置为`auto`,`yes`,`no`和`no-hide-descendants`(最后一个值会强制辅助服务忽略当前组件及其所有子组件)。
+
+```javascript
+
+
+ First layout
+
+
+ Second layout
+
+
+```
+
+上面这个例子里,第二个View的组件对于TalkBack和其他一些辅助服务来说是完全不可见的。这样我们就可以轻易地把两个视图覆盖到同一个父容器上,而不用担心影响TalkBack服务。
+
+
+
+### 发送无障碍功能的相关事件 (Android)
+
+有时候需要在UI组件上主动触发一个无障碍功能的事件(比如当某个自定义的视图出现在屏幕上或是某个自定义的单选框被选中)。为此Native UIManager模块提供了一个`sendAccessibilityEvent`方法。它接受两个参数:view标签和事件类型。
+
+```javascript
+_onPress: function() {
+ this.state.radioButton = this.state.radioButton === “radiobutton_checked” ?
+ “radiobutton_unchecked” : “radiobutton_checked”;
+ if (this.state.radioButton === “radiobutton_checked”) {
+ RCTUIManager.sendAccessibilityEvent(
+ React.findNodeHandle(this),
+ RCTUIManager.AccessibilityEventTypes.typeViewClicked);
+ }
+}
+
+
+```
+
+在上面这个例子里我们创建了一个自定义的单选框(CustomRadioButton),并且使其具有了和原生单选框一样的无障碍功能。具体来说,也就是TalkBack可以正确地通知用户当前选项的变更了。
+
+
+## 测试VoiceOver (iOS)
+
+要开启VoiceOver功能,先打开iOS设备的设置选项。点击“通用”,然后是“辅助选项”,你会看到很多为残障人群使用手机减少障碍的工具,比如更大的字体、更高的对比度以及VoiceOver。
+
+在“视觉”菜单下点击VoiceOver,将开关置为打开状态即可启用。
+
+在辅助选项的最底部,有一个“辅助选项快捷键”,开启之后可以通过点击三次Home按钮来快速关闭或打开VoiceOver工具。
diff --git a/docs/docs/0.43/actionsheetios.md b/docs/docs/0.43/actionsheetios.md
new file mode 100644
index 0000000..a9764ea
--- /dev/null
+++ b/docs/docs/0.43/actionsheetios.md
@@ -0,0 +1,249 @@
+### 截图
+
+
+
+
+### 方法
+
+
+
static showActionSheetWithOptions(options: Object, callback: Function) #
+
+
在iOS设备上显示一个ActionSheet弹出框,其中options参数为一个对象,其属性必须包含以下一项或多项:
+
+ options(字符串数组) - 一组按钮的标题(必选)
+ cancelButtonIndex(整型) - 选项中取消按钮所在的位置(索引)
+ destructiveButtonIndex(整型) - 选项中删除按钮所在的位置(索引)
+ title(字符串) - 弹出框顶部的标题
+ message(字符串) - 弹出框顶部标题下方的信息
+
+
+
+
static showShareActionSheetWithOptions(options: Object, failureCallback: Function, successCallback: Function) #
+
+
+
在iOS设备上显示一个分享弹出框,其中options参数为一个对象,其属性包含以下几项(必须至少有message或url):
+
+ message(字符串) - 要分享的信息
+ url(字符串) - 要分享的URL地址
+ subject(字符串) - 要分享的信息主题
+ excludedActivityTypes(数组) - 指定在actionsheet中不显示的活动
+
+
注:如果url指向本地文件,或者是一个base64编码的url,则会直接读取并分享相应的文件。你可以用这样的方式来分享图片、视频以及PDF文件等。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActionSheetIOS,
+ StyleSheet,
+ Text,
+ UIManager,
+ View,
+} = ReactNative;
+
+var BUTTONS = [
+ 'Option 0',
+ 'Option 1',
+ 'Option 2',
+ 'Delete',
+ 'Cancel',
+];
+var DESTRUCTIVE_INDEX = 3;
+var CANCEL_INDEX = 4;
+
+var ActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ActionSheetTintExample = React.createClass({
+ getInitialState() {
+ return {
+ clicked: 'none',
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the ActionSheet
+
+
+ Clicked button: {this.state.clicked}
+
+
+ );
+ },
+
+ showActionSheet() {
+ ActionSheetIOS.showActionSheetWithOptions({
+ options: BUTTONS,
+ cancelButtonIndex: CANCEL_INDEX,
+ destructiveButtonIndex: DESTRUCTIVE_INDEX,
+ tintColor: 'green',
+ },
+ (buttonIndex) => {
+ this.setState({ clicked: BUTTONS[buttonIndex] });
+ });
+ }
+});
+
+var ShareActionSheetExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: this.props.url,
+ message: 'message to go with the shared url',
+ subject: 'a subject to go in the email heading',
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }
+});
+
+var ShareScreenshotExample = React.createClass({
+ getInitialState() {
+ return {
+ text: ''
+ };
+ },
+
+ render() {
+ return (
+
+
+ Click to show the Share ActionSheet
+
+
+ {this.state.text}
+
+
+ );
+ },
+
+ showShareActionSheet() {
+ // Take the snapshot (returns a temp file uri)
+ UIManager.takeSnapshot('window').then((uri) => {
+ // Share image data
+ ActionSheetIOS.showShareActionSheetWithOptions({
+ url: uri,
+ excludedActivityTypes: [
+ 'com.apple.UIKit.activity.PostToTwitter'
+ ]
+ },
+ (error) => alert(error),
+ (success, method) => {
+ var text;
+ if (success) {
+ text = `Shared via ${method}`;
+ } else {
+ text = 'You didn\'t share';
+ }
+ this.setState({text});
+ });
+ }).catch((error) => alert(error));
+ }
+});
+
+var style = StyleSheet.create({
+ button: {
+ marginBottom: 10,
+ fontWeight: '500',
+ }
+});
+
+exports.title = 'ActionSheetIOS';
+exports.description = 'Interface to show iOS\' action sheets';
+exports.examples = [
+ {
+ title: 'Show Action Sheet',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Action Sheet with tinted buttons',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Show Share Action Sheet',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Local Image',
+ render(): ReactElement {
+ return ;
+ }
+ },
+ {
+ title: 'Share Screenshot',
+ render(): ReactElement {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.43/activityindicator.md b/docs/docs/0.43/activityindicator.md
new file mode 100644
index 0000000..0092a18
--- /dev/null
+++ b/docs/docs/0.43/activityindicator.md
@@ -0,0 +1,196 @@
+显示一个圆形的loading提示符号。
+
+### 属性
+
+
+
+
+
animating bool #
+
+
是否要显示指示器,默认为true,表示显示。
+
+
+
+
+
ios hidesWhenStopped bool #
+
+
在没有动画的时候,是否要隐藏指示器(默认为true)。
+
+
+
+
size enum('small', 'large') #
+
+
指示器的大小。small的高度为20,large为36。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ ActivityIndicator,
+ StyleSheet,
+ View,
+} = ReactNative;
+const TimerMixin = require('react-timer-mixin');
+
+const ToggleAnimatingActivityIndicator = React.createClass({
+ mixins: [TimerMixin],
+
+ getInitialState() {
+ return {
+ animating: true,
+ };
+ },
+
+ setToggleTimeout() {
+ this.setTimeout(() => {
+ this.setState({animating: !this.state.animating});
+ this.setToggleTimeout();
+ }, 2000);
+ },
+
+ componentDidMount() {
+ this.setToggleTimeout();
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Animated loading indicators.';
+
+exports.examples = [
+ {
+ title: 'Default (small, white)',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Gray',
+ render() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Large',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Large, custom colors',
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ },
+ {
+ title: 'Start/stop',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom size',
+ render() {
+ return (
+
+ );
+ }
+ },
+];
+
+const styles = StyleSheet.create({
+ centering: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 8,
+ },
+ gray: {
+ backgroundColor: '#cccccc',
+ },
+ horizontal: {
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ padding: 8,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/adsupportios.md b/docs/docs/0.43/adsupportios.md
new file mode 100644
index 0000000..29cbc09
--- /dev/null
+++ b/docs/docs/0.43/adsupportios.md
@@ -0,0 +1,111 @@
+
+### 方法
+
+
+
+
+
+ static getAdvertisingId(onSuccess, onFailure)
+ #
+
+
+
+
+
+ static getAdvertisingTrackingEnabled(onSuccess, onFailure)
+ #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ AdSupportIOS,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Advertising ID';
+exports.description = 'Example of using the ad support API.';
+
+exports.examples = [
+ {
+ title: 'Ad Support IOS',
+ render: function(): ReactElement {
+ return ;
+ },
+ }
+];
+
+class AdSupportIOSExample extends React.Component {
+ state = {
+ deviceID: 'No IDFA yet',
+ hasAdvertiserTracking: 'unset',
+ };
+
+ componentDidMount() {
+ AdSupportIOS.getAdvertisingId(
+ this._onDeviceIDSuccess,
+ this._onDeviceIDFailure
+ );
+
+ AdSupportIOS.getAdvertisingTrackingEnabled(
+ this._onHasTrackingSuccess,
+ this._onHasTrackingFailure
+ );
+ }
+
+ _onHasTrackingSuccess = (hasTracking) => {
+ this.setState({
+ 'hasAdvertiserTracking': hasTracking,
+ });
+ };
+
+ _onHasTrackingFailure = (e) => {
+ this.setState({
+ 'hasAdvertiserTracking': 'Error!',
+ });
+ };
+
+ _onDeviceIDSuccess = (deviceID) => {
+ this.setState({
+ 'deviceID': deviceID,
+ });
+ };
+
+ _onDeviceIDFailure = (e) => {
+ this.setState({
+ 'deviceID': 'Error!',
+ });
+ };
+
+ render() {
+ return (
+
+
+ Advertising ID:
+ {JSON.stringify(this.state.deviceID)}
+
+
+ Has Advertiser Tracking:
+ {JSON.stringify(this.state.hasAdvertiserTracking)}
+
+
+ );
+ }
+}
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: '500',
+ },
+});
+```
diff --git a/docs/docs/0.43/alert.md b/docs/docs/0.43/alert.md
new file mode 100644
index 0000000..8f6d15b
--- /dev/null
+++ b/docs/docs/0.43/alert.md
@@ -0,0 +1,166 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+本接口可以在iOS和Android上显示一个静态的提示框。如果要在显示提示框的同时接受用户输入一些信息,那你可能需要[`AlertIOS`](alertios.html)。
+
+### iOS
+在iOS上你可以指定任意数量的按钮。每个按钮还都可以指定自己的样式,此外还可以指定提示的类别。参阅[AlertIOS](alertios.html)来了解更多细节。
+
+### Android
+在Android上最多能指定三个按钮,这三个按钮分别具有“中间态”、“消极态”和“积极态”的概念:
+
+如果你只指定一个按钮,则它具有“积极态”的属性(比如“确定”);两个按钮,则分别是“消极态”和“积极态”(比如“取消”和“确定”);三个按钮则意味着“中间态”、“消极态”和“积极态”(比如“稍候再说”,“取消”,“确定”)。
+
+在Android上默认情况下点击提示框的外面会自动取消提示框。你可以提供一个额外参数来处理这一事件:`{ onDismiss: () => {} }`。
+
+还有另外一个参数也可以用来阻止提示框被自动取消,即`{ cancelable: false }`。
+
+一个简单的例子:
+
+```javascript
+// iOS和Android上都可用
+Alert.alert(
+ 'Alert Title',
+ 'My Alert Msg',
+ [
+ {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
+ {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
+ {text: 'OK', onPress: () => console.log('OK Pressed')},
+ ],
+ { cancelable: false }
+)
+```
+
+### 方法
+
+
+
static alert(title: string, message?: string, button?: Buttons, type?: AlertType) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Alert,
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+
+// corporate ipsum > lorem ipsum
+var alertMessage = 'Credibly reintermediate next-generation potentialities after goal-oriented ' +
+ 'catalysts for change. Dynamically revolutionize.';
+
+/**
+ * Simple alert examples.
+ */
+var SimpleAlertExampleBlock = React.createClass({
+
+ render: function() {
+ return (
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ )}>
+
+ Alert with message and default button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with one button
+
+
+ Alert.alert(
+ 'Alert Title',
+ alertMessage,
+ [
+ {text: 'Cancel', onPress: () => console.log('Cancel Pressed!')},
+ {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ ]
+ )}>
+
+ Alert with two buttons
+
+
+ Alert.alert(
+ 'Alert Title',
+ null,
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ {text: 'Baz', onPress: () => console.log('Baz Pressed!')},
+ ]
+ )}>
+
+ Alert with three buttons
+
+
+ Alert.alert(
+ 'Foo Title',
+ alertMessage,
+ '..............'.split('').map((dot, index) => ({
+ text: 'Button ' + index,
+ onPress: () => console.log('Pressed ' + index)
+ }))
+ )}>
+
+ Alert with too many buttons
+
+
+
+ );
+ },
+});
+
+var AlertExample = React.createClass({
+ statics: {
+ title: 'Alert',
+ description: 'Alerts display a concise and informative message ' +
+ 'and prompt the user to make a decision.',
+ },
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+
+module.exports = {
+ AlertExample,
+ SimpleAlertExampleBlock,
+};
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/alertios.md b/docs/docs/0.43/alertios.md
new file mode 100644
index 0000000..a078b66
--- /dev/null
+++ b/docs/docs/0.43/alertios.md
@@ -0,0 +1,204 @@
+启动一个提示对话框,包含对应的标题和信息。
+
+你还可以指定一系列的按钮,点击对应的按钮会调用对应的onPress回调并且关闭提示框。默认情况下,对话框会仅有一个'确定'按钮。
+
+这个API主要用于需要iOS特有功能的场景,比如提示用户输入一些信息等。其他情况下,尤其是仅仅显示一个静态的提示框时,应该使用跨平台的[`Alert`](alert.html)接口。
+
+```javascript
+AlertIOS.alert(
+ 'Foo Title',
+ 'My Alert Msg',
+ [
+ {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+ {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ ]
+)
+```
+### 截图
+
+
+
+
+### 方法
+
+
+
static alert(title: string, message?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, type?: AlertType) #
+
static prompt(title: string, value?: string, buttons?: Array<{
+ text?: string;
+ onPress?: ?Function;
+ style?: AlertButtonStyle;
+ }>, callback?: Function) #
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ View,
+ Text,
+ TouchableHighlight,
+ AlertIOS,
+} = ReactNative;
+
+var { SimpleAlertExampleBlock } = require('./AlertExample');
+
+exports.framework = 'React';
+exports.title = 'AlertIOS';
+exports.description = 'iOS alerts and action sheets';
+exports.examples = [{
+ title: 'Alerts',
+ render() {
+ return ;
+ }
+},
+{
+ title: 'Prompt Options',
+ render(): ReactElement {
+ return ;
+ }
+},
+{
+ title: 'Prompt Types',
+ render() {
+ return (
+
+ AlertIOS.prompt('Plain Text Entry')}>
+
+
+
+ plain-text
+
+
+
+
+ AlertIOS.prompt('Secure Text', null, null, 'secure-text')}>
+
+
+
+ secure-text
+
+
+
+
+ AlertIOS.prompt('Login & Password', null, null, 'login-password')}>
+
+
+
+ login-password
+
+
+
+
+
+ );
+ }
+}];
+
+class PromptOptions extends React.Component {
+ state: any;
+ customButtons: Array;
+
+ constructor(props) {
+ super(props);
+
+ // $FlowFixMe this seems to be a Flow bug, `saveResponse` is defined below
+ this.saveResponse = this.saveResponse.bind(this);
+
+ this.customButtons = [{
+ text: 'Custom OK',
+ onPress: this.saveResponse
+ }, {
+ text: 'Custom Cancel',
+ style: 'cancel',
+ }];
+
+ this.state = {
+ promptValue: undefined,
+ };
+ }
+
+ render() {
+ return (
+
+
+ Prompt value: {this.state.promptValue}
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse)}>
+
+
+
+ prompt with title & callback
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons)}>
+
+
+
+ prompt with title & custom buttons
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.saveResponse, undefined, 'Default value')}>
+
+
+
+ prompt with title, callback & default value
+
+
+
+
+ AlertIOS.prompt('Type a value', null, this.customButtons, 'login-password', 'admin@site.com')}>
+
+
+
+ prompt with title, custom buttons, login/password & default value
+
+
+
+
+ );
+ }
+
+ saveResponse(promptValue) {
+ this.setState({ promptValue: JSON.stringify(promptValue) });
+ }
+}
+
+var styles = StyleSheet.create({
+ wrapper: {
+ borderRadius: 5,
+ marginBottom: 5,
+ },
+ button: {
+ backgroundColor: '#eeeeee',
+ padding: 10,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/android-building-from-source.md b/docs/docs/0.43/android-building-from-source.md
new file mode 100644
index 0000000..459f04e
--- /dev/null
+++ b/docs/docs/0.43/android-building-from-source.md
@@ -0,0 +1,143 @@
+如果你想使用新的功能,获得官方的修复补丁,尝试还没发布的最新特性,或者维护你自己的不能合并到核心版本的补丁,你可能需要自己从源代码编译React Native。
+
+# 预备条件
+
+如果你已经安装了安卓SDK,那么运行`android`命令打开安卓SDK管理器。
+
+确保你已经安装了以下模块:
+
+* Android SDK version 23 (编译SDK版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* SDK build tools version 23.0.1(编译工具版本号在[build.gradle](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)中可以找到)
+* Android Support Repository >= 17
+* Android NDK(下载及解压指南看[这里](http://developer.android.com/ndk/downloads/index.html))
+
+将Gradle指向你的安卓SDK: 设置`$ANDROID_SDK`和`$ANDORID_NDK`为对应的目录,或者按照以下内容在react-native根目录下创建local.properties文件(注意:windows下需要使用反双斜杠)。
+
+```
+sdk.dir=指向android sdk目录的绝对路径
+ndk.dir=指向android ndk目录的绝对路径
+```
+例如:
+
+```
+sdk.dir=/Users/your_unix_name/android-sdk-macosx
+ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
+```
+# 从下载链接安装Android NDK
+
+1. Mac OS (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip
+2. Linux (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip
+3. Windows (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip
+4. Windows (32-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86.zip
+
+更多参考您可以访问官网NDK界面 [official page](http://developer.android.com/ndk/downloads/index.html).
+
+__译注__:建议安装r10e版本,否则在编译过程可能会出错。
+
+# 编译源代码:
+
+## 1.在你的分支代码中进行安装
+
+首先,在你的分支代码中安装react-native。例如从官方地址安装主干版本:
+
+```
+npm install --save github:facebook/react-native#master
+```
+
+或者,你也可以把仓库克隆到你的`node_modules`目录,然后运行`npm install`进行安装
+
+## 2.添加gradle依赖
+
+在`android/build.gradle`中添加`gradle-download-task`依赖
+
+```
+...
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.1'
+ classpath 'de.undercouch:gradle-download-task:3.1.2'
+
+ // 注意:不要把你的应用的依赖放在这里;
+ // 它们应该放在各自模块的build.gradle文件中
+ }
+...
+```
+
+## 添加`:ReactAndroid `项目
+
+在`android/settings.gradle`中添加`:ReactAndroid`项目
+
+```
+...
+include ':ReactAndroid'
+
+project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
+...
+```
+
+修改你的`android/app/build.gradle`文件,使用`:ReactAndroid`替换预编译库。例如用`compile project(':ReactAndroid')`替换`compile 'com.facebook.react:react-native:0.16.+'`
+
+```
+...
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.android.support:appcompat-v7:23.0.1'
+
+ compile project(':ReactAndroid')
+
+ ...
+}
+...
+```
+
+## 让第三方模块使用你的分支
+如果你使用第三方的React Native模块,你需要重写它们的依赖以避免它们仍然打包官方的预编译库。否则当你编译时会报错-`Error: more than one library with package name 'com.facebook.react'.`(错误:有几个重名的'com.facebook.react'的包)
+
+修改你的`android/app/build.gradle`文件,添加如下内容:
+
+```
+configurations.all {
+ exclude group: 'com.facebook.react', module: 'react-native'
+}
+```
+
+# 在Android Studio中构建您的项目
+
+在Android Studio欢迎页中选择`Import project`,随后选择您应用所在的文件夹。
+
+您还需要使用_Run_按钮(__译注__:Android Studio中绿色的运行按钮)来在设备上运行您的app,此外Android Studio不会自动开启服务,你还需要通过`npm start`来启动。
+
+# 其他注意事项
+从源码进行编译将会花费很长时间,尤其是第一次编译,需要下载接近200M的文件然后编译原生代码。每次你在自己的仓库更新`react-native`版本时,构建的目录可能会被删除,所有的文件都需要重新下载。为了避免构建目录被删,你需要编辑`~/.gradle/init.gradle`文件来修改构建目录路径。
+
+```
+gradle.projectsLoaded {
+ rootProject.allprojects {
+ buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+ }
+}
+```
+
+## Additional notes
+
+Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of artifacts and compile the native code. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file:
+
+```gradle
+gradle.projectsLoaded {
+ rootProject.allprojects {
+ buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+ }
+}
+```
+
+## Building for Maven/Nexus deployment
+
+If you find that you need to push up a locally compiled React Native .aar and related files to a remote Nexus repository, you can.
+
+Start by following the `Point Gradle to your Android SDK` section of this page. Once you do this, assuming you have Gradle configured properly, you can then run the following command from the root of your React Native checkout to build and package all required files:
+
+```
+./gradlew ReactAndroid:installArchives
+```
+
+This will package everything that would typically be included in the `android` directory of your `node_modules/react-native/` installation in the root directory of your React Native checkout.
+
diff --git a/docs/docs/0.43/android-setup.md b/docs/docs/0.43/android-setup.md
new file mode 100644
index 0000000..549954c
--- /dev/null
+++ b/docs/docs/0.43/android-setup.md
@@ -0,0 +1,86 @@
+本指南主要介绍在Android模拟器上运行React Native Android应用所必须的准备步骤。
+
+### 安装Git
+
+ - **Mac**上如果你已经安装了[XCode](https://developer.apple.com/xcode/),那么Git也就随之安装了,否则请使用homebrew进行安装:
+
+ brew install git
+
+ - **Linux**上请使用你系统对应的[包管理器](https://git-scm.com/download/linux)来安装Git。
+
+ - **Windows**上请下载并安装[Git for Windows](https://git-for-windows.github.io/)。在安装过程中,请务必记得勾选`Run Git from Windows Command Prompt`,这样会把Git的可执行程序加入到`PATH`环境变量中,这样其他程序才能在命令行中正确调用Git。
+
+
+### 安装Android SDK(已安装的请跳过这一步)
+
+1. [安装最新版的JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+
+2. 安装Android SDK:
+ - **Mac**: `brew install android-sdk`
+ - **Linux或Windows**: [从Android开发者官网下载](https://developer.android.com/sdk/installing/index.html)
+__译注__:国内用户推荐从[AndroidDevTools](http://androiddevtools.cn/)下载。
+
+### 定义ANDROID_HOME环境变量
+
+__重要__: 确保`ANDROID_HOME`环境变量指向你已经安装的Android SDK目录:
+
+ - **Mac**, 往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+ (__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这两个文件有可能还没有被创建。请在终端下使用`sudo vi ~/.bashrc`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+ # 如果你是通过Homebrew安装SDK的,则加入下列路径
+ export ANDROID_HOME=/usr/local/opt/android-sdk
+ # 否则可能是(当然具体视你把SDK放在哪):
+ export ANDROID_HOME=~/Library/Android/sdk
+ - **Linux**,往你的`~/.bashrc`, `~/.bash_profile` 或者你终端所用的其它配置文件中增加以下内容:
+
+ export ANDROID_HOME=<你把Android SDK解压后放置的位置>
+
+ - **Windows**,打开控制面板,选择`系统和安全`->`系统`->`高级系统设置`->`高级`->`环境变量`->`新建`,变量名填写ANDROID_HOME,变量值填写你把Android SDK解压后放置的位置。
+
+__译注__: 如果你在windows下找不到对应的控制面板项,也可以右键点击`我的电脑`,然后在菜单中选择`属性`,然后选择`高级系统设置`->`高级`->`环境变量`->`新建`。__注意__:必须将现有的CMD窗口全部关闭,重新打开后新的环境变量才能生效。
+
+
+### 开启gradle daemon
+
+React Native Android使用的构建系统是[gradle](https://docs.gradle.org)。我们建议你开启gradle daemon功能,它可以带来高达50%的java编译速度提升。点击[这里](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)来了解如何针对你的平台开启这一功能。
+
+
+### 设置SDK
+
+1. 打开Android SDK Manager(**Mac**用户在终端下输入`android`)。
+2. 选中以下项目:
+ * Android SDK Build-tools version 23.0.1(这个必须版本严格匹配23.0.1)
+ * Android 6.0 (API 23)
+ * Local Maven repository for Support Libraries(之前叫做Android Support Repository)
+3. 点击"Install Packages"
+ (__译注__:国内用户推荐使用[腾讯Bugly的镜像](http://android-mirror.bugly.qq.com:8080/include/usage.html)来加速下载)
+ 
+
+### 安装Genymotion
+
+Genymotion是一个第三方模拟器,它比Google官方的模拟器更易设置且性能更好。但是,它只针对个人用户免费。如果你想使用Google模拟器,请往下看。
+
+1. 下载并安装[Genymotion](https://www.genymotion.com/)。
+2. 打开Genymotion。如果你尚未安装VirtualBox,它有可能会提示你安装。
+3. 创建一个模拟器并启动。
+4. 按下`⌘+M`可以打开开发者菜单(在安装并启动了React Native应用之后)。
+
+### 备选方案:使用Google官方模拟器
+
+1. 打开Android SDK Manager(参见"设置SDK"一步)
+2. 选中以下项目:
+ * Intel x86 Atom System Image (for Android 5.1.1 - API 22)
+ * Intel x86 Emulator Accelerator (HAXM installer)
+3. 点击"Install Packages"
+4. [配置硬件加速(HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac),否则模拟器会运行的相当缓慢。
+5. 创建Android虚拟设备(AVD):
+ 1. 运行`android avd`并且点击**Create...**
+ (__译注__:在Windows系统下,android.bat在Android SDK的`tools`文件夹下,请注意设置PATH环境变量以便于使用)
+ 
+ 2. 选中新创建的虚拟设备,并点击`Start...`
+
+__译注__:对于Windows用户而言,Intel x86 Emulator Accelerator和HyperV(系统内置的虚拟机功能)不能同时启用。所以要么选择关闭HyperV(控制面板-程序-启动和关闭Windows功能,取消选择HyperV并点确定),要么选择Genymotion、Bluestacks或Visual Studio Emulator for Android作为模拟器。
+
+### 在Android Studio中编辑Java代码
+
+对于JavaScript代码,你可以使用任何编辑器来编辑。如果你想在Android Studio中编辑原生Java代码的话,请在Android Studio的欢迎屏幕上选择"Import project",然后选择你的项目目录中的`android`文件夹即可。
diff --git a/docs/docs/0.43/android-ui-performance.md b/docs/docs/0.43/android-ui-performance.md
new file mode 100644
index 0000000..842da69
--- /dev/null
+++ b/docs/docs/0.43/android-ui-performance.md
@@ -0,0 +1,147 @@
+我们尽最大的努力来争取使UI组件的性能如丝般顺滑,但有的时候这根本不可能做到。要知道,Android有超过一万种不同型号的手机,而在框架底层进行软件渲染的时候是统一处理的,这意味着你没办法像iOS那样自由。不过有些时候,你还是可以想办法提升应用的性能(有的时候问题根本不是出在原生代码上!)
+
+要想解决应用的性能问题,第一步就是搞明白在每个16毫秒的帧中,时间都去哪儿了。为此,我们会使用一个标准的Android性能分析工具`systrace`,不过在此之前……
+
+> 请先确定JS的开发者模式已经关闭!
+>
+> 你应该在应用的日志里看到`__DEV__ === false, development-level warning are OFF, performance optimizations are ON`等字样(你可以通过adb logcat来查看应用日志)
+
+## 使用Systrace进行性能分析
+
+Systrace是一个标准的基于标记的Android性能分析工具(如果你安装了Android platform-tool包,它也会一同安装)。被调试的代码段在开始和结束处加上标记,在执行的过程中标记会被记录,最后会以图表形式展现统计结果。包括Android SDK自己和React Native框架都已经提供了标准的标记供你查看。
+
+### 收集一次数据
+
+> 注意:
+>
+> Systrace从React Native `v0.15`版本开始支持。你需要在此版本下构建项目才能收集相应的性能数据。
+
+首先,把你想分析的、运行不流畅的设备使用USB线链接到电脑上,然后操作应用来到你想分析的导航/动画之前,接着这样运行systrace:
+
+```
+$ /platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a <你的应用包名>
+```
+
+对于此命令做一个简单的说明:
+
+- `time`参数控制本次数据收集的持续时间,单位是秒。
+- `schd`, `gfx`, 和`view`是我们所关心的Android SDK内置的tag(标记的集合):`schd`提供了你的设备的每个CPU核心正在做什么的信息,`gfx`提供了你的图形相关信息,譬如每帧的时间范围,而`view`提供了一些关于视图布局和渲染相关性能的信息。
+- `-a <你的应用包名>`启用了针对应用的过滤。在这里填写你用React Native创建的应用包名。`你的应用包名`可以在你应用中的`AndroidManifest.xml`里找到,形如`com.example.app`
+
+_译注_:实际上,AndroidManifest.xml里的应用包名会被`app/build.gradle`里的`applicationId`取代。如果二者不一致,应当以`app/build.gradle`里的为准。
+
+一旦systrace开始收集数据,你可以操作应用执行你所关心的动画和操作。在收集结束后,systrace会给你提供一个链接,你可以在浏览器中打开这个链接来查看数据收集的结果。
+
+## 查看性能数据
+
+在浏览器中打开数据页面(建议使用Chrome),你应该能看到类似这样的结果:
+
+
+
+**提示**: 你可以使用WSAD键来滚动和缩放性能数据图表。
+
+### 启用垂直同步高亮
+
+接下来你首先应该启用16毫秒帧区间的高亮。在屏幕顶端点击对应的复选框:
+
+
+
+然后你应该能在屏幕上看到类似上图的斑马状条纹。如果你无法看到这样的条纹,可以尝试换一台设备来进行分析:部分三星手机显示垂直同步高亮存在已知问题,而Nexus系列大部分情况都相当可靠。
+
+### 找到你的进程
+
+滚动图表直到你找到你的应用包名。在上面的例子里,我正在分析`com.facebook.adsmanager`,由于内核的线程名字长度限制,它会显示成`book.adsmanager`。
+
+在左侧,你应该能看到一系列线程对应着右边的时间轴。有3到4个线程是我们必须关注的:UI线程(名字可能是`UI Thread`或者是你的包名), `mqt_js`和`mqt_native_modules`。如果你在Android 5.0以上版本运行,我们还需要关注`Render`(渲染)线程。
+
+### UI 线程
+
+标准的Android布局和绘制都在UI线程里发生。右侧显示的线程名字会是你的包名(在我的例子里是book.adsmanager)或者UI Thread.你在这个线程里看到的事件可能会是一些`Choreographer`, `traversals`或者`DispatchUI`:
+
+
+
+### JS线程
+
+这是用于执行JavaScript代码的线程。根据Android系统版本或者设备的不同,线程名可能是`mqt_js`或者`<...>`。如果看不到对应的名字的话,寻找类似`JSCall`,`Bridge.executeJSCall`这样的事件。
+
+
+
+### 原生模块线程
+
+这里是用于原生模块执行代码(譬如`UIManager`)的线程,线程名可能是`mqt_native_modules`或`<...>`。在后一种情况下,寻找类似`NativeCall`, `CallJavaModuleMethod`, 还有`onBatchComplete`这样的事件名:
+
+
+
+### 额外的:渲染线程
+
+如果你在使用Android L(5.0)或者更高版本,你应该还会在你的应用里看到一个渲染线程。这个线程真正生成OpenGL渲染序列来渲染你的UI。这个线程的名字可能为`RenderThread`或者`<...>`,在后一种情况下,寻找类似`DrawFrame`或`queueBuffer`这样的事件:
+
+
+
+## 寻找导致卡顿的罪魁祸首
+
+一个流畅的动画应该看起来像这样:
+
+
+
+每个背景颜色不同的部分我们称作“一帧”——记住要渲染一个流畅的帧,我们所有的界面工作都需要在16毫秒内完成。注意没有任何一个线程在靠近帧的边界处工作。类似这样的一个应用程序就正在60FPS(帧每秒)的情况下流畅表现。
+
+如果你发现一些起伏的地方,譬如这样:
+
+
+
+注意在上图中JS线程基本上一直在执行,并且超越了帧的边界。这个应用就没法以60FPS渲染了。在这种情况下,**问题出在JS中**。
+
+你还有可能会看到一些类似这样的东西:
+
+
+
+在这种情况下,UI和渲染线程有一些重负荷的工作,以至于超越了帧的边界。这可能是由于我们每帧试图渲染的UI太多了导致的。在这种情况下,**问题出在需要渲染的原生视图上**。
+
+并且,你还应该能看到一些可以指导接下来优化工作的有用的信息。
+
+## JS的问题
+
+如果你发现问题出在JS上,在你正在执行的JS代码中寻找线索。在上面的图中,我们会发现`RCTEventEmitter`每帧被执行了很多次。这是上面的数据统计放大后的内容:
+
+
+
+这看起来不是很正常,为什么事件被调用的如此频繁?它们是不同的事件吗?具体的答案取决于你的产品的代码。在许多情况下,你可能需要看看[shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate)的介绍。
+
+> **TODO**: 我们还在准备更多的JS性能分析的工具,会在将来的版本中加入。
+
+## 原生UI问题
+
+如果你发现问题出在原生UI上,有两种常见的情况:
+
+1. 你每帧在渲染的UI给GPU带来了太重的负载,或者:
+2. 你在动画、交互的过程中不断创建新的UI对象(譬如在scroll的过程中加载新的内容)
+
+### GPU负担过重
+
+在第一种情况下,你应该能看到UI线程的图表类似这样:
+
+
+
+注意`DrawFrame`花费了很多时间,超越了帧的边界。这些时间用来等待GPU获取它的操作缓存。
+
+要缓解这个问题,你应该:
+
+- 检查`renderToHardwareTextureAndroid`的使用,有这个属性的View的子节点正在进行动画或变形会导致性能大幅下降(譬如`Navigator`提供的滑动、淡入淡出动画)。
+- 确保你**没有**使用`needsOffscreenAlphaCompositing`,这个默认是关闭的,因为它在大部分情况下都会带来GPU消耗的大幅提升。
+
+如果这还不能帮你解决问题,你可能需要更深入的探索GPU到底在做什么。参见[Tracer for OpenGL ES](http://developer.android.com/tools/help/gltracer.html)。
+
+### 在UI线程创建大量视图
+
+如果是第二种情况,你可能会看到类似这样的结果:
+
+
+
+注意一开始JS线程工作了很久,然后你看到原生模块线程干了些事情,最后带来了UI线程的巨大开销。
+
+这个问题并没有什么简单直接的优化办法,除非你能把创建UI的步骤推迟到交互结束以后去进行,或者你能直接简化你所要创建的UI。React Native小组正在架构层设法提供一个方案,使得新的UI视图可以在主线程之外去创建和配置,这样就可以使得交互变得更加流畅。
+
+## 还是没搞定?
+
+如果你还是很迷惑或者不知如何进展,你可以在[Stack Overflow的react-native标签下](http://stackoverflow.com/tags/react-native)提交一个问题。如果你在这里得不到响应,或者找到了一个核心组件的问题,你可以[提交一个Github issue](https://github.com/facebook/react-native/issues)给我们。
diff --git a/docs/docs/0.43/animated.md b/docs/docs/0.43/animated.md
new file mode 100644
index 0000000..b1d50b4
--- /dev/null
+++ b/docs/docs/0.43/animated.md
@@ -0,0 +1,535 @@
+动画是现代用户体验中非常重要的一个部分,`Animated`库就是用来创造流畅、强大、并且易于构建和维护的动画。
+
+最简单的工作流程就是创建一个`Animated.Value`,把它绑定到组件的一个或多个样式属性上。然后可以通过动画驱动它,譬如`Animated.timing`,或者通过`Animated.event`把它关联到一个手势上,譬如拖动或者滑动操作。除了样式,`Animated.value`还可以绑定到props上,并且一样可以被插值。这里有一个简单的例子,一个容器视图会在加载的时候淡入显示:
+
+```javascript
+class FadeInView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // init opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {toValue: 1}, // Configuration
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+ // Binds
+ {this.props.children}
+
+ );
+ }
+ }
+```
+
+
+注意只有声明为可动画化的组件才能被关联动画。`View`、`Text`,还有`Image`都是可动画化的。如果你想让自定义组件可动画化,可以用`createAnimatedComponent`。这些特殊的组件里面用了一些黑魔法,来把动画数值绑定到属性上,然后在每帧去执行原生更新,来避免每次render和同步过程的开销。他们还处理了在节点卸载时的清理工作以确保使用安全。
+
+动画具备很强的可配置性。自定义或者预定义的过渡函数、延迟、时间、衰减比例、刚度等等。取决于动画类型的不同,你还可以配置更多的参数。
+
+一个`Animated.Value`可以驱动任意数量的属性,并且每个属性可以配置一个不同的插值函数。插值函数把一个输入的范围映射到输出的范围,通常我们用线性插值,不过你也可以使用其他的过渡函数。默认情况下,当输入超出范围时,它也会对应的进行转换,不过你也可以把输出约束到范围之内。
+
+举个例子,你可能希望你的`Animated.Value`从0变化到1时,把组件的位置从150px移动到0px,不透明度从0到1。可以通过以下的方法修改`style`属性来实现:
+
+```javascript
+ style={{
+ opacity: this.state.fadeAnim, // Binds directly
+ transform: [{
+ translateY: this.state.fadeAnim.interpolate({
+ inputRange: [0, 1],
+ outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
+ }),
+ }],
+ }}>
+```
+
+动画还可以被更复杂地组合,通过一些辅助函数例如`sequence`或者`parallel`(它们分别用于先后执行多个动画和同时执行多个动画),而且还可以通过把toValue设置为另一个Animated.Value来产生一个动画序列。
+
+`Animated.ValueXY`则用来处理一些2D动画,譬如滑动。并且还有一些辅助功能譬如`setOffset`和`getLayout`来帮助实现一些常见的交互效果,譬如拖放操作(Drag and drop)。
+
+你可以在`AnimationExample.js`中找到一些更复杂的例子。你还可以看看Gratuitous Animation App,以及[动画指南文档](animations.html)。
+
+注意`Animated`模块被设计为可完全序列化的,这样动画可以脱离JavaScript事件循环,以一种高性能的方式运行。这可能会导致API看起来比较难懂,与一个完全同步的动画系统相比稍微有一些奇怪。`Animated.Value.addListener`可以帮助你解决一些相关限制,不过使用它的时候需要小心,因为将来的版本中它可能会牵扯到性能问题。
+
+### 方法
+
+
+
+
static decay(value: AnimatedValue | AnimatedValueXY, config: DecayAnimationConfig) #
+
+
推动一个值以一个初始的速度和一个衰减系数逐渐变为0。
+
+
+
+
static timing(value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig) #
+
+
推动一个值按照一个过渡曲线而随时间变化。Easing模块定义了一大堆曲线,你也可以使用你自己的函数。
+
+
+
+
static spring(value: AnimatedValue | AnimatedValueXY, config: SpringAnimationConfig) #
+
+
产生一个基于Rebound和Origami实现的Spring动画。它会在toValue值更新的同时跟踪当前的速度状态,以确保动画连贯。可以链式调用。
+
+
+
static add(a: Animated, b: Animated) #
+
static multiply(a: Animated, b: Animated) #
+
+
static delay(time: number) #
+
+
+
+
static sequence(animations: Array<CompositeAnimation>) #
+
+
按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行。
+
+
+
+
static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig) #
+
+
同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。你可以通过stopTogether选项来改变这个效果。
+
+
+
+
static stagger(time: number, animations: Array<CompositeAnimation>) #
+
+
一个动画数组,里面的动画有可能会同时执行(重叠),不过会以指定的延迟来开始。用来制作拖尾效果非常合适。
+
+
+
+
static event(argMapping: Array<Mapping>, config?: EventConfig) #
+
+
接受一个映射的数组,对应的解开每个值,然后调用所有对应的输出的setValue方法。例如:
+
onScroll={this .AnimatedEvent(
+ [{nativeEvent: {contentOffset: {x: this ._scrollX}}}]
+ {listener},
+ )
+ ...
+ onPanResponderMove: this .AnimatedEvent([
+ null ,
+ {dx: this ._panX},
+ ]),
+
+
+
+
+
static createAnimatedComponent(Component: any) #
+
+
使得任何一个React组件支持动画。用它来创建Animated.View等等。
+
+
+
+
+### 属性
+
+
+
+
Value: AnimatedValue #
+
+
表示一个数值的类,用于驱动动画。通常用new Animated.Value(0);来初始化。
+
+
+
+
ValueXY: AnimatedValueXY #
+
+
表示一个2D值的类,用来驱动2D动画,例如拖动操作等。
+
+
+
+
+## class AnimatedValue
+
+用于驱动动画的标准值。一个`Animated.Value`可以用一种同步的方式驱动多个属性,但同时只能被一个行为所驱动。启用一个新的行为(譬如开始一个新的动画,或者运行`setValue`)会停止任何之前的动作。
+
+### 方法
+
+
+
+
constructor(value: number) #
+
+
+
setValue(value: number) #
+
+
直接设置它的值。这个会停止任何正在进行的动画,然后更新所有绑定的属性。
+
+
+
+
setOffset(offset: number) #
+
+
设置一个相对值,不论接下来的值是由setValue、一个动画,还是Animated.event产生的,都会加上这个值。常用来在拖动操作一开始的时候用来记录一个修正值(譬如当前手指位置和View位置)。
+
+
+
+
flattenOffset() #
+
+
把当前的相对值合并到值里,并且将相对值设为0。最终输出的值不会变化。常在拖动操作结束后调用。
+
+
+
+
addListener(callback: ValueListenerCallback) #
+
+
添加一个异步监听函数,这样你就可以监听动画值的变更。这有时候很有用,因为你没办法同步的读取动画的当前值,因为有时候动画会在原生层次运行。
+
+
+
+
removeListener(id: string) #
+
+
+
removeAllListeners() #
+
+
+
stopAnimation(callback?: ?(value: number) => void) #
+
+
停止任何正在运行的动画或跟踪值。callback会被调用,参数是动画结束后的最终值,这个值可能会用于同步更新状态与动画位置。
+
+
+
+
interpolate(config: InterpolationConfigType) #
+
+
在更新属性之前对值进行插值。譬如:把0-1映射到0-10。
+
+
+
+
animate(animation: Animation, callback: EndCallback) #
+
+
一般仅供内部使用。不过有可能一个自定义的动画类会用到此方法。
+
+
+
+
+
track(tracking: Animated) #
+
+
+
+
+## class AnimatedValueXY
+
+用来驱动2D动画的2D值,譬如滑动操作等。API和普通的`Animated.Value`几乎一样,只不过是个复合结构。它实际上包含两个普通的`Animated.Value`。
+
+例子:
+
+```javascript
+class DraggableView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ pan: new Animated.ValueXY(), // inits to zero
+ };
+ this.state.panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: () => true,
+ onPanResponderMove: Animated.event([null, {
+ dx: this.state.pan.x, // x,y are Animated.Value
+ dy: this.state.pan.y,
+ }]),
+ onPanResponderRelease: () => {
+ Animated.spring(
+ this.state.pan, // Auto-multiplexed
+ {toValue: {x: 0, y: 0}} // Back to zero
+ ).start();
+ },
+ });
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+```
+
+### 方法
+
+
+
+
constructor(valueIn?: ?{x: number | AnimatedValue; y: number | AnimatedValue}) #
+
+
+
+
setValue(value: {x: number; y: number}) #
+
+
+
+
setOffset(offset: {x: number; y: number}) #
+
+
+
+
+
stopAnimation(callback?: ?() => number) #
+
+
+
+
addListener(callback: ValueXYListenerCallback) #
+
+
+
+
removeListener(id: string) #
+
+
+
+
getLayout() #
+
+
将一个{x, y}组合转换为{left, top}以用于样式。例如:
+
style={this .state.anim.getLayout()}
+
+
+
+
+
getTranslateTransform() #
+
+
将一个{x, y} 组合转换为一个可用的位移变换(translation transform),例如:
+
style={{
+ transform: this .state.anim.getTranslateTransform()
+ }}
+
+
+
+
+
+ ### 例子
+
+ ```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Animated,
+ Easing,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+var UIExplorerButton = require('./UIExplorerButton');
+
+exports.framework = 'React';
+exports.title = 'Animated - Examples';
+exports.description = 'Animated provides a powerful ' +
+ 'and easy-to-use API for building modern, ' +
+ 'interactive user experiences.';
+
+exports.examples = [
+ {
+ title: 'FadeInView',
+ description: 'Uses a simple timing animation to ' +
+ 'bring opacity from 0 to 1 when the component ' +
+ 'mounts.',
+ render: function() {
+ class FadeInView extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {
+ toValue: 1, // Target
+ duration: 2000, // Configuration
+ },
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+ class FadeInExample extends React.Component {
+ state: any;
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ show: true,
+ };
+ }
+ render() {
+ return (
+
+ {
+ this.setState((state) => (
+ {show: !state.show}
+ ));
+ }}>
+ Press to {this.state.show ?
+ 'Hide' : 'Show'}
+
+ {this.state.show &&
+
+ FadeInView
+
+ }
+
+ );
+ }
+ }
+ return ;
+ },
+ },
+ {
+ title: 'Transform Bounce',
+ description: 'One `Animated.Value` is driven by a ' +
+ 'spring with custom constants and mapped to an ' +
+ 'ordered set of transforms. Each transform has ' +
+ 'an interpolation to convert the value into the ' +
+ 'right range and units.',
+ render: function() {
+ this.anim = this.anim || new Animated.Value(0);
+ return (
+
+ {
+ Animated.spring(this.anim, {
+ toValue: 0, // Returns to the start
+ velocity: 3, // Velocity makes it move
+ tension: -10, // Slow
+ friction: 1, // Oscillate a lot
+ }).start(); }}>
+ Press to Fling it!
+
+
+ Transforms!
+
+
+ );
+ },
+ },
+ {
+ title: 'Composite Animations with Easing',
+ description: 'Sequence, parallel, delay, and ' +
+ 'stagger with different easing functions.',
+ render: function() {
+ this.anims = this.anims || [1,2,3].map(
+ () => new Animated.Value(0)
+ );
+ return (
+
+ {
+ var timing = Animated.timing;
+ Animated.sequence([ // One after the other
+ timing(this.anims[0], {
+ toValue: 200,
+ easing: Easing.linear,
+ }),
+ Animated.delay(400), // Use with sequence
+ timing(this.anims[0], {
+ toValue: 0,
+ easing: Easing.elastic(2), // Springy
+ }),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(
+ anim, {toValue: 200}
+ )).concat(
+ this.anims.map((anim) => timing(
+ anim, {toValue: 0}
+ ))),
+ ),
+ Animated.delay(400),
+ Animated.parallel([
+ Easing.inOut(Easing.quad), // Symmetric
+ Easing.back(1.5), // Goes backwards first
+ Easing.ease // Default bezier
+ ].map((easing, ii) => (
+ timing(this.anims[ii], {
+ toValue: 320, easing, duration: 3000,
+ })
+ ))),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(anim, {
+ toValue: 0,
+ easing: Easing.bounce, // Like a ball
+ duration: 2000,
+ })),
+ ),
+ ]).start(); }}>
+ Press to Animate
+
+ {['Composite', 'Easing', 'Animations!'].map(
+ (text, ii) => (
+
+ {text}
+
+ )
+ )}
+
+ );
+ },
+ },
+ {
+ title: 'Continuous Interactions',
+ description: 'Gesture events, chaining, 2D ' +
+ 'values, interrupting and transitioning ' +
+ 'animations, etc.',
+ render: () => (
+ Checkout the Gratuitous Animation App!
+ ),
+ }
+];
+
+var styles = StyleSheet.create({
+ content: {
+ backgroundColor: 'deepskyblue',
+ borderWidth: 1,
+ borderColor: 'dodgerblue',
+ padding: 20,
+ margin: 20,
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+});
+ ```
\ No newline at end of file
diff --git a/docs/docs/0.43/animations.md b/docs/docs/0.43/animations.md
new file mode 100644
index 0000000..d516571
--- /dev/null
+++ b/docs/docs/0.43/animations.md
@@ -0,0 +1,384 @@
+流畅、有意义的动画对于移动应用用户体验来说是非常重要的。现实生活中的物体在开始移动和停下来的时候都具有一定的惯性,我们在界面中也可以使用动画来实现契合物理规律的交互。
+React Native提供了两个互补的动画系统:用于全局的布局动画`LayoutAnimation`,和用于创建更精细的交互控制的动画`Animated`。
+
+### Animated
+
+`Animated`库使得开发者可以非常容易地实现各种各样的动画和交互方式,并且具备极高的性能。`Animated`旨在以声明的形式来定义动画的输入与输出,在其中建立一个可配置的变化函数,然后使用简单的`start/stop`方法来控制动画按顺序执行。
+`Animated`仅封装了四个可以动画化的组件:`View`、`Text`、`Image`和`ScrollView`,不过你也可以使用`Animated.createAnimatedComponent()`来封装你自己的组件。
+下面是一个在加载时带有淡入动画效果的视图:
+
+```javascript
+// FadeInView.js
+import React, { Component } from 'react';
+import {
+ Animated,
+} from 'react-native';
+
+export default class FadeInView extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // 透明度初始值设为0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // 随时间变化而执行的动画类型
+ this.state.fadeAnim, // 动画中的变量值
+ {
+ toValue: 1, // 透明度最终变为1,即完全不透明
+ }
+ ).start(); // 开始执行动画
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+}
+
+```
+
+然后你就可以在组件中像使用`View`那样去使用`FadeInView`了,比如像下面这样:
+
+```javascript
+render() {
+ return (
+
+ Fading in
+
+ )
+}
+```
+
+
+
+Let's break down what's happening here.
+In the `FadeInView` constructor, a new `Animated.Value` called `fadeAnim` is initialized as part of `state`.
+The opacity property on the `View` is mapped to this animated value.
+Behind the scenes, the numeric value is extracted and used to set opacity.
+
+When the component mounts, the opacity is set to 0.
+Then, an easing animation is started on the `fadeAnim` animated value,
+which will update all of its dependent mappings (in this case, just the opacity) on each frame as the value animates to the final value of 1.
+
+This is done in an optimized way that is faster than calling `setState` and re-rendering.
+Because the entire configuration is declarative, we will be able to implement further optimizations that serialize the configuration and runs the animation on a high-priority thread.
+
+
+### Configuring animations
+
+Animations are heavily configurable. Custom and predefined easing functions, delays, durations, decay factors, spring constants, and more can all be tweaked depending on the type of animation.
+
+`Animated` provides several animation types, the most commonly used one being [`Animated.timing()`](animated.html#timing).
+It supports animating a value over time using one of various predefined easing functions, or you can use your own.
+Easing functions are typically used in animation to convey gradual acceleration and deceleration of objects.
+
+By default, `timing` will use a easeInOut curve that conveys gradual acceleration to full speed and concludes by gradually decelerating to a stop.
+You can specify a different easing function by passing a `easing` parameter.
+Custom `duration` or even a `delay` before the animation starts is also supported.
+
+For example, if we want to create a 2-second long animation of an object that slightly backs up before moving to its final position:
+
+```javascript
+Animated.timing(
+ this.state.xPosition,
+ {
+ toValue: 100,
+ easing: Easing.back,
+ duration: 2000,
+ }
+).start();
+```
+
+Take a look at the [Configuring animations](animated.html#configuring-animations) section of the `Animated` API reference to learn more about all the config parameters supported by the built-in animations.
+
+
+### 组合动画
+
+多个动画可以通过`parallel`(同时执行)、`sequence`(顺序执行)、`stagger`和`delay`来组合使用。它们中的每一个都接受一个要执行的动画数组,并且自动在适当的时候调用start/stop。举个例子:
+
+```javascript
+Animated.sequence([ // 首先执行decay动画,结束后同时执行spring和twirl动画
+ Animated.decay(position, { // 滑行一段距离后停止
+ velocity: {x: gestureState.vx, y: gestureState.vy}, // 根据用户的手势设置速度
+ deceleration: 0.997,
+ }),
+ Animated.parallel([ // 在decay之后并行执行:
+ Animated.spring(position, {
+ toValue: {x: 0, y: 0} // 返回到起始点开始
+ }),
+ Animated.timing(twirl, { // 同时开始旋转
+ toValue: 360,
+ }),
+ ]),
+]).start(); // 执行这一整套动画序列
+```
+
+默认情况下,如果任何一个动画被停止或中断了,组内所有其它的动画也会被停止。Parallel有一个`stopTogether`属性,如果设置为`false`,可以禁用自动停止。
+
+You can find a full list of composition methods in the [Composing animations](animated.html#composing-animations) section of the `Animated` API reference.
+
+### Combining animated values
+
+You can [combine two animated values](docs/animated.html#combining-animated-values) via addition, multiplication, division, or modulo to make a new animated value.
+
+There are some cases where an animated value needs to invert another animated value for calculation.
+An example is inverting a scale (2x --> 0.5x):
+
+```javascript
+const a = Animated.Value(1);
+const b = Animated.divide(1, a);
+
+Animated.spring(a, {
+ toValue: 2,
+}).start();
+```
+
+### 插值(Interpolation)
+
+`Animated` API还有一个很强大的部分就是`interpolate`插值函数。它可以接受一个输入区间,然后将其映射到另一个的输出区间。下面是一个一个简单的从0-1区间到0-100区间的映射示例:
+
+```javascript
+value.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 100],
+});
+```
+
+`interpolate`还支持定义多个区间段落,常用来定义静止区间等。举个例子,要让输入在接近-300时取相反值,然后在输入接近-100时到达0,然后在输入接近0时又回到1,接着一直到输入到100的过程中逐步回到0,最后形成一个始终为0的静止区间,对于任何大于100的输入都返回0。具体写法如下:
+
+```javascript
+value.interpolate({
+ inputRange: [-300, -100, 0, 100, 101],
+ outputRange: [300, 0, 1, 0, 0],
+});
+```
+
+它的最终映射结果如下:
+
+输入 | 输出
+------|-------
+ -400| 450
+ -300| 300
+ -200| 150
+ -100| 0
+ -50| 0.5
+ 0| 1
+ 50| 0.5
+ 100| 0
+ 101| 0
+ 200| 0
+
+`interpolate`还支持到字符串的映射,从而可以实现颜色以及带有单位的值的动画变换。例如你可以像下面这样实现一个旋转动画:
+
+ ```javascript
+ value.interpolate({
+ inputRange: [0, 360],
+ outputRange: ['0deg', '360deg']
+ })
+ ```
+
+`interpolation`还支持任意的渐变函数,其中有很多已经在`Easing`类中定义了,包括二次、指数、贝塞尔等曲线以及step、bounce等方法。`interpolation`还支持限制输出区间`outputRange`。你可以通过设置`extrapolate`、`extrapolateLeft`或`extrapolateRight`属性来限制输出区间。默认值是`extend`(允许超出),不过你可以使用`clamp`选项来阻止输出值超过`outputRange`。
+
+### 跟踪动态值
+
+动画中所设的值还可以通过跟踪别的值得到。你只要把toValue设置成另一个动态值而不是一个普通数字就行了。比如我们可以用弹跳动画来实现聊天头像的闪动,又比如通过`timing`设置`duration:0`来实现快速的跟随。他们还可以使用插值来进行组合:
+
+```javascript
+Animated.spring(follower, {toValue: leader}).start();
+Animated.timing(opacity, {
+ toValue: pan.x.interpolate({
+ inputRange: [0, 300],
+ outputRange: [1, 0],
+ }),
+}).start();
+```
+
+`ValueXY`是一个方便的处理2D交互的办法,譬如旋转或拖拽。它是一个简单的包含了两个`Animated.Value`实例的包装,然后提供了一系列辅助函数,使得`ValueXY`在许多时候可以替代`Value`来使用。比如在上面的代码片段中,`leader`和`follower`可以同时为`valueXY`类型,这样x和y的值都会被跟踪。
+
+### 输入事件
+
+`Animated.event`是Animated API中与输入有关的部分,允许手势或其它事件直接绑定到动态值上。它通过一个结构化的映射语法来完成,使得复杂事件对象中的值可以被正确的解开。第一层是一个数组,允许同时映射多个值,然后数组的每一个元素是一个嵌套的对象。在下面的例子里,你可以发现`scrollX`被映射到了`event.nativeEvent.contentOffset.x`(`event`通常是回调函数的第一个参数),并且`pan.x`和`pan.y`分别映射到`gestureState.dx`和`gestureState.dy`(`gestureState`是传递给`PanResponder`回调函数的第二个参数)。
+
+```javascript
+onScroll={Animated.event(
+ [{nativeEvent: {contentOffset: {x: scrollX}}}] // scrollX = e.nativeEvent.contentOffset.x
+)}
+onPanResponderMove={Animated.event([
+ null, // 忽略原生事件
+ {dx: pan.x, dy: pan.y} // 从gestureState中解析出dx和dy的值
+]);
+```
+
+#### 响应当前的动画值
+
+你可能会注意到这里没有一个明显的方法来在动画的过程中读取当前的值——这是出于优化的角度考虑,有些值只有在原生代码运行阶段中才知道。如果你需要在JavaScript中响应当前的值,有两种可能的办法:
+
+* `spring.stopAnimation(callback)`会停止动画并且把最终的值作为参数传递给回调函数`callback`——这在处理手势动画的时候非常有用。
+* `spring.addListener(callback)` 会在动画的执行过程中持续异步调用`callback`回调函数,提供一个最近的值作为参数。这在用于触发状态切换的时候非常有用,譬如当用户拖拽一个东西靠近的时候弹出一个新的气泡选项。不过这个状态切换可能并不会十分灵敏,因为它不像许多连续手势操作(如旋转)那样在60fps下运行。
+
+`Animated` is designed to be fully serializable so that animations can be run in a high performance way, independent of the normal JavaScript event loop.
+This does influence the API, so keep that in mind when it seems a little trickier to do something compared to a fully synchronous system.
+Check out `Animated.Value.addListener` as a way to work around some of these limitations,
+but use it sparingly since it might have performance implications in the future.
+
+### Using the native driver
+
+The `Animated` API is designed to be serializable.
+By using the [native driver](http://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html),
+we send everything about the animation to native before starting the animation,
+allowing native code to perform the animation on the UI thread without having to go through the bridge on every frame.
+Once the animation has started, the JS thread can be blocked without affecting the animation.
+
+Using the native driver for normal animations is quite simple.
+Just add `useNativeDriver: true` to the animation config when starting it.
+
+```javascript
+Animated.timing(this.state.animatedValue, {
+ toValue: 1,
+ duration: 500,
+ useNativeDriver: true, // <-- Add this
+}).start();
+```
+
+Animated values are only compatible with one driver so if you use native driver when starting an animation on a value,
+make sure every animation on that value also uses the native driver.
+
+The native driver also works with `Animated.event`.
+This is specially useful for animations that follow the scroll position as without the native driver,
+the animation will always run a frame behind the gesture due to the async nature of React Native.
+
+```javascript
+
+ {content}
+
+```
+
+You can see the native driver in action by running the [UIExplorer sample app](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/),
+then loading the Native Animated Example.
+You can also take a look at the [source code](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/NativeAnimationsExample.js) to learn how these examples were produced.
+
+#### Caveats
+
+Not everything you can do with `Animated` is currently supported by the native driver.
+The main limitation is that you can only animate non-layout properties:
+things like `transform`, `opacity` and `backgroundColor` will work, but flexbox and position properties will not.
+When using `Animated.event`, it will only work with direct events and not bubbling events.
+This means it does not work with `PanResponder` but does work with things like `ScrollView#onScroll`.
+
+### Additional examples
+
+The UIExplorer sample app has various examples of `Animated` in use:
+
+- [AnimatedGratuitousApp](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/js/AnimatedGratuitousApp)
+- [NativeAnimationsExample](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/NativeAnimationsExample.js)
+
+### LayoutAnimation
+
+`LayoutAnimation`允许你在全局范围内`创建`和`更新`动画,这些动画会在下一次渲染或布局周期运行。它常用来更新flexbox布局,因为它可以无需测量或者计算特定属性就能直接产生动画。尤其是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增加父节点的尺寸又会将位于本行之下的所有行向下推动)时,如果不使用`LayoutAnimation`,可能就需要显式声明组件的坐标,才能使得所有受影响的组件能够同步运行动画。
+
+注意尽管`LayoutAnimation`非常强大且有用,但它对动画本身的控制没有`Animated`或者其它动画库那样方便,所以如果你使用`LayoutAnimation`无法实现一个效果,那可能还是要考虑其他的方案。
+
+另外,如果要在**Android**上使用LayoutAnimation,那么目前还需要在`UIManager`中启用:
+```javascript
+UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
+```
+
+
+
+```javascript
+import React from 'react';
+import {
+ NativeModules,
+ LayoutAnimation,
+ Text,
+ TouchableOpacity,
+ StyleSheet,
+ View,
+} from 'react-native';
+
+const { UIManager } = NativeModules;
+
+UIManager.setLayoutAnimationEnabledExperimental &&
+ UIManager.setLayoutAnimationEnabledExperimental(true);
+
+export default class App extends React.Component {
+ state = {
+ w: 100,
+ h: 100,
+ };
+
+ _onPress = () => {
+ // Animate the update
+ LayoutAnimation.spring();
+ this.setState({w: this.state.w + 15, h: this.state.h + 15})
+ }
+
+ render() {
+ return (
+
+
+
+
+ Press me!
+
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ box: {
+ width: 200,
+ height: 200,
+ backgroundColor: 'red',
+ },
+ button: {
+ backgroundColor: 'black',
+ paddingHorizontal: 20,
+ paddingVertical: 15,
+ marginTop: 15,
+ },
+ buttonText: {
+ color: '#fff',
+ fontWeight: 'bold',
+ },
+});
+```
+
+This example uses a preset value, you can customize the animations as
+you need, see [LayoutAnimation.js](https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js)
+for more information.
+
+## Additional notes
+
+### `requestAnimationFrame`
+
+`requestAnimationFrame`是一个对浏览器标准API的兼容实现,你可能已经熟悉它了。它接受一个函数作为唯一的参数,并且在下一次重绘之前调用此函数。一些基于JavaScript的动画库高度依赖于这一API。通常你不必直接调用它——那些动画库会替你管理好帧的更新。
+
+### `setNativeProps`
+
+正如[直接操作](direct-manipulation.html)文档所说,`setNativeProps`方法可以使我们直接修改基于原生视图的组件的属性,而不需要使用`setState`来重新渲染整个组件树。如果我们要更新的组件有一个非常深的内嵌结构,并且没有使用`shouldComponentUpdate`来优化,那么使用`setNativeProps`就将大有裨益。
+
+如果你发现你的动画丢帧(低于60帧每秒),可以尝试使用`setNativeProps`或者`shouldComponentUpdate`来优化它们。Or you could run the animations on the UI thread rather than
+the JavaScript thread [with the useNativeDriver
+option](http://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html)。你还可以考虑将部分计算工作放在动画完成之后进行,这时可以使用[InteractionManager](interactionmanager.html)。你还可以使用应用内的开发者菜单中的“FPS Monitor”工具来监控应用的帧率。
diff --git a/docs/docs/0.43/appregistry.md b/docs/docs/0.43/appregistry.md
new file mode 100644
index 0000000..f4d5dde
--- /dev/null
+++ b/docs/docs/0.43/appregistry.md
@@ -0,0 +1,16 @@
+`AppRegistry`是JS运行所有React Native应用的入口。应用的根组件应当通过`AppRegistry.registerComponent`方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用`AppRegistry.runApplication`来真正运行应用。
+
+要“结束”一个应用并销毁视图的话,请调用`AppRegistry.unmountApplicationComponentAtRootTag`方法,参数为在`runApplication`中使用的标签名。它们必须严格匹配。
+
+`AppRegistry`应当在`require`序列中尽可能早的被require到,以确保JS运行环境在其它模块之前被准备好。
+
+### 方法
+
+
+
static registerConfig(config: Array<AppConfig>) #
+
static registerComponent(appKey: string, getComponentFunc: ComponentProvider) #
+
static registerRunnable(appKey: string, func: Function) #
+
+
static runApplication(appKey: string, appParameters: any) #
+
static unmountApplicationComponentAtRootTag(rootTag: number) #
+
diff --git a/docs/docs/0.43/appstate.md b/docs/docs/0.43/appstate.md
new file mode 100644
index 0000000..a824b94
--- /dev/null
+++ b/docs/docs/0.43/appstate.md
@@ -0,0 +1,157 @@
+`AppState`能告诉你应用当前是在前台还是在后台,并且能在状态变化的时候通知你。
+
+AppState通常在处理推送通知的时候用来决定内容和对应的行为。
+
+### App States
+
+* `active` - 应用正在前台运行
+* `background` - 应用正在后台运行。用户既可能在别的应用中,也可能在桌面。
+* `inactive` - 这是一个过渡状态,不会在正常的React Native应用中出现。
+
+要了解更多信息,可以阅读[Apple的文档](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)。
+
+### 基本用法
+
+要获取当前的状态,你可以使用`AppState.currentState`,这个变量会一直保持更新。不过在启动的过程中,`currentState`可能为null,直到`AppState`从原生代码得到通知为止。
+
+```javascript
+constructor(props) {
+ super(props);
+ this.state = {
+ currentAppState: AppState.currentState,
+ };
+}
+componentDidMount() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+}
+componentWillUnmount() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+}
+_handleAppStateChange = (nextAppState) => {
+ if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
+ console.log('App has come to the foreground!')
+ }
+ this.setState({appState: nextAppState});
+}
+render() {
+ return (
+ Current state is: {this.state.currentAppState}
+ );
+}
+```
+
+上面的这个例子只会显示"Current state is: active",这是因为应用只有在`active`状态下才能被用户看到。并且null状态只会在一开始的一瞬间出现。
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听函数,用于监听应用状态的变化。type参数应填`change` 。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
移除一个监听函数。type参数应填change。
+
+
+
+
+### 属性
+
+
+
+
currentState: TypeCastExpression #
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ AppState,
+ Text,
+ View
+} = ReactNative;
+
+var AppStateSubscription = React.createClass({
+ getInitialState() {
+ return {
+ appState: AppState.currentState,
+ previousAppStates: [],
+ memoryWarnings: 0,
+ };
+ },
+ componentDidMount: function() {
+ AppState.addEventListener('change', this._handleAppStateChange);
+ AppState.addEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ componentWillUnmount: function() {
+ AppState.removeEventListener('change', this._handleAppStateChange);
+ AppState.removeEventListener('memoryWarning', this._handleMemoryWarning);
+ },
+ _handleMemoryWarning: function() {
+ this.setState({memoryWarnings: this.state.memoryWarnings + 1});
+ },
+ _handleAppStateChange: function(appState) {
+ var previousAppStates = this.state.previousAppStates.slice();
+ previousAppStates.push(this.state.appState);
+ this.setState({
+ appState,
+ previousAppStates,
+ });
+ },
+ render() {
+ if (this.props.showMemoryWarnings) {
+ return (
+
+ {this.state.memoryWarnings}
+
+ );
+ }
+ if (this.props.showCurrentOnly) {
+ return (
+
+ {this.state.appState}
+
+ );
+ }
+ return (
+
+ {JSON.stringify(this.state.previousAppStates)}
+
+ );
+ }
+});
+
+exports.title = 'AppState';
+exports.description = 'app background status';
+exports.examples = [
+ {
+ title: 'AppState.currentState',
+ description: 'Can be null on app initialization',
+ render() { return {AppState.currentState} ; }
+ },
+ {
+ title: 'Subscribed AppState:',
+ description: 'This changes according to the current state, so you can only ever see it rendered as "active"',
+ render(): ReactElement { return ; }
+ },
+ {
+ title: 'Previous states:',
+ render(): ReactElement { return ; }
+ },
+ {
+ platform: 'ios',
+ title: 'Memory Warnings',
+ description: 'In the IOS simulator, hit Shift+Command+M to simulate a memory warning.',
+ render(): ReactElement { return ; }
+ },
+];
+```
diff --git a/docs/docs/0.43/asyncstorage.md b/docs/docs/0.43/asyncstorage.md
new file mode 100644
index 0000000..d1cc11d
--- /dev/null
+++ b/docs/docs/0.43/asyncstorage.md
@@ -0,0 +1,76 @@
+AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统,它对于App来说是全局性的。它用来代替LocalStorage。
+
+我们推荐您在AsyncStorage的基础上做一层抽象封装,而不是直接使用AsyncStorage。
+
+__译注__:推荐由`React Native中文网`封装维护的[`react-native-storage`](https://github.com/sunnylqm/react-native-storage/blob/master/README-CHN.md)模块,提供了较多便利功能。
+
+本模块的JS代码提供了对原生实现的一个封装,以提供一个更清晰的JS API、返回真正的错误对象,以及简单的单项对象操作函数。每个方法都会返回一个`Promise`对象。
+
+### 方法
+
+
+
+
static getItem(key: string, callback?: ?(error: ?Error, result: ?string) => void) #
+
+
读取key字段并将结果作为第二个参数传递给callback。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static setItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
将key字段的值设置成value,并在完成后调用callback函数。如果有任何错误发生,则会传递一个Error对象作为第一个参数。返回一个Promise对象。
+
+
+
+
static removeItem(key: string, callback?: ?(error: ?Error) => void) #
+
+
删除一个字段。返回一个Promise对象。
+
+
+
+
static mergeItem(key: string, value: string, callback?: ?(error: ?Error) => void) #
+
+
假设已有的值和新的值都是字符串化的JSON,则将两个值合并。返回一个Promise对象。还没有被所有原生实现都支持。
+
+
+
+
static clear(callback?: ?(error: ?Error) => void) #
+
+
删除全部的 AsyncStorage数据,不论来自什么库或调用者。通常不应该调用这个函数——使用removeItem或者multiRemove来清除你自己的key。返回一个Promise对象。
+
+
+
+
static getAllKeys(callback?: ?(error: ?Error, keys: ?Array<string>) => void) #
+
+
获取所有 本应用可以访问到的数据,不论来自什么库或调用者。返回一个Promise对象。
+
+
+
static flushGetRequests() #
+
+
static multiGet(keys: Array<string>, callback?: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void) #
+
+
获取keys所包含的所有字段的值,调用callback回调函数时返回一个key-value数组形式的数组。返回一个Promise对象。
+
multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
+
+
+
+
static multiSet(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
multiSet和multiMerge都接受一个与multiGet输出值一致的key-value数组的数组。返回一个Promise对象。
+
multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
+
+
+
+
static multiRemove(keys: Array<string>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
删除所有键在keys数组中的数据。返回一个Promise对象。
+
+
+
+
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: ?(errors: ?Array<Error>) => void) #
+
+
将多个输入的值和已有的值合并,要求都是字符串化的JSON。返回一个Promise对象。
+
还没有被所有原生实现都支持。
+
+
+
diff --git a/docs/docs/0.43/backandroid.md b/docs/docs/0.43/backandroid.md
new file mode 100644
index 0000000..b7c014a
--- /dev/null
+++ b/docs/docs/0.43/backandroid.md
@@ -0,0 +1,22 @@
+监听硬件的`back`键操作。如果没有任何监听函数,或者监听函数的返回值不是true,则会调用默认的back键功能来退出应用。
+
+例子:
+
+```javascript
+BackAndroid.addEventListener('hardwareBackPress', function() {
+ if (!this.onMainScreen()) {
+ this.goBack();
+ return true;
+ }
+ return false;
+});
+```
+__译注__:以上的`this.onMainScreen()`和`this.goBack()`两个方法都只是伪方法,需要你自己去实现!具体可以参考这篇[博文](http://bbs.reactnative.cn/topic/480)。
+
+### 方法
+
+
+
+
static addEventListener(eventName: BackPressEventName, handler: Function) #
+
static removeEventListener(eventName: BackPressEventName, handler: Function) #
+
diff --git a/docs/docs/0.43/button.md b/docs/docs/0.43/button.md
new file mode 100644
index 0000000..c8e75cc
--- /dev/null
+++ b/docs/docs/0.43/button.md
@@ -0,0 +1,134 @@
+一个简单的跨平台的按钮组件。可以进行一些简单的定制。
+
+
+
+如果这个组件外观并不怎么搭配你的设计,那你可以使用`TouchableOpacity`或是`TouchableNativeFeedback`组件来制作自己所需要的按钮,视频教程[如何制作一个按钮](http://v.youku.com/v_show/id_XMTQ5OTE3MjkzNg==.html?f=26822355&from=y1.7-1.3)讲述了完整的过程。或者你也可以在github.com网站上搜索'react native button'来看看社区其他人的作品。
+
+
+用法示例:
+
+```js
+
+```
+
+### 属性
+
+
accessibilityLabel string #
+
用于给残障人士显示的文本(比如读屏器软件可能会读取这一内容)
+
+
+
文本的颜色(iOS),或是按钮的背景色(Android)
+
+
+
+
+
+
+### 例子
+
+```javascript
+use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ Alert,
+ Button,
+ View,
+} = ReactNative;
+
+const onButtonPress = () => {
+ Alert.alert('Button has been pressed!');
+};
+
+exports.displayName = 'ButtonExample';
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Simple React Native button component.';
+
+exports.examples = [
+ {
+ title: 'Simple Button',
+ description: 'The title and onPress handler are required. It is ' +
+ 'recommended to set accessibilityLabel to help make your app usable by ' +
+ 'everyone.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Adjusted color',
+ description: 'Adjusts the color in a way that looks standard on each ' +
+ 'platform. On iOS, the color prop controls the color of the text. On ' +
+ 'Android, the color adjusts the background color of the button.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Fit to text layout',
+ description: 'This layout strategy lets the title define the width of ' +
+ 'the button',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Disabled Button',
+ description: 'All interactions for the component are disabled.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+];
+```
diff --git a/docs/docs/0.43/cameraroll.md b/docs/docs/0.43/cameraroll.md
new file mode 100644
index 0000000..da08b4d
--- /dev/null
+++ b/docs/docs/0.43/cameraroll.md
@@ -0,0 +1,175 @@
+`CameraRoll`模块提供了访问本地相册的功能。在iOS上使用这个模块之前,你需要先链接`RCTCameraRoll`库,具体做法请参考[链接原生库](linking-libraries-ios.html)文档。
+
+**译注**:本模块只提供了基本的访问图片的功能,并没有提供相册界面。对于多数开发者来说,可能[react-native-image-picker](https://github.com/marcshilling/react-native-image-picker)的功能更为完整易用。
+
+### iOS 10的权限要求
+从iOS10开始,访问相册需要用户授权。你需要在`Info.plist`中添加一条名为`NSCameraUsageDescription`的键,然后在其值中填写向用户请求权限的具体描述。编辑完成后这个键在Xcode中实际会显示为`Privacy - Camera Usage Description`。
+
+### 截图
+
+
+### 方法
+
+
+
+
static saveImageWithTag(tag) #
+
+
保存一个图片到相册。
+
@param {string} tag 在安卓上,本参数是一个本地URI,例如"file:///sdcard/img.png".
+
在iOS设备上可能是以下之一:
+
+ 本地URI
+ 资源库的标签
+ 非以上两种类型,表示图片数据将会存储在内存中(并且在本进程持续的时候一直会占用内存)。
+
+
返回一个Promise,操作成功时返回新的URI。
+
+
+
+
static saveToCameraRoll(tag, type?) #
+
把图片或视频保存到相册中。
+
On Android, the tag must be a local image or video URI, such as "file:///sdcard/img.png".
On iOS, the tag can be any image URI (including local, remote asset-library and base64 data URIs) or a local video file URI (remote or data URIs are not supported for saving video at this time).
+
If the tag has a file extension of .mov or .mp4, it will be inferred as a video. Otherwise it will be treated as a photo. To override the automatic choice, you can pass an optional
+type parameter that must be one of 'photo' or 'video'.
Returns a Promise which will resolve with the new URI.
+
+
+
+
static getPhotos(params: object) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ CameraRoll,
+ Image,
+ Slider,
+ StyleSheet,
+ Switch,
+ Text,
+ View,
+ TouchableOpacity
+} = ReactNative;
+
+const invariant = require('fbjs/lib/invariant');
+
+const CameraRollView = require('./CameraRollView');
+
+const AssetScaledImageExampleView = require('./AssetScaledImageExample');
+
+class CameraRollExample extends React.Component {
+ state = {
+ groupTypes: 'SavedPhotos',
+ sliderValue: 1,
+ bigImages: true,
+ };
+ _cameraRollView: ?CameraRollView;
+ render() {
+ return (
+
+
+ {(this.state.bigImages ? 'Big' : 'Small') + ' Images'}
+
+ {'Group Type: ' + this.state.groupTypes}
+ { this._cameraRollView = ref; }}
+ batchSize={20}
+ groupTypes={this.state.groupTypes}
+ renderImage={this._renderImage}
+ />
+
+ );
+ }
+
+ loadAsset = (asset) => {
+ if (this.props.navigator) {
+ this.props.navigator.push({
+ title: 'Camera Roll Image',
+ component: AssetScaledImageExampleView,
+ backButtonTitle: 'Back',
+ passProps: { asset: asset },
+ });
+ }
+ };
+
+ _renderImage = (asset) => {
+ const imageSize = this.state.bigImages ? 150 : 75;
+ const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
+ const {location} = asset.node;
+ const locationStr = location ? JSON.stringify(location) : 'Unknown location';
+ return (
+
+
+
+
+ {asset.node.image.uri}
+ {locationStr}
+ {asset.node.group_name}
+ {new Date(asset.node.timestamp).toString()}
+
+
+
+ );
+ };
+
+ _onSliderChange = (value) => {
+ const options = CameraRoll.GroupTypesOptions;
+ const index = Math.floor(value * options.length * 0.99);
+ const groupTypes = options[index];
+ if (groupTypes !== this.state.groupTypes) {
+ this.setState({groupTypes: groupTypes});
+ }
+ };
+
+ _onSwitchChange = (value) => {
+ invariant(this._cameraRollView, 'ref should be set');
+ this._cameraRollView.rendererChanged();
+ this.setState({ bigImages: value });
+ };
+}
+
+const styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ flex: 1,
+ },
+ url: {
+ fontSize: 9,
+ marginBottom: 14,
+ },
+ image: {
+ margin: 4,
+ },
+ info: {
+ flex: 1,
+ },
+});
+
+exports.title = 'Camera Roll';
+exports.description = 'Example component that uses CameraRoll to list user\'s photos';
+exports.examples = [
+ {
+ title: 'Photos',
+ render(): React.Element { return ; }
+ }
+];
+```
diff --git a/docs/docs/0.43/clipboard.md b/docs/docs/0.43/clipboard.md
new file mode 100644
index 0000000..94eae4b
--- /dev/null
+++ b/docs/docs/0.43/clipboard.md
@@ -0,0 +1,87 @@
+`Clipboard`组件可以在iOS和Android的剪贴板中读写内容。
+
+### 方法
+
+
+
static getString() #
+
获取剪贴板的文本内容,返回一个Promise你可以用下面的方式来调用。
+
async _getContent( ) {
+ var content = await
+ Clipboard. getString( ) ;
+ }
+
+
+
static setString(content: string) #
+
+
设置剪贴板的文本内容。你可以用下面的方式来调用。
+
_setContent( ) {
+ Clipboard. setString( 'hello world' ) ;
+ }
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Clipboard,
+ View,
+ Text,
+} = ReactNative;
+
+var ClipboardExample = React.createClass({
+ getInitialState() {
+ return {
+ content: 'Content will appear here'
+ };
+ },
+
+ async _setClipboardContent(){
+ Clipboard.setString('Hello World');
+ try {
+ var content = await Clipboard.getString();
+ this.setState({content});
+ } catch (e) {
+ this.setState({content:e.message});
+ }
+ },
+
+ render() {
+ return (
+
+
+ Tap to put "Hello World" in the clipboard
+
+
+ {this.state.content}
+
+
+ );
+ }
+});
+
+exports.title = 'Clipboard';
+exports.description = 'Show Clipboard contents.';
+exports.examples = [
+ {
+ title: 'Clipboard.setString() and getString()',
+ render() {
+ return ;
+ }
+ }
+];
+```
diff --git a/docs/docs/0.43/colors.md b/docs/docs/0.43/colors.md
new file mode 100644
index 0000000..2912ede
--- /dev/null
+++ b/docs/docs/0.43/colors.md
@@ -0,0 +1,166 @@
+以下这些格式的颜色代码都是支持的:
+
+ - `'#f0f'` (#rgb)
+ - `'#f0fc'` (#rgba)
+ - `'#ff00ff'` (#rrggbb)
+ - `'#ff00ff00'` (#rrggbbaa)
+ - `'rgb(255, 255, 255)'`
+ - `'rgba(255, 255, 255, 1.0)'`
+ - `'hsl(360, 100%, 100%)'`
+ - `'hsla(360, 100%, 100%, 1.0)'`
+ - `'transparent'`
+ - `'red'`
+ - `0xff00ff00` (0xrrggbbaa)
+
+对于有称谓的颜色,React Native遵循的是[CSS3的规范](http://www.w3.org/TR/css3-color/#svg-color):
+
+
+ aliceblue (#f0f8ff)
+ antiquewhite (#faebd7)
+ aqua (#00ffff)
+ aquamarine (#7fffd4)
+ azure (#f0ffff)
+ beige (#f5f5dc)
+ bisque (#ffe4c4)
+ black (#000000)
+ blanchedalmond (#ffebcd)
+ blue (#0000ff)
+ blueviolet (#8a2be2)
+ brown (#a52a2a)
+ burlywood (#deb887)
+ cadetblue (#5f9ea0)
+ chartreuse (#7fff00)
+ chocolate (#d2691e)
+ coral (#ff7f50)
+ cornflowerblue (#6495ed)
+ cornsilk (#fff8dc)
+ crimson (#dc143c)
+ cyan (#00ffff)
+ darkblue (#00008b)
+ darkcyan (#008b8b)
+ darkgoldenrod (#b8860b)
+ darkgray (#a9a9a9)
+ darkgreen (#006400)
+ darkgrey (#a9a9a9)
+ darkkhaki (#bdb76b)
+ darkmagenta (#8b008b)
+ darkolivegreen (#556b2f)
+ darkorange (#ff8c00)
+ darkorchid (#9932cc)
+ darkred (#8b0000)
+ darksalmon (#e9967a)
+ darkseagreen (#8fbc8f)
+ darkslateblue (#483d8b)
+ darkslategray (#2f4f4f)
+ darkslategrey (#2f4f4f)
+ darkturquoise (#00ced1)
+ darkviolet (#9400d3)
+ deeppink (#ff1493)
+ deepskyblue (#00bfff)
+ dimgray (#696969)
+ dimgrey (#696969)
+ dodgerblue (#1e90ff)
+ firebrick (#b22222)
+ floralwhite (#fffaf0)
+ forestgreen (#228b22)
+ fuchsia (#ff00ff)
+ gainsboro (#dcdcdc)
+ ghostwhite (#f8f8ff)
+ gold (#ffd700)
+ goldenrod (#daa520)
+ gray (#808080)
+ green (#008000)
+ greenyellow (#adff2f)
+ grey (#808080)
+ honeydew (#f0fff0)
+ hotpink (#ff69b4)
+ indianred (#cd5c5c)
+ indigo (#4b0082)
+ ivory (#fffff0)
+ khaki (#f0e68c)
+ lavender (#e6e6fa)
+ lavenderblush (#fff0f5)
+ lawngreen (#7cfc00)
+ lemonchiffon (#fffacd)
+ lightblue (#add8e6)
+ lightcoral (#f08080)
+ lightcyan (#e0ffff)
+ lightgoldenrodyellow (#fafad2)
+ lightgray (#d3d3d3)
+ lightgreen (#90ee90)
+ lightgrey (#d3d3d3)
+ lightpink (#ffb6c1)
+ lightsalmon (#ffa07a)
+ lightseagreen (#20b2aa)
+ lightskyblue (#87cefa)
+ lightslategray (#778899)
+ lightslategrey (#778899)
+ lightsteelblue (#b0c4de)
+ lightyellow (#ffffe0)
+ lime (#00ff00)
+ limegreen (#32cd32)
+ linen (#faf0e6)
+ magenta (#ff00ff)
+ maroon (#800000)
+ mediumaquamarine (#66cdaa)
+ mediumblue (#0000cd)
+ mediumorchid (#ba55d3)
+ mediumpurple (#9370db)
+ mediumseagreen (#3cb371)
+ mediumslateblue (#7b68ee)
+ mediumspringgreen (#00fa9a)
+ mediumturquoise (#48d1cc)
+ mediumvioletred (#c71585)
+ midnightblue (#191970)
+ mintcream (#f5fffa)
+ mistyrose (#ffe4e1)
+ moccasin (#ffe4b5)
+ navajowhite (#ffdead)
+ navy (#000080)
+ oldlace (#fdf5e6)
+ olive (#808000)
+ olivedrab (#6b8e23)
+ orange (#ffa500)
+ orangered (#ff4500)
+ orchid (#da70d6)
+ palegoldenrod (#eee8aa)
+ palegreen (#98fb98)
+ paleturquoise (#afeeee)
+ palevioletred (#db7093)
+ papayawhip (#ffefd5)
+ peachpuff (#ffdab9)
+ peru (#cd853f)
+ pink (#ffc0cb)
+ plum (#dda0dd)
+ powderblue (#b0e0e6)
+ purple (#800080)
+ rebeccapurple (#663399)
+ red (#ff0000)
+ rosybrown (#bc8f8f)
+ royalblue (#4169e1)
+ saddlebrown (#8b4513)
+ salmon (#fa8072)
+ sandybrown (#f4a460)
+ seagreen (#2e8b57)
+ seashell (#fff5ee)
+ sienna (#a0522d)
+ silver (#c0c0c0)
+ skyblue (#87ceeb)
+ slateblue (#6a5acd)
+ slategray (#708090)
+ slategrey (#708090)
+ snow (#fffafa)
+ springgreen (#00ff7f)
+ steelblue (#4682b4)
+ tan (#d2b48c)
+ teal (#008080)
+ thistle (#d8bfd8)
+ tomato (#ff6347)
+ turquoise (#40e0d0)
+ violet (#ee82ee)
+ wheat (#f5deb3)
+ white (#ffffff)
+ whitesmoke (#f5f5f5)
+ yellow (#ffff00)
+ yellowgreen (#9acd32)
+
diff --git a/docs/docs/0.43/communication-ios.md b/docs/docs/0.43/communication-ios.md
new file mode 100644
index 0000000..a38a4d4
--- /dev/null
+++ b/docs/docs/0.43/communication-ios.md
@@ -0,0 +1,190 @@
+通过[植入原生应用](integration-with-existing-apps.html.html)和[原生UI组件](native-component-ios.html)两篇文档,我们学习了React Native和原生组件的互相整合。在整合的过程中,我们会需要在两个世界间互相通信。有些方法已经在其他的指南中提到了,这篇文章总结了所有可行的技术。
+## 简介
+React Native是从React中得到的灵感,因此基本的信息流是类似的。在React中信息是单向的。我们维护了组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(properties)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
+
+React Native也运用了相同的概念。只要我们完全在框架内构建应用,就可以通过属性和回调函数来调动整个应用。但是,当我们混合React Native和原生组件时,我们需要一些特殊的,跨语言的机制来传递信息。
+
+## 属性
+属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到React Native或者从React Native到原生组件。
+
+### 从原生组件传递属性到React Native
+
+我们使用`RCTRootView`将React Natvie视图封装到原生组件中。`RCTRootView`是一个`UIView`容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。
+
+通过`RCTRootView`的初始化函数你可以将任意属性传递给React Native应用。参数`initialProperties `必须是`NSDictionary`的一个实例。这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。
+```
+NSArray *imageList = @[@"http://foo.com/bar1.png",
+ @"http://foo.com/bar2.png"];
+
+NSDictionary *props = @{@"images" : imageList};
+
+RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"ImageBrowserApp"
+ initialProperties:props];
+```
+
+```
+'use strict';
+import React, { Component } from 'react';
+import {
+ AppRegistry,
+ View,
+ Image,
+} from 'react-native';
+
+class ImageBrowserApp extends Component {
+ renderImage(imgURI) {
+ return (
+
+ );
+ }
+ render() {
+ return (
+
+ {this.props.images.map(this.renderImage)}
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);
+```
+
+`RCTRootView`同样提供了一个可读写的属性`appProperties`。在`appProperties`设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。
+```
+NSArray *imageList = @[@"http://foo.com/bar3.png",
+ @"http://foo.com/bar4.png"];
+rootView.appProperties = @{@"images" : imageList};
+```
+你可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。
+更新属性时并不能做到只更新一部分属性。我们建议你自己封装一个函数来构造属性。
+
+> 注意:目前,最顶层的RN组件(即registerComponent方法中调用的那个)的`componentWillReceiveProps`和`componentWillUpdateProps`方法在属性更新后不会触发。但是,你可以通过`componentWillMount`访问新的属性值。
+
+## 从React Native传递属性到原生组件
+
+这篇[文档](native-component-ios.html#属性)详细讨论了暴露原生组件属性的问题。简而言之,在你自定义的原生组件中通过`RCT_CUSTOM_VIEW_PROPERTY`宏导出属性,就可以直接在React Native中使用,就好像它们是普通的React Native组件一样。
+
+## 属性的限制
+跨语言属性的主要缺点是不支持回调方法,因而无法实现自下而上的数据绑定。设想你有一个小的RN视图,当一个JS动作触发时你想从原生的父视图中移除它。此时你会发现根本做不到,因为信息需要自下而上进行传递。
+
+虽然我们有跨语言回调([参阅这里](native-modules-ios.html#回调函数)),但是这些回调函数并不总能满足需求。最主要的问题是它们并不是被设计来当作属性进行传递。这一机制的本意是允许我们从JS触发一个原生动作,然后用JS处理那个动作的处理结果。
+
+## 其他的跨语言交互(事件和原生模块)
+如上一章所说,使用属性总会有一些限制。有时候属性并不足以满足应用逻辑,因此我们需要更灵活的解决办法。这一章描述了其他的在React Native中可用的通信方法。他们可以用来内部通信(在JS和RN的原生层之间),也可以用作外部通信(在RN和纯原生部分之间)。
+
+React Native允许使用跨语言的函数调用。你可以在JS中调用原生代码,也可以在原生代码中调用JS。在不同端需要用不同的方法来实现相同的目的。在原生代码中我们使用事件机制来调度JS中的处理函数,而在React Native中我们直接使用原生模块导出的方法。
+
+### 从原生代码调用React Natvie函数(事件)
+事件的详细用法在这篇[文章](native-component-ios.html#事件)中进行了讨论。注意使用事件无法确保执行的时间,因为事件的处理函数是在单独的线程中执行。
+
+事件很强大,它可以不需要引用直接修改React Native组件。但是,当你使用时要注意下面这些陷阱:
+
+* 由于事件可以从各种地方产生,它们可能导致混乱的依赖。
+* 事件共享相同的命名空间,因此你可能遇到名字冲突。冲突不会在编写代码时被探测到,因此很难排错。
+* 如果你使用了同一个React Native组件的多个引用,然后想在事件中区分它们,name你很可能需要在事件中同时传递一些标识(你可以使用原生视图中的`reactTag`作为标识)。
+
+在React Native中嵌入原生组件时,通常的做法是用原生组件的RCTViewManager作为视图的代理,通过bridge向JS发送事件。这样可以集中在一处调用相关的事件。
+
+### 从React Native中调用原生方法(原生模块)
+
+原生模块是JS中也可以使用的Objective-C类。一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的。他们可以导出任意的函数和常量给React Native。相关细节可以参阅这篇[文章](native-modules-ios.html#content)。
+
+事实上原生模块的单实例模式限制了嵌入。假设我们有一个React Native组件被嵌入了一个原生视图,并且我们希望更新原生的父视图。使用原生模块机制,我们可以导出一个函数,不仅要接收预设参数,还要接收父视图的标识。这个标识将会用来获得父视图的引用以更新父视图。那样的话,我们需要维持模块中标识到原生模块的映射。
+虽然这个解决办法很复杂,它仍被用在了管理所有React Native视图的`RCTUIManager`类中,
+
+原生模块同样可以暴露已有的原生库给JS,[地理定位库](https://github.com/facebook/react-native/tree/master/Libraries/Geolocation)就是一个现成的例子。
+
+>警告:所有原生模块共享同一个命名空间。创建新模块时注意命名冲突。
+
+## 布局计算流
+
+当集成原生模块和React Natvie时,我们同样需要一个能协同不同的布局系统的办法。这一章节讨论了常见的布局问题,并且提供了解决机制的简单说明。
+
+### 在React Native中嵌入一个原生组件
+这个情况在[这篇文章](native-component-ios.html#样式)中进行了讨论。基本上,由于所有的原生视图都是`UIView`的子集,大多数类型和尺寸属性将和你期望的一样可以使用。
+
+### 在原生中嵌入一个React Native组件
+
+#### 固定大小的React Native内容
+
+最简单的情况是一个对于原生端已知的,固定大小的React Native应用,尤其是一个全屏的React Native视图。如果我们需要一个小一点的根视图,我们可以明确的设置`RCTRootView`的frame。
+比如说,创建一个200像素高,宿主视图那样宽的RN app,我们可以这样做:
+```
+// SomeViewController.m
+
+- (void)viewDidLoad
+{
+ [...]
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:appName
+ initialProperties:props];
+ rootView.frame = CGMakeRect(0, 0, self.view.width, 200);
+ [self.view addSubview:rootView];
+}
+```
+当我们创建了一个固定大小的根视图,则需要在JS中遵守它的边界。换句话说,我们需要确保React Native内容能够在固定的大小中放下。最简单的办法是使用flexbox布局。如果你使用绝对定位,并且React组件在根视图边界外可见,则React Native组件将会和原生视图重叠,导致某些不符合期望的行为。比如说,当你点击根视图边界之外的区域`TouchableHighlight`将不会高亮。
+通过重新设置frame的属性来动态更新根视图的大小是完全可行的。React Native将会关注内容布局的变化。
+
+#### 弹性大小的React Native
+有时候我们需要渲染一些不知道大小的内容。假设尺寸将会在JS中动态指定。我们有两个解决办法。
+
+* 你可以将React Native视图包裹在`ScrollView`中。这样可以保证你的内容总是可以访问,并且不会和原生视图重叠。
+* React Native允许你在JS中决定RN应用的尺寸,并且将它传递给宿主视图`RCTRootView`。然后宿主视图将重新布局子视图,保证UI统一。我们通过`RCTRootView`的弹性模式来达到目的。
+
+`RCTRootView`支持4种不同的弹性模式:
+```
+// RCTRootView.h
+
+typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
+ RCTRootViewSizeFlexibilityNone = 0,
+ RCTRootViewSizeFlexibilityWidth,
+ RCTRootViewSizeFlexibilityHeight,
+ RCTRootViewSizeFlexibilityWidthAndHeight,
+};
+```
+默认值是`RCTRootViewSizeFlexibilityNone`,表示使用固定大小的根视图(仍然可以通过`setFrame`更改)。其他三种模式可以跟踪React Native尺寸的变化。比如说,设置模式为`RCTRootViewSizeFlexibilityHeight`,React Native将会测量内容的高度然后传递回
+`RCTRootView`的代理。代理可以执行任意的行为,包括设置根视图的frame以使内容尺寸相匹配。
+代理仅仅在内容的尺寸发生变化时才进行调用。
+
+>注意:在JS和原生中都设置弹性尺寸可能导致不确定的行为。比如--不要在设置`RCTRootView`为`RCTRootViewSizeFlexibilityWidth`时同时指定最顶层的RN组件宽度可变(使用Flexbox)。
+
+看一个例子。
+```
+// FlexibleSizeExampleView.m
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ [...]
+
+ _rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"FlexibilityExampleApp"
+ initialProperties:@{}];
+
+ _rootView.delegate = self;
+ _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
+ _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0);
+}
+
+#pragma mark - RCTRootViewDelegate
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
+{
+ CGRect newFrame = rootView.frame;
+ newFrame.size = rootView.intrinsicSize;
+
+ rootView.frame = newFrame;
+}
+```
+在例子中我们使用一个`FlexibleSizeExampleView`视图来包含根视图。我们创建了根视图,初始化并且设置了代理。代理将会处理尺寸更新。然后,我们设置根视图的弹性尺寸为`RCTRootViewSizeFlexibilityHeight`,意味着`rootViewDidChangeIntrinsicSize:`方法将会在每次React Native内容高度变化时进行调用。最后,我们设置根视图的宽度和位置。注意我们也设置了高度,但是并没有效果,因为我们已经将高度设置为根据RN内容进行弹性变化了。
+
+你可以在这里查看完整的例子[源代码](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m)。
+
+动态改变根视图的弹性模式是可行的。改变根视图的弹性模式将会导致布局的重新计算,并且在重新量出内容尺寸时会调用`rootViewDidChangeIntrinsicSize`方法。
+
+>注意:React Native布局是通过一个特殊的线程进行计算,而原生UI视图是通过主线程更新。这可能导致短暂的原生端和React Native端的不一致。这是一个已知的问题,我们的团队已经在着手解决不同源的UI同步更新。
+>注意:除非根视图成为其他视图的子视图,否则React Native不会进行任何的布局计算。如果你想在还没有获得React Native视图的尺寸之前先隐藏视图,请将根视图添加为子视图并且在初始化的时候进行隐藏(使用`UIView`的`hidden`属性),然后在代理方法中改变它的可见性。
+
+
+
+
+
diff --git a/docs/docs/0.43/datepickerandroid.md b/docs/docs/0.43/datepickerandroid.md
new file mode 100644
index 0000000..6bf2f5b
--- /dev/null
+++ b/docs/docs/0.43/datepickerandroid.md
@@ -0,0 +1,57 @@
+本组件会打开一个标准的Android日期选择器的对话框。
+
+### 示例
+```js
+try {
+ const {action, year, month, day} = await DatePickerAndroid.open({
+ // 要设置默认值为今天的话,使用`new Date()`即可。
+ // 下面显示的会是2020年5月25日。月份是从0开始算的。
+ date: new Date(2020, 4, 25)
+ });
+ if (action !== DatePickerAndroid.dismissedAction) {
+ // 这里开始可以处理用户选好的年月日三个参数:year, month (0-11), day
+ }
+} catch ({code, message}) {
+ console.warn('Cannot open date picker', message);
+}
+```
+
+### 方法
+
+
+
static open(options: Object) #
+
+
打开一个标准的Android日期选择器的对话框。
+
可选的options对象的key值如下:
+
+ date (Date对象或毫秒时间戳) - 默认显示的日期
+ minDate (Date对象或毫秒时间戳) - 可选的最小日期
+ maxDate (Date对象或毫秒时间戳) - 可选的最大日期
+ mode ((enum('calendar', 'spinner', 'default')) - 设置选择器的模式:
+
+ calendar: Show a date picker in calendar mode.
+ spinner: Show a date picker in spinner mode.
+ default: Show a default native date picker(spinner/calendar) based on android versions.
+
+
+
+ 在用户选好日期后返回一个Promise,回调参数为一个对象,其中包含有action, year,
+ month (0-11),
+ day。如果用户取消了对话框,Promise仍然会执行,返回的action为DatePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必 先检查action的值。
+
+
+
static dateSetAction() #
+
+
+
+
static dismissedAction() #
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/datepickerios.md b/docs/docs/0.43/datepickerios.md
new file mode 100644
index 0000000..7621d1f
--- /dev/null
+++ b/docs/docs/0.43/datepickerios.md
@@ -0,0 +1,217 @@
+使用`DatePickerIOS`来在iOS平台上渲染一个日期/时间选择器。这是一个受约束的(Controlled)组件,所以你必须监听`onDateChange`回调函数并且及时更新`date`属性来使得组件更新,否则用户的修改会立刻被撤销来确保当前显示值和`props.date`一致。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
+
maximumDate Date #
+
+
可选的最大日期。
+
限制可选的日期/时间范围。
+
+
+
+
minimumDate Date #
+
+
可选的最小日期。
+
限制可选的日期/时间范围。
+
+
+
+
minuteInterval enum(1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30) #
+
+
+
+
mode enum('date', 'time', 'datetime') #
+
+
+
+
onDateChange function #
+
+
当用户修改日期或时间时调用此回调函数。
+
唯一的参数是一个日期对象,表示新的日期和时间。
+
+
+
+
timeZoneOffsetInMinutes number #
+
+
时区差,单位是分钟。
+
默认情况下,选择器会选择设备的默认时区。通过此参数,可以指定一个时区。举个例子,要使用北京时间(东八区),可以传递8 * 60。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ DatePickerIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ View,
+} = ReactNative;
+
+var DatePickerExample = React.createClass({
+ getDefaultProps: function () {
+ return {
+ date: new Date(),
+ timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ date: this.props.date,
+ timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
+ };
+ },
+
+ onDateChange: function(date) {
+ this.setState({date: date});
+ },
+
+ onTimezoneChange: function(event) {
+ var offset = parseInt(event.nativeEvent.text, 10);
+ if (isNaN(offset)) {
+ return;
+ }
+ this.setState({timeZoneOffsetInHours: offset});
+ },
+
+ render: function() {
+ // Ideally, the timezone input would be a picker rather than a
+ // text input, but we don't have any pickers yet :(
+ return (
+
+
+ {
+ this.state.date.toLocaleDateString() +
+ ' ' +
+ this.state.date.toLocaleTimeString()
+ }
+
+
+
+ hours from UTC
+
+
+
+
+
+
+
+
+ );
+ },
+});
+
+var WithLabel = React.createClass({
+ render: function() {
+ return (
+
+
+
+ {this.props.label}
+
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var Heading = React.createClass({
+ render: function() {
+ return (
+
+
+ {this.props.label}
+
+
+ );
+ }
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Select dates and times using the native UIDatePicker.';
+exports.examples = [
+{
+ title: '',
+ render: function(): ReactElement {
+ return ;
+ },
+}];
+
+var styles = StyleSheet.create({
+ textinput: {
+ height: 26,
+ width: 50,
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ padding: 4,
+ fontSize: 13,
+ },
+ labelContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginVertical: 2,
+ },
+ labelView: {
+ marginRight: 10,
+ paddingVertical: 2,
+ },
+ label: {
+ fontWeight: '500',
+ },
+ headingContainer: {
+ padding: 4,
+ backgroundColor: '#f6f7f8',
+ },
+ heading: {
+ fontWeight: '500',
+ fontSize: 14,
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/debugging.md b/docs/docs/0.43/debugging.md
new file mode 100644
index 0000000..1c6cc0a
--- /dev/null
+++ b/docs/docs/0.43/debugging.md
@@ -0,0 +1,140 @@
+## 访问App内的开发菜单
+
+你可以通过摇晃设备或是选择iOS模拟器的"Hardware"菜单中的"Shake Gesture"选项来打开开发菜单。另外,如果是在iOS模拟器中运行,还可以按下**`Command`**`⌘` + **`D`** 快捷键,Android模拟器对应的则是**`Command`**`⌘` + **`M`**(windows上可能是F1或者F2)。
+
+
+
+> 注意:在成品(release/producation builds)中开发者菜单会被关闭。
+
+## 刷新JavaScript
+
+传统的原生应用开发中,每一次修改都需要重新编译,但在RN中你只需要刷新一下JavaScript代码,就能立刻看到变化。具体的操作就是在开发菜单中点击"Reload"选项。也可以在iOS模拟器中按下**`Command`**`⌘` + **`R`** ,Android模拟器上对应的则是按两下**`R`**。(注意,某些RN版本可能在windows中reload无效,请等待官方修复)
+
+> 如果在iOS模拟器中按下**`Command`**`⌘` + **`R`**没啥感觉,则注意检查Hardware菜单中,Keyboard选项下的"Connect Hardware Keyboard"是否被选中。
+
+### 自动刷新
+
+选择开发菜单中的"Enable Live Reload"可以开启自动刷新,这样可以节省你开发中的时间。
+
+更神奇的是,你还可以保持应用的当前运行状态,修改后的JavaScript文件会自动注入进来(就好比行驶中的汽车不用停下就能更换新的轮胎)。要实现这一特性只需开启开发菜单中的[Hot Reloading](https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html)选项。
+
+> 某些情况下hot reload并不能顺利实施。如果碰到任何界面刷新上的问题,请尝试手动完全刷新。
+
+但有些时候你必须要重新编译应用才能使修改生效:
+
+* 增加了新的资源(比如给iOS的`Images.xcassets`或是Andorid的`res/drawable`文件夹添加了图片)
+* 更改了任何的原生代码(objective-c/swift/java)
+
+## 应用内的错误与警告提示(红屏和黄屏)
+
+红屏或黄屏提示都只会在开发版本中显示,正式的离线包中是不会显示的。
+
+### 红屏错误
+
+应用内的报错会以全屏红色显示在应用中(调试模式下),我们称为红屏(red box)报错。你可以使用`console.error()`来手动触发红屏错误。
+
+### 黄屏警告
+
+应用内的警告会以全屏黄色显示在应用中(调试模式下),我们称为黄屏(yellow box)报错。点击警告可以查看详情或是忽略掉。
+和红屏报警类似,你可以使用`console.warn()`来手动触发黄屏警告。
+在默认情况下,开发模式中启用了黄屏警告。可以通过以下代码关闭:
+```js
+console.disableYellowBox = true;
+console.warn('YellowBox is disabled.');
+```
+你也可以通过代码屏蔽指定的警告,像下面这样设置一个数组:
+```js
+console.ignoredYellowBox = ['Warning: ...'];
+```
+数组中的字符串就是要屏蔽的警告的开头的内容。(例如上面的代码会屏蔽掉所有以Warning开头的警告内容)
+
+> 红屏和黄屏在发布版(release/production)中都是自动禁用的。
+
+## 访问控制台日志
+
+在运行RN应用时,可以在终端中运行如下命令来查看控制台的日志:
+
+```
+$ react-native log-ios
+$ react-native log-android
+```
+
+此外,你也可以在iOS模拟器的菜单中选择`Debug → Open System Log...`来查看。如果是Android应用,无论是运行在模拟器或是真机上,都可以通过在终端命令行里运行`adb logcat *:S ReactNative:V ReactNativeJS:V`命令来查看。
+
+## Chrome开发者工具
+
+在开发者菜单中选择"Debug JS Remotely"选项,即可以开始在Chrome中调试JavaScript代码。点击这个选项的同时会自动打开调试页面 .
+
+在Chrome的菜单中选择`Tools → Developer Tools`可以打开开发者工具,也可以通过键盘快捷键来打开(Mac上是**`Command`**`⌘` + **`Option`**`⌥` + **`I`**,Windows上是**`Ctrl`** + **`Shift`** + **`I`**或是F12)。打开[有异常时暂停(Pause On Caught Exceptions)](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511)选项,能够获得更好的开发体验。
+
+__译注__:Chrome中并不能直接看到App的用户界面,而只能提供console的输出,以及在sources项中断点调试js脚本。
+
+> [目前无法正常使用React开发插件](https://github.com/facebook/react-devtools/issues/229)(就是某些教程或截图上提到的Chrome开发工具上多出来的React选项),但这并不影响代码的调试。如果你需要像调试web页面那样查看RN应用的jsx结构,暂时只能使用Nuclide的"React Native Inspector"这一功能来代替。
+
+### 使用Chrome开发者工具来在设备上调试
+
+对于iOS真机来说,需要打开 [`RCTWebSocketExecutor.m`](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m)文件,然后将其中的"localhost"改为你的电脑的IP地址,最后启用开发者菜单中的"Debug JS Remotely"选项。
+
+对于Android 5.0+设备(包括模拟器)来说,将设备通过USB连接到电脑上后,可以使用[`adb`命令行工具](http://developer.android.com/tools/help/adb.html)来设定从设备到电脑的端口转发:
+
+`adb reverse tcp:8081 tcp:8081`
+
+如果设备Android版本在5.0以下,则可以在开发者菜单中选择"Dev Settings - Debug server host for device",然后在其中填入电脑的”IP地址:端口“。
+
+> 如果在Chrome调试时遇到一些问题,那有可能是某些Chrome的插件引起的。试着禁用所有的插件,然后逐个启用,以确定是否某个插件影响到了调试。
+
+### 使用自定义的JavaScript调试器来调试
+
+如果想用其他的JavaScript调试器来代替Chrome,可以设置一个名为`REACT_DEBUGGER`的环境变量,其值为启动自定义调试器的命令。调试的流程依然是从开发者菜单中的"Debug JS Remotely"选项开始。
+
+被指定的调试器需要知道项目所在的目录(可以一次传递多个目录参数,以空格隔开)。例如,如果你设定了`REACT_DEBUGGER="node /某个路径/launchDebugger.js --port 2345 --type ReactNative"`,那么启动调试器的命令就应该是`node /某个路径/launchDebugger.js --port 2345 --type ReactNative /某个路径/你的RN项目目录`。
+
+> 以这种方式执行的调试器最好是一个短进程(short-lived processes),同时最好也不要有超过200k的文字输出。
+
+### 在Android上使用[Stetho](http://facebook.github.io/stetho/)来调试
+
+1. 在```android/app/build.gradle```文件中添加:
+
+ ```gradle
+ compile 'com.facebook.stetho:stetho:1.3.1'
+ compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
+ ```
+
+2. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+
+ ```java
+ import com.facebook.react.modules.network.ReactCookieJarContainer;
+ import com.facebook.stetho.Stetho;
+ import okhttp3.OkHttpClient;
+ import com.facebook.react.modules.network.OkHttpClientProvider;
+ import com.facebook.stetho.okhttp3.StethoInterceptor;
+ import java.util.concurrent.TimeUnit;
+ ```
+
+3. 在```android/app/src/main/java/com/{yourAppName}/MainApplication.java```文件中添加:
+ ```java
+ public void onCreate() {
+ super.onCreate();
+ Stetho.initializeWithDefaults(this);
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(0, TimeUnit.MILLISECONDS)
+ .readTimeout(0, TimeUnit.MILLISECONDS)
+ .writeTimeout(0, TimeUnit.MILLISECONDS)
+ .cookieJar(new ReactCookieJarContainer())
+ .addNetworkInterceptor(new StethoInterceptor())
+ .build();
+ OkHttpClientProvider.replaceOkHttpClient(client);
+ }
+ ```
+
+4. 运行```react-native run-android ```
+
+5. 打开一个新的Chrome选项卡,在地址栏中输入```chrome://inspect```并回车。在页面中选择'Inspect device' (标有"Powered by Stetho"字样)。
+
+## 调试原生代码
+
+在和原生代码打交道时(比如编写原生模块),可以直接从Android Studio或是Xcode中启动应用,并利用这些IDE的内置功能来调试(比如设置断点)。这一方面和开发原生应用并无二致。
+
+## 性能监测
+
+你可以在开发者菜单中选择"Pref Monitor"选项以开启一个悬浮层,其中会显示应用的当前帧数。
diff --git a/docs/docs/0.43/dimensions.md b/docs/docs/0.43/dimensions.md
new file mode 100644
index 0000000..b427a50
--- /dev/null
+++ b/docs/docs/0.43/dimensions.md
@@ -0,0 +1,23 @@
+__译注__:本模块用于获取设备屏幕的宽高。
+
+### 方法
+
+
+
+
static set(dims: {[key:string]: any}) #
+
+
这个函数只应该被原生代码调用。.
+
@param {object} dims 一个简单的字符串作为key的对象,包含了需要设置的尺寸信息。
+
+
+
+
static get(dim: string) #
+
+
初始的尺寸信息应该在runApplication之后被执行,所以它可以在任何其他的require被执行之前就可用。不过在稍后可能还会更新。
+
注意:尽管尺寸信息立即就可用,但它可能会在将来被修改(譬如设备的方向改变),所以基于这些常量的渲染逻辑和样式应当每次render之后都调用此函数,而不是将对应的值保存下来。(举例来说,你可能需要使用内联的样式而不是在StyleSheet中保存相应的尺寸)。
+
例子:var {height, width} = Dimensions.get('window');
+
@param {string} dim 想要获取的尺寸信息的字段名。
+
@returns {Object?} 返回的尺寸信息值。
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/direct-manipulation.md b/docs/docs/0.43/direct-manipulation.md
new file mode 100644
index 0000000..f0b4b66
--- /dev/null
+++ b/docs/docs/0.43/direct-manipulation.md
@@ -0,0 +1,117 @@
+有时候我们需要直接改动组件并触发局部的刷新,但不使用state或是props。譬如在浏览器中使用React库,有时候会需要直接修改一个DOM节点,而在手机App中操作View时也会碰到同样的情况。在React Native中,`setNativeProps`就是等价于直接操作DOM节点的方法。
+
+> 什么时候使用setNativeProps呢?在(不得不)频繁刷新而又遇到了性能瓶颈的时候。
+>
+> 直接操作组件并不是应该经常使用的工具。一般来说只是用来创建连续的动画,同时避免渲染组件结构和同步太多视图变化所带来的大量开销。`setNativeProps`是一个“简单粗暴”的方法,它直接在底层(DOM、UIView等)而不是React组件中记录state,这样会使代码逻辑难以理清。所以在使用这个方法之前,请尽量先尝试用`setState`和[shouldComponentUpdate](http://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action)方法来解决问题。
+
+## setNativeProps与TouchableOpacity
+
+[TouchableOpacity](https://github.com/facebook/react-native/blob/master/Libraries/Components/Touchable/TouchableOpacity.js)这个组件就在内部使用了`setNativeProps`方法来更新其子组件的透明度:
+
+```javascript
+setOpacityTo: function(value) {
+ // Redacted: animation related code
+ this.refs[CHILD_REF].setNativeProps({
+ opacity: value
+ });
+},
+```
+
+由此我们可以写出下面这样的代码:子组件可以响应点击事件,更改自己的透明度。而子组件自身并不需要处理这件事情,也不需要在实现中做任何修改。
+
+```javascript
+
+
+ Press me!
+
+
+```
+
+如果不使用`setNativeProps`这个方法来实现这一需求,那么一种可能的办法是把透明值保存到state中,然后在`onPress`事件触发时更新这个值:
+
+```javascript
+getInitialState() {
+ return { myButtonOpacity: 1, }
+},
+
+render() {
+ return (
+ this.setState({myButtonOpacity: 0.5})}
+ onPressOut={() => this.setState({myButtonOpacity: 1})}>
+
+ Press me!
+
+
+ )
+}
+```
+
+比起之前的例子,这一做法会消耗大量的计算 —— 每一次透明值变更的时候React都要重新渲染组件结构,即便视图的其他属性和子组件并没有变化。一般来说这一开销也不足为虑,但当执行连续的动画以及响应用户手势的时候,只有正确地优化组件才能提高动画的流畅度。
+
+如果你看过[NativeMethodsMixin.js]()中的`setNativeProps`方法的实现,你就会发现它实际是对`RCTUIManager.updateView`的封装 —— 而这正是重渲染所触发的函数调用,具体可以参看[ReactNativeBaseComponent.js中的receiveComponent]().
+
+## 复合组件与setNativeProps
+
+复合组件并不是单纯的由一个原生视图构成,所以你不能对其直接使用`setNativeProps`。比如下面这个例子:
+
+```javascript
+var MyButton = React.createClass({
+ render() {
+ return (
+
+ {this.props.label}
+
+ )
+ },
+});
+
+var App = React.createClass({
+ render() {
+ return (
+
+
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/JXkgmQ)
+
+跑这个例子会马上看到一行报错: `Touchable child
+must either be native or forward setNativeProps to a native component`.
+这是因为`MyButton`并非直接由原生视图构成,而我们只能给原生视图设置透明值。你可以尝试这样去理解:如果你通过`React.createClass`方法自定义了一个组件,直接给它设置样式prop是不会生效的,你得把样式props层层向下传递给子组件,直到子组件是一个能够直接定义样式的原生组件。同理,我们也需要把`setNativeProps`传递给由原生组件封装的子组件。
+
+#### 将setNativeProps传递给子组件
+
+具体要做的就是在我们的自定义组件中再封装一个`setNativeProps`方法,其内容为对合适的子组件调用真正的`setNativeProps`方法,并传递要设置的参数。
+
+```javascript
+var MyButton = React.createClass({
+ setNativeProps(nativeProps) {
+ this._root.setNativeProps(nativeProps);
+ },
+
+ render() {
+ return (
+ this._root = component} {...this.props}>
+ {this.props.label}
+
+ )
+ },
+});
+```
+[运行这个例子(可能需要科学上网)](https://rnplay.org/apps/YJxnEQ)
+
+现在你可以在`TouchableOpacity`中嵌入`MyButton`了!有一点需要特别说明:这里我们使用了[ref回调](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute)语法,而不是传统的字符串型ref引用。
+
+你可能还会注意到我们在向下传递props时使用了`{...this.props}`语法(这一用法的说明请参考[对象的扩展运算符](http://es6.ruanyifeng.com/#docs/object))。这是因为`TouchableOpacity`本身其实也是个复合组件, 它除了要求在子组件上执行`setNativeProps` 以外,还要求子组件对触摸事件进行处理。因此,它会传递多个props,其中包含了[onmoveshouldsetresponder](view.html#onmoveshouldsetresponder) 函数,这个函数需要回调给`TouchableOpacity`组件,以完成触摸事件的处理。与之相对的是`TouchableHighlight`组件,它本身是由原生视图构成,因而只需要我们实现`setNativeProps`。
+
+## 避免和render方法的冲突
+
+如果要更新一个由render方法来维护的属性,则可能会碰到一些出人意料的bug。因为每一次组件重新渲染都可能引起属性变化,这样一来,之前通过`setNativeProps`所设定的值就被完全忽略和覆盖掉了。[这个例子(可能需要科学上网)](https://rnplay.org/apps/bp1DvQ)
+演示了两者冲突时的情形 —— 注意看由于`setState`触发的重新渲染(每250ms)导致的动画卡顿。
+
+## setNativeProps与shouldComponentUpdate
+
+通过[巧妙运用
+`shouldComponentUpdate`方法](https://facebook.github.io/react/docs/advanced-performance.html#avoiding-reconciling-the-dom),可以避免重新渲染那些实际没有变化的子组件所带来的额外开销,此时使用`setState`的性能已经可以与`setNativeProps`相媲美了。
diff --git a/docs/docs/0.43/drawerlayoutandroid.md b/docs/docs/0.43/drawerlayoutandroid.md
new file mode 100644
index 0000000..3c81143
--- /dev/null
+++ b/docs/docs/0.43/drawerlayoutandroid.md
@@ -0,0 +1,108 @@
+封装了平台`DrawerLayout`(仅限安卓平台)的React组件。抽屉(通常用于导航切换)是通过`renderNavigationView`方法渲染的,并且DrawerLayoutAndroid的直接子视图会成为主视图(用于放置你的内容)。导航视图一开始在屏幕上并不可见,不过可以从`drawerPosition`指定的窗口侧面拖拽出来,并且抽屉的宽度可以使用`drawerWidth`属性来指定。
+
+### 截图
+
+
+### 例子
+
+```javascript
+render: function() {
+ var navigationView = (
+
+ I'm in the Drawer!
+
+ );
+ return (
+ navigationView}>
+
+ Hello
+ World!
+
+
+ );
+},
+```
+
+### 属性
+
+
+
+
drawerLockMode enum('unlocked', 'locked-closed', 'locked-open')
+ #
+
+
+
设置抽屉的锁定模式。有三种状态:
+
+ unlocked (默认值),意味着此时抽屉可以响应打开和关闭的手势操作。
+ locked-closed,意味着此时抽屉将保持关闭,不可用手势打开。
+ locked-open,意味着此时抽屉将保持打开,不可用手势关闭。
+
+ 无论抽屉处于那种状态,都仍然可以调用
openDrawer/
closeDrawer这两个方法打开和关闭。
+
+
+
+
+
+
drawerPosition enum(DrawerConsts.DrawerPosition.Left, DrawerConsts.DrawerPosition.Right) #
+
+
+
+
drawerWidth number #
+
+
指定抽屉的宽度,也就是从屏幕边缘拖进的视图的宽度。
+
+
+
+
keyboardDismissMode enum('none', "on-drag") #
+
+
指定在拖拽的过程中是否要隐藏软键盘。
+
+ none (默认值),拖拽不会隐藏软键盘。
+ on-drag 当拖拽开始的时候隐藏软键盘。
+
+
+
+
+
onDrawerClose function #
+
+
每当导航视图(抽屉)被关闭之后调用此回调函数。
+
+
+
+
onDrawerOpen function #
+
+
每当导航视图(抽屉)被打开之后调用此回调函数。
+
+
+
+
onDrawerSlide function #
+
+
每当导航视图(抽屉)产生交互的时候调用此回调函数。
+
+
+
+
onDrawerStateChanged function #
+
+
每当抽屉的状态变化时调用此回调函数。抽屉可以有3种状态:
+
+ idle(空闲),表示现在导航条上没有任何正在进行的交互。
+ dragging(拖拽中),表示用户正在与导航条进行交互。
+ settling(停靠中),表示用户刚刚结束与导航条的交互,导航条正在结束打开或者关闭的动画。
+
+
+
+
+
renderNavigationView function #
+
+
此方法用于渲染一个可以从屏幕一边拖入的导航视图。
+
+
+
diff --git a/docs/docs/0.43/easing.md b/docs/docs/0.43/easing.md
new file mode 100644
index 0000000..5a48b93
--- /dev/null
+++ b/docs/docs/0.43/easing.md
@@ -0,0 +1,63 @@
+This class implements common easing functions. The math is pretty obscure, but this cool website has nice visual illustrations of what they represent:
+
+### 方法
+
+
+
+
+
+
+
+
+
+
+
+
+
static elastic(bounciness) #
+
+
A simple elastic interaction, similar to a spring. Default bounciness
+ is 1, which overshoots a little bit once. 0 bounciness doesn't overshoot
+ at all, and bounciness of N > 1 will overshoot about N times.
+
Wolfram Plots:
+
http://tiny.cc/elastic_b_1 (default bounciness = 1)
+ http://tiny.cc/elastic_b_3 (bounciness = 3)
+
+
+
+
static bezier(x1, y1, x2, y2) #
+
+
+
static out(easing) #
+
Runs an easing function backwards.
+
+
static inOut(easing) #
+
Makes any easing function symmetrical.
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/flatlist.md b/docs/docs/0.43/flatlist.md
new file mode 100644
index 0000000..fe0ea74
--- /dev/null
+++ b/docs/docs/0.43/flatlist.md
@@ -0,0 +1,419 @@
+高性能的简单列表组件,支持下面这些常用的功能:
+
+- 完全跨平台。
+- 支持水平布局模式。
+- 行组件显示或隐藏时可配置回调事件。
+- 支持单独的头部组件。
+- 支持单独的尾部组件。
+- 支持自定义行间分隔线。
+- 支持下拉刷新。
+- 支持上拉加载。
+
+如果需要分组/类/区(section),请使用[``](sectionlist.html).
+
+一个简单的例子:
+
+```javascript
+ {item.key} }
+/>
+```
+
+本组件实质是基于[``](virtualizedlist.html)组件的封装,因此也有下面这些需要注意的事项:
+
+- 当某行滑出渲染区域之外后,其内部状态将不会保留。请确保你在行组件以外的地方保留了数据。
+- 本组件继承自`PureComponent`而非通常的`Component`,这意味着如果其`props`在`浅比较`中是相等的,则不会重新渲染。所以请先检查你的`renderItem`函数所依赖的`props`数据(包括`data`属性以及可能用到的父组件的state),如果是一个引用类型(Object或者数组都是引用类型),则需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。(译注:这一段不了解的朋友建议先学习下[js中的基本类型和引用类型](https://segmentfault.com/a/1190000002789651)。)
+- 为了优化内存占用同时保持滑动的流畅,列表内容会在屏幕外异步绘制。这意味着如果用户滑动的速度超过渲染的速度,则会先看到空白的内容。这是为了优化不得不作出的妥协,而我们也在设法持续改进。
+- 默认情况下每行都需要提供一个不重复的key属性。你也可以提供一个`keyExtractor`函数来生成key。
+
+### 属性
+
+
+
ItemSeparatorComponent?: ?ReactClass<any> #
+
+
行与行之间的分隔线组件。不会出现在第一行之前和最后一行之后。
+
+
ListFooterComponent?: ?ReactClass<any> #
+
+
+
+
ListHeaderComponent?: ?ReactClass<any> #
+
+
+
+
columnWrapperStyle?: StyleObj #
+
如果设置了多列布局(即将numColumns值设为大于1的整数),则可以额外指定此样式作用在每行容器上。
+
+
data: ?Array<ItemT>
+ #
+
为了简化起见,data属性目前只支持普通数组。如果需要使用其他特殊数据结构,例如immutable数组,请直接使用更底层的VirtualizedList组件。
+
+
+
+
getItemLayout?: (data: ?Array<ItemT>, index: number) =>
+ {length: number, offset: number, index: number} #
+
getItemLayout是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。如果你的行高是固定的,getItemLayout用起来就既高效又简单,类似下面这样:
+
getItemLayout= { ( data, index) = > (
+ { length: 行高, offset: 行高
+ * index, index}
+ ) }
+
注意如果你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中。
+
+
horizontal?: ?boolean
+ #
+
+
+
keyExtractor: (item: ItemT, index: number) => string #
+
+
此函数用于为给定的item生成一个不重复的key。Key的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。
+
+
legacyImplementation?:
+ ?boolean #
+
+
+
numColumns: number #
+
+
多列布局只能在非水平模式下使用。此时组件内元素会从左到右从上到下按Z字形排列,类似启用了flexWrap的布局。组件内元素必须是等高的——暂时还无法支持瀑布流布局。
+
+
onEndReached?: ?(info: {distanceFromEnd: number}) => void #
+
+
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。
+
+
onEndReachedThreshold?:
+ ?number #
+
+
onRefresh?: ?() => void #
+
如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性。
+
+
onViewableItemsChanged?:
+ ?(info: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void
+ #
+
Called when the viewability of rows changes, as defined by the
+ viewablePercentThreshold prop.
+
+
refreshing?: ?boolean
+ #
+
Set this true while waiting for new data from a refresh.
+
+
renderItem: (info: {item: ItemT, index: number}) => ?React.Element<any> #
+
根据行数据data渲染每一行的组件。典型用法:
+
_renderItem = ( { item} ) = > (
+ <TouchableOpacity onPress= { ( ) = > this . _onPress( item) } >
+ <Text> { item. title} } </ Text>
+ </TouchableOpacity>
+ ) ;
+ . . .
+ <FlatList data= { [ { title: 'Title Text' , key: 'item1' } ] } renderItem= { this . _renderItem} / >
+
除data外还有第二个参数index可供使用。
+
+
viewabilityConfig?: ViewabilityConfig #
+
+
+
+
+
+### 方法
+
+
+
scrollToEnd(params?: object) #
+
+
滚动到底部。如果不设置getItemLayout属性的话,可能会比较卡。
+
+
scrollToIndex(params: object) #
+
Scrolls to the item at a the specified index such that it is positioned in the viewable area
+ such that viewPosition 0 places it at the top, 1 at the bottom, and 0.5 centered in the
+ middle.
+
May be janky without getItemLayout prop.
+
+
scrollToItem(params: object) #
+
+
Requires linear scan through data - use scrollToIndex instead if possible. May be janky
+ without getItemLayout prop.
+
+
scrollToOffset(params: object) #
+
Scroll to a specific content pixel offset, like a normal ScrollView.
+
+
recordInteraction() #
+
Tells the list an interaction has occured, which should trigger viewability calculations, e.g.
+ if waitForInteractions is true and the user has not scrolled. This is typically called by
+ taps on items or by navigation actions.
+
+
+
+
+### 例子
+```javascript
+'use strict';
+
+const React = require('react');
+const ReactNative = require('react-native');
+const {
+ Animated,
+ FlatList,
+ StyleSheet,
+ View,
+} = ReactNative;
+
+const UIExplorerPage = require('./UIExplorerPage');
+
+const infoLog = require('infoLog');
+
+const {
+ FooterComponent,
+ HeaderComponent,
+ ItemComponent,
+ PlainInput,
+ SeparatorComponent,
+ genItemData,
+ getItemLayout,
+ pressItem,
+ renderSmallSwitchOption,
+} = require('./ListExampleShared');
+
+const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
+
+const VIEWABILITY_CONFIG = {
+ minimumViewTime: 3000,
+ viewAreaCoveragePercentThreshold: 100,
+ waitForInteraction: true,
+};
+
+class FlatListExample extends React.PureComponent {
+ static title = '';
+ static description = 'Performant, scrollable list of data.';
+
+ state = {
+ data: genItemData(1000),
+ debug: false,
+ horizontal: false,
+ filterText: '',
+ fixedHeight: true,
+ logViewable: false,
+ virtualized: true,
+ };
+
+ _onChangeFilterText = (filterText) => {
+ this.setState({filterText});
+ };
+
+ _onChangeScrollToIndex = (text) => {
+ this._listRef.getNode().scrollToIndex({viewPosition: 0.5, index: Number(text)});
+ };
+
+ _scrollPos = new Animated.Value(0);
+ _scrollSinkX = Animated.event(
+ [{nativeEvent: { contentOffset: { x: this._scrollPos } }}],
+ {useNativeDriver: true},
+ );
+ _scrollSinkY = Animated.event(
+ [{nativeEvent: { contentOffset: { y: this._scrollPos } }}],
+ {useNativeDriver: true},
+ );
+
+ componentDidUpdate() {
+ this._listRef.getNode().recordInteraction(); // e.g. flipping logViewable switch
+ }
+
+ render() {
+ const filterRegex = new RegExp(String(this.state.filterText), 'i');
+ const filter = (item) => (
+ filterRegex.test(item.text) || filterRegex.test(item.title)
+ );
+ const filteredData = this.state.data.filter(filter);
+ return (
+
+
+
+
+
+
+
+ {renderSmallSwitchOption(this, 'virtualized')}
+ {renderSmallSwitchOption(this, 'horizontal')}
+ {renderSmallSwitchOption(this, 'fixedHeight')}
+ {renderSmallSwitchOption(this, 'logViewable')}
+ {renderSmallSwitchOption(this, 'debug')}
+
+
+
+
+
+
+ );
+ }
+ _captureRef = (ref) => { this._listRef = ref; };
+ _getItemLayout = (data: any, index: number) => {
+ return getItemLayout(data, index, this.state.horizontal);
+ };
+ _onRefresh = () => alert('onRefresh: nothing to refresh :P');
+ _renderItemComponent = ({item}) => {
+ return (
+
+ );
+ };
+ _shouldItemUpdate(prev, next) {
+ /**
+ * Note that this does not check state.horizontal or state.fixedheight
+ * because we blow away the whole list by changing the key in those cases.
+ * Make sure that you do the same in your code, or incorporate all relevant
+ * data into the item data, or skip this optimization entirely.
+ */
+ return prev.item !== next.item;
+ }
+ // This is called when items change viewability by scrolling into or out of
+ // the viewable area.
+ _onViewableItemsChanged = (info: {
+ changed: Array<{
+ key: string,
+ isViewable: boolean,
+ item: any,
+ index: ?number,
+ section?: any,
+ }>
+ }
+ ) => {
+ // Impressions can be logged here
+ if (this.state.logViewable) {
+ infoLog(
+ 'onViewableItemsChanged: ',
+ info.changed.map((v) => ({...v, item: '...'})),
+ );
+ }
+ };
+ _pressItem = (key: number) => {
+ this._listRef.getNode().recordInteraction();
+ pressItem(this, key);
+ };
+ _listRef: FlatList<*>;
+}
+
+
+const styles = StyleSheet.create({
+ options: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ alignItems: 'center',
+ },
+ searchRow: {
+ paddingHorizontal: 10,
+ },
+ spindicator: {
+ marginLeft: 'auto',
+ width: 2,
+ height: 16,
+ backgroundColor: 'darkgray',
+ },
+});
+
+module.exports = FlatListExample;
+```
diff --git a/docs/docs/0.43/geolocation.md b/docs/docs/0.43/geolocation.md
new file mode 100644
index 0000000..2cbee51
--- /dev/null
+++ b/docs/docs/0.43/geolocation.md
@@ -0,0 +1,111 @@
+定位API遵循[web标准](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation)。
+
+## iOS
+你需要在Info.plist中增加`NSLocationWhenInUseUsageDescription`字段来启用定位功能。如果你使用`react-native init`创建项目,定位会被默认启用。
+
+## Android
+要请求访问地理位置的权限,你需要在`AndroidManifest.xml`文件中加入如下一行:
+
+` `
+
+## 方法
+
+
static getCurrentPosition(geo_success: Function, geo_error?: Function, geo_options?: GeoOptions) #
+
成功时会调用geo_success回调,参数中包含最新的位置信息。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static watchPosition(success: Function, error?: Function, options?: GeoOptions)
+ #
+
持续监听位置,每当位置变化之后都调用success回调。支持的选项:timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+
+
static clearWatch(watchID: number) #
+
static stopObserving() #
+
+
+
+## 例子
+
+```javascript
+/* eslint no-console: 0 */
+'use strict';
+
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+exports.framework = 'React';
+exports.title = 'Geolocation';
+exports.description = 'Examples of using the Geolocation API.';
+
+exports.examples = [
+ {
+ title: 'navigator.geolocation',
+ render: function(): ReactElement {
+ return ;
+ },
+ }
+];
+
+var GeolocationExample = React.createClass({
+ watchID: (null: ?number),
+
+ getInitialState: function() {
+ return {
+ initialPosition: 'unknown',
+ lastPosition: 'unknown',
+ };
+ },
+
+ componentDidMount: function() {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ var initialPosition = JSON.stringify(position);
+ this.setState({initialPosition});
+ },
+ (error) => alert(error.message),
+ {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
+ );
+ this.watchID = navigator.geolocation.watchPosition((position) => {
+ var lastPosition = JSON.stringify(position);
+ this.setState({lastPosition});
+ });
+ },
+
+ componentWillUnmount: function() {
+ navigator.geolocation.clearWatch(this.watchID);
+ },
+
+ render: function() {
+ return (
+
+
+ Initial position:
+ {this.state.initialPosition}
+
+
+ Current position:
+ {this.state.lastPosition}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: '500',
+ },
+});
+```
+
diff --git a/docs/docs/0.43/gesture-responder-system.md b/docs/docs/0.43/gesture-responder-system.md
new file mode 100644
index 0000000..7314e0c
--- /dev/null
+++ b/docs/docs/0.43/gesture-responder-system.md
@@ -0,0 +1,62 @@
+移动设备上的手势识别要比在web上复杂得多。用户的一次触摸操作的真实意图是什么,App要经过好几个阶段才能判断。比如App需要判断用户的触摸到底是在滚动页面,还是滑动一个widget,或者只是一个单纯的点击。甚至随着持续时间的不同,这些操作还会转化。此外,还有多点同时触控的情况。
+
+触摸响应系统可以使组件在不关心父组件或子组件的前提下自行处理触摸交互。具体的实现在`ResponderEventPlugin.js`文件中,你可以在源码中读到更多细节和文档。
+
+### 最佳实践
+
+用户之所以会觉得web app和原生app在体验上有巨大的差异,触摸响应是一大关键因素。用户的每一个操作都应该具有下列属性:
+
+- 反馈/高亮 —— 让用户看到他们到底按到了什么东西,以及松开手后会发生什么。
+- 取消功能 —— 当用户正在触摸操作时,应该是可以通过把手指移开来终止操作。
+
+这些特性使得用户在使用App时体验更好,因为它们可以让用户大胆试用,而不必担心点错了什么。
+
+### TouchableHighlight与Touchable系列组件
+
+响应系统用起来可能比较复杂。所以我们提供了一个抽象的`Touchable`实现,用来做“可触控”的组件。这一实现利用了响应系统,使得你可以简单地以声明的方式来配置触控处理。如果要做一个按钮或者网页链接,那么使用`TouchableHighlight`就可以。
+
+
+## 响应者的生命周期
+
+一个View只要实现了正确的协商方法,就可以成为触摸事件的响应者。我们通过两个方法去“询问”一个View是否愿意成为响应者:
+
+ - `View.props.onStartShouldSetResponder: (evt) => true,` - 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
+ - `View.props.onMoveShouldSetResponder: (evt) => true,` - 如果View不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?
+
+如果View返回true,并开始尝试成为响应者,那么会触发下列事件之一:
+
+ - `View.props.onResponderGrant: (evt) => {}` - View现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里。
+ - `View.props.onResponderReject: (evt) => {}` - 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。
+
+如果View已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:
+
+ - `View.props.onResponderMove: (evt) => {}` - 用户正在屏幕上移动手指时(没有停下也没有离开屏幕)。
+ - `View.props.onResponderRelease: (evt) => {}` - 触摸操作结束时触发,比如"touchUp"(手指抬起离开屏幕)。
+ - `View.props.onResponderTerminationRequest: (evt) => true` - 有其他组件请求接替响应者,当前的View是否“放权”?返回true的话则释放响应者权力。
+ - `View.props.onResponderTerminate: (evt) => {}` - 响应者权力已经交出。这可能是由于其他View通过`onResponderTerminationRequest`请求的,也可能是由操作系统强制夺权(比如iOS上的控制中心或是通知中心)。
+
+`evt`是一个合成事件,它包含以下结构:
+
+ - `nativeEvent`
+ + `changedTouches` - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
+ + `identifier` - 触摸点的ID
+ + `locationX` - 触摸点相对于父元素的横坐标
+ + `locationY` - 触摸点相对于父元素的纵坐标
+ + `pageX` - 触摸点相对于根元素的横坐标
+ + `pageY` - 触摸点相对于根元素的纵坐标
+ + `target` - 触摸点所在的元素ID
+ + `timestamp` - 触摸事件的时间戳,可用于移动速度的计算
+ + `touches` - 当前屏幕上的所有触摸点的集合
+
+### 捕获ShouldSet事件处理
+
+`onStartShouldSetResponder`与`onMoveShouldSetResponder`是以冒泡的形式调用的,即嵌套最深的节点最先调用。这意味着当多个View同时在`*ShouldSetResponder`中返回true时,最底层的View将优先“夺权”。在多数情况下这并没有什么问题,因为这样可以确保所有控件和按钮是可用的。
+
+但是有些时候,某个父View会希望能先成为响应者。我们可以利用“捕获期”来解决这一需求。响应系统在从最底层的组件开始冒泡之前,会首先执行一个“捕获期”,在此期间会触发`on*ShouldSetResponderCapture`系列事件。因此,如果某个父View想要在触摸操作开始时阻止子组件成为响应者,那就应该处理`onStartShouldSetResponderCapture`事件并返回true值。
+
+ - `View.props.onStartShouldSetResponderCapture: (evt) => true,`
+ - `View.props.onMoveShouldSetResponderCapture: (evt) => true,`
+
+### PanResponder
+
+要使用更高级的手势功能,请参看[PanResponder](panresponder.html).
diff --git a/docs/docs/0.43/getting-started.md b/docs/docs/0.43/getting-started.md
new file mode 100644
index 0000000..5f732d6
--- /dev/null
+++ b/docs/docs/0.43/getting-started.md
@@ -0,0 +1,760 @@
+欢迎使用React Native!这篇文档会帮助你搭建基本的React Native开发环境。如果你已经搭好了环境,那么可以尝试一下[编写Hello World](tutorial.html)。
+
+根据你所使用的操作系统、针对的目标平台不同,具体步骤有所不同。如果想同时开发iOS和Android也没问题,你只需要先选一个平台开始,另一个平台的环境搭建只是稍有不同。
+
+如果`阅读完本文档`后还碰到很多环境搭建的问题,我们建议你还可以再看看由本站提供的`环境搭建视频教程`([macOS iOS](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220865928921581&vid=a1417i5op7k)、[macOS Android](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220870223888877&vid=z1417kmxask)、[windows Android](https://ke.qq.com/webcourse/index.html#course_id=197101&term_id=100233637&taid=1220874518856173&vid=d1417tgg1ez))、[windows环境搭建文字教程](http://bbs.reactnative.cn/topic/10)、以及[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+
+
+
+## 暂不支持
+
+苹果公司目前只允许在Mac电脑上开发iOS应用。如果你没有Mac电脑,那么只能考虑先开发Android应用了。
+
+
+
+
+
+
+
+
+## 安装
+
+### 必需的软件
+
+#### Homebrew
+
+[Homebrew](http://brew.sh/), Mac系统的包管理器,用于安装NodeJS和一些其他必需的工具软件。
+
+```
+/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+
+译注:在Max OS X 10.11(El Capitan)版本中,homebrew在安装软件时可能会碰到`/usr/local`目录不可写的权限问题。可以使用下面的命令修复:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+#### Node
+
+使用Homebrew来安装[Node.js](https://nodejs.org/).
+
+> React Native目前需要NodeJS 5.0或更高版本。本文发布时Homebrew默认安装的是最新版本,一般都满足要求。
+
+```
+brew install node
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+
+如果你看到`EACCES: permission denied`这样的权限报错,那么请参照上文的homebrew译注,修复`/usr/local`目录的所有权:
+
+```bash
+sudo chown -R `whoami` /usr/local
+```
+
+
+
+#### Xcode
+
+React Native目前需要[Xcode](https://developer.apple.com/xcode/downloads/) 8.0 或更高版本。你可以通过App Store或是到[Apple开发者官网](https://developer.apple.com/xcode/downloads/)上下载。这一步骤会同时安装Xcode IDE和Xcode的命令行工具。
+
+> 虽然一般来说命令行工具都是默认安装了,但你最好还是启动Xcode,并在`Xcode | Preferences | Locations`菜单中检查一下是否装有某个版本的`Command Line Tools`。Xcode的命令行工具中也包含一些必须的工具,比如`git`等。
+
+
+
+#### Android Studio
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 勾选`Performance`和`Android Virtual Device`
+
+
+
+- 安装完成后,在Android Studio的启动欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。具体的做法是把下面的命令加入到`~/.bash_profile`文件中:(__译注__:~表示用户目录,即`/Users/你的用户名/`,而小数点开头的文件在Finder中是隐藏的,并且这个文件有可能并不存在。请在终端下使用`vi ~/.bash_profile`命令创建或编辑。如不熟悉vi操作,请点击[这里](http://www.eepw.com.cn/article/48018.htm)学习)
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ~/.bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+
+### 推荐安装的工具
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+```
+brew install watchman
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+
+```
+brew install flow
+```
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。具体做法仍然是在`~/.bash_profile`中添加:
+
+```
+export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
+```
+
+### 其他可选的安装项
+
+#### Git
+
+Git版本控制。如果你已经安装过[Xcode](https://developer.apple.com/xcode/),则Git也已经一并安装了。如若没有,则使用下列命令安装:
+
+```
+brew install git
+```
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下⌘+M来打开开发者菜单。
+
+
+
+
+## 安装
+
+### 必需的软件
+
+
+
+#### Chocolatey
+
+[Chocolatey](https://chocolatey.org)是一个Windows上的包管理器,类似于linux上的`yum`和
+`apt-get`。 你可以在其[官方网站](https://chocolatey.org)上查看具体的使用说明。一般的安装步骤应该是下面这样:
+
+```
+@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
+```
+
+> 一般来说,使用Chocolatey来安装软件的时候,需要以管理员的身份来运行命令提示符窗口。译注:chocolatey的网站可能在国内访问困难,导致上述安装命令无法正常完成。请使用稳定的翻墙工具。
+> 如果你实在装不上这个工具,也不要紧。下面所需的python2和nodejs你可以分别单独去对应的官方网站下载安装即可。
+
+#### Python 2
+
+打开命令提示符窗口,使用Chocolatey来安装Python 2.
+
+> 注意目前不支持Python 3版本。
+
+```
+choco install python2
+```
+
+
+
+#### Node
+
+
+
+打开终端窗口,输入下面的命令来安装NodeJS:
+
+```
+sudo apt-get install -y build-essential
+curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -
+sudo apt-get install -y nodejs
+sudo ln -s /usr/bin/nodejs /usr/bin/node
+```
+
+
+
+
+打开命令提示符窗口,使用Chocolatey来安装NodeJS。注意,目前已知Node 7.1版本在windows上无法正常工作,请避开这个版本!
+
+```
+choco install nodejs.install
+```
+
+安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
+
+```
+npm config set registry https://registry.npm.taobao.org --global
+npm config set disturl https://npm.taobao.org/dist --global
+```
+
+
+
+#### Yarn、React Native的命令行工具(react-native-cli)
+
+[Yarn](http://yarnpkg.com)是Facebook提供的替代npm的工具,可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
+
+```
+npm install -g yarn react-native-cli
+```
+
+安装完yarn后同理也要设置镜像源:
+
+```
+yarn config set registry https://registry.npm.taobao.org --global
+yarn config set disturl https://npm.taobao.org/dist --global
+```
+
+> 如果你遇到`EACCES: permission denied`权限错误,可以尝试运行下面的命令(限linux系统):
+> `sudo npm install -g yarn react-native-cli`.
+
+#### Android Studio
+
+[Android Studio](http://developer.android.com/sdk/index.html) 2.0 or higher.
+
+React Native目前需要[Android Studio](http://developer.android.com/sdk/index.html)2.0或更高版本。
+
+> Android Studio需要Java Development Kit [JDK] 1.8或更高版本。你可以在命令行中输入
+> `javac -version`来查看你当前安装的JDK版本。如果版本不合要求,则可以到
+> [官网](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上下载。
+> 或是使用包管理器来安装(比如`choco install jdk8`或是
+> `apt-get install default-jdk`)
+
+Android Studio包含了运行和测试React Native应用所需的Android SDK和模拟器。
+
+> 除非特别注明,请不要改动安装过程中的选项。比如Android Studio默认安装了
+> `Android Support Repository`,而这也是React Native必须的(否则在react-native run-android时会报appcompat-v7包找不到的错误)。
+
+
+
+安装过程中有一些需要改动的选项:
+
+- 选择`Custom`选项:
+
+
+
+- 选择`Android Virtual Device`
+
+
+
+
+
+- 确定所有安装都勾选了,尤其是`Android SDK`和`Android Device Emulator`。
+
+- 在初步安装完成后,选择`Custom`安装项:
+
+
+
+- 检查已安装的组件,尤其是模拟器和HAXM加速驱动。
+
+
+
+
+
+- 安装完成后,在Android Studio的欢迎界面中选择`Configure | SDK Manager`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Platforms`窗口中,选择`Show Package Details`,然后在`Android 6.0 (Marshmallow)`中勾选`Google APIs`、`Android SDK Platform 23`、`Intel x86 Atom System Image`、`Intel x86 Atom_64 System Image`以及`Google APIs Intel x86 Atom_64 System Image`。
+
+
+
+
+
+
+
+
+
+
+
+- 在`SDK Tools`窗口中,选择`Show Package Details`,然后在`Android SDK Build Tools`中勾选`Android SDK Build-Tools 23.0.1`(必须是这个版本)。然后还要勾选最底部的`Android Support Repository`.
+
+
+
+
+
+
+
+
+
+
+
+
+#### ANDROID_HOME环境变量
+
+确保`ANDROID_HOME`环境变量正确地指向了你安装的Android SDK的路径。
+
+
+
+具体的做法是把下面的命令加入到`~/.bashrc`、`~/.bash_profile`文件中。如果你使用的是其他的shell,则选择对应的配置文件:
+
+```
+# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
+export ANDROID_HOME=~/Library/Android/sdk
+```
+
+然后使用下列命令使其立即生效(否则重启后才生效):
+
+```bash
+source ~/.bash_profile
+```
+
+可以使用`echo $ANDROID_HOME`检查此变量是否已正确设置。
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> `新建`
+
+> 具体的路径可能和下图不一致,请自行确认。
+
+
+
+> 你需要关闭现有的命令符提示窗口然后重新打开,这样新的环境变量才能生效。
+
+
+
+### 推荐安装的工具
+
+
+
+#### Watchman
+
+[Watchman](https://facebook.github.io/watchman/docs/install.html)是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。
+
+> 安装watchman还可以避免node的一个与文件监视有关的bug。
+
+在终端中输入以下命令来编译并安装watchman:
+
+```
+git clone https://github.com/facebook/watchman.git
+cd watchman
+git checkout v4.5.0 # 这是本文发布时的最新版本
+./autogen.sh
+./configure
+make
+sudo make install
+```
+
+#### Flow
+
+[Flow](http://www.flowtype.org)是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
+
+在终端中输入以下命令来安装flow:
+
+```
+npm install -g flow-bin
+```
+
+
+
+
+#### Gradle Daemon
+
+开启[Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html)可以极大地提升java代码的增量编译速度。
+
+
+
+
+```
+touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties
+```
+
+
+
+
+```
+(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo org.gradle.daemon=true >> "%USERPROFILE%/.gradle/gradle.properties")
+```
+
+
+
+
+#### Android模拟器加速器
+
+在安装Android Studio时你可能会看到下面这样的提示:
+
+
+
+如果你的系统支持KVM,那就应该安装[Intel的Android模拟器加速器](https://software.intel.com/en-us/android/articles/speeding-up-the-android-emulator-on-intel-architecture#_Toc358213272)。
+
+
+
+#### 将Android SDK的Tools目录添加到`PATH`变量中
+
+你可以把Android SDK的tools和platform-tools目录添加到`PATH`变量中,以便在终端中运行一些Android工具,例如`android avd`或是`adb logcat`等。
+
+
+
+在`~/.bashrc`或是`~/.bash_profile`文件中添加:
+
+```
+# 你的具体路径可能有所不同,请自行确认。
+PATH="~/Android/Sdk/tools:~/Android/Sdk/platform-tools:${PATH}"
+export PATH
+```
+
+
+
+打开`控制面板` -> `系统和安全` -> `系统` -> `高级系统设置` ->
+`高级` -> `环境变量` -> 选中`PATH` -> 双击进行编辑
+
+> 注意你的具体路径可能和下图不同
+
+
+
+
+
+### 可选的安装项
+
+#### Git
+
+
+
+[使用包管理器](https://git-scm.com/download/linux)来安装Git
+(例如`sudo apt-get install git-all`).
+
+
+
+你可以使用Chocolatey来安装`git`:
+
+```
+choco install git
+```
+
+另外你也可以直接去下载[Git for Windows](https://git-for-windows.github.io/)。
+在安装过程中注意勾选"Run Git from Windows Command Prompt",这样才会把`git`命令添加到`PATH`环境变量中。
+
+
+
+#### Nuclide
+
+[Nuclide](http://nuclide.io)(此链接需要科学上网)是由Facebook提供的基于atom的集成开发环境,可用于编写、[运行](http://nuclide.io/docs/platforms/react-native/#running-applications)和
+[调试](http://nuclide.io/docs/platforms/react-native/#debugging)React Native应用。
+
+点击这里阅读[Nuclide的入门文档](http://nuclide.io/docs/quick-start/getting-started/)。
+
+译注:我们更推荐使用[WebStorm](https://www.jetbrains.com/webstorm/)或[Sublime Text](http://www.sublimetext.com/)来编写React Native应用。
+
+
+
+#### Genymotion
+
+比起Android Studio自带的原装模拟器,Genymotion是一个性能更好的选择,但它只对个人用户免费。
+
+1. 下载和安装[Genymotion](https://www.genymotion.com/download)(genymotion需要依赖VirtualBox虚拟机,下载选项中提供了包含VirtualBox和不包含的选项,请按需选择)。
+2. 打开Genymotion。如果你还没有安装VirtualBox,则此时会提示你安装。
+3. 创建一个新模拟器并启动。
+4. 启动React Native应用后,可以按下F1来打开开发者菜单。
+
+
+
+#### Visual Studio Emulator for Android
+
+[Visual Studio Emulator for Android](https://www.visualstudio.com/zh-cn/features/msft-android-emulator-vs.aspx#中国 (简体中文))是利用了Hyper-V技术进行硬件加速的免费android模拟器。也是Android Studio自带的原装模拟器之外的一个很好的选择。而且你并不需要安装Visual Studio。
+在用于React Native开发前,需要先在注册表中进行一些修改:
+
+1. 打开运行命令(按下Windows+R键)
+2. 输入`regedit.exe`然后回车
+3. 在注册表编辑器中找到`HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools`条目
+4. 右键点击`Android SDK Tools`,选择`新建 > 字符串值`
+5. 名称设为`Path`
+6. 双击`Path`,将其值设为你的Android SDK的路径。(例如`C:\Program Files\Android\sdk`)
+
+
+
+
+## 测试安装
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-ios
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹
+然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line),或是双击`ios/AwesomeProject.xcodeproj`文件然后在Xcode中点击`Run`按钮。
+
+
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+你也可以在[Nuclide](http://nuclide.io)中打开[`AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project)文件夹然后[运行](http://nuclide.io/docs/platforms/react-native/#command-line)。
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+
+
+- 使用你喜欢的编辑器打开`index.ios.js`并随便改上几行。
+- 在iOS Emulator中按下`⌘-R`就可以刷新APP并看到你的最新修改!
+
+
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 测试安装
+
+```
+react-native init AwesomeProject
+cd AwesomeProject
+react-native run-android
+```
+
+> 提示:你可以使用`--version`参数创建指定版本的项目。例如`react-native init MyApp --version 0.39.2`。注意版本号必须精确到两个小数点。
+
+__Windows用户请注意,请不要在命令行默认的System32目录中init项目!会有各种权限限制导致不能运行!__
+
+
+
+### 修改项目
+
+现在你已经成功运行了项目,我们可以开始尝试动手改一改了:
+
+- 使用你喜欢的文本编辑器打开`index.android.js`并随便改上几行
+- 按两下R键,或是用Menu键(通常是F2,在Genymotion模拟器中是`⌘+M`)打开开发者菜单,然后选择 *Reload JS* 就可以看到你的最新修改。
+- 在终端下运行`adb logcat *:S ReactNative:V ReactNativeJS:V`可以看到你的应用的日志。
+
+### 完成了!
+
+恭喜!你已经成功运行并修改了你的第一个React Native应用。
+
+
+
+
+
+## 接下来
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-ios.html#content)。
+
+
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
+
+## 接下来
+
+- 如果你想要在真机上运行应用,请参阅[在设备上运行](running-on-device-android.html#content)。
+
+- 如果你碰到了一些问题,请参阅[常见问题](http://bbs.reactnative.cn/topic/130)。
+
+
+
diff --git a/docs/docs/0.43/handling-text-input.md b/docs/docs/0.43/handling-text-input.md
new file mode 100644
index 0000000..52bb4eb
--- /dev/null
+++ b/docs/docs/0.43/handling-text-input.md
@@ -0,0 +1,39 @@
+[`TextInput`](textinput.html#content)是一个允许用户输入文本的基础组件。它有一个名为`onChangeText`的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为`onSubmitEditing`的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。
+
+假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。我们假设这另一种文字来自某个吃货星球,只有一个单词: 🍕。所以"Hello there Bob"将会被翻译为"🍕🍕🍕"。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, Text, TextInput, View } from 'react-native';
+
+class PizzaTranslator extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {text: ''};
+ }
+
+ render() {
+ return (
+
+ this.setState({text})}
+ />
+
+ {this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
+
+
+ );
+ }
+}
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('PizzaTranslator', () => PizzaTranslator);
+```
+
+在上面的例子里,我们把`text`保存到state中,因为它会随着时间变化。
+
+文本输入方面还有很多其他的东西要处理。比如你可能想要在用户输入的时候进行验证,在[React的表单组件中的受限组件](http://reactjs.cn/react/docs/forms.html)一节中有一些详细的示例(注意react中的onChange对应的是rn中的onChangeText)。此外你还需要看看[TextInput的文档](textinput.html)。
+
+TextInput可能是天然具有“动态状态”的最简单的组件了。下面我们来看看另一类控制布局的组件,先从[ScrollView开始学习](using-a-scrollview.html)。
diff --git a/docs/docs/0.43/handling-touches.md b/docs/docs/0.43/handling-touches.md
new file mode 100644
index 0000000..3808eae
--- /dev/null
+++ b/docs/docs/0.43/handling-touches.md
@@ -0,0 +1,57 @@
+移动应用上的用户交互基本靠“摸”。当然,“摸”也是有各种姿势的:在一个按钮上点击,在一个列表上滑动,或是在一个地图上缩放。
+
+React Native提供了可以处理常见触摸手势(例如点击或滑动)的组件, 以及可用于识别更复杂的手势的完整的[手势响应系统](gesturerespondersystem.html)。
+
+## 可点击的组件
+
+在需要捕捉用户点击操作时,可以使用"Touchable"开头的一系列组件。这些组件通过`onPress`属性接受一个点击事件的处理函数。当一个点击操作开始并且终止于本组件时(即在本组件上按下手指并且抬起手指时也没有移开到组件外),此函数会被调用。
+
+示例:
+
+```javascript
+class MyButton extends Component {
+ _onPressButton() {
+ console.log("You tapped the button!");
+ }
+
+ render() {
+ return (
+
+ Button
+
+ );
+ }
+}
+```
+
+可点击的组件需要给用户提供视觉反馈,例如是哪个组件正在响应用户的操作,以及当用户抬起手指后会发生什么。用户也应该可以通过把手指移到一边来取消点击操作。
+
+具体使用哪种组件,取决于你希望给用户什么样的视觉反馈:
+
+- 一般来说,你可以使用[**TouchableHighlight**](touchablehighlight.html)来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。
+
+- 在Android上还可以使用[**TouchableNativeFeedback**](touchablenativefeedback.html),它会在用户手指按下时形成类似墨水涟漪的视觉效果。
+
+- [**TouchableOpacity**](touchableopacity.html)会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
+
+- 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用[**TouchableWithoutFeedback**](touchablewithoutfeedback.html)。
+
+### 长按
+
+某些场景中你可能需要检测用户是否进行了长按操作。可以在上面列出的任意组件中使用`onLongPress`属性来实现。
+
+## 在列表中上下滑动和在视图上左右滑动
+
+可滚动的列表是移动应用中一个常见的模式。用户会在列表中或快或慢的各种滑动。[ScrollView](using-a-scrollView.html)组件可以满足这一需求。
+
+ScrollView可以在垂直或水平方向滚动,还可以配置`pagingEnabled`属性来让用户整屏整屏的滑动。此外,水平方向的滑动还可以使用Android上的[ViewPagerAndroid](viewpagerandroid.html) 组件。
+
+[ListView](using-a-listview.html)则是一种特殊的ScrollView,用于显示比较长的垂直列表。它还可以显示分区块的头部和尾部,类似iOS上的`UITableView`控件。
+
+### 双指缩放
+
+如果在ScrollView中只放置一个组件,则可以用来实现缩放操作。设置`maximumZoomScale`和`minimumZoomScale`属性即可以使用户能够缩放其中的内容。
+
+## 处理其他的手势
+
+如果你想实现视图的拖拽,或是实现自定义的手势,那么请参阅[PanResponder](panresponder.html) API或是[手势识别系统](gesture-responder-system.html)的文档。
diff --git a/docs/docs/0.43/headless-js-android.md b/docs/docs/0.43/headless-js-android.md
new file mode 100644
index 0000000..0cc71fd
--- /dev/null
+++ b/docs/docs/0.43/headless-js-android.md
@@ -0,0 +1,49 @@
+Headless JS是一种使用js在后台执行任务的方法。它可以用来在后台同步数据、处理推送通知或是播放音乐等等。
+
+## JS端的API
+
+首先我们要通过`AppRegistry`来注册一个async函数,这个函数我们称之为“任务”。注册方式类似在index.js中注册RN应用:
+
+```js
+AppRegistry.registerHeadlessTask('SomeTaskName', () => require('SomeTaskName'));
+```
+
+然后创建require对应的`SomeTaskName.js`文件:
+
+```js
+module.exports = async (taskData) => {
+ // 要做的事情
+}
+```
+
+你可以在任务中处理任何事情(网络请求、定时器等等),但唯独**不要涉及用户界面**!在任务完成后(例如在promise中调用resolve),RN会进入一个“暂停”模式,直到有新任务需要执行或者是应用回到前台。
+
+## Java端的API
+
+没错,我们还需要一些原生代码,但是请放心并不麻烦。你需要像下面这样继承`HeadlessJsTaskService`,然后覆盖`getTaskConfig`方法的实现:
+
+```java
+public class MyTaskService extends HeadlessJsTaskService {
+
+ @Override
+ protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ return new HeadlessJsTaskConfig(
+ "SomeTaskName",
+ Arguments.fromBundle(extras),
+ 5000);
+ }
+ return null;
+ }
+}
+```
+
+好了,现在当你[启动服务时][0](例如一个周期性的任务或是响应一些系统事件/广播),JS任务就会开始执行。
+
+## 注意事项
+
+* 默认情况下,如果应用正在前台运行时尝试执行任务,那么应用会崩溃。这是为了防止开发者在任务中处理太多逻辑而拖慢用户界面。
+* 如果你是通过`BroadcastReceiver`来启动的服务,那么谨记在从`onReceive()`返回之前要调用`HeadlessJsTaskService.acquireWakelockNow()`。
+
+[0]: https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)
\ No newline at end of file
diff --git a/docs/docs/0.43/height-and-width.md b/docs/docs/0.43/height-and-width.md
new file mode 100644
index 0000000..6431b24
--- /dev/null
+++ b/docs/docs/0.43/height-and-width.md
@@ -0,0 +1,56 @@
+组件的高度和宽度决定了其在屏幕上显示的尺寸。
+
+#### 指定宽高
+
+最简单的给组件设定尺寸的方式就是在样式中指定固定的`width`和`height`。React Native中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FixedDimensionsBasics extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+};
+// 注册应用(registerComponent)后才能正确渲染
+// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
+AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
+```
+这样给组件设置尺寸也是一种常见的模式,比如要求在不同尺寸的屏幕上都显示成一样的大小。
+
+#### 弹性(Flex)宽高
+
+在组件样式中使用`flex`可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用`flex:1`来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了`flex:1`,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的`flex`值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间`flex`值的比)。
+
+> 组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的`width`和`height`,也没有设定`flex`,则父容器的尺寸为零。其子组件如果使用了`flex`,也是无法显示的。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDimensionsBasics extends Component {
+ render() {
+ return (
+ // 试试去掉父View中的`flex: 1`。
+ // 则父View不再具有尺寸,因此子组件也无法再撑开。
+ // 然后再用`height: 300`来代替父View的`flex: 1`试试看?
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
+```
+
+当你熟练掌握了如何控制组件的尺寸后,下一步可以[学习如何在屏幕上排列组件了](layout-with-flexbox.html)。
diff --git a/docs/docs/0.43/image.md b/docs/docs/0.43/image.md
new file mode 100644
index 0000000..71dace2
--- /dev/null
+++ b/docs/docs/0.43/image.md
@@ -0,0 +1,956 @@
+一个用于显示多种不同类型图片的React组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。详细用法参阅[图片文档](images.html)。
+
+用法样例:
+
+```javascript
+renderImages() {
+ return (
+
+
+
+
+ );
+}
+```
+
+### 截图
+
+
+### 在Android上支持GIF和WebP格式图片
+
+默认情况下Android是不支持GIF和WebP格式的。你需要在`android/app/build.gradle`文件中根据需要手动添加以下模块:
+
+```
+dependencies {
+ // 如果你需要支持Android4.0(API level 14)之前的版本
+ compile 'com.facebook.fresco:animated-base-support:1.0.1'
+
+ // 如果你需要支持GIF动图
+ compile 'com.facebook.fresco:animated-gif:1.0.1'
+
+ // 如果你需要支持WebP格式,包括WebP动图
+ compile 'com.facebook.fresco:animated-webp:1.0.1'
+ compile 'com.facebook.fresco:webpsupport:1.0.1'
+
+ // 如果只需要支持WebP格式而不需要动图
+ compile 'com.facebook.fresco:webpsupport:1.0.1'
+}
+```
+
+如果你在使用GIF的同时还使用了ProGuard,那么需要在`proguard-rules.pro`中添加如下规则 :
+
+```
+-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl {
+ public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory, com.facebook.imagepipeline.core.ExecutorSupplier);
+}
+```
+
+### 属性
+
+
+
+
onLayout function #
+
+
当元素挂载或者布局改变的时候调用,参数为:{nativeEvent: {layout: {x, y, width, height}}}.
+
+
+
+
+
onLoadEnd function #
+
+
加载结束后,不论成功还是失败,调用此回调函数。
+
+
+
+
onLoadStart function #
+
+
+
+
resizeMode enum('cover', 'contain', 'stretch', 'repeat', 'center') #
+
+
决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。
+
+ cover: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全覆盖甚至超出容器,容器中不留任何空白。
+ contain: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。__译注__:这样图片完全被包裹在容器中,容器中可能留有空白
+ stretch: 拉伸图片且不维持宽高比,直到宽高都刚好填满容器。
+ repeat: 重复平铺图片直到填满容器。图片会维持原始尺寸。仅iOS可用。
+ center: 居中不拉伸。
+
+
+
+
+
source {uri: string}, number #
+
+
uri是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+
+
+
style style #
+
+
+
+
+
+
backfaceVisibility ReactPropTypes.oneOf(['visible', 'hidden'])
+
+
+
resizeMode Object.keys(ImageResizeMode)
+
+
+
backgroundColor color
+
+
+
borderBottomLeftRadius ReactPropTypes.number
+
+
+
borderBottomRightRadius ReactPropTypes.number
+
+
+
+
borderRadius number
+
+
+
borderTopLeftRadius ReactPropTypes.number
+
+
+
borderTopRightRadius ReactPropTypes.number
+
+
+
borderWidth number
+
+
+
overflow enum('visible', 'hidden')
+
+
+
+
opacity number
+
+
+
android overlayColor ReactPropTypes.string
+
+
+
+
+
+
+
testID string #
+
+
一个唯一的资源标识符,用来在自动测试脚本中标识这个元素。
+
+
+
android resizeMethod
+ enum('auto', 'resize', 'scale') #
+
当图片实际尺寸和容器样式尺寸不一致时,决定以怎样的策略来调整图片的尺寸。默认值为auto。
+
+ auto:使用启发式算法来在resize和scale中自动决定。
+
+ resize: 在图片解码之前,使用软件算法对其在内存中的数据进行修改。当图片尺寸比容器尺寸大得多时,应该优先使用此选项。
+ scale:对图片进行缩放。和resize相比,
+ scale速度更快(一般有硬件加速),而且图片质量更优。在图片尺寸比容器尺寸小或者只是稍大一点时,应该优先使用此选项。
+
+
关于resize和scale的详细说明请参考http://frescolib.org/docs/resizing-rotating.html .
+
+
+
+
ios accessibilityLabel string #
+
+
当用户与图片交互时,读屏器(无障碍功能)会朗读的文字。
+
+
+
+
ios accessible bool #
+
+
当此属性为真的时候,表示这个图片是一个启用了无障碍功能的元素。
+
+
+
+
ios blurRadius number #
+
+
+
blurRadius(模糊半径):为图片添加一个指定半径的模糊滤镜。
+
+
+
+
ios capInsets {top: number, left: number, bottom: number, right: number} #
+
+
当图片被缩放的时候,capInsets指定的角上的尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用(译注:这就是常说的九宫格或者.9图。了解更多信息,可以参见苹果官方文档
+
+
+
ios defaultSource
+ {uri: string, width: number, height: number, scale: number}, number #
+
在读取图片时默认显示的加载提示图片
+
+ uri - 是一个表示图片的资源标识的字符串,它可以是一个http地址或是一个本地文件路径(使用require(相对路径)来引用)。
+
+ width, height - 如果你知道图片的尺寸,那么可以在这里指定。这一尺寸会被用作<Image/>组件的默认尺寸。
+
+ scale - 图片的缩放系数。默认是1.0,意味着每一个图片像素都对应一个设备独立像素(DIP)。
+
+ number - 本地图片引用语法require('./image.jpg')所返回的内部资源id。
+
+
+
+
+
ios onError function #
+
+
当加载错误的时候调用此回调函数,参数为{nativeEvent: {error}}
+
+
+
ios onPartialLoad
+ function #
+
如果图片本身支持逐步加载,则逐步加载的过程中会调用此方法。“逐步加载”的具体定义与具体的标准和实现有关。
+
+
+
ios onProgress function #
+
+
在加载过程中不断调用,参数为{nativeEvent: {loaded, total}}
+
+
+
+
+### 方法
+
+
+
static getSize(uri: string, success: (width: number, height: number) => void, failure: (error: any) => void)
+ #
+
在显示图片前获取图片的宽高(以像素为单位)。如果图片地址不正确或下载失败,此方法也会失败。
+
要获取图片的尺寸,首先需要加载或下载图片(同时会被缓存起来)。这意味着理论上你可以用这个方法来预加载图片,虽然此方法并没有针对这一用法进行优化,而且将来可能会换一些实现方案使得并不需要完整下载图片即可获取尺寸。所以更好的预加载方案是使用下面那个专门的预加载方法。
+
+
static prefetch(url: string) #
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ ActivityIndicator,
+ Image,
+ Platform,
+ StyleSheet,
+ Text,
+ View,
+} = ReactNative;
+
+var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
+
+var ImageCapInsetsExample = require('./ImageCapInsetsExample');
+const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
+var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
+
+var NetworkImageCallbackExample = React.createClass({
+ getInitialState: function() {
+ return {
+ events: [],
+ startLoadPrefetched: false,
+ mountTime: new Date(),
+ };
+ },
+
+ componentWillMount() {
+ this.setState({mountTime: new Date()});
+ },
+
+ render: function() {
+ var { mountTime } = this.state;
+
+ return (
+
+ this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => {
+ this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`);
+ this.setState({startLoadPrefetched: true}, () => {
+ prefetchTask.then(() => {
+ this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
+ }, error => {
+ this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
+ });
+ });
+ }}
+ />
+ {this.state.startLoadPrefetched ?
+ this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
+ onLoad={(event) => {
+ // Currently this image source feature is only available on iOS.
+ if (event.nativeEvent.source) {
+ const url = event.nativeEvent.source.url;
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms) for URL ${url}`);
+ } else {
+ this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`);
+ }
+ }}
+ onLoadEnd={() => this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
+ />
+ : null}
+
+ {this.state.events.join('\n')}
+
+
+ );
+ },
+
+ _loadEventFired(event) {
+ this.setState((state) => {
+ return state.events = [...state.events, event];
+ });
+ }
+});
+
+var NetworkImageExample = React.createClass({
+ getInitialState: function() {
+ return {
+ error: false,
+ loading: false,
+ progress: 0
+ };
+ },
+ render: function() {
+ var loader = this.state.loading ?
+
+ {this.state.progress}%
+
+ : null;
+ return this.state.error ?
+ {this.state.error} :
+ this.setState({loading: true})}
+ onError={(e) => this.setState({error: e.nativeEvent.error, loading: false})}
+ onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})}
+ onLoad={() => this.setState({loading: false, error: false})}>
+ {loader}
+ ;
+ }
+});
+
+var ImageSizeExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 0,
+ height: 0,
+ };
+ },
+ componentDidMount: function() {
+ Image.getSize(this.props.source.uri, (width, height) => {
+ this.setState({width, height});
+ });
+ },
+ render: function() {
+ return (
+
+
+
+ Actual dimensions:{'\n'}
+ Width: {this.state.width}, Height: {this.state.height}
+
+
+ );
+ },
+});
+
+var MultipleSourcesExample = React.createClass({
+ getInitialState: function() {
+ return {
+ width: 30,
+ height: 30,
+ };
+ },
+ render: function() {
+ return (
+
+
+
+ Decrease image size
+
+
+ Increase image size
+
+
+ Container image size: {this.state.width}x{this.state.height}
+
+
+
+
+ );
+ },
+ increaseImageSize: function() {
+ if (this.state.width >= 100) {
+ return;
+ }
+ this.setState({
+ width: this.state.width + 10,
+ height: this.state.height + 10,
+ });
+ },
+ decreaseImageSize: function() {
+ if (this.state.width <= 10) {
+ return;
+ }
+ this.setState({
+ width: this.state.width - 10,
+ height: this.state.height - 10,
+ });
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Base component for displaying different types of images.';
+
+exports.examples = [
+ {
+ title: 'Plain Network Image',
+ description: 'If the `source` prop `uri` property is prefixed with ' +
+ '"http", then it will be downloaded from the network.',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Plain Static Image',
+ description: 'Static assets should be placed in the source code tree, and ' +
+ 'required in the same way as JavaScript modules.',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Image Loading Events',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Error Handler',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Download Progress',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'defaultSource',
+ description: 'Show a placeholder image when a network image is loading',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Border Color',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Width',
+ render: function() {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Border Radius',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Background Color',
+ render: function() {
+ return (
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Opacity',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Nesting',
+ render: function() {
+ return (
+
+
+ React
+
+
+ );
+ },
+ },
+ {
+ title: 'Tint Color',
+ description: 'The `tintColor` style prop changes all the non-alpha ' +
+ 'pixels to the tint color.',
+ render: function() {
+ return (
+
+
+
+
+
+
+
+
+ It also works with downloaded images:
+
+
+
+
+
+
+
+
+ );
+ },
+ },
+ {
+ title: 'Resize Mode',
+ description: 'The `resizeMode` style prop controls how the image is ' +
+ 'rendered within the frame.',
+ render: function() {
+ return (
+
+ {[smallImage, fullImage].map((image, index) => {
+ return (
+
+
+
+
+ Contain
+
+
+
+
+
+ Cover
+
+
+
+
+
+
+
+ Stretch
+
+
+
+ { Platform.OS === 'ios' ?
+
+
+ Repeat
+
+
+
+ : null }
+ { Platform.OS === 'android' ?
+
+
+ Center
+
+
+
+ : null }
+
+
+ );
+ })}
+
+ );
+ },
+ },
+ {
+ title: 'Animated GIF',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Base64 image',
+ render: function() {
+ return (
+
+ );
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Cap Insets',
+ description:
+ 'When the image is resized, the corners of the size specified ' +
+ 'by capInsets will stay a fixed size, but the center content and ' +
+ 'borders of the image will be stretched. This is useful for creating ' +
+ 'resizable rounded buttons, shadows, and other resizable assets.',
+ render: function() {
+ return ;
+ },
+ platform: 'ios',
+ },
+ {
+ title: 'Image Size',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'MultipleSourcesExample',
+ description:
+ 'The `source` prop allows passing in an array of uris, so that native to choose which image ' +
+ 'to diplay based on the size of the of the target image',
+ render: function() {
+ return ;
+ },
+ },
+ {
+ title: 'Legacy local image',
+ description:
+ 'Images shipped with the native bundle, but not managed ' +
+ 'by the JS packager',
+ render: function() {
+ return (
+
+ );
+ },
+ },
+ {
+ title: 'Bundled images',
+ description:
+ 'Images shipped in a separate native bundle',
+ render: function() {
+ return (
+
+
+
+
+ );
+ },
+ platform: 'ios',
+ },
+];
+
+var fullImage = {uri: 'https://facebook.github.io/react/img/logo_og.png'};
+var smallImage = {uri: 'https://facebook.github.io/react/img/logo_small_2x.png'};
+
+var styles = StyleSheet.create({
+ base: {
+ width: 38,
+ height: 38,
+ },
+ progress: {
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ width: 100
+ },
+ leftMargin: {
+ marginLeft: 10,
+ },
+ background: {
+ backgroundColor: '#222222'
+ },
+ sectionText: {
+ marginVertical: 6,
+ },
+ nestedText: {
+ marginLeft: 12,
+ marginTop: 20,
+ backgroundColor: 'transparent',
+ color: 'white'
+ },
+ resizeMode: {
+ width: 90,
+ height: 60,
+ borderWidth: 0.5,
+ borderColor: 'black'
+ },
+ resizeModeText: {
+ fontSize: 11,
+ marginBottom: 3,
+ },
+ icon: {
+ width: 15,
+ height: 15,
+ },
+ horizontal: {
+ flexDirection: 'row',
+ },
+ gif: {
+ flex: 1,
+ height: 200,
+ },
+ base64: {
+ flex: 1,
+ height: 50,
+ resizeMode: 'contain',
+ },
+ touchableText: {
+ fontWeight: '500',
+ color: 'blue',
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/imageeditor.md b/docs/docs/0.43/imageeditor.md
new file mode 100644
index 0000000..b77155e
--- /dev/null
+++ b/docs/docs/0.43/imageeditor.md
@@ -0,0 +1,10 @@
+### 方法
+
+
+
static cropImage(uri, cropData, success, failure)
+ #
+
根据指定的URI参数剪裁对应的图片。如果URI指向一个远程图片,则首先会自动下载该图片。如果图片无法下载或读取,则调用failure回调函数。
+
如果剪裁成功完成,则剪裁好的图片会被存放在ImageStore 中,同时success回调函数中返回的URI参数会指向ImageStore中的此图片。请记得在完成处理逻辑后删除ImageStore中的图片。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/imagepickerios.md b/docs/docs/0.43/imagepickerios.md
new file mode 100644
index 0000000..06a8484
--- /dev/null
+++ b/docs/docs/0.43/imagepickerios.md
@@ -0,0 +1,28 @@
+### 方法
+
+
+
+
static canRecordVideos(callback)
+ #
+
+
+
+
static canUseCamera(callback)
+ #
+
+
+
+
static openCameraDialog(config, successCallback, cancelCallback)
+ #
+
+
+
+
static openSelectDialog(config, successCallback, cancelCallback)
+ #
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/images.md b/docs/docs/0.43/images.md
new file mode 100644
index 0000000..0f01c9e
--- /dev/null
+++ b/docs/docs/0.43/images.md
@@ -0,0 +1,156 @@
+## 静态图片资源
+
+从0.14版本开始,React Native提供了一个统一的方式来管理iOS和Android应用中的图片。要往App中添加一个静态图片,只需把图片文件放在代码文件夹中某处,然后像下面这样去引用它:
+
+```javascript
+
+```
+
+图片文件的查找会和JS模块的查找方式一样。在上面的这个例子里,是哪个组件引用了这个图片,Packager就会去这个组件所在的文件夹下查找`my-icon.png`。并且,如果你有`my-icon.ios.png`和`my-icon.android.png`,Packager就会根据平台而选择不同的文件。
+
+你还可以使用`@2x`,`@3x`这样的文件名后缀,来为不同的屏幕精度提供图片。比如下面这样的代码结构:
+
+```
+.
+├── button.js
+└── img
+ ├── check@2x.png
+ └── check@3x.png
+```
+
+并且`button.js`里有这样的代码:
+
+```javascript
+
+```
+
+Packager会打包所有的图片并且依据屏幕精度提供对应的资源。譬如说,iPhone 5s会使用`check@2x.png`,而Nexus 5上则会使用`check@3x.png`。如果没有图片恰好满足屏幕分辨率,则会自动选中最接近的一个图片。
+
+_注意_:如果你添加图片的时候packager正在运行,可能需要重启packager以便能正确引入新添加的图片。
+
+这样会带来如下的一些好处:
+
+1. iOS和Android一致的文件系统。
+2. 图片和JS代码处在相同的文件夹,这样组件就可以包含自己所用的图片而不用单独去设置。
+3. 不需要全局命名。你不用再担心图片名字的冲突问题了。
+4. 只有实际被用到(即被require)的图片才会被打包到你的app。
+5. 现在在开发期间,增加和修改图片不需要重新编译了,只要和修改js代码一样刷新你的模拟器就可以了。
+6. 与访问网络图片相比,Packager可以得知图片大小了,不需要在代码里再声明一遍尺寸。
+7. 现在通过npm来分发组件或库可以包含图片了。
+
+注意:为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串。
+
+```javascript
+// 正确
+
+
+// 错误
+var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
+
+
+// 正确
+var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png');
+
+```
+
+请注意:通过这种方式引用的图片资源包含图片的尺寸(宽度,高度)信息,如果你需要动态缩放图片(例如,通过flex),你可能必须手动在style属性设置`{ width: undefined, height: undefined }`。
+
+## 静态非图片资源
+
+上面描述的`require`语法也可以用来静态地加载你项目中的声音、视频或者文档文件。大多数的文件类型包括`.mp3`, `.wav`, `.mp4`, `.mov`, `.htm` 和 `.pdf`(完整列表请看 [packager defaults](https://github.com/facebook/react-native/blob/master/packager/defaults.js))
+
+需要注意的是视频必须使用绝对定位而不是`flexGrow`,因为尺寸信息当前未通过非图片资源传递。这个限制对于直接链接到Xcode或者Android资源文件夹的视频不会出现。
+
+## 使用混合App的图片资源
+
+如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(通过Xcode的asset类目或者Android的drawable文件夹打包):
+
+```javascript
+
+```
+
+注意:这一做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸。
+
+
+## 网络图片
+
+很多要在App中显示的图片并不能在编译的时候获得,又或者有时候需要动态载入来减少打包后的二进制文件的大小。这些时候,与静态资源不同的是,`你需要手动指定图片的尺寸`。同时我们强烈建议你使用https以满足iOS [App Transport Security](https://segmentfault.com/a/1190000002933776) 的要求。
+
+```javascript
+// 正确
+
+
+// 错误
+
+```
+
+## 缓存控制(仅iOS)
+
+在某些情况下你可能仅仅想展示一张已经在本地缓存的图片,例如一个低分辨率的占位符,直到高分辨率的图片可用。在其他情况下你不关心图片是否是过时的,并愿意显示过时的图片,以节省带宽。缓存资源属性给你控制网络层与缓存交互的方式。
+
+* `default`:使用原生平台默认策略。
+* `reload`:URL的数据将从原始地址加载。不使用现有的缓存数据。
+* `force-cache`:现有的缓存数据将用于满足请求,忽略其期限或到期日。如果缓存中没有对应请求的数据,则从原始地址加载。
+* `only-if-cached`:现有的缓存数据将用于满足请求,忽略其期限或到期日。如果缓存中没有对应请求的数据,则不尝试从原始地址加载,并且认为请求是失败的。
+
+```javascript
+
+```
+
+## 本地文件系统中的图片
+
+参考[相册(CameraRoll)](cameraroll.html)这个例子来看如何使用在`Images.xcassets`以外的本地资源。
+
+### 最合适的相册图片
+
+iOS会为同一张图片在相册中保存多个不同尺寸的副本。为了性能考虑,从这些副本中挑出最合适的尺寸显得尤为重要。对于一处200x200大小的缩略图,显然不应该选择最高质量的3264x2448大小的图片。如果恰好有匹配的尺寸,那么React Native会自动为你选好。如果没有,则会选择最接近的尺寸进行缩放,但也至少缩放到比所需尺寸大出50%,以使图片看起来仍然足够清晰。这一切过程都是自动完成的,所以你不用操心自己去完成这些繁琐且易错的代码。
+
+## 为什么不在所有情况下都自动指定尺寸呢?
+
+`在浏览器中`,如果你不给图片指定尺寸,那么浏览器会首先渲染一个0x0大小的元素占位,然后下载图片,在下载完成后再基于正确的尺寸来渲染图片。这样做的最大问题是UI会在图片加载的过程中上下跳动,使得用户体验非常糟糕。
+
+`在React Native`中我们有意避免了这一行为。如此一来开发者就需要做更多工作来提前知晓远程图片的尺寸(或宽高比),但我们相信这样可以带来更好的用户体验。然而,从已经打包好的应用资源文件中读取图片(使用`require('image!x')`语法)则`无需指定尺寸`,因为它们的尺寸在加载时就可以立刻知道。
+
+比如这样一个引用`require('image!logo')`的实际输出结果可能是:
+
+```javascript
+{"__packager_asset":true,"isStatic":true,"path":"/Users/react/HelloWorld/iOS/Images.xcassets/react.imageset/logo.png","uri":"logo","width":591,"height":573}
+```
+
+## 资源属性是一个对象(object)
+
+在React Native中,另一个值得一提的变动是我们把`src`属性改为了`source`属性,而且并不接受字符串,正确的值是一个带有`uri`属性的对象。
+
+```javascript
+
+```
+
+深层次的考虑是,这样可以使我们在对象中添加一些元数据(metadata)。假设你在使用`require('./my-icon.png')`,那么我们就会在其中添加真实文件路径以及尺寸等信息(这只是举个例子,未来的版本中require的具体行为可能会变化)。此外这也是考虑了未来的扩展性,比如我们可能会加入精灵图(sprites)的支持:在输出`{uri: ...}`的基础上,我们可以进一步输出裁切信息`{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}`,这样理论上就可以在现有的代码中无缝支持精灵图的切分。
+
+对于开发者来说,则可以在其中标注一些有用的属性,例如图片的尺寸,这样可以使图片自己去计算将要显示的尺寸(而不必在样式中写死)。请在这一数据结构中自由发挥,存储你可能需要的任何图片相关的信息。
+
+## 通过嵌套来实现背景图片
+
+开发者们常面对的一种需求就是类似web中的背景图(`background-image`)。要实现这一用例,只需简单地创建一个``组件,然后把需要背景图的子组件嵌入其中即可。
+
+```javascript
+return (
+
+ Inside
+
+);
+```
+## iOS边框圆角的注意事项
+
+请注意下列边框圆角样式目前在iOS的图片组件上还不支持:
+
+* `borderTopLeftRadius`
+* `borderTopRightRadius`
+* `borderBottomLeftRadius`
+* `borderBottomRightRadius`
+
+## 在主线程外解码图片
+
+图片解码有可能会需要超过一帧的时间。在web上这是页面掉帧的一大因素,因为解码是在主线程中完成的。然而在React Native中,图片解码则是在另一线程中完成的。在实际开发中,一般对图片还没下载完成时的场景都做了处理(添加loading等),而图片解码时显示的占位符只占用几帧时间,并不需要你改动代码去额外处理。
diff --git a/docs/docs/0.43/imagestore.md b/docs/docs/0.43/imagestore.md
new file mode 100644
index 0000000..75b2759
--- /dev/null
+++ b/docs/docs/0.43/imagestore.md
@@ -0,0 +1,33 @@
+### 属性
+
+
+
+
static hasImageForTag(uri, callback) #
+
检查ImageStore中是否包含了指定URI的图片数据。目前仅限iOS。
+
+
+
static removeImageForTag(uri) #
+
从ImageStore中删除指定图片。存储在ImageStore中的图标必须手动删除,否则在应用退出之前将会一直占用内存。调用此删除方法并不需要先调用hasImageForTag()方法来检查,此方法会自动处理异常情况。目前仅限iOS。
+
+
+
static addImageFromBase64(base64ImageData, success, failure)
+ #
+
+
+
在ImageStore中以base64编码格式存储一幅图片,并返回一个URI以便访问或显示此图片。图片数据仅仅保存在内存中,在使用完毕后请调用removeImageForTag()方法来手动删除。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。目前仅限iOS。
+
+
+
static getBase64ForTag(uri, success, failure)
+ #
+
+
将ImageStore中的指定URI图片以base64编码格式的数据返回。如果找不到指定的URI,则会调用failure回调函数。
+
注意在JS和原生代码间传递大量二进制数据是非常低效的,所以若非必要,请尽量少用此方法。如果只是为了显示图片,可以直接把URI传递给<Image/>组件,并不需要额外取base64数据。
+
+
+
diff --git a/docs/docs/0.43/img/AddToBuildPhases.png b/docs/docs/0.43/img/AddToBuildPhases.png
new file mode 100644
index 0000000..7b83937
Binary files /dev/null and b/docs/docs/0.43/img/AddToBuildPhases.png differ
diff --git a/docs/docs/0.43/img/AddToLibraries.png b/docs/docs/0.43/img/AddToLibraries.png
new file mode 100644
index 0000000..652cdfd
Binary files /dev/null and b/docs/docs/0.43/img/AddToLibraries.png differ
diff --git a/docs/docs/0.43/img/AddToSearchPaths.png b/docs/docs/0.43/img/AddToSearchPaths.png
new file mode 100644
index 0000000..ccbe819
Binary files /dev/null and b/docs/docs/0.43/img/AddToSearchPaths.png differ
diff --git a/docs/docs/0.43/img/AndroidSDK1.png b/docs/docs/0.43/img/AndroidSDK1.png
new file mode 100644
index 0000000..9b9add7
Binary files /dev/null and b/docs/docs/0.43/img/AndroidSDK1.png differ
diff --git a/docs/docs/0.43/img/AndroidSDK2.png b/docs/docs/0.43/img/AndroidSDK2.png
new file mode 100644
index 0000000..663b8cc
Binary files /dev/null and b/docs/docs/0.43/img/AndroidSDK2.png differ
diff --git a/docs/docs/0.43/img/AnimationExperimentalOpacity.gif b/docs/docs/0.43/img/AnimationExperimentalOpacity.gif
new file mode 100644
index 0000000..cdc7902
Binary files /dev/null and b/docs/docs/0.43/img/AnimationExperimentalOpacity.gif differ
diff --git a/docs/docs/0.43/img/AnimationExperimentalScaleXY.gif b/docs/docs/0.43/img/AnimationExperimentalScaleXY.gif
new file mode 100644
index 0000000..850cfd1
Binary files /dev/null and b/docs/docs/0.43/img/AnimationExperimentalScaleXY.gif differ
diff --git a/docs/docs/0.43/img/CreateAVD.png b/docs/docs/0.43/img/CreateAVD.png
new file mode 100644
index 0000000..5a3d494
Binary files /dev/null and b/docs/docs/0.43/img/CreateAVD.png differ
diff --git a/docs/docs/0.43/img/DeveloperMenu.png b/docs/docs/0.43/img/DeveloperMenu.png
new file mode 100644
index 0000000..bb29544
Binary files /dev/null and b/docs/docs/0.43/img/DeveloperMenu.png differ
diff --git a/docs/docs/0.43/img/EmbeddedAppAndroid.png b/docs/docs/0.43/img/EmbeddedAppAndroid.png
new file mode 100644
index 0000000..126ba2d
Binary files /dev/null and b/docs/docs/0.43/img/EmbeddedAppAndroid.png differ
diff --git a/docs/docs/0.43/img/EmbeddedAppContainerViewExample.png b/docs/docs/0.43/img/EmbeddedAppContainerViewExample.png
new file mode 100644
index 0000000..6130dfb
Binary files /dev/null and b/docs/docs/0.43/img/EmbeddedAppContainerViewExample.png differ
diff --git a/docs/docs/0.43/img/EmbeddedAppExample.png b/docs/docs/0.43/img/EmbeddedAppExample.png
new file mode 100644
index 0000000..fefd306
Binary files /dev/null and b/docs/docs/0.43/img/EmbeddedAppExample.png differ
diff --git a/docs/docs/0.43/img/LayoutAnimationExample.gif b/docs/docs/0.43/img/LayoutAnimationExample.gif
new file mode 100644
index 0000000..68fcfce
Binary files /dev/null and b/docs/docs/0.43/img/LayoutAnimationExample.gif differ
diff --git a/docs/docs/0.43/img/NavigationStack-Navigator.gif b/docs/docs/0.43/img/NavigationStack-Navigator.gif
new file mode 100644
index 0000000..c1f8313
Binary files /dev/null and b/docs/docs/0.43/img/NavigationStack-Navigator.gif differ
diff --git a/docs/docs/0.43/img/NavigationStack-NavigatorIOS.gif b/docs/docs/0.43/img/NavigationStack-NavigatorIOS.gif
new file mode 100644
index 0000000..c1d56a1
Binary files /dev/null and b/docs/docs/0.43/img/NavigationStack-NavigatorIOS.gif differ
diff --git a/docs/docs/0.43/img/Rebound.gif b/docs/docs/0.43/img/Rebound.gif
new file mode 100644
index 0000000..0371663
Binary files /dev/null and b/docs/docs/0.43/img/Rebound.gif differ
diff --git a/docs/docs/0.43/img/ReboundExample.png b/docs/docs/0.43/img/ReboundExample.png
new file mode 100644
index 0000000..db33e5f
Binary files /dev/null and b/docs/docs/0.43/img/ReboundExample.png differ
diff --git a/docs/docs/0.43/img/ReboundImage.gif b/docs/docs/0.43/img/ReboundImage.gif
new file mode 100644
index 0000000..9c1da74
Binary files /dev/null and b/docs/docs/0.43/img/ReboundImage.gif differ
diff --git a/docs/docs/0.43/img/StaticImageAssets.png b/docs/docs/0.43/img/StaticImageAssets.png
new file mode 100644
index 0000000..e79acdc
Binary files /dev/null and b/docs/docs/0.43/img/StaticImageAssets.png differ
diff --git a/docs/docs/0.43/img/SystraceBadCreateUI.png b/docs/docs/0.43/img/SystraceBadCreateUI.png
new file mode 100644
index 0000000..813b101
Binary files /dev/null and b/docs/docs/0.43/img/SystraceBadCreateUI.png differ
diff --git a/docs/docs/0.43/img/SystraceBadJS.png b/docs/docs/0.43/img/SystraceBadJS.png
new file mode 100644
index 0000000..c67c840
Binary files /dev/null and b/docs/docs/0.43/img/SystraceBadJS.png differ
diff --git a/docs/docs/0.43/img/SystraceBadJS2.png b/docs/docs/0.43/img/SystraceBadJS2.png
new file mode 100644
index 0000000..de972c6
Binary files /dev/null and b/docs/docs/0.43/img/SystraceBadJS2.png differ
diff --git a/docs/docs/0.43/img/SystraceBadUI.png b/docs/docs/0.43/img/SystraceBadUI.png
new file mode 100644
index 0000000..ebd9faf
Binary files /dev/null and b/docs/docs/0.43/img/SystraceBadUI.png differ
diff --git a/docs/docs/0.43/img/SystraceExample.png b/docs/docs/0.43/img/SystraceExample.png
new file mode 100644
index 0000000..521ee16
Binary files /dev/null and b/docs/docs/0.43/img/SystraceExample.png differ
diff --git a/docs/docs/0.43/img/SystraceHighlightVSync.png b/docs/docs/0.43/img/SystraceHighlightVSync.png
new file mode 100644
index 0000000..dc7595a
Binary files /dev/null and b/docs/docs/0.43/img/SystraceHighlightVSync.png differ
diff --git a/docs/docs/0.43/img/SystraceJSThreadExample.png b/docs/docs/0.43/img/SystraceJSThreadExample.png
new file mode 100644
index 0000000..736af7d
Binary files /dev/null and b/docs/docs/0.43/img/SystraceJSThreadExample.png differ
diff --git a/docs/docs/0.43/img/SystraceNativeModulesThreadExample.png b/docs/docs/0.43/img/SystraceNativeModulesThreadExample.png
new file mode 100644
index 0000000..7e919f2
Binary files /dev/null and b/docs/docs/0.43/img/SystraceNativeModulesThreadExample.png differ
diff --git a/docs/docs/0.43/img/SystraceRenderThreadExample.png b/docs/docs/0.43/img/SystraceRenderThreadExample.png
new file mode 100644
index 0000000..2fa05bd
Binary files /dev/null and b/docs/docs/0.43/img/SystraceRenderThreadExample.png differ
diff --git a/docs/docs/0.43/img/SystraceUIThreadExample.png b/docs/docs/0.43/img/SystraceUIThreadExample.png
new file mode 100644
index 0000000..4883e85
Binary files /dev/null and b/docs/docs/0.43/img/SystraceUIThreadExample.png differ
diff --git a/docs/docs/0.43/img/SystraceWellBehaved.png b/docs/docs/0.43/img/SystraceWellBehaved.png
new file mode 100644
index 0000000..9540873
Binary files /dev/null and b/docs/docs/0.43/img/SystraceWellBehaved.png differ
diff --git a/docs/docs/0.43/img/TutorialFinal.png b/docs/docs/0.43/img/TutorialFinal.png
new file mode 100644
index 0000000..2f05b13
Binary files /dev/null and b/docs/docs/0.43/img/TutorialFinal.png differ
diff --git a/docs/docs/0.43/img/TutorialFinal2.png b/docs/docs/0.43/img/TutorialFinal2.png
new file mode 100644
index 0000000..75ec47c
Binary files /dev/null and b/docs/docs/0.43/img/TutorialFinal2.png differ
diff --git a/docs/docs/0.43/img/TutorialMock.png b/docs/docs/0.43/img/TutorialMock.png
new file mode 100644
index 0000000..6a267d0
Binary files /dev/null and b/docs/docs/0.43/img/TutorialMock.png differ
diff --git a/docs/docs/0.43/img/TutorialMock2.png b/docs/docs/0.43/img/TutorialMock2.png
new file mode 100644
index 0000000..94c7f65
Binary files /dev/null and b/docs/docs/0.43/img/TutorialMock2.png differ
diff --git a/docs/docs/0.43/img/TutorialSingleFetched.png b/docs/docs/0.43/img/TutorialSingleFetched.png
new file mode 100644
index 0000000..914cb88
Binary files /dev/null and b/docs/docs/0.43/img/TutorialSingleFetched.png differ
diff --git a/docs/docs/0.43/img/TutorialSingleFetched2.png b/docs/docs/0.43/img/TutorialSingleFetched2.png
new file mode 100644
index 0000000..c7dfd69
Binary files /dev/null and b/docs/docs/0.43/img/TutorialSingleFetched2.png differ
diff --git a/docs/docs/0.43/img/TutorialStyledMock.png b/docs/docs/0.43/img/TutorialStyledMock.png
new file mode 100644
index 0000000..48fb1c5
Binary files /dev/null and b/docs/docs/0.43/img/TutorialStyledMock.png differ
diff --git a/docs/docs/0.43/img/TutorialStyledMock2.png b/docs/docs/0.43/img/TutorialStyledMock2.png
new file mode 100644
index 0000000..16e99c2
Binary files /dev/null and b/docs/docs/0.43/img/TutorialStyledMock2.png differ
diff --git a/docs/docs/0.43/img/TweenState.gif b/docs/docs/0.43/img/TweenState.gif
new file mode 100644
index 0000000..84f34d2
Binary files /dev/null and b/docs/docs/0.43/img/TweenState.gif differ
diff --git a/docs/docs/0.43/img/Upgrading1.png b/docs/docs/0.43/img/Upgrading1.png
new file mode 100644
index 0000000..b60a852
Binary files /dev/null and b/docs/docs/0.43/img/Upgrading1.png differ
diff --git a/docs/docs/0.43/img/Upgrading2.png b/docs/docs/0.43/img/Upgrading2.png
new file mode 100644
index 0000000..c9a109d
Binary files /dev/null and b/docs/docs/0.43/img/Upgrading2.png differ
diff --git a/docs/docs/0.43/img/Upgrading3.png b/docs/docs/0.43/img/Upgrading3.png
new file mode 100644
index 0000000..3150aab
Binary files /dev/null and b/docs/docs/0.43/img/Upgrading3.png differ
diff --git a/docs/docs/0.43/img/alertIOS.png b/docs/docs/0.43/img/alertIOS.png
new file mode 100644
index 0000000..b35a2a4
Binary files /dev/null and b/docs/docs/0.43/img/alertIOS.png differ
diff --git a/docs/docs/0.43/img/api/actionsheetios1.png b/docs/docs/0.43/img/api/actionsheetios1.png
new file mode 100644
index 0000000..9f7f489
Binary files /dev/null and b/docs/docs/0.43/img/api/actionsheetios1.png differ
diff --git a/docs/docs/0.43/img/api/actionsheetios2.png b/docs/docs/0.43/img/api/actionsheetios2.png
new file mode 100644
index 0000000..4cf739f
Binary files /dev/null and b/docs/docs/0.43/img/api/actionsheetios2.png differ
diff --git a/docs/docs/0.43/img/api/alertios1.png b/docs/docs/0.43/img/api/alertios1.png
new file mode 100644
index 0000000..0406823
Binary files /dev/null and b/docs/docs/0.43/img/api/alertios1.png differ
diff --git a/docs/docs/0.43/img/api/alertios2.png b/docs/docs/0.43/img/api/alertios2.png
new file mode 100644
index 0000000..6c3964b
Binary files /dev/null and b/docs/docs/0.43/img/api/alertios2.png differ
diff --git a/docs/docs/0.43/img/api/cameraroll.png b/docs/docs/0.43/img/api/cameraroll.png
new file mode 100644
index 0000000..129b98b
Binary files /dev/null and b/docs/docs/0.43/img/api/cameraroll.png differ
diff --git a/docs/docs/0.43/img/api/statusbarios.png b/docs/docs/0.43/img/api/statusbarios.png
new file mode 100644
index 0000000..15e1ee7
Binary files /dev/null and b/docs/docs/0.43/img/api/statusbarios.png differ
diff --git a/docs/docs/0.43/img/api/toastandroid.png b/docs/docs/0.43/img/api/toastandroid.png
new file mode 100644
index 0000000..a4ec2a2
Binary files /dev/null and b/docs/docs/0.43/img/api/toastandroid.png differ
diff --git a/docs/docs/0.43/img/chrome_breakpoint.png b/docs/docs/0.43/img/chrome_breakpoint.png
new file mode 100644
index 0000000..d37c953
Binary files /dev/null and b/docs/docs/0.43/img/chrome_breakpoint.png differ
diff --git a/docs/docs/0.43/img/components/activityindicatorios.png b/docs/docs/0.43/img/components/activityindicatorios.png
new file mode 100644
index 0000000..57567ca
Binary files /dev/null and b/docs/docs/0.43/img/components/activityindicatorios.png differ
diff --git a/docs/docs/0.43/img/components/buttonExample.png b/docs/docs/0.43/img/components/buttonExample.png
new file mode 100644
index 0000000..40ce923
Binary files /dev/null and b/docs/docs/0.43/img/components/buttonExample.png differ
diff --git a/docs/docs/0.43/img/components/datepickerios.png b/docs/docs/0.43/img/components/datepickerios.png
new file mode 100644
index 0000000..bf34f1c
Binary files /dev/null and b/docs/docs/0.43/img/components/datepickerios.png differ
diff --git a/docs/docs/0.43/img/components/drawerlayoutandroid.png b/docs/docs/0.43/img/components/drawerlayoutandroid.png
new file mode 100644
index 0000000..f4911dd
Binary files /dev/null and b/docs/docs/0.43/img/components/drawerlayoutandroid.png differ
diff --git a/docs/docs/0.43/img/components/image.png b/docs/docs/0.43/img/components/image.png
new file mode 100644
index 0000000..1a2158d
Binary files /dev/null and b/docs/docs/0.43/img/components/image.png differ
diff --git a/docs/docs/0.43/img/components/listview1.png b/docs/docs/0.43/img/components/listview1.png
new file mode 100644
index 0000000..36a072e
Binary files /dev/null and b/docs/docs/0.43/img/components/listview1.png differ
diff --git a/docs/docs/0.43/img/components/listview2.png b/docs/docs/0.43/img/components/listview2.png
new file mode 100644
index 0000000..aceb4b5
Binary files /dev/null and b/docs/docs/0.43/img/components/listview2.png differ
diff --git a/docs/docs/0.43/img/components/listview3.png b/docs/docs/0.43/img/components/listview3.png
new file mode 100644
index 0000000..4b777a6
Binary files /dev/null and b/docs/docs/0.43/img/components/listview3.png differ
diff --git a/docs/docs/0.43/img/components/mapview.png b/docs/docs/0.43/img/components/mapview.png
new file mode 100644
index 0000000..12277f1
Binary files /dev/null and b/docs/docs/0.43/img/components/mapview.png differ
diff --git a/docs/docs/0.43/img/components/modal.png b/docs/docs/0.43/img/components/modal.png
new file mode 100644
index 0000000..9ff9dd0
Binary files /dev/null and b/docs/docs/0.43/img/components/modal.png differ
diff --git a/docs/docs/0.43/img/components/navigator1.png b/docs/docs/0.43/img/components/navigator1.png
new file mode 100644
index 0000000..1baadd9
Binary files /dev/null and b/docs/docs/0.43/img/components/navigator1.png differ
diff --git a/docs/docs/0.43/img/components/navigator2.png b/docs/docs/0.43/img/components/navigator2.png
new file mode 100644
index 0000000..4e86cb5
Binary files /dev/null and b/docs/docs/0.43/img/components/navigator2.png differ
diff --git a/docs/docs/0.43/img/components/navigatorios1.png b/docs/docs/0.43/img/components/navigatorios1.png
new file mode 100644
index 0000000..f7a8630
Binary files /dev/null and b/docs/docs/0.43/img/components/navigatorios1.png differ
diff --git a/docs/docs/0.43/img/components/navigatorios2.png b/docs/docs/0.43/img/components/navigatorios2.png
new file mode 100644
index 0000000..c4484c6
Binary files /dev/null and b/docs/docs/0.43/img/components/navigatorios2.png differ
diff --git a/docs/docs/0.43/img/components/pickerios.png b/docs/docs/0.43/img/components/pickerios.png
new file mode 100644
index 0000000..0a285dd
Binary files /dev/null and b/docs/docs/0.43/img/components/pickerios.png differ
diff --git a/docs/docs/0.43/img/components/progressbarandroid.png b/docs/docs/0.43/img/components/progressbarandroid.png
new file mode 100644
index 0000000..ce6be4c
Binary files /dev/null and b/docs/docs/0.43/img/components/progressbarandroid.png differ
diff --git a/docs/docs/0.43/img/components/progressviewios.png b/docs/docs/0.43/img/components/progressviewios.png
new file mode 100644
index 0000000..b37bf1e
Binary files /dev/null and b/docs/docs/0.43/img/components/progressviewios.png differ
diff --git a/docs/docs/0.43/img/components/scrollview.png b/docs/docs/0.43/img/components/scrollview.png
new file mode 100644
index 0000000..399b8e8
Binary files /dev/null and b/docs/docs/0.43/img/components/scrollview.png differ
diff --git a/docs/docs/0.43/img/components/segmentedcontrolios.png b/docs/docs/0.43/img/components/segmentedcontrolios.png
new file mode 100644
index 0000000..3cf27d6
Binary files /dev/null and b/docs/docs/0.43/img/components/segmentedcontrolios.png differ
diff --git a/docs/docs/0.43/img/components/sliderios.png b/docs/docs/0.43/img/components/sliderios.png
new file mode 100644
index 0000000..aba2736
Binary files /dev/null and b/docs/docs/0.43/img/components/sliderios.png differ
diff --git a/docs/docs/0.43/img/components/switchandroid.png b/docs/docs/0.43/img/components/switchandroid.png
new file mode 100644
index 0000000..c6e5342
Binary files /dev/null and b/docs/docs/0.43/img/components/switchandroid.png differ
diff --git a/docs/docs/0.43/img/components/switchios.png b/docs/docs/0.43/img/components/switchios.png
new file mode 100644
index 0000000..6dcf042
Binary files /dev/null and b/docs/docs/0.43/img/components/switchios.png differ
diff --git a/docs/docs/0.43/img/components/tabbarios.png b/docs/docs/0.43/img/components/tabbarios.png
new file mode 100644
index 0000000..1f203e8
Binary files /dev/null and b/docs/docs/0.43/img/components/tabbarios.png differ
diff --git a/docs/docs/0.43/img/components/text.png b/docs/docs/0.43/img/components/text.png
new file mode 100644
index 0000000..031593e
Binary files /dev/null and b/docs/docs/0.43/img/components/text.png differ
diff --git a/docs/docs/0.43/img/components/textinput.png b/docs/docs/0.43/img/components/textinput.png
new file mode 100644
index 0000000..57b579e
Binary files /dev/null and b/docs/docs/0.43/img/components/textinput.png differ
diff --git a/docs/docs/0.43/img/components/toolbarandroid.png b/docs/docs/0.43/img/components/toolbarandroid.png
new file mode 100644
index 0000000..6805c5a
Binary files /dev/null and b/docs/docs/0.43/img/components/toolbarandroid.png differ
diff --git a/docs/docs/0.43/img/components/touchable.png b/docs/docs/0.43/img/components/touchable.png
new file mode 100644
index 0000000..b4083e9
Binary files /dev/null and b/docs/docs/0.43/img/components/touchable.png differ
diff --git a/docs/docs/0.43/img/components/view.png b/docs/docs/0.43/img/components/view.png
new file mode 100644
index 0000000..d917353
Binary files /dev/null and b/docs/docs/0.43/img/components/view.png differ
diff --git a/docs/docs/0.43/img/components/viewpager.png b/docs/docs/0.43/img/components/viewpager.png
new file mode 100644
index 0000000..99ce67f
Binary files /dev/null and b/docs/docs/0.43/img/components/viewpager.png differ
diff --git a/docs/docs/0.43/img/components/webview.png b/docs/docs/0.43/img/components/webview.png
new file mode 100644
index 0000000..2315a19
Binary files /dev/null and b/docs/docs/0.43/img/components/webview.png differ
diff --git a/docs/docs/0.43/img/react-native-add-react-native-integration-example-high-scores.png b/docs/docs/0.43/img/react-native-add-react-native-integration-example-high-scores.png
new file mode 100644
index 0000000..6d07707
Binary files /dev/null and b/docs/docs/0.43/img/react-native-add-react-native-integration-example-high-scores.png differ
diff --git a/docs/docs/0.43/img/react-native-add-react-native-integration-example-home-screen.png b/docs/docs/0.43/img/react-native-add-react-native-integration-example-home-screen.png
new file mode 100644
index 0000000..2b1b8b2
Binary files /dev/null and b/docs/docs/0.43/img/react-native-add-react-native-integration-example-home-screen.png differ
diff --git a/docs/docs/0.43/img/react-native-add-react-native-integration-link.png b/docs/docs/0.43/img/react-native-add-react-native-integration-link.png
new file mode 100644
index 0000000..3d89eaf
Binary files /dev/null and b/docs/docs/0.43/img/react-native-add-react-native-integration-link.png differ
diff --git a/docs/docs/0.43/img/react-native-add-react-native-integration-wire-up.png b/docs/docs/0.43/img/react-native-add-react-native-integration-wire-up.png
new file mode 100644
index 0000000..43d2add
Binary files /dev/null and b/docs/docs/0.43/img/react-native-add-react-native-integration-wire-up.png differ
diff --git a/docs/docs/0.43/img/react-native-android-sdk-environment-variable-windows.png b/docs/docs/0.43/img/react-native-android-sdk-environment-variable-windows.png
new file mode 100644
index 0000000..6b3d981
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-sdk-environment-variable-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-additional-installs-linux.png b/docs/docs/0.43/img/react-native-android-studio-additional-installs-linux.png
new file mode 100644
index 0000000..3a0eda5
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-additional-installs-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-additional-installs.png b/docs/docs/0.43/img/react-native-android-studio-additional-installs.png
new file mode 100644
index 0000000..de32a09
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-additional-installs.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-linux.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-linux.png
new file mode 100644
index 0000000..10391c7
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-windows.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-windows.png
new file mode 100644
index 0000000..600ef3a
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools.png
new file mode 100644
index 0000000..a1d80be
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-build-tools.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-linux.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-linux.png
new file mode 100644
index 0000000..8c43a49
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-windows.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-windows.png
new file mode 100644
index 0000000..a5cf175
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms.png b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms.png
new file mode 100644
index 0000000..751fb93
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-android-sdk-platforms.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-avd-linux.png b/docs/docs/0.43/img/react-native-android-studio-avd-linux.png
new file mode 100644
index 0000000..de5f254
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-avd-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-avd-windows.png b/docs/docs/0.43/img/react-native-android-studio-avd-windows.png
new file mode 100644
index 0000000..ddc8f47
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-avd-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-avd.png b/docs/docs/0.43/img/react-native-android-studio-avd.png
new file mode 100644
index 0000000..74c053b
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-avd.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-configure-sdk-linux.png b/docs/docs/0.43/img/react-native-android-studio-configure-sdk-linux.png
new file mode 100644
index 0000000..8bb9d5f
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-configure-sdk-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-configure-sdk-windows.png b/docs/docs/0.43/img/react-native-android-studio-configure-sdk-windows.png
new file mode 100644
index 0000000..1adf5cb
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-configure-sdk-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-configure-sdk.png b/docs/docs/0.43/img/react-native-android-studio-configure-sdk.png
new file mode 100644
index 0000000..acfe1f3
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-configure-sdk.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-custom-install-linux.png b/docs/docs/0.43/img/react-native-android-studio-custom-install-linux.png
new file mode 100644
index 0000000..4410948
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-custom-install-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-custom-install-windows.png b/docs/docs/0.43/img/react-native-android-studio-custom-install-windows.png
new file mode 100644
index 0000000..7ed385a
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-custom-install-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-custom-install.png b/docs/docs/0.43/img/react-native-android-studio-custom-install.png
new file mode 100644
index 0000000..01ab7b2
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-custom-install.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-kvm-linux.png b/docs/docs/0.43/img/react-native-android-studio-kvm-linux.png
new file mode 100644
index 0000000..dab0810
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-kvm-linux.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-no-virtual-device-windows.png b/docs/docs/0.43/img/react-native-android-studio-no-virtual-device-windows.png
new file mode 100644
index 0000000..933a583
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-no-virtual-device-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-studio-verify-installs-windows.png b/docs/docs/0.43/img/react-native-android-studio-verify-installs-windows.png
new file mode 100644
index 0000000..8f0cf1b
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-studio-verify-installs-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-android-tools-environment-variable-windows.png b/docs/docs/0.43/img/react-native-android-tools-environment-variable-windows.png
new file mode 100644
index 0000000..5ddeb61
Binary files /dev/null and b/docs/docs/0.43/img/react-native-android-tools-environment-variable-windows.png differ
diff --git a/docs/docs/0.43/img/react-native-congratulations.png b/docs/docs/0.43/img/react-native-congratulations.png
new file mode 100644
index 0000000..92f520e
Binary files /dev/null and b/docs/docs/0.43/img/react-native-congratulations.png differ
diff --git a/docs/docs/0.43/img/react-native-existing-app-integration-ios-before.png b/docs/docs/0.43/img/react-native-existing-app-integration-ios-before.png
new file mode 100644
index 0000000..445dd79
Binary files /dev/null and b/docs/docs/0.43/img/react-native-existing-app-integration-ios-before.png differ
diff --git a/docs/docs/0.43/img/react-native-sorry-not-supported.png b/docs/docs/0.43/img/react-native-sorry-not-supported.png
new file mode 100644
index 0000000..8848f4c
Binary files /dev/null and b/docs/docs/0.43/img/react-native-sorry-not-supported.png differ
diff --git a/docs/docs/0.43/img/segmentedcontrolios.jpg b/docs/docs/0.43/img/segmentedcontrolios.jpg
new file mode 100644
index 0000000..5a01172
Binary files /dev/null and b/docs/docs/0.43/img/segmentedcontrolios.jpg differ
diff --git a/docs/docs/0.43/indexes.json b/docs/docs/0.43/indexes.json
new file mode 100644
index 0000000..a3cd433
--- /dev/null
+++ b/docs/docs/0.43/indexes.json
@@ -0,0 +1,507 @@
+{
+ "contains": [
+ {
+ "group": "入门基础",
+ "contains": [
+ {
+ "subject": "搭建开发环境",
+ "mdlink": "getting-started"
+ },
+ {
+ "subject": "编写Hello World",
+ "mdlink": "tutorial"
+ },
+ {
+ "subject": "Props(属性)",
+ "mdlink": "props"
+ },
+ {
+ "subject": "State(状态)",
+ "mdlink": "state"
+ },
+ {
+ "subject": "样式",
+ "mdlink": "style"
+ },
+ {
+ "subject": "高度与宽度",
+ "mdlink": "height-and-width"
+ },
+ {
+ "subject": "使用Flexbox布局",
+ "mdlink": "layout-with-flexbox"
+ },
+ {
+ "subject": "处理文本输入",
+ "mdlink": "handling-text-input"
+ },
+ {
+ "subject": "如何使用ScrollView",
+ "mdlink": "using-a-scrollview"
+ },
+ {
+ "subject": "如何使用ListView",
+ "mdlink": "using-a-listview"
+ },
+ {
+ "subject": "网络",
+ "mdlink": "network"
+ },
+ {
+ "subject": "其他参考资源",
+ "mdlink": "more-resources"
+ }
+ ]
+ },
+ {
+ "group": "进阶指南",
+ "contains": [
+ {
+ "subject": "嵌入到现有原生应用",
+ "mdlink": "integration-with-existing-apps"
+ },
+ {
+ "subject": "颜色",
+ "mdlink": "colors"
+ },
+ {
+ "subject": "图片",
+ "mdlink": "images"
+ },
+ {
+ "subject": "处理触摸事件",
+ "mdlink": "handling-touches"
+ },
+ {
+ "subject": "动画",
+ "mdlink": "animations"
+ },
+ {
+ "subject": "无障碍功能",
+ "mdlink": "accessibility"
+ },
+ {
+ "subject": "定时器",
+ "mdlink": "timers"
+ },
+ {
+ "subject": "直接操作",
+ "mdlink": "direct-manipulation"
+ },
+ {
+ "subject": "调试",
+ "mdlink": "debugging"
+ },
+ {
+ "subject": "自动化测试",
+ "mdlink": "testing"
+ },
+ {
+ "subject": "JavaScript环境",
+ "mdlink": "javascript-environment"
+ },
+ {
+ "subject": "导航器对比",
+ "mdlink": "navigation"
+ },
+ {
+ "subject": "性能",
+ "mdlink": "performance"
+ },
+ {
+ "subject": "升级",
+ "mdlink": "upgrading"
+ },
+ {
+ "subject": "特定平台代码",
+ "mdlink": "platform-specific-code"
+ },
+ {
+ "subject": "手势响应系统",
+ "mdlink": "gesture-responder-system"
+ }
+ ]
+ },
+ {
+ "group": "社区资源",
+ "contains": [
+ {
+ "subject": "中文视频教程",
+ "external": "/videos.html"
+ },
+ {
+ "subject": "js.coach第三方组件库",
+ "external": "https://js.coach/react-native"
+ },
+ {
+ "subject": "中文论坛组件分享区",
+ "external": "http://bbs.reactnative.cn/category/5"
+ },
+ {
+ "subject": "中文论坛问题求助区",
+ "external": "http://bbs.reactnative.cn/category/4"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(iOS)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-ios"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-ios"
+ },
+ {
+ "subject": "链接原生库",
+ "mdlink": "linking-libraries-ios"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-ios"
+ },
+ {
+ "subject": "在模拟器上运行",
+ "mdlink": "running-on-simulator-ios"
+ },
+ {
+ "subject": "在原生和React Native间通信",
+ "mdlink": "communication-ios"
+ }
+ ]
+ },
+ {
+ "group": "使用指南(Android)",
+ "contains": [
+ {
+ "subject": "原生模块",
+ "mdlink": "native-modules-android"
+ },
+ {
+ "subject": "原生UI组件",
+ "mdlink": "native-component-android"
+ },
+ {
+ "subject": "Headless JS(后台任务)",
+ "mdlink": "headless-js-android"
+ },
+ {
+ "subject": "在设备上运行",
+ "mdlink": "running-on-device-android"
+ },
+ {
+ "subject": "打包APK",
+ "mdlink": "signed-apk-android"
+ },
+ {
+ "subject": "调试Android UI性能",
+ "mdlink": "android-ui-performance"
+ },
+ {
+ "subject": "从源代码编译React Native",
+ "mdlink": "android-building-from-source"
+ }
+ ]
+ },
+ {
+ "group": "组件",
+ "contains": [
+ {
+ "subject": "ActivityIndicator",
+ "mdlink": "activityindicator"
+ },
+ {
+ "subject": "Button",
+ "mdlink": "button"
+ },
+ {
+ "subject": "DatePickerIOS",
+ "mdlink": "datepickerios"
+ },
+ {
+ "subject": "DrawerLayoutAndroid",
+ "mdlink": "drawerlayoutandroid"
+ },
+ {
+ "subject": "FlatList",
+ "mdlink": "flatlist"
+ },
+ {
+ "subject": "Image",
+ "mdlink": "image"
+ },
+ {
+ "subject": "KeyboardAvoidingView",
+ "mdlink": "keyboardavoidingview"
+ },
+ {
+ "subject": "ListView",
+ "mdlink": "listview"
+ },
+ {
+ "subject": "ListView.DataSource",
+ "mdlink": "listviewdatasource"
+ },
+ {
+ "subject": "Modal",
+ "mdlink": "modal"
+ },
+ {
+ "subject": "Navigator",
+ "mdlink": "navigator"
+ },
+ {
+ "subject": "NavigatorIOS",
+ "mdlink": "navigatorios"
+ },
+ {
+ "subject": "Picker",
+ "mdlink": "picker"
+ },
+ {
+ "subject": "PickerIOS",
+ "mdlink": "pickerios"
+ },
+ {
+ "subject": "ProgressBarAndroid",
+ "mdlink": "progressbarandroid"
+ },
+ {
+ "subject": "ProgressViewIOS",
+ "mdlink": "progressviewios"
+ },
+ {
+ "subject": "RefreshControl",
+ "mdlink": "refreshcontrol"
+ },
+ {
+ "subject": "ScrollView",
+ "mdlink": "scrollview"
+ },
+ {
+ "subject": "SectionList",
+ "mdlink": "sectionlist"
+ },
+ {
+ "subject": "SegmentedControlIOS",
+ "mdlink": "segmentedcontrolios"
+ },
+ {
+ "subject": "Slider",
+ "mdlink": "slider"
+ },
+ {
+ "subject": "StatusBar",
+ "mdlink": "statusbar"
+ },
+ {
+ "subject": "Switch",
+ "mdlink": "switch"
+ },
+ {
+ "subject": "TabBarIOS",
+ "mdlink": "tabbarios"
+ },
+ {
+ "subject": "TabBarIOS.Item",
+ "mdlink": "tabbarios-item"
+ },
+ {
+ "subject": "Text",
+ "mdlink": "text"
+ },
+ {
+ "subject": "TextInput",
+ "mdlink": "textinput"
+ },
+ {
+ "subject": "ToolbarAndroid",
+ "mdlink": "toolbarandroid"
+ },
+ {
+ "subject": "TouchableHighlight",
+ "mdlink": "touchablehighlight"
+ },
+ {
+ "subject": "TouchableNativeFeedback",
+ "mdlink": "touchablenativefeedback"
+ },
+ {
+ "subject": "TouchableOpacity",
+ "mdlink": "touchableopacity"
+ },
+ {
+ "subject": "TouchableWithoutFeedback",
+ "mdlink": "touchablewithoutfeedback"
+ },
+ {
+ "subject": "View",
+ "mdlink": "view"
+ },
+ {
+ "subject": "ViewPagerAndroid",
+ "mdlink": "viewpagerandroid"
+ },
+ {
+ "subject": "VirtualizedList",
+ "mdlink": "virtualizedlist"
+ },
+ {
+ "subject": "WebView",
+ "mdlink": "webview"
+ }
+ ]
+ },
+ {
+ "group": "API",
+ "contains": [
+ {
+ "subject": "ActionSheetIOS",
+ "mdlink": "actionsheetios"
+ },
+ {
+ "subject": "AdSupportIOS",
+ "mdlink": "adsupportios"
+ },
+ {
+ "subject": "Alert",
+ "mdlink": "alert"
+ },
+ {
+ "subject": "AlertIOS",
+ "mdlink": "alertios"
+ },
+ {
+ "subject": "Animated",
+ "mdlink": "animated"
+ },
+ {
+ "subject": "AppRegistry",
+ "mdlink": "appregistry"
+ },
+ {
+ "subject": "AppState",
+ "mdlink": "appstate"
+ },
+ {
+ "subject": "AsyncStorage",
+ "mdlink": "asyncstorage"
+ },
+ {
+ "subject": "BackAndroid",
+ "mdlink": "backandroid"
+ },
+ {
+ "subject": "CameraRoll",
+ "mdlink": "cameraroll"
+ },
+ {
+ "subject": "Clipboard",
+ "mdlink": "clipboard"
+ },
+ {
+ "subject": "DatePickerAndroid",
+ "mdlink": "datepickerandroid"
+ },
+ {
+ "subject": "Dimensions",
+ "mdlink": "dimensions"
+ },
+ {
+ "subject": "Easing",
+ "mdlink": "easing"
+ },
+ {
+ "subject": "Geolocation",
+ "mdlink": "geolocation"
+ },
+ {
+ "subject": "ImageEditor",
+ "mdlink": "imageeditor"
+ },
+ {
+ "subject": "ImagePickerIOS",
+ "mdlink": "imagepickerios"
+ },
+ {
+ "subject": "ImageStore",
+ "mdlink": "imagestore"
+ },
+ {
+ "subject": "InteractionManager",
+ "mdlink": "interactionmanager"
+ },
+ {
+ "subject": "Keyboard",
+ "mdlink": "keyboard"
+ },
+ {
+ "subject": "LayoutAnimation",
+ "mdlink": "layoutanimation"
+ },
+ {
+ "subject": "Linking",
+ "mdlink": "linking"
+ },
+ {
+ "subject": "NativeMethodsMixin",
+ "mdlink": "nativemethodsmixin"
+ },
+ {
+ "subject": "NetInfo",
+ "mdlink": "netinfo"
+ },
+ {
+ "subject": "PanResponder",
+ "mdlink": "panresponder"
+ },
+ {
+ "subject": "PermissionsAndroid",
+ "mdlink": "permissionsandroid"
+ },
+ {
+ "subject": "PixelRatio",
+ "mdlink": "pixelratio"
+ },
+ {
+ "subject": "PushNotificationIOS",
+ "mdlink": "pushnotificationios"
+ },
+ {
+ "subject": "Share",
+ "mdlink": "share"
+ },
+ {
+ "subject": "StyleSheet",
+ "mdlink": "stylesheet"
+ },
+ {
+ "subject": "Systrace",
+ "mdlink": "systrace"
+ },
+ {
+ "subject": "TimePickerAndroid",
+ "mdlink": "timepickerandroid"
+ },
+ {
+ "subject": "ToastAndroid",
+ "mdlink": "toastandroid"
+ },
+ {
+ "subject": "Vibration",
+ "mdlink": "vibration"
+ },
+ {
+ "subject": "布局样式属性",
+ "mdlink": "layout-props"
+ },
+ {
+ "subject": "阴影样式属性",
+ "mdlink": "shadow-props"
+ }
+ ]
+ }
+ ]
+}
diff --git a/docs/docs/0.43/integration-with-existing-apps.md b/docs/docs/0.43/integration-with-existing-apps.md
new file mode 100644
index 0000000..95ef4dd
--- /dev/null
+++ b/docs/docs/0.43/integration-with-existing-apps.md
@@ -0,0 +1,853 @@
+
+
+
+## 核心概念
+
+如果你正准备从头开始制作一个新的应用,那么React Native会是个非常好的选择。但如果你只想给现有的原生应用中添加一两个视图或是业务流程,React Native也同样不在话下。只需简单几步,你就可以给原有应用加上新的基于React Native的特性、画面和视图等。
+
+
+
+
+把React Native组件植入到iOS应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 创建一个`Podfile`,在其中以`subspec`的形式填写所有你要植入的React Native的组件。
+3. 创建js文件,编写React Native组件的js代码。
+4. 添加一个事件处理函数,用于创建一个`RCTRootView`。这个`RCTRootView`正是用来承载你的React Native组件的,而且它必须对应你在`index.ios.js`中使用`AppRegistry`注册的模块名字。
+5. 启动React Native的Packager服务,运行应用。
+6. 根据需要添加更多React Native的组件。
+7. [调试](debugging.html)。
+8. 准备[部署发布](running-on-device-ios.html) (比如可以利用`react-native-xcode.sh`脚本)。
+9. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+把React Native组件植入到Android应用中有如下几个主要步骤:
+
+1. 首先当然要了解你要植入的React Native组件。
+2. 在Android项目根目录中使用npm来安装`react-native` ,这样同时会创建一个`node_modules/`的目录。
+3. 创建js文件,编写React Native组件的js代码。
+4. 在`build.gradle`文件中添加`com.facebook.react:react-native:+`,以及一个指向`node_nodules/`目录中的`react-native`预编译库的`maven`路径。
+5. 创建一个React Native专属的`Activity`,在其中再创建`ReactRootView`。
+6. 启动React Native的Packager服务,运行应用。
+7. 根据需要添加更多React Native的组件。
+8. 在真机上[运行](running-on-device-android.html)、[调试](debugging.html)。
+9. [打包](signed-apk-android.html)。
+10. 发布应用,升职加薪,走向人生巅峰!😘
+
+
+
+
+## 开发环境准备
+
+
+
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在安卓平台上所需的一切依赖软件(比如`npm`)。
+
+
+
+
+### 基础环境
+
+首先按照[开发环境搭建教程](getting-started.html)来安装React Native在iOS平台上所需的一切依赖软件(比如`npm`)。
+
+### CocoaPods
+
+[CocoaPods](http://cocoapods.org)是针对iOS和Mac开发的包管理工具。我们用它来把React Native框架的代码下载下来并添加到你当前的项目中。
+
+```bash
+$ sudo gem install cocoapods
+```
+
+> 从技术上来讲,我们完全可以跳过CocoaPods,但是这样一来我们就需要手工来完成很多配置项。CocoaPods可以帮我们完成这些繁琐的工作。
+
+
+## 示例App
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/iOS-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。 下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+在本教程中我们用于[示范的app](https://github.com/JoelMarcey/swift-2048)是一个[2048](https://en.wikipedia.org/wiki/2048_(video_game)类型的游戏。下面是这个游戏还没有植入React Native时的主界面:
+
+
+
+
+
+
+## 依赖包
+
+React Native的植入过程同时需要React和React Native两个node依赖包。
+
+### `package.json`
+
+我们把具体的依赖包记录在`package.json`文件中。如果项目根目录中没有这个文件,那就自己创建一个。
+
+> 对于一个典型的React Native项目来说,一般`package.json`和`index.ios.js`等文件会放在项目的根目录下。而iOS相关的原生代码会放在一个名为`ios/`的子目录中,这里也同时放着你的Xcode项目文件(`.xcodeproj`)。
+
+下面是一个最简单的`package.json`的内容示例。
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+```bash
+{
+ "name": "swift-2048",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+
+
+### 安装依赖包
+
+使用npm(node包管理器,Node package manager)来安装React和React Native模块。这些模块会被安装到项目根目录下的`node_modules/`目录中。
+在包含有package.json文件的目录(一般也就是项目根目录)中运行下列命令来安装:
+
+```bash
+$ npm install
+```
+
+## React Native框架
+
+React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的`Podfile`中指定我们所需要使用的组件。
+
+### Subspecs
+
+在你开始把React Native植入到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是`subspec`要做的工作。在创建`Podfile`文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个`subspec`。
+
+可用的`subspec`都列在[`node_modules/react-native/React.podspec`](https://github.com/facebook/react-native/blob/master/React.podspec)中,基本都是按其功能命名的。一般来说你首先需要添加`Core`,这一`subspec`包含了必须的`AppRegistry`、`StyleSheet`、`View`以及其他的一些React Native核心库。如果你想使用React Native的`Text`库(即``组件),那就需要添加`RCTText`的`subspec`。同理,`Image`需要加入`RCTImage`,等等。
+
+#### Podfile
+
+在React和React Native模块成功安装到`node_modules`目录之后,你就可以开始创建`Podfile`以便选择所需的组件安装到应用中。
+
+创建`Podfile`的最简单的方式就是在iOS原生代码所在的目录中使用CocoaPods的`init`命令:
+
+```bash
+## 在iOS原生代码所在的目录中(也就是`.xcodeproj`文件所在的目录)执行:
+$ pod init
+```
+
+`Podfile`会创建在执行命令的目录中。你需要调整其内容以满足你的植入需求。调整后的`Podfile`的内容看起来类似下面这样:
+
+
+
+```
+# target的名字一般与你的项目名字相同
+target 'NumberTileGame' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+ # 如果你的RN版本 >= 0.42.0,请加入下面这行
+ pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"
+
+end
+```
+
+
+
+```
+source 'https://github.com/CocoaPods/Specs.git'
+
+# 对于Swift应用来说下面两句是必须的
+platform :ios, '8.0'
+use_frameworks!
+
+# target的名字一般与你的项目名字相同
+target 'swift-2048' do
+
+ # 'node_modules'目录一般位于根目录中
+ # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # 这个模块是用于调试功能的
+ # 在这里继续添加你所需要的模块
+ ]
+ # 如果你的RN版本 >= 0.42.0,请加入下面这行
+ pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"
+
+end
+```
+
+
+
+#### Pod安装
+
+创建好了`Podfile`后,就可以开始安装React Native的pod包了。
+
+```bash
+$ pod install
+```
+
+然后你应该可以看到类似下面的输出(译注:同样由于众所周知的网络原因,pod install的过程在国内非常不顺利,请自行配备稳定的翻墙工具,或是尝试一些[镜像源](https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&ch=2&tn=98010089_dg&wd=cocoapods%20%E9%95%9C%E5%83%8F&oq=cocoapods%E9%95%9C%E5%83%8F&rsv_pq=8fe4602600052d40&rsv_t=5d9fNEvNrqwcBS3rvMCKw0Cc%2FoW6XdW%2Bm4zks2nF3BxZ6cyWtJx1g%2F39Id6cUzeRTLM&rqlang=cn&rsv_enter=0&inputT=809&rsv_sug3=9&rsv_sug1=7&rsv_sug7=100&prefixsug=cocoapods%20%E9%95%9C%E5%83%8F&rsp=0&rsv_sug4=1010)):
+
+```bash
+Analyzing dependencies
+Fetching podspec for `React` from `../node_modules/react-native`
+Downloading dependencies
+Installing React (0.26.0)
+Generating Pods project
+Integrating client project
+Sending stats
+Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.
+```
+
+
+
+> 如果你看到类似"*The `swift-2048 [Debug]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig`. This can lead to problems with the CocoaPods installation*"的警告,请查看Xcode的`Build Settings`中的`Framework Search Paths`选项,确保其中的`Debug`和`Release`都只包含`$(inherited)`。
+
+
+
+## 代码集成
+
+现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正植入到应用中了。在我们的2048示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的React Native页面。
+
+### React Native组件
+
+我们首先要写的是"High Score"(得分排行榜)的JavaScript端的代码。
+
+#### 创建一个`index.ios.js`文件
+
+首先创建一个空的`index.ios.js`文件。一般来说我们把它放置在项目根目录下。
+
+> `index.ios.js`是React Native应用在iOS上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行`require/import`导入语句。本教程中为了简单示范,把全部的代码都写到了`index.ios.js`里(当然实际开发中我们并不推荐这样做)。
+
+```bash
+# 在项目根目录执行以下命令创建文件:
+$ touch index.ios.js
+```
+
+#### 添加你自己的React Native代码
+
+在`index.ios.js`中添加你自己的组件。这里我们只是简单的添加一个``组件,然后用一个带有样式的``组件把它包起来。
+
+```js
+'use strict';
+
+import React from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class RNHighScores extends React.Component {
+ render() {
+ var contents = this.props["scores"].map(
+ score => {score.name}:{score.value}{"\n"}
+ );
+ return (
+
+
+ 2048 High Scores!
+
+
+ {contents}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#FFFFFF',
+ },
+ highScoresTitle: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ scores: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+});
+
+// 整体js模块的名称
+AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
+```
+
+> `RNHighScores`是整体js模块(即你所有的js代码)的名称。你在iOS原生代码中添加React Native视图时会用到这个名称。
+
+## The Magic: `RCTRootView`
+
+现在我们已经在`index.ios.js`中创建了React Native组件,下一步就是把这个组件添加给一个新的或已有的`ViewController`。 The easiest path to take is to optionally create an event path to your component and then add that component to an existing `ViewController`.
+
+We will tie our React Native component with a new native view in the `ViewController` that will actually host it called `RCTRootView` .
+
+### Create an Event Path
+
+You can add a new link on the main game menu to go to the "High Score" React Native page.
+
+
+
+#### 事件处理
+
+We will now add an event handler from the menu link. A method will be added to the main `ViewController` of your application. This is where `RCTRootView` comes into play.
+
+When you build a React Native application, you use the React Native packager to create an `index.ios.bundle` that will be served by the React Native server. Inside `index.ios.bundle` will be our `RNHighScore` module. So, we need to point our `RCTRootView` to the location of the `index.ios.bundle` resource (via `NSURL`) and tie it to the module.
+
+We will, for debugging purposes, log that the event handler was invoked. Then, we will create a string with the location of our React Native code that exists inside the `index.ios.bundle`. Finally, we will create the main `RCTRootView`. Notice how we provide `RNHighScores` as the `moduleName` that we created [above](#the-react-native-component) when writing the code for our React Native component.
+
+
+
+首先导入`RCTRootView`的头文件。
+
+```
+#import "RCTRootView.h"
+```
+
+> 这里的`initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+- (IBAction)highScoreButtonPressed:(id)sender {
+ NSLog(@"High Score Button Pressed");
+ NSURL *jsCodeLocation = [NSURL
+ URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
+ RCTRootView *rootView =
+ [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
+ moduleName : @"RNHighScores"
+ initialProperties :
+ @{
+ @"scores" : @[
+ @{
+ @"name" : @"Alex",
+ @"value": @"42"
+ },
+ @{
+ @"name" : @"Joel",
+ @"value": @"10"
+ }
+ ]
+ }
+ launchOptions : nil];
+ UIViewController *vc = [[UIViewController alloc] init];
+ vc.view = rootView;
+ [self presentViewController:vc animated:YES completion:nil];
+}
+```
+
+> Note that `RCTRootView initWithURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `[RCTRootView alloc] initWithURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+首先`import`导入`React`库。
+
+```
+import React
+```
+
+> The `initialProperties` are here for illustration purposes so we have some data for our high score screen. In our React Native component, we will use `this.props` to get access to that data.
+
+```
+@IBAction func highScoreButtonTapped(sender : UIButton) {
+ NSLog("Hello")
+ let jsCodeLocation = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")
+ let mockData:NSDictionary = ["scores":
+ [
+ ["name":"Alex", "value":"42"],
+ ["name":"Joel", "value":"10"]
+ ]
+ ]
+
+ let rootView = RCTRootView(
+ bundleURL: jsCodeLocation,
+ moduleName: "RNHighScores",
+ initialProperties: mockData as [NSObject : AnyObject],
+ launchOptions: nil
+ )
+ let vc = UIViewController()
+ vc.view = rootView
+ self.present(vc, animated: true, completion: nil)
+}
+```
+
+> 注意`RCTRootView bundleURL` starts up a new JSC VM. To save resources and simplify the communication between RN views in different parts of your native app, you can have multiple views powered by React Native that are associated with a single JS runtime. To do that, instead of using `RCTRootView bundleURL`, use [`RCTBridge initWithBundleURL`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridge.h#L93) to create a bridge and then use `RCTRootView initWithBridge`.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+> When moving your app to production, the `NSURL` can point to a pre-bundled file on disk via something like `let mainBundle = NSBundle(URLForResource: "main" withExtension:"jsbundle")`. You can use the `react-native-xcode.sh` script in `node_modules/react-native/packager/` to generate that pre-bundled file.
+
+
+
+#### Wire Up
+
+Wire up the new link in the main menu to the newly added event handler method.
+
+
+
+> One of the easier ways to do this is to open the view in the storyboard and right click on the new link. Select something such as the `Touch Up Inside` event, drag that to the storyboard and then select the created method from the list provided.
+
+## 测试植入结果
+
+You have now done all the basic steps to integrate React Native with your current application. Now we will start the React Native packager to build the `index.ios.bundle` packager and the server running on `localhost` to serve it.
+
+### App Transport Security
+
+Apple has blocked implicit cleartext HTTP resource loading. So we need to add the following our project's `Info.plist` (or equivalent) file.
+
+```xml
+NSAppTransportSecurity
+
+ NSExceptionDomains
+
+ localhost
+
+ NSTemporaryExceptionAllowsInsecureHTTPLoads
+
+
+
+
+```
+
+### 运行Packager
+
+```bash
+# From the root of your project, where the `node_modules` directory is located.
+$ npm start
+```
+
+### 运行应用
+
+如果你使用的是Xcode,那么照常编译和运行应用即可。如果你没有使用Xcode(但是你仍然必须安装Xcode),则可以在命令行中使用以下命令来运行应用:
+
+```bash
+# 在项目的根目录中执行:
+$ react-native run-ios
+```
+
+In our sample application, you should see the link to the "High Scores" and then when you click on that you will see the rendering of your React Native component.
+
+Here is the *native* application home screen:
+
+
+
+Here is the *React Native* high score screen:
+
+
+
+> If you are getting module resolution issues when running your application please see [this GitHub issue](https://github.com/facebook/react-native/issues/4968) for information and possible resolution. [This comment](https://github.com/facebook/react-native/issues/4968#issuecomment-220941717) seemed to be the latest possible resolution.
+
+### 看一下完整的代码变更
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/iOS-2048/commit/9ae70c7cdd53eb59f5f7c7daab382b0300ed3585)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+你可以在这个[GitHub提交记录](https://github.com/JoelMarcey/swift-2048/commit/13272a31ee6dd46dc68b1dcf4eaf16c1a10f5229)里查看一次完整的植入过程具体有哪些代码/文件变更。
+
+
+
+## 在应用中添加JS代码
+
+在项目的根目录中运行:
+
+ $ npm init
+ $ npm install --save react react-native
+ $ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
+
+`npm init`创建了一个空的node模块(其实就是创建了一个package.json描述文件),而`npm install`则创建了node_modules目录并把react和react-native下载到了其中。至于第三步curl命令,其实质是`下载`.flowconfig配置文件,这个文件用于约束js代码的写法。这一步非必需,可跳过。下面我们打开新创建的`package.json`文件,然后在其`scripts`字段中加入:
+
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+
+现在你的`package.json`内容应该类似这样:
+
+```bash
+{
+ "name": "NumberTileGame",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react": "15.4.1",
+ "react-native": "0.39.2"
+ }
+}
+```
+
+> 示例中的`version`字段没有太大意义(除非你要把你的项目发布到npm仓库)。`scripts`中是用于启动packager服务的命令。`dependencies`中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用`npm info react`和`npm info react-native`来查看当前的最新版本。另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install,然后注意观察安装过程中的报错信息,例如`require react@某.某.某版本, but none was installed`,然后根据这样的提示,执行`npm i -S react@某.某.某版本`。
+
+
+接下来在项目根目录中创建`index.android.js`文件,然后将下面的代码复制粘贴进来:
+
+```js
+'use strict';
+
+import React from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View
+} from 'react-native';
+
+class HelloWorld extends React.Component {
+ render() {
+ return (
+
+ Hello, World
+
+ )
+ }
+}
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ hello: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+});
+
+AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
+```
+
+## 准备工作
+
+在你的app中 `build.gradle` 文件中添加 React Native 依赖:
+
+```
+ dependencies {
+ ...
+ compile "com.facebook.react:react-native:+" // From node_modules.
+ }
+```
+
+> 你想要指定构建时的 React Native 版本,请用 `npm` 已下载的本地 React Native 的版本号替换 `+` 。
+
+在项目的 `build.gradle` 文件中为 React Native 添加一个 maven 依赖的入口,必须写在 "allprojects" 代码块中:
+
+```
+allprojects {
+ repositories {
+ ...
+ maven {
+ // All of React Native (JS, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+ }
+ ...
+}
+```
+
+> 确保依赖路径的正确!以免在 Android Studio 运行Gradle同步构建时抛出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 异常。
+
+接着,在 `AndroidManifest.xml` 清单文件中声明网络权限:
+
+
+
+如果需要访问 `DevSettingsActivity` 界面,也需要在 `AndroidManifest.xml` 中声明:
+
+
+
+
+This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.
+
+## 添加原生代码
+
+想要通过原生代码调用 React Native ,就像这样,我们需要在一个 `Activity` 中创建一个 `ReactRootView` 对象,将它关联一个 React application 并设为界面的主视图。
+
+> 如果你想在安卓5.0以下的系统上运行,请用 `com.android.support:appcompat` 包中的 `AppCompatActivity` 代替 `Activity` 。
+
+
+```java
+public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
+ private ReactRootView mReactRootView;
+ private ReactInstanceManager mReactInstanceManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mReactRootView = new ReactRootView(this);
+ mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ .setBundleAssetName("index.android.bundle")
+ .setJSMainModuleName("index.android")
+ .addPackage(new MainReactPackage())
+ .setUseDeveloperSupport(BuildConfig.DEBUG)
+ .setInitialLifecycleState(LifecycleState.RESUMED)
+ .build();
+
+ // 注意这里的HelloWorld必须对应“index.android.js”中的
+ // “AppRegistry.registerComponent()”的第一个参数
+ mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
+
+ setContentView(mReactRootView);
+ }
+
+ @Override
+ public void invokeDefaultOnBackPressed() {
+ super.onBackPressed();
+ }
+}
+```
+
+> 如果你的项目名字不是叫“HelloWorld”,则需要将“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一个参数替换为对应的名字。
+
+如果你使用的是 Android Studio , 可以使用`Alt + Enter`快捷键来自动为MyReactActivity类补上缺失的import语句。注意引入的`BuildConfig`应该是在你自己的包中,而不是在`...facebook...`的包中。
+
+我们需要把 `MyReactActivity` 的主题设定为 `Theme.AppCompat.Light.NoActionBar` ,因为里面有许多组件都使用了这一主题。
+
+ ```xml
+
+
+ ```
+
+> 一个`ReactInstanceManager`可以在多个activities或fragments间共享。 You will want to make your own `ReactFragment` or `ReactActivity` and have a singleton *holder* that holds a `ReactInstanceManager`. When you need the `ReactInstanceManager` (e.g., to hook up the `ReactInstanceManager` to the lifecycle of those Activities or Fragments) use the one provided by the singleton.
+
+下一步我们需要把一些activity的生命周期回调传递给`ReactInstanceManager`:
+
+```java
+@Override
+protected void onPause() {
+ super.onPause();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostPause(this);
+ }
+}
+
+@Override
+protected void onResume() {
+ super.onResume();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostResume(this, this);
+ }
+}
+
+@Override
+protected void onDestroy() {
+ super.onDestroy();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onHostDestroy();
+ }
+}
+```
+
+We also need to pass back button events to React Native:
+
+```java
+@Override
+ public void onBackPressed() {
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+}
+```
+
+This allows JavaScript to control what happens when the user presses the hardware back button (e.g. to implement navigation). When JavaScript doesn't handle a back press, your `invokeDefaultOnBackPressed` method will be called. By default this simply finishes your `Activity`.
+
+Finally, we need to hook up the dev menu. By default, this is activated by (rage) shaking the device, but this is not very useful in emulators. So we make it show when you press the hardware menu button (use `Ctrl + M` if you're using Android Studio emulator):
+
+```java
+@Override
+public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
+ mReactInstanceManager.showDevOptionsDialog();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+}
+```
+
+现在activity已就绪,可以运行一些JavaScript代码了。
+
+### 配置权限以便开发中的红屏错误能正确显示
+
+如果你的应用会运行在Android 6.0(API level 23)或更高版本,请确保你在开发版本中有打开`悬浮窗(overlay)`权限。If your app is targeting the Android `API level 23` or greater, make sure you have the `overlay` permission enabled for the development build. You can check it with `Settings.canDrawOverlays(this);`. This is required in dev builds because react native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23, the user needs to approve it. This can be acheived by adding the following code to the Activity file in the onCreate() method. OVERLAY_PERMISSION_REQ_CODE is a field of the class which would be responsible for passing the result back to the Activity.
+
+```java
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:" + getPackageName()));
+ startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
+ }
+}
+```
+
+Finally, the `onActivityResult()` method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX.
+
+```java
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this)) {
+ // SYSTEM_ALERT_WINDOW permission not granted...
+ }
+ }
+ }
+}
+```
+
+
+## 运行你的应用
+
+运行应用首先需要启动开发服务器(Packager)。你只需在项目根目录中执行以下命令即可:
+
+ $ npm start
+
+保持packager的窗口运行不要关闭,然后像往常一样编译运行你的Android应用(在命令行中执行`./gradlew installDebug`或是在Android Studio中编译运行)。
+
+> 如果你是使用Android Studio来编译运行,有可能会导致packger报错退出。这种情况下你需要安装[watchman](https://facebook.github.io/watchman/)。但是watchman目前没有稳定的Windows版本,所以在Windows下这种崩溃情况暂时没有特别好的解决方案。
+
+编译执行一切顺利进行之后,在进入到MyReactActivity时应该就能立刻从packager中读取JavaScript代码并执行和显示:
+
+
+
+## 在Android Studio中打包
+
+你也可以使用Android Studio来打release包!其步骤基本和原生应用一样,只是在每次编译打包之前需要先执行js文件的打包(即生成离线的jsbundle文件)。具体的js打包命令如下:
+
+ $ react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/
+
+注意把上述命令中的路径替换为你实际项目的路径。如果assets目录不存在,需要提前自己创建一个。
+
+然后在Android Studio中正常生成release版本即可!
+
+
diff --git a/docs/docs/0.43/interactionmanager.md b/docs/docs/0.43/interactionmanager.md
new file mode 100644
index 0000000..16555fb
--- /dev/null
+++ b/docs/docs/0.43/interactionmanager.md
@@ -0,0 +1,58 @@
+Interactionmanager可以将一些耗时较长的工作安排到所有互动或动画完成之后再进行。这样可以保证JavaScript动画的流畅运行。
+
+应用这样可以安排一个任务在交互和动画完成之后执行:
+
+```javascript
+InteractionManager.runAfterInteractions(() => {
+ // ...耗时较长的同步的任务...
+});
+```
+
+把这个和其他的延迟计划函数对比:
+
+- requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
+- setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
+- runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
+
+触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将`runAfterInteractions()`的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
+
+InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
+
+```javascript
+var handle = InteractionManager.createInteractionHandle();
+// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
+// 在动画完成之后
+InteractionManager.clearInteractionHandle(handle);
+// 在所有句柄都清除之后,现在开始依序执行队列中的任务
+```
+`runAfterInteractions`接受一个普通的回调函数,或是一个`PromiseTask`对象,该对象需要带有名为`gen`的方法,并返回一个`Promise`。如果提供的参数是一个`PromiseTask`, 那么即便它是异步的它也会阻塞任务队列,直到它(以及它所有的依赖任务,哪怕这些依赖任务也是异步的)执行完毕后,才会执行下一个任务。
+
+默认情况下,排队的任务会在一次setImmediate方法中依序批量执行。如果你调用了setDeadLine方法并设定了一个正整数值,则任务只会在设定的时间到达后开始执行。在此之前,任务会通过setTimeout来挂起并阻塞其他任务执行,这样可以给诸如触摸交互一类的事件留出时间,使应用可以更快地响应用户。
+
+### 方法
+
+
+
+
static runAfterInteractions(callback: Function) #
+
安排一个函数在所有的交互和动画完成之后运行。返回一个可取消的promise。
+
+
+
static createInteractionHandle() #
+
+
+
+
static clearInteractionHandle(handle: Handle) #
+
+
+
+
static setDeadline(deadline: number) #
+
如果设定了一个正整数值,则会使用setTimeout来挂起所有尚未执行的任务。在eventLoopRunningTime到达设定时间后,才开始使用一个setImmediate方法来批量执行所有任务。
+
+
+
+### 属性
+
+
+
+
addListener: CallExpression #
+
diff --git a/docs/docs/0.43/javascript-environment.md b/docs/docs/0.43/javascript-environment.md
new file mode 100644
index 0000000..d95513d
--- /dev/null
+++ b/docs/docs/0.43/javascript-environment.md
@@ -0,0 +1,75 @@
+在使用React Native时,你的JavaScript代码将会运行在两个不同的环境上:
+
+* 在iOS、Android的模拟器或是真机上,React Native使用的是[JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore),也就是Safari所使用的JavaScript引擎。但是在iOS上JavaScriptCore并没有使用即时编译技术(JIT),因为在iOS中应用无权拥有可写可执行的内存页(因而无法动态生成代码)。
+* 在使用Chrome调试时,所有的JavaScript代码都运行在Chrome中,并且通过WebSocket与原生代码通信。此时的运行环境是[V8引擎](https://code.google.com/p/v8/)。
+
+虽然两个环境非常类似,但开发者还是可能碰到一些不一致的地方。未来我们很可能会尝试一些其他的JS引擎,所以请尽量避免使用依赖于特定运行环境的代码。
+
+## JavaScript语法转换器
+
+语法转换器可以使编写代码的过程更加享受,因为开发者可以借助转换器直接使用新的JavaScirpt语法标准,而无需等待JS解释器的支持。
+
+React Native从0.5.0版本开始已经内置[Babel转换器](https://babeljs.io)。你可以查看[Babel的文档](https://babeljs.io/docs/plugins/#transform-plugins)来了解有关它可以转换的语法的详情。
+
+这里可以看到目前React Native默认开启的[语法转换特性](https://github.com/facebook/react-native/blob/master/babel-preset/configs/main.js#L16)。
+注:若想学习相关语法,译者推荐阮一峰老师的[《ECMAScript 6入门》](http://es6.ruanyifeng.com/)以及论坛的[讨论帖](http://bbs.reactnative.cn/topic/15)。
+
+ES5
+
+* 保留关键字: `promise.catch(function() { });`
+
+ES6
+
+* [箭头函数Arrow functions](http://babeljs.io/docs/learn-es2015/#arrows): ` this.setState({pressed: true})}`
+* [块级作用域Block scoping](https://babeljs.io/docs/learn-es2015/#let-const): `let greeting = 'hi';`
+* [数组的扩展运算Call spread](http://babeljs.io/docs/learn-es2015/#default-rest-spread): `Math.max(...array);`
+* [类Classes](http://babeljs.io/docs/learn-es2015/#classes): `class C extends React.Component { render() { return ; } }`
+* [常量Constants](https://babeljs.io/docs/learn-es2015/#let-const): `const answer = 42;`
+* [解构Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring): `var {isActive, style} = this.props;`
+* [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of): `for (var num of [1, 2, 3]) {}`
+* [模块Modules](http://babeljs.io/docs/learn-es2015/#modules): `import React, { Component } from 'react';`
+* [动态属性键Computed Properties](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var key = 'abc'; var obj = {[key]: 10};`
+* 对象方法的简写Object Consise Method: `var obj = { method() { return 10; } };`
+* [对象属性的简写Object Short Notation](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var name = 'vjeux'; var obj = { name };`
+* [参数的扩展运算Rest Params](https://github.com/sebmarkbage/ecmascript-rest-spread): `function(type, ...args) { }`
+* [字符串模板Template Literals](http://babeljs.io/docs/learn-es2015/#template-strings): ``var who = 'world'; var str = `Hello ${who}`;``
+
+ES7
+
+* [对象的扩展运算Object Spread](https://github.com/sebmarkbage/ecmascript-rest-spread): `var extended = { ...obj, a: 10 };`
+* [参数列表末尾允许放置逗号Function Trailing Comma](https://github.com/jeffmo/es-trailing-function-commas): `function f(a, b, c,) { }`
+* [Async函数](https://github.com/tc39/ecmascript-asyncawait): `async function doStuffAsync() { const foo = await doOtherStuffAsync(); }`;
+
+其他特性
+
+* [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): ` `
+* [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
+
+## 接口兼容(Polyfills)
+
+许多标准功能也都在支持的JavaScript运行环境上做了兼容支持。
+
+浏览器
+
+* [console.{log, warn, error, info, trace, table}](https://developer.chrome.com/devtools/docs/console-api)
+* [CommonJS require](https://nodejs.org/docs/latest/api/modules.html)
+* [XMLHttpRequest, fetch](/react-native/docs/network.html#content)
+* [{set, clear}{Timeout, Interval, Immediate}, {request, cancel}AnimationFrame](/react-native/docs/timers.html#content)
+* [navigator.geolocation](/react-native/docs/geolocation.html#content)
+
+ES6
+
+* [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+* String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)}
+* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
+* Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)}
+
+ES7
+
+* Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)}
+
+其他特性
+
+* `__DEV__`
+
+
diff --git a/docs/docs/0.43/keyboard.md b/docs/docs/0.43/keyboard.md
new file mode 100644
index 0000000..7eca107
--- /dev/null
+++ b/docs/docs/0.43/keyboard.md
@@ -0,0 +1,76 @@
+`Keyboard`组件可以用来控制键盘相关的事件。
+
+### 用法
+`Keyboard`组件可以监听原生键盘事件以做出相应回应,比如收回键盘。
+
+```js
+import React, { Component } from 'react';
+import { Keyboard, TextInput } from 'react-native';
+
+class Example extends Component {
+ componentWillMount () {
+ this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
+ this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
+ }
+
+ componentWillUnmount () {
+ this.keyboardDidShowListener.remove();
+ this.keyboardDidHideListener.remove();
+ }
+
+ _keyboardDidShow () {
+ alert('Keyboard Shown');
+ }
+
+ _keyboardDidHide () {
+ alert('Keyboard Hidden');
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+```
+### 方法
+
+
+
static addListener(nativeEvent, jsFunction) #
+
addListener用于注册一个JavaScript函数来监听处理原生键盘通知事件。
+
此方法会返回监听函数的引用。
+
@param {string} nativeEvent nativeEvent参数用来指明要监听的事件,具体有以下几种:
+
+ keyboardWillShow
+ keyboardDidShow
+ keyboardWillHide
+ keyboardDidHide
+ keyboardWillChangeFrame
+ keyboardDidChangeFrame
+
+
注意如果你把`android:windowSoftInputMode`设置为`adjustResize`或是`adjustNothing`,则在Android上只有`keyboardDidShow`和`keyboardDidHide`事件有效。
>
+
@param {function} jsFunction 事件触发时调用的js函数。
+
+
static removeAllListeners(eventType) #
+
移除某个类型事件的所有监听函数.
+
@param {string} eventType 要移除的原生事件类型
+
+
static removeSubscription(subscription) #
+
+
@param {EmitterSubscription} subscription 要移除的监听函数
+
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/keyboardavoidingview.md b/docs/docs/0.43/keyboardavoidingview.md
new file mode 100644
index 0000000..9b98529
--- /dev/null
+++ b/docs/docs/0.43/keyboardavoidingview.md
@@ -0,0 +1,150 @@
+本组件用于解决一个常见的尴尬问题:手机上弹出的键盘常常会挡住当前的视图。本组件可以自动根据键盘的位置,调整自身的position或底部的padding,以避免被遮挡。
+
+### 属性
+
+
+
+
behavior PropTypes.oneOf(['height', 'position', 'padding'])
+ #
+
+
+
+
contentContainerStyle
+ View#style
+ #
+
+
如果设定behavior值为'position',则会生成一个View作为内容容器。此属性用于指定此内容容器的样式。
+
+
+
keyboardVerticalOffset
+ PropTypes.number.isRequired
+ #
+
+
有时候应用离屏幕顶部还有一些距离(比如状态栏等等),利用此属性来补偿修正这段距离。
+
+
+
+### 方法
+
+
+
relativeKeyboardHeight(keyboardFrame): #
+
+
+
+
onKeyboardChange(event) #
+
+
+
+
onLayout(event)
+ #
+
+
+
+
+### 例子
+
+```js
+'use strict';
+
+const React = require('React');
+const ReactNative = require('react-native');
+const {
+ KeyboardAvoidingView,
+ Modal,
+ SegmentedControlIOS,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+const UIExplorerBlock = require('./UIExplorerBlock');
+const UIExplorerPage = require('./UIExplorerPage');
+
+class KeyboardAvoidingViewExample extends React.Component {
+ static title = '';
+ static description = 'Base component for views that automatically adjust their height or position to move out of the way of the keyboard.';
+
+ state = {
+ behavior: 'padding',
+ modalOpen: false,
+ };
+
+ onSegmentChange = (segment: String) => {
+ this.setState({behavior: segment.toLowerCase()});
+ };
+
+ renderExample = () => {
+ return (
+
+
+
+
+
+
+ this.setState({modalOpen: false})}
+ style={styles.closeButton}>
+ Close
+
+
+
+ this.setState({modalOpen: true})}>
+ Open Example
+
+
+ );
+ };
+
+ render() {
+ return (
+
+
+ {this.renderExample()}
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ outerContainer: {
+ flex: 1,
+ },
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ paddingHorizontal: 20,
+ paddingTop: 20,
+ },
+ textInput: {
+ borderRadius: 5,
+ borderWidth: 1,
+ height: 44,
+ paddingHorizontal: 10,
+ },
+ segment: {
+ marginBottom: 10,
+ },
+ closeButton: {
+ position: 'absolute',
+ top: 30,
+ left: 10,
+ }
+});
+
+module.exports = KeyboardAvoidingViewExample;
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/known-issues.md b/docs/docs/0.43/known-issues.md
new file mode 100644
index 0000000..2fe0cd0
--- /dev/null
+++ b/docs/docs/0.43/known-issues.md
@@ -0,0 +1,78 @@
+### Chrome开发工具中的"React"选项无法使用
+目前[无法使用](https://github.com/facebook/react-devtools/issues/229)开发工具中的"React"选项来查看App的组件。这是由于脚本在开发工具插件中的运行方式改变了;它们现在在Web Worker内部运行,插件并不知道,因此无法很好的和React Native进行通讯。
+即便如此,你仍然可以使用开发工具的Console和Sources选项,而且可以使用断点来调试JavaScript。为了能够使用Console功能,你必须确认在开发工具下拉菜单中选择入口文件为 ⚙debuggerWorker.js,(默认选择为<top frame>)。
+
+
+### 缺失的Android模块和视图
+
+虽然React Native的Android版本的开发工作晚于iOS版本,但目前大多数视图都在Android上实现了,除了下面几个例外:
+
+#### 视图
+
+- Maps —— 我们推荐使用Leland Richardson的[react-native-maps](https://github.com/lelandrichardson/react-native-maps),它比我们内部实现的map功能更完善。
+
+
+#### 模块
+- Android推送通知 (请使用第三方模块,比如[react-native-jpush](https://github.com/reactnativecn/react-native-jpush))
+
+
+### 某些属性仅仅支持单个平台
+
+有些属性只能在单个平台上使用,这是由于这些特性仅有单个平台支持或者是尚未在其他平台上实现。所有这些都在JS文档中被`@platform`标注,并且左侧有一个小标记。
+
+### 平台一致性
+以下是一些本该(或将要)设计得更通用的API或组件:
+
+- ``和``功能类似。我们或许希望统一成``。
+
+- `ActivityIndicator`可以跨平台地渲染一个原生的加载(loading)指示器(目前在iOS上使用`ActivityIndicatorIOS`,而在Android上使用`ProgressBarAndroid`)
+
+- `ProgressBar`可以跨平台渲染一个水平的进度条(目前只在iOS上支持,使用`ProgressViewIOS `)
+
+
+### 使用第三方的原生模块
+
+[JS.coach](https://js.coach/react-native)上有很多非常优秀的第三方模块。
+在你的项目中集成这些模块应该并不困难,这里有一个[实际应用的例子](https://github.com/apptailor/react-native-google-signin)。
+
+### overflow样式在Android默认为hidden而且无法更改
+
+这是Android本身的渲染机制所致。我们没有实现这一特性,因为这是个大工程,而且我们还有很多其他重要的任务。
+Android的`overflow:hidden`还有另外一个问题:如果父容器有`borderRadius`圆角边框样式,那么即便开启了`overflow:hidden`也仍然无法把子视图超出圆角边框的部分裁切掉。这个问题只存在于Android上,iOS并没有这个问题(子视图的内容不会超出父容器的圆角边框)。你可以在[这里](https://rnplay.org/apps/BlGjdQ)看到问题的演示,以及在[这里](https://github.com/facebook/react-native/issues/3198)查看这个问题的报告以及后续进展。
+
+### 视图阴影
+
+`shadow`开头的[样式](view.html#style)现在可以在iOS上应用,而Android上对应的属性(props)是`elevation`。设置`elevation`属性就等价于使用原生的[`elevation API`](https://developer.android.com/training/material/shadows-clipping.html#Elevation),因而也有同样的限制(比如最明显的就是需要Android 5.0以上版本)。此外还会影响到层叠视图在空间z轴上的顺序。
+
+### Android M(6.0)的权限
+
+当前版本的React Native还不支持Android M的[权限模型](http://developer.android.com/training/permissions/requesting.html)。
+
+### Android纯布局(Layout-only)节点
+
+Android版本的React Native有一个优化的特性:有些视图,只起布局作用而没有对应的原生视图,那么只有它们的布局属性会被传递给子视图。这个优化对于深层次的视图的稳定性很重要因此默认开启。要关闭这个特性,请设置`collapsable`为false:
+
+```
+
+ ...
+
+```
+
+### PNG图片的内存问题
+React Native Android 依靠[Fresco](https://github.com/facebook/fresco)载入和显示图片。目前我们关闭了下采样(downsampling)(这一特性还不稳定),因此有可能载入较大的PNG图片时会出现内存问题。
+
+### react-native init时卡住
+
+尝试运行`react-native init`时加上`--verbose`参数,点这里[#2797](https://github.com/facebook/react-native/issues/2797)查看一般可能的原因。
+译注:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请将npm仓库源替换为国内镜像:
+
+```
+npm config set registry https://registry.npm.taobao.org
+npm config set disturl https://npm.taobao.org/dist
+```
+另,执行init时切记不要在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题,请使用chown修复)。
+又,react-native.cn中文网提供了完整的[绿色纯净新项目包](http://bbs.reactnative.cn/topic/11)。完整打包全部iOS和Android的第三方依赖,只要环境配置正确,无需科学上网漫长等待,解压后即可直接运行。
+
+### 文本框的边界(border)
+
+文本框默认的边界在视图的底部。这个边界有一个内衬(padding),这个padding由系统提供的背景图片所设定,并且无法改变。解决这个问题有两个方案,一是可以不指定高度,这样系统会自动处理,在恰当的位置显示边界;或者干脆通过设定[underlineColorAndroid](textinput.html#underlinecolorandroid)为透明来隐藏边界。
diff --git a/docs/docs/0.43/layout-props.md b/docs/docs/0.43/layout-props.md
new file mode 100644
index 0000000..4998bc6
--- /dev/null
+++ b/docs/docs/0.43/layout-props.md
@@ -0,0 +1,236 @@
+
+
alignItems enum('flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
alignSelf enum('auto', 'flex-start', 'flex-end', 'center', 'stretch')
+ #
+
+
+
borderBottomWidth number #
+
+
+
+
borderLeftWidth number #
+
+
+
borderRightWidth number #
+
+
+
+
borderTopWidth number #
+
+
+
borderWidth number
+ #
+
+
+
+
flex number
+ #
+
在React Native中flex的表现和CSS有些区别。
+ flex在RN中只能为整数值,其具体表现请参考yoga引擎库的文档,其网址是https://github.com/facebook/yoga
+
当flex取正整数值时, is a positive number, it makes the component flexible
+ and it will be sized proportional to its flex value. So a
+ component with flex set to 2 will take twice the space as a
+ component with flex set to 1.
+
When flex is 0, the component is sized according to width
+ and height and it is inflexible.
+
When flex is -1, the component is normally sized according
+ width and height. However, if there's not enough space,
+ the component will shrink to its minWidth and minHeight.
+
flexGrow, flexShrink, and flexBasis work the same as in CSS.
+
+
+
flexDirection enum('row', 'row-reverse', 'column', 'column-reverse') #
+
+
flexDirection controls which directions children of a container go.
+ row goes left to right, column goes top to bottom, and you may
+ be able to guess what the other two do. It works like flex-direction
+ in CSS, except the default is column.访问https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction 来进一步了解。
+
+
+
+
flexWrap enum('wrap', 'nowrap')
+ #
+
+
+
+
justifyContent enum('flex-start', 'flex-end', 'center', 'space-between', 'space-around') #
+
+
+
+
+
marginBottom number #
+
+
+
marginHorizontal number #
+
+
Setting marginHorizontal has the same effect as setting
+ both marginLeft and marginRight.
+
+
marginLeft number
+ #
+
+
+
marginRight number
+ #
+
+
+
+
marginVertical number #
+
Setting marginVertical has the same effect as setting both
+ marginTop and marginBottom.
+
+
+
+
+
+
overflow enum('visible', 'hidden', 'scroll')
+ #
+
overflow controls how a children are measured and displayed.
+ overflow: hidden causes views to be clipped while overflow: scroll
+ causes views to be measured independently of their parents main axis.It works likeoverflow` in
+ CSS (default: visible).访问https://developer.mozilla.org/en/docs/Web/CSS/overflow 来进一步了解。
+
+
+
paddingBottom number #
+
+
+
paddingHorizontal number #
+
+
Setting paddingHorizontal is like setting both of
+ paddingLeft and paddingRight.
+
+
paddingLeft number
+ #
+
+
+
paddingRight number #
+
+
+
paddingTop number
+ #
+
+
+
paddingVertical number #
+
Setting paddingVertical is like setting both of
+ paddingTop and paddingBottom.
+
+
position enum('absolute', 'relative')
+ #
+
position in React Native is similar to regular CSS, but
+ everything is set to relative by default, so absolute
+ positioning is always just relative to the parent.
+
If you want to position a child using specific numbers of logical
+ pixels relative to its parent, set the child to have absolute
+ position.
+
If you want to position a child relative to something
+ that is not its parent, just don't use styles for that. Use the
+ component tree.
+
访问https://facebook.github.io/yoga/docs/absolute-position/ 来进一步了解position在React Native和CSS中的差异。
+
+
+
+
+
zIndex number #
+
zIndex controls which components display on top of others.
+ Normally, you don't use zIndex. Components render according to
+ their order in the document tree, so later components draw over
+ earlier ones. zIndex may be useful if you have animations or custom
+ modal interfaces where you don't want this behavior.
+
It works like the CSS z-index property - components with a larger
+ zIndex will render on top. Think of the z-direction like it's
+ pointing from the phone into your eyeball.访问https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
+来进一步了解。
+
+
\ No newline at end of file
diff --git a/docs/docs/0.43/layout-with-flexbox.md b/docs/docs/0.43/layout-with-flexbox.md
new file mode 100644
index 0000000..9b1130f
--- /dev/null
+++ b/docs/docs/0.43/layout-with-flexbox.md
@@ -0,0 +1,97 @@
+我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
+
+一般来说,使用`flexDirection`、`alignItems`和 `justifyContent`三个样式属性就已经能满足大多数布局需求。译注:这里有一份[简易布局图解](http://weibo.com/1712131295/CoRnElNkZ?ref=collection&type=comment),可以给你一个大概的印象。
+
+> React Native中的Flexbox的工作原理和web上的CSS基本一致,当然也存在少许差异。首先是默认值不同:`flexDirection`的默认值是`column`而不是`row`,而`flex`也只能指定一个数字值。
+
+#### Flex Direction
+
+在组件的`style`中指定`flexDirection`可以决定布局的**主轴**。子元素是应该沿着**水平轴(`row`)**方向排列,还是沿着**竖直轴(`column`)**方向排列呢?默认值是**竖直轴(`column`)**方向。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class FlexDirectionBasics extends Component {
+ render() {
+ return (
+ // 尝试把`flexDirection`改为`column`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
+```
+
+#### Justify Content
+
+在组件的style中指定`justifyContent`可以决定其子元素沿着**主轴**的**排列方式**。子元素是应该靠近主轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`、`space-around`以及`space-between`。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class JustifyContentBasics extends Component {
+ render() {
+ return (
+ // 尝试把`justifyContent`改为`center`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
+```
+
+#### Align Items
+
+在组件的style中指定`alignItems`可以决定其子元素沿着**次轴**(与主轴垂直的轴,比如若主轴方向为`row`,则次轴方向为`column`)的**排列方式**。子元素是应该靠近次轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:`flex-start`、`center`、`flex-end`以及`stretch`。
+
+> 注意:要使`stretch`选项生效的话,子元素在次轴方向上不能有固定的尺寸。以下面的代码为例:只有将子元素样式中的`width: 50`去掉之后,`alignItems: 'stretch'`才能生效。
+
+```ReactNativeWebPlayer
+import React, { Component } from 'react';
+import { AppRegistry, View } from 'react-native';
+
+class AlignItemsBasics extends Component {
+ render() {
+ return (
+ // 尝试把`alignItems`改为`flex-start`看看
+ // 尝试把`justifyContent`改为`flex-end`看看
+ // 尝试把`flexDirection`改为`row`看看
+
+
+
+
+
+ );
+ }
+};
+
+AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
+```
+
+#### 深入学习
+
+以上我们已经介绍了一些基础知识,但要运用好布局,我们还需要很多其他的样式。对于布局有影响的完整样式列表记录在[这篇文档中](layout-props.html)。
+
+现在我们已经差不多可以开始真正的开发工作了。哦,忘了还有个常用的知识点:[如何使用TextInput组件来处理用户输入](handling-text-input.html)。
diff --git a/docs/docs/0.43/layoutanimation.md b/docs/docs/0.43/layoutanimation.md
new file mode 100644
index 0000000..3d83a15
--- /dev/null
+++ b/docs/docs/0.43/layoutanimation.md
@@ -0,0 +1,43 @@
+当布局变化时,自动将视图运动到它们新的位置上。
+
+
+一个常用的调用此API的办法是调用`LayoutAnimation.configureNext`,然后调用`setState`。
+
+
+### 方法
+
+
+
+
static configureNext(config: Config, onAnimationDidEnd?: Function) #
+
+
计划下一次布局要发生的动画。
+
@param config 表示动画相应的属性
+
+ duration 动画持续时间,单位是毫秒
+ create, 配置创建新视图时的动画。(参阅 Anim 类型)
+ update, 配置被更新的视图的动画。(参阅 Anim 类型)
+
+
@param onAnimationDidEnd 当动画结束的时候被调用。只在iOS设备上支持。
+
@param onError 当动画产生错误的时候被调用。只在iOS设备上支持。
+
+
+
+
static create(duration: number, type, creationProp) #
+
+
用来创建configureNext所需的config参数的辅助函数。
+
+
+
+
+### 属性
+
+
+
+
Properties: CallExpression #
+
configChecker: CallExpression #
+
Presets: ObjectExpression #
+
easeInEaseOut: CallExpression #
+
+
+
+
diff --git a/docs/docs/0.43/linking-libraries-ios.md b/docs/docs/0.43/linking-libraries-ios.md
new file mode 100644
index 0000000..ac7a243
--- /dev/null
+++ b/docs/docs/0.43/linking-libraries-ios.md
@@ -0,0 +1,62 @@
+并不是所有的APP都需要使用全部的原生功能,包含支持全部特性的代码会增大应用的体积。但我们仍然希望能让你简单地根据自己的需求添加需要的特性。
+
+在这种思想下,我们把许多特性都发布成为互不相关的静态库。
+
+大部分的库只需要拖进两个文件就可以使用了,偶尔你还需要几步额外的工作,但不会再有更多的事情要做了。
+
+_我们随着React Native发布的所有库都在仓库中的`Libraries`文件夹下。其中有一些是纯Javascript代码,你只需要去`require`它们就可以使用了。另外有一些库基于一些原生代码实现,你必须把这些文件添加到你的应用,否则应用会在你使用这些库的时候产生报错。_
+
+## 添加包含原生代码的库需要几个步骤:
+
+### 自动链接
+
+#### 第一步
+安装一个带原生依赖的库:
+
+```bash
+$ npm install 某个带有原生依赖的库 --save
+```
+
+**注意:** 这一步中`--save`或`--save-dev`参数是非常重要的。React Native需要根据`package.json`文件中的`dependencies`和`devDependencies`记录来链接库。
+
+#### 第二步
+
+链接原生依赖:
+
+```bash
+$ react-native link
+```
+
+完成了!现在所有的原生依赖都成功地链接到你的iOS/Android项目了。
+
+### 手动链接
+
+#### 第一步
+
+如果该库包含原生代码,那么在它的文件夹下一定有一个`.xcodeproj`文件。
+把这个文件拖到你的XCode工程下(通常拖到XCode的`Libraries`分组里)
+
+
+
+#### 第二步
+
+点击你的主工程文件,选择`Build Phases`,然后把刚才所添加进去的`.xcodeproj`下的`Products`文件夹中的静态库文件(.a文件),拖到`Link Binary With Libraries`组内。
+
+
+
+#### 第三步
+
+不是所有的库都需要进行这个步骤,你需要考虑的问题在于:
+
+_我需要在编译的期间了解库的内容吗?_
+
+这个问题的意思是,你是需要在原生代码中使用这个库,还是只需要通过JavaScript访问?如果你只需要通过JavaScript访问这个库,你就可以跳过这步了。
+
+这一步骤对于我们随React Native发布的大部分库来说都不是必要的,但有两个例外是`PushNotificationIOS`和`LinkingIOS`。
+
+以`PushNotificationIOS`为例,你需要在`AppDelegate`每收到一条推送通知之后,调用库中的一个方法。
+
+这种情况下我们需要能够访问到库的头文件。为了能够顺利打包,你需要打开你的工程文件,选择`Build Settings`,然后搜索`Header Search Paths`,然后添加库所在的目录(如果它还有像`React`这样的子目录需要包含,注意要选中`recursive`选项)
+
+
+
diff --git a/docs/docs/0.43/linking.md b/docs/docs/0.43/linking.md
new file mode 100644
index 0000000..be2b129
--- /dev/null
+++ b/docs/docs/0.43/linking.md
@@ -0,0 +1,123 @@
+`Linking`提供了一个通用的接口来与传入和传出的App链接进行交互。
+
+### 基本用法
+
+#### 处理链接
+
+如果你的应用被其注册过的外部url调起,则可以在任何组件内这样获取和处理它:
+
+```javascript
+componentDidMount() {
+ Linking.getInitialURL().then((url) => {
+ if (url) {
+ console.log('Initial url is: ' + url);
+ }
+ }).catch(err => console.error('An error occurred', err));
+}
+```
+注:要了解更多如何在Android上支持深度链接的说明,请参阅[Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters)。
+
+如果要在现有的MainActivity中监听传入的intent,那么需要在`AndroidManifest.xml`中将MainActivity的`launchMode`设置为`singleTask`。相关解释可参考[``](http://developer.android.com/guide/topics/manifest/activity-element.html)文档。
+
+```xml
+
+```
+
+对于iOS来说,如果要在App启动后也监听传入的App链接,那么首先需要在项目中链接`RCTLinking`,具体步骤请参考[使用链接库](linking-libraries-ios.html)这篇文档,然后需要在`AppDelegate.m`中增加以下代码:
+
+```objective-c
+#import
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+ {
+ return [RCTLinkingManager application:application openURL:url
+ sourceApplication:sourceApplication annotation:annotation];
+ }
+
+// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+ {
+ return [RCTLinkingManager application:application
+ continueUserActivity:userActivity
+ restorationHandler:restorationHandler];
+ }
+```
+
+然后你的React组件就可以监听`Linking`的相关事件:
+
+```javascript
+componentDidMount() {
+ Linking.addEventListener('url', this._handleOpenURL);
+},
+componentWillUnmount() {
+ Linking.removeEventListener('url', this._handleOpenURL);
+},
+_handleOpenURL(event) {
+ console.log(event.url);
+}
+```
+
+
+#### 打开外部链接
+
+要启动一个链接相对应的应用(打开浏览器、邮箱或者其它的应用),只需调用:
+
+```javascript
+Linking.openURL(url).catch(err => console.error('An error occurred', err));
+```
+如果想在打开链接前先检查是否安装了对应的应用,则调用以下方法:
+
+```javascript
+Linking.canOpenURL(url).then(supported => {
+ if (!supported) {
+ console.log('Can\'t handle url: ' + url);
+ } else {
+ return Linking.openURL(url);
+ }
+}).catch(err => console.error('An error occurred', err));
+```
+
+### 方法
+
+
+
+
static addEventListener(type: string, handler: Function) #
+
+
添加一个监听Linking变化的事件。type参数应填`url`,并提供一个处理函数。
+
+
+
+
static removeEventListener(type: string, handler: Function) #
+
+
删除一个事件处理函数。type参数应填`url`。
+
+
+
+
static openURL(url: string) #
+
+
尝试使用设备上已经安装的应用打开指定的url。
+
你还可以使用其他类型的URL,比如一个地理位置(形如"geo:37.484847,-122.148386"或是一个通讯录名片,只要是可以通过{@code Intent.ACTION_VIEW}打开的即可。
+
注:如果系统不知道如何处理给定的URL,则此方法会调用失败。如果你传入的URL不是一个http链接,则最好先通过{@code canOpenURL}方法检查一下。
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
+
+
+
static canOpenURL(url: string, callback: Function) #
+
+
判断设备上是否有已经安装的应用可以处理指定的URL。回调函数的参数只有一个:bool supported
+
注:对于web链接来说,协议头("http://", "https://")不能省略!
+
注:对于iOS 9以上版本,你还需要在Info.plist中添加LSApplicationQueriesSchemes字段。
+
+
+
+
static getInitialURL() #
+
+
+
diff --git a/docs/docs/0.43/listview.md b/docs/docs/0.43/listview.md
new file mode 100644
index 0000000..2f95e36
--- /dev/null
+++ b/docs/docs/0.43/listview.md
@@ -0,0 +1,315 @@
+ListView - 一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个`ListView.DataSource`数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个`ListView`组件,并且定义它的`renderRow`回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)。
+
+最简单的例子:
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ dataSource: ds.cloneWithRows(['row 1', 'row 2']),
+ };
+}
+render() {
+ return (
+ {rowData} }
+ />
+ );
+}
+```
+
+ListView还支持一些高级特性,譬如给每段/组(section)数据添加一个带有粘性的头部(类似iPhone的通讯录,其首字母会在滑动过程中吸附在屏幕上方);在列表头部和尾部增加单独的内容;在到达列表尾部的时候调用回调函数(`onEndReached`),还有在视野内可见的数据变化时调用回调函数(`onChangeVisibleRows`),以及一些性能方面的优化。
+
+有一些性能优化使得ListView可以滚动的更加平滑,尤其是在动态加载可能很大(或者概念上无限长的)数据集的时候:
+
+* 只更新变化的行 - 提供给数据源的rowHasChanged函数可以告诉ListView它是否需要重绘一行数据(即:数据是否发生了变化)参见ListViewDataSource
+* 限制频率的行渲染 - 默认情况下,每次消息循环只有一行会被渲染(可以用`pageSize`属性配置)。这把较大的工作分散成小的碎片,以降低因为渲染而导致丢帧的可能性。
+
+### 截图
+
+
+
+
+
+
+### 属性
+
+
+
+
+
+
译注:这意味着ListView可以使用所有ScrollView的属性。
+
+
+
+
dataSource ListViewDataSource #
+
+
+
+
initialListSize number #
+
+
指定在组件刚挂载的时候渲染多少行数据。用这个属性来确保首屏显示合适数量的数据,而不是花费太多帧逐步显示出来。
+
+
+
+
onChangeVisibleRows function #
+
+
(visibleRows, changedRows) => void
+
当可见的行的集合变化的时候调用此回调函数。visibleRows 以 { sectionID: { rowID: true }}的格式包含了所有可见行,而changedRows 以{ sectionID: { rowID: true | false }}的格式包含了所有刚刚改变了可见性的行,其中如果值为true表示一个行变得可见,而为false表示行刚刚离开可视区域而变得不可见。
+
+
+
+
onEndReached function #
+
+
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。
+
+
+
+
onEndReachedThreshold number #
+
+
调用onEndReached之前的临界值,单位是像素。
+
+
+
+
+
removeClippedSubviews bool #
+
+
用于提升大列表的滚动性能。需要给行容器添加样式overflow:'hidden'。(Android已默认添加此样式)。此属性默认开启。
+
+
+
+
renderFooter function #
+
+
() => renderable
+
页头与页脚会在每次渲染过程中都重新渲染(如果提供了这些属性)。如果它们重绘的性能开销很大,把他们包装到一个StaticContainer或者其它恰当的结构中。页脚会永远在列表的最底部,而页头会在最顶部。
+
+
+
+
renderHeader function #
+
+
+
renderRow function #
+
+
(rowData, sectionID, rowID, highlightRow) => renderable
+
从数据源(Data source)中接受一条数据,以及它和它所在section的ID。返回一个可渲染的组件来为这行数据进行渲染。默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。
+
如果某一行正在被高亮(通过调用highlightRow函数),ListView会得到相应的通知。当一行被高亮时,其两侧的分割线会被隐藏。行的高亮状态可以通过调用highlightRow(null)来重置。
+
+
+
+
renderScrollComponent function #
+
+
(props) => renderable
+
指定一个函数,在其中返回一个可以滚动的组件。ListView将会在该组件内部进行渲染。默认情况下会返回一个包含指定属性的ScrollView。
+
+
+
+
renderSectionHeader function #
+
+
(sectionData, sectionID) => renderable
+
如果提供了此函数,会为每个小节(section)渲染一个粘性的标题。
+
粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。可以使用 stickySectionHeadersEnabled来决定是否启用其粘性特性。
+
+
+
+
renderSeparator function #
+
+
(sectionID, rowID, adjacentRowHighlighted) => renderable
+
如果提供了此属性,一个可渲染的组件会被渲染在每一行下面,除了小节标题的前面的最后一行。在其上方的小节ID和行ID,以及邻近的行是否被高亮会作为参数传递进来。
+
+
+
+
scrollRenderAheadDistance number #
+
+
当一个行接近屏幕范围多少像素之内的时候,就开始渲染这一行。
+
+
+
+
stickyHeaderIndices [number] #
+
+
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。举个例子,传递stickyHeaderIndices={[0]}会让第一个成员固定在滚动视图顶端。这个属性不能和horizontal={true}一起使用。
+
+
+
+
stickySectionHeadersEnabled?: bool #
+
+
设置小节标题(section header)是否具有粘性。粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。注意此设置在水平模式(horizontal={true})下无效。由于不同平台的设计原则不同,此选项在iOS上默认开启,andriod上默认关闭。
+
+
+
+
+### 方法
+
+
+
+
scrollTo(...args)
+ #
+
+
+
scrollToEnd(options?) #
+
+
滚动到视图底部(水平方向的视图则滚动到最右边)。
加上动画参数 scrollToEnd({animated: true})则启用平滑滚动动画,或是调用
+scrollToEnd({animated: false})来立即跳转。如果不使用参数,则animated选项默认启用。
+
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Image,
+ ListView,
+ TouchableHighlight,
+ StyleSheet,
+ RecyclerViewBackedScrollView,
+ Text,
+ View,
+} = ReactNative;
+
+var UIExplorerPage = require('./UIExplorerPage');
+
+var ListViewSimpleExample = React.createClass({
+ statics: {
+ title: '',
+ description: 'Performant, scrollable list of data.'
+ },
+
+ getInitialState: function() {
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ return {
+ dataSource: ds.cloneWithRows(this._genRows({})),
+ };
+ },
+
+ _pressData: ({}: {[key: number]: boolean}),
+
+ componentWillMount: function() {
+ this._pressData = {};
+ },
+
+ render: function() {
+ return (
+ '}
+ noSpacer={true}
+ noScroll={true}>
+ }
+ renderSeparator={this._renderSeperator}
+ />
+
+ );
+ },
+
+ _renderRow: function(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
+ var rowHash = Math.abs(hashCode(rowData));
+ var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
+ return (
+ {
+ this._pressRow(rowID);
+ highlightRow(sectionID, rowID);
+ }}>
+
+
+
+
+ {rowData + ' - ' + LOREM_IPSUM.substr(0, rowHash % 301 + 10)}
+
+
+
+
+ );
+ },
+
+ _genRows: function(pressData: {[key: number]: boolean}): Array {
+ var dataBlob = [];
+ for (var ii = 0; ii < 100; ii++) {
+ var pressedText = pressData[ii] ? ' (pressed)' : '';
+ dataBlob.push('Row ' + ii + pressedText);
+ }
+ return dataBlob;
+ },
+
+ _pressRow: function(rowID: number) {
+ this._pressData[rowID] = !this._pressData[rowID];
+ this.setState({dataSource: this.state.dataSource.cloneWithRows(
+ this._genRows(this._pressData)
+ )});
+ },
+
+ _renderSeperator: function(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
+ return (
+
+ );
+ }
+});
+
+var THUMB_URLS = [
+ require('./Thumbnails/like.png'),
+ require('./Thumbnails/dislike.png'),
+ require('./Thumbnails/call.png'),
+ require('./Thumbnails/fist.png'),
+ require('./Thumbnails/bandaged.png'),
+ require('./Thumbnails/flowers.png'),
+ require('./Thumbnails/heart.png'),
+ require('./Thumbnails/liking.png'),
+ require('./Thumbnails/party.png'),
+ require('./Thumbnails/poke.png'),
+ require('./Thumbnails/superlike.png'),
+ require('./Thumbnails/victory.png'),
+ ];
+var LOREM_IPSUM = 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';
+
+/* eslint no-bitwise: 0 */
+var hashCode = function(str) {
+ var hash = 15;
+ for (var ii = str.length - 1; ii >= 0; ii--) {
+ hash = ((hash << 5) - hash) + str.charCodeAt(ii);
+ }
+ return hash;
+};
+
+var styles = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ padding: 10,
+ backgroundColor: '#F6F6F6',
+ },
+ thumb: {
+ width: 64,
+ height: 64,
+ },
+ text: {
+ flex: 1,
+ },
+});
+
+module.exports = ListViewSimpleExample;
+```
diff --git a/docs/docs/0.43/listviewdatasource.md b/docs/docs/0.43/listviewdatasource.md
new file mode 100644
index 0000000..7aa981e
--- /dev/null
+++ b/docs/docs/0.43/listviewdatasource.md
@@ -0,0 +1,106 @@
+`ListViewDataSource`为`ListView`组件提供高性能的数据处理和访问。我们需要调用方法从原始输入数据中抽取数据来创建`ListViewDataSource`对象,并用其进行数据变更的比较。原始输入数据可以是简单的字符串数组,也可以是复杂嵌套的对象——分不同区(section)各自包含若干行(row)数据。
+
+要更新datasource中的数据,请(每次都重新)调用`cloneWithRows`方法(如果用到了section,则对应`cloneWithRowsAndSections`方法)。数据源中的数据本身是不可修改的,所以请勿直接尝试修改。clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。
+
+在下面这个例子中,一个组件在分块接受数据,这些数据由`_onDataArrived`方法处理——将新数据拼接(concat)到旧数据尾部,同时使用clone方法更新DataSource。我们使用concat方法来修改`this._data`以创建新数组,注意不能使用push方法拼接数组。实现`_rowHasChanged`方法需要透彻了解行数据的结构,以便提供高效的比对策略。
+
+```javascript
+constructor(props) {
+ super(props);
+ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
+ this.state = {
+ ds,
+ };
+ this._data = [];
+}
+
+_onDataArrived = (newData) => {
+ this._data = this._data.concat(newData);
+ this.setState({
+ ds: this.state.ds.cloneWithRows(this._data)
+ });
+};
+```
+
+
+### 方法
+
+
constructor(params)
+ #
+
你可以在构造函数中针对section标题和行数据提供自定义的提取方法和hasChanged比对方法。如果不提供,则会使用默认的defaultGetRowData和defaultGetSectionHeaderData方法来提取行数据和section标题。
+
默认的提取函数可以处理下列形式的数据:
+
{ sectionID_1: { rowID_1: rowData1, ... }, ... }
+
或者:
+
{ sectionID_1: [ rowData1, rowData2, ... ], ... }
+
或者:
+
[ [ rowData1, rowData2, ... ], ... ]
+
构造函数可以接受下列四种参数(都是可选):
+
+ getRowData(dataBlob, sectionID, rowID);
+ getSectionHeaderData(dataBlob, sectionID);
+ rowHasChanged(prevRowData, nextRowData);
+ sectionHeaderHasChanged(prevSectionData, nextSectionData);
+
+
+
+
cloneWithRows(dataBlob, rowIdentities) #
+
+
根据指定的dataBlob和
+ rowIdentities为ListViewDataSource复制填充数据。dataBlob即原始数据。需要在初始化时定义抽取函数(否则使用默认的抽取函数)。
+
rowIdentities是一个二维数组,包含了行数据对应的id标识符,例如[['a1', 'a2'], ['b1', 'b2', 'b3'], ...]。如果没有指定此数组,则默认取行数据的key。
+
注:此方法实际并没有 复制数据。它只是重新创建一个datasource,然后将你指定的dataBlob传递给构造函数中指定的提取函数,因而会抛弃先前的数据。如果你希望保留先前的数据,则必须先自行进行新老数据的合并处理,然后再将合并后的结果作为dataBlob传递给此方法调用。
+
+
cloneWithRowsAndSections(dataBlob, sectionIdentities, rowIdentities) #
+
+
此方法作用基本等同cloneWithRows,区别在于可以额外指定sectionIdentities 。如果你不需要section,则直接使用cloneWithRows即可。
+
sectionIdentities同理是包含了section标识符的数组。例如['s1', 's2', ...]。如果没有指定此数组,则默认取section的key。
+
注:此方法会返回新的对象!
+
+
+
getRowAndSectionCount() #
+
rowShouldUpdate(sectionIndex, rowIndex) #
+
+
+
+
getRowData(sectionIndex, rowIndex)
+ #
+
返回渲染行所需的数据(指定如何从原始dataBlob中提取数据)。
+
+
getRowIDForFlatIndex(index) #
+
给定索引值,求其对应rowID。如果查找不到则返回null。
+
+
getSectionIDForFlatIndex(index) #
+
给定索引值,求其对应sectionID。如果查找不到则返回null。
+
+
getSectionLengths() #
+
+
+
+
sectionHeaderShouldUpdate(sectionIndex) #
+
+
返回值用于说明section标题是否需要重新渲染。
+
+
getSectionHeaderData(sectionIndex) #
+
+
+
+
diff --git a/docs/docs/0.43/mapview.md b/docs/docs/0.43/mapview.md
new file mode 100644
index 0000000..75ad320
--- /dev/null
+++ b/docs/docs/0.43/mapview.md
@@ -0,0 +1,567 @@
+官方建议使用[react-native-maps](https://github.com/airbnb/react-native-maps)代替此地图组件。
+
+### 截图
+
+
+### 属性
+
+
+
+
+
ios annotations [{latitude: number, longitude: number, animateDrop: bool, title: string, subtitle: string, hasLeftCallout: bool, hasRightCallout: bool, onLeftCalloutPress: function, onRightCalloutPress: function, id: string}] #
+
+
+
+
ios legalLabelInsets {top: number, left: number, bottom: number, right: number} #
+
+
地图上标签的合法范围。默认在地图底部左侧。参见EdgeInsetsPropType.js了解更多信息。
+
+
+
+
ios mapType enum('standard', 'satellite', 'hybrid') #
+
+
要显示的地图类型。
+
+ standard: 标准道路地图(默认)。
+ satellite: 卫星视图。
+ hybrid: 卫星视图并附带道路和感兴趣的点标记。
+
+
+
+
+
ios maxDelta number #
+
+
+
+
ios minDelta number #
+
+
+
+
ios overlays [{coordinates: [{latitude: number, longitude: number}], lineWidth: number, strokeColor: ColorPropType, fillColor: ColorPropType, id: string}] #
+
+
+
onAnnotationPress function #
+
+
当用户点击地图上的标注之后会调用此回调函数一次。
+
+
+
+
onRegionChange function #
+
+
+
+
onRegionChangeComplete function #
+
+
当用户停止拖拽地图之后,调用此回调函数一次。
+
+
+
+
pitchEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的抬起角度会使地图平面倾斜。当此属性设为false,镜头的抬起角度会忽略,地图永远都显示为俯视角度。
+
+
+
+
region {latitude: number, longitude: number, latitudeDelta: number, longitudeDelta: number} #
+
+
地图显示的区域。
+
区域使用中心的坐标和要显示的范围来定义。
+
+
+
+
rotateEnabled bool #
+
+
当此属性设为true并且地图上关联了一个有效的镜头时,镜头的朝向角度会用于基于中心点旋转地图平面。当此属性设置为false时,朝向角度会被忽略,并且地图永远都显示为顶部方向为正北方。
+
+
+
+
scrollEnabled bool #
+
+
如果此属性设为false,用户不能改变地图所显示的区域。默认值为true。
+
+
+
+
showsUserLocation bool #
+
+
如果此属性为true,应用会请求用户当前的位置并且聚焦到该位置。默认值是false。
+
注意 :你需要在Info.plist中增加NSLocationWhenInUseUsageDescription字段。否则它会没有任何提示而直接失败 !
+
+
+
+
+
zoomEnabled bool #
+
+
如果此属性为false,用户则不能旋转/缩放地图。默认值为true。
+
+
+
+
+
ios showsCompass bool #
+
+
如果此属性为false,地图上不会显示指南针。默认值为true。
+
+
+
+
ios showsPointsOfInterest bool #
+
+
如果此属性为false,感兴趣的点不会在地图上显示。默认为true。
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var { PropTypes } = React;
+var {
+ Image,
+ MapView,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ View,
+} = ReactNative;
+
+var regionText = {
+ latitude: '0',
+ longitude: '0',
+ latitudeDelta: '0',
+ longitudeDelta: '0',
+};
+
+var MapRegionInput = React.createClass({
+
+ propTypes: {
+ region: PropTypes.shape({
+ latitude: PropTypes.number.isRequired,
+ longitude: PropTypes.number.isRequired,
+ latitudeDelta: PropTypes.number,
+ longitudeDelta: PropTypes.number,
+ }),
+ onChange: PropTypes.func.isRequired,
+ },
+
+ getInitialState() {
+ return {
+ region: {
+ latitude: 0,
+ longitude: 0,
+ }
+ };
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ this.setState({
+ region: nextProps.region || this.getInitialState().region
+ });
+ },
+
+ render: function() {
+ var region = this.state.region || this.getInitialState().region;
+ return (
+
+
+
+ {'Latitude'}
+
+
+
+
+
+ {'Longitude'}
+
+
+
+
+
+ {'Latitude delta'}
+
+
+
+
+
+ {'Longitude delta'}
+
+
+
+
+
+ {'Change'}
+
+
+
+ );
+ },
+
+ _onChangeLatitude: function(e) {
+ regionText.latitude = e.nativeEvent.text;
+ },
+
+ _onChangeLongitude: function(e) {
+ regionText.longitude = e.nativeEvent.text;
+ },
+
+ _onChangeLatitudeDelta: function(e) {
+ regionText.latitudeDelta = e.nativeEvent.text;
+ },
+
+ _onChangeLongitudeDelta: function(e) {
+ regionText.longitudeDelta = e.nativeEvent.text;
+ },
+
+ _change: function() {
+ this.setState({
+ region: {
+ latitude: parseFloat(regionText.latitude),
+ longitude: parseFloat(regionText.longitude),
+ latitudeDelta: parseFloat(regionText.latitudeDelta),
+ longitudeDelta: parseFloat(regionText.longitudeDelta),
+ },
+ });
+ this.props.onChange(this.state.region);
+ },
+
+});
+
+var MapViewExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ mapRegion: undefined,
+ mapRegionInput: undefined,
+ annotations: [],
+ };
+ },
+
+ render() {
+ return (
+
+
+
+
+ );
+ },
+
+ _getAnnotations(region) {
+ return [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ title: 'You Are Here',
+ }];
+ },
+
+ _onRegionChange(region) {
+ this.setState({
+ mapRegionInput: region,
+ });
+ },
+
+ _onRegionChangeComplete(region) {
+ if (this.state.isFirstLoad) {
+ this.setState({
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ isFirstLoad: false,
+ });
+ }
+ },
+
+ _onRegionInputChanged(region) {
+ this.setState({
+ mapRegion: region,
+ mapRegionInput: region,
+ annotations: this._getAnnotations(region),
+ });
+ },
+
+});
+
+var AnnotationExample = React.createClass({
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ this.setState({
+ isFirstLoad: false,
+ annotations: [{
+ longitude: region.longitude,
+ latitude: region.latitude,
+ ...this.props.annotation,
+ }],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var DraggableAnnotationExample = React.createClass({
+
+ createAnnotation(longitude, latitude) {
+ return {
+ longitude,
+ latitude,
+ draggable: true,
+ onDragStateChange: (event) => {
+ if (event.state === 'idle') {
+ this.setState({
+ annotations: [this.createAnnotation(event.longitude, event.latitude)],
+ });
+ }
+ console.log('Drag state: ' + event.state);
+ },
+ };
+ },
+
+ getInitialState() {
+ return {
+ isFirstLoad: true,
+ annotations: [],
+ mapRegion: undefined,
+ };
+ },
+
+ render() {
+ if (this.state.isFirstLoad) {
+ var onRegionChangeComplete = (region) => {
+ //When the MapView loads for the first time, we can create the annotation at the
+ //region that was loaded.
+ this.setState({
+ isFirstLoad: false,
+ annotations: [this.createAnnotation(region.longitude, region.latitude)],
+ });
+ };
+ }
+
+ return (
+
+ );
+ },
+
+});
+
+var styles = StyleSheet.create({
+ map: {
+ height: 150,
+ margin: 10,
+ borderWidth: 1,
+ borderColor: '#000000',
+ },
+ row: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ textInput: {
+ width: 150,
+ height: 20,
+ borderWidth: 0.5,
+ borderColor: '#aaaaaa',
+ fontSize: 13,
+ padding: 4,
+ },
+ changeButton: {
+ alignSelf: 'center',
+ marginTop: 5,
+ padding: 3,
+ borderWidth: 0.5,
+ borderColor: '#777777',
+ },
+});
+
+exports.displayName = (undefined: ?string);
+exports.title = '';
+exports.description = 'Base component to display maps';
+exports.examples = [
+ {
+ title: 'Map',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'showsUserLocation + followUserLocation',
+ render() {
+ return (
+
+ );
+ }
+ },
+ {
+ title: 'Callout example',
+ render() {
+ return {
+ alert('You Are Here');
+ }}>
+
+
+ ),
+ }}/>;
+ }
+ },
+ {
+ title: 'Annotation focus example',
+ render() {
+ return {
+ alert('Annotation gets focus');
+ },
+ onBlur: () => {
+ alert('Annotation lost focus');
+ }
+ }}/>;
+ }
+ },
+ {
+ title: 'Draggable pin',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin color',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin image',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Custom pin view',
+ render() {
+ return
+
+ Thumbs Up!
+
+
+ ,
+ }}/>;
+ }
+ },
+ {
+ title: 'Custom overlay',
+ render() {
+ return ;
+ }
+ },
+];
+```
\ No newline at end of file
diff --git a/docs/docs/0.43/modal.md b/docs/docs/0.43/modal.md
new file mode 100644
index 0000000..d99b00a
--- /dev/null
+++ b/docs/docs/0.43/modal.md
@@ -0,0 +1,298 @@
+Modal组件可以用来覆盖包含React Native根视图的原生视图(如UIViewController,Activity)。
+
+在嵌入React Native的混合应用中可以使用Modal。Modal可以使你应用中RN编写的那部分内容覆盖在原生视图上显示。
+
+```js
+import React, { Component } from 'react';
+import { Modal, Text, TouchableHighlight, View } from 'react-native';
+
+class ModalExample extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {modalVisible: false};
+ }
+
+ setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ }
+
+ render() {
+ return (
+
+ {alert("Modal has been closed.")}}
+ >
+
+
+ Hello World!
+
+ {
+ this.setModalVisible(!this.state.modalVisible)
+ }}>
+ Hide Modal
+
+
+
+
+
+
+ {
+ this.setModalVisible(true)
+ }}>
+ Show Modal
+
+
+
+ );
+ }
+}
+```
+
+### 截图
+
+
+### 属性
+
+
+
+
animationType PropTypes.oneOf(['none', 'slide', 'fade']) #
+
+
The animationType prop controls how the modal animates.
+
+ slide slides in from the bottom
+ fade fades into view
+ none appears without an animation
+
+
+
+
onRequestClose Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func #
+
+
The onRequestClose prop allows passing a function that will be called once the modal has been dismissed.
+
On the Android platform, this is a required function.
+
+
+
onShow function #
+
+
The onShow prop allows passing a function that will be called once the modal has been shown.
+
+
+
transparent bool
+ #
+
+
The transparent prop determines whether your modal will fill the entire view. Setting this to true will render the modal over a transparent background.
+
+
+
visible bool #
+
The visible prop determines whether your modal is visible.
+
+
+
ios onOrientationChange PropTypes.func
+ #
+
+
The onOrientationChange callback is called when the orientation changes while the modal is being displayed.
+ The orientation provided is only 'portrait' or 'landscape'. This callback is also called on initial render, regardless of the current orientation.
+
+
+
+
ios supportedOrientations PropTypes.arrayOf(PropTypes.oneOf(['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right']))
+ #
+
+
+
The supportedOrientations prop allows the modal to be rotated to any of the specified orientations. On iOS, the modal is still restricted by what's specified in your app's Info.plist's UISupportedInterfaceOrientations field.
+
+
+
+
+### 例子
+
+```javascript
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var {
+ Modal,
+ StyleSheet,
+ Switch,
+ Text,
+ TouchableHighlight,
+ View,
+} = ReactNative;
+
+exports.displayName = (undefined: ?string);
+exports.framework = 'React';
+exports.title = '';
+exports.description = 'Component for presenting modal views.';
+
+var Button = React.createClass({
+ getInitialState() {
+ return {
+ active: false,
+ };
+ },
+
+ _onHighlight() {
+ this.setState({active: true});
+ },
+
+ _onUnhighlight() {
+ this.setState({active: false});
+ },
+
+ render() {
+ var colorStyle = {
+ color: this.state.active ? '#fff' : '#000',
+ };
+ return (
+
+ {this.props.children}
+
+ );
+ }
+});
+
+var ModalExample = React.createClass({
+ getInitialState() {
+ return {
+ animationType: 'none',
+ modalVisible: false,
+ transparent: false,
+ };
+ },
+
+ _setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ },
+
+ _setAnimationType(type) {
+ this.setState({animationType: type});
+ },
+
+ _toggleTransparent() {
+ this.setState({transparent: !this.state.transparent});
+ },
+
+ render() {
+ var modalBackgroundStyle = {
+ backgroundColor: this.state.transparent ? 'rgba(0, 0, 0, 0.5)' : '#f5fcff',
+ };
+ var innerContainerTransparentStyle = this.state.transparent
+ ? {backgroundColor: '#fff', padding: 20}
+ : null;
+ var activeButtonStyle = {
+ backgroundColor: '#ddd'
+ };
+
+ return (
+
+ {this._setModalVisible(false)}}
+ >
+
+
+ This modal was presented {this.state.animationType === 'none' ? 'without' : 'with'} animation.
+
+ Close
+
+
+
+
+
+ Animation Type
+
+ none
+
+
+ slide
+
+
+ fade
+
+
+
+
+ Transparent
+
+
+
+
+ Present
+
+
+ );
+ },
+});
+
+exports.examples = [
+ {
+ title: 'Modal Presentation',
+ description: 'Modals can be presented with or without animation',
+ render: () => ,
+ },
+];
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ padding: 20,
+ },
+ innerContainer: {
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+ row: {
+ alignItems: 'center',
+ flex: 1,
+ flexDirection: 'row',
+ marginBottom: 20,
+ },
+ rowTitle: {
+ flex: 1,
+ fontWeight: 'bold',
+ },
+ button: {
+ borderRadius: 5,
+ flex: 1,
+ height: 44,
+ alignSelf: 'stretch',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ },
+ buttonText: {
+ fontSize: 18,
+ margin: 5,
+ textAlign: 'center',
+ },
+ modalButton: {
+ marginTop: 10,
+ },
+});
+```
diff --git a/docs/docs/0.43/more-resources.md b/docs/docs/0.43/more-resources.md
new file mode 100644
index 0000000..6735969
--- /dev/null
+++ b/docs/docs/0.43/more-resources.md
@@ -0,0 +1,43 @@
+如果你耐心的读完并理解了本网站上的所有文档,那么你应该已经可以编写一个像样的React Native应用了。但是React Native并不全是某一家公司的作品——它汇聚了成千上万开源社区开发者的智慧结晶。如果你想深入研究React Native,那么建议不要错过下面这些参考资源。
+
+## 常用的第三方库
+
+如果你正在使用React Native,那你应该已经对[React](https://facebook.github.io/react/)有一定的了解了。React是基础中的基础所以我其实不太好意思提这个——但是,如果不幸你属于“但是”,那么请一定先了解下React,它也非常适合编写现代化的网站。
+
+开发实践中的一个常见问题就是如何管理应用的“状态(state)”。这方面目前最流行的库非[Redux](http://redux.js.org/)莫属了。不要被Redux中经常出现的类似"reducer"这样的概念术语给吓住了——它其实是个很简单的库,网上也有很多优秀的[视频教程(英文)](https://egghead.io/courses/getting-started-with-redux) 。。
+
+如果你在寻找具有某个特定功能的第三方库,那么可以看看别人[精心整理的资源列表](https://github.com/jondot/awesome-react-native)。这里还有个类似的[中文资源列表](https://github.com/reactnativecn/react-native-guide)。
+
+## 示例应用
+
+在[React Native Playground](https://rnplay.org/apps/picks)网站上有很多示例的代码。这个网站有个很酷的特性:它直接对接了真实设备,可以实时在网页上显示运行效果。当然,对于国内用户来说,可能访问很困难。
+
+另外就是Facebook的F8开发大会有一个对应的app,这个app现在已经[开源](https://github.com/fbsamples/f8app),其开发者还详细地撰写了[相关教程](http://f8-app.liaohuqiu.net/#content)。如果你想学习一个更实际更有深度的例子,那你应该看看这个。
+
+## 开发工具
+
+[Nuclide](https://nuclide.io/)是Facebook内部所使用的React Native开发工具。它最大的特点是自带调试功能,并且非常好地支持flow语法规则。(译注:然而我们还是推荐webstorm或是sublime text)。
+
+[Ignite](https://github.com/infinitered/ignite)是一套整合了Redux以及一些常见UI组件的脚手架。它带有一个命令行可以生成app、组件或是容器。如果你喜欢它的选择搭配,那么不妨一试。
+
+[CodePush](https://microsoft.github.io/code-push/)是由微软提供的热更新服务。热更新可以使你绕过AppStore的审核机制,直接修改已经上架的应用。对于国内用户,我们也推荐由本网站提供的[Pushy](http://update.reactnative.cn)热更新服务,相比CodePush来说,提供了全中文的文档和技术支持,服务器部署在国内速度更快,还提供了全自动的差量更新方式,大幅节约更新流量,欢迎朋友们试用和反馈意见!
+
+[Exponent](http://docs.getexponent.com/versions/v6.0.0/index.html)是一套开发环境,还带有一个已上架的空应用容器。这样你可以在没有原生开发平台(Xcode或是Android Studio)的情况下直接编写React Native应用(当然这样你只能写js部分代码而没法写原生代码)。
+
+[Deco](https://www.decosoftware.com/)是一个专为React Native设计的集成开发环境。它可以自动创建新项目、搜索开源组件并插入到项目中。你还可以实时地可视化地调整应用的界面。不过目前还只支持mac。
+
+## React Native的交流社区
+
+以下这些都是英文的交流区,我也就不翻译了……
+
+The [React Native Community](https://www.facebook.com/groups/react.native.community) Facebook group has thousands of developers, and it's pretty active. Come there to show off your project, or ask how other people solved similar problems.
+
+[Reactiflux](https://discord.gg/0ZcbPKXt5bZjGY5n) is a Discord chat where a lot of React-related discussion happens, including React Native. Discord is just like Slack except it works better for open source projects with a zillion contributors. Check out the #react-native channel.
+
+The [React Twitter account](https://twitter.com/reactjs) covers both React and React Native. Following that account is a pretty good way to find out what's happening in the world of React.
+
+There are a lot of [React Native Meetups](http://www.meetup.com/topics/react-native/) that happen around the world. Often there is React Native content in React meetups as well.
+
+Sometimes we have React conferences. We posted the [videos from React.js Conf 2016](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY), and we'll probably have more conferences in the future, too. Stay tuned.
+
+欢迎朋友们在下方评论区分享中文教程和资源。
\ No newline at end of file
diff --git a/docs/docs/0.43/native-component-android.md b/docs/docs/0.43/native-component-android.md
new file mode 100644
index 0000000..714423f
--- /dev/null
+++ b/docs/docs/0.43/native-component-android.md
@@ -0,0 +1,172 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对Android编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`ImageView`组件的具体实现。
+
+## ImageView样例
+
+在这个例子里,我们来看看为了让JavaScript中可以使用ImageView,需要做哪些准备工作。
+
+原生视图需要被一个`ViewManager`的派生类(或者更常见的,`SimpleViewManage`的派生类)创建和管理。一个`SimpleViewManager`可以用于这个场景,是因为它能够包含更多公共的属性,譬如背景颜色、透明度、Flexbox布局等等。
+
+这些子类本质上都是单例——React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`NativeViewHierarchyManager`,NativeViewHierarchyManager则会反过来委托它们在需要的时候去设置和更新视图的属性。`ViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+1. 创建一个ViewManager的子类。
+2. 实现`createViewInstance`方法。
+3. 导出视图的属性设置器:使用`@ReactProp`(或`@ReactPropGroup`)注解。
+4. 把这个视图管理类注册到应用程序包的`createViewManagers`里。
+5. 实现JavaScript模块。
+
+## 1. 创建`ViewManager`的子类
+
+在这个例子里我们创建一个视图管理类`ReactImageManager`,它继承自`SimpleViewManager`。`ReactImageView`是这个视图管理类所管理的对象类型,这应当是一个自定义的原生视图。`getName`方法返回的名字会用于在JavaScript端引用这个原生视图类型。
+
+```java
+...
+
+public class ReactImageManager extends SimpleViewManager {
+
+ public static final String REACT_CLASS = "RCTImageView";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+```
+
+## 2. 实现方法`createViewInstance`
+
+视图在`createViewInstance`中创建,且应当把自己初始化为默认的状态。所有属性的设置都通过后续的`updateView`来进行。
+
+```java
+ @Override
+ public ReactImageView createViewInstance(ThemedReactContext context) {
+ return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext);
+ }
+```
+
+## 3. 通过`@ReactProp`(或`@ReactPropGroup`)注解来导出属性的设置方法。
+
+要导出给JavaScript使用的属性,需要申明带有`@ReactProp`(或`@ReactPropGroup`)注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为`void`,而且访问控制必须被声明为`public`。JavaScript所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:`boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`。
+
+`@ReactProp`注解必须包含一个字符串类型的参数`name`。这个参数指定了对应属性在JavaScript端的名字。
+
+除了`name`,`@ReactProp`注解还接受这些可选的参数:`defaultBoolean`, `defaultInt`, `defaultFloat`。这些参数必须是对应的基础类型的值(也就是`boolean`, `int`, `float`),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。注意这个"默认"值只对基本类型生效,对于其他的类型而言,当对应的属性删除时,`null`会作为默认值提供给方法。
+
+使用`@ReactPropGroup`来注解的设置方法和`@ReactProp`不同。请参见`@ReactPropGroup`注解类源代码中的文档来获取更多详情。
+
+**重要!** 在ReactJS里,修改一个属性会引发一次对设置方法的调用。有一种修改情况是,移除掉之前设置的属性。在这种情况下设置方法也一样会被调用,并且“默认”值会被作为参数提供(对于基础类型来说可以通过`defaultBoolean`、`defaultFloat`等`@ReactProp`的属性提供,而对于复杂类型来说参数则会设置为`null`)
+
+```java
+ @ReactProp(name = "src")
+ public void setSrc(ReactImageView view, @Nullable String src) {
+ view.setSource(src);
+ }
+
+ @ReactProp(name = "borderRadius", defaultFloat = 0f)
+ public void setBorderRadius(ReactImageView view, float borderRadius) {
+ view.setBorderRadius(borderRadius);
+ }
+
+ @ReactProp(name = ViewProps.RESIZE_MODE)
+ public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
+ view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
+ }
+```
+
+## 4. 注册`ViewManager`
+
+在Java中的最后一步就是把视图控制器注册到应用中。这和[原生模块](NativeModulesAndroid.md)的注册方法类似,唯一的区别是我们把它放到`createViewManagers`方法的返回值里。
+
+```java
+ @Override
+ public List createViewManagers(
+ ReactApplicationContext reactContext) {
+ return Arrays.asList(
+ new ReactImageManager()
+ );
+ }
+```
+
+## 5. 实现对应的JavaScript模块
+
+整个过程的最后一步就是创建JavaScript模块并且定义Java和JavaScript之间的接口层。大部分过程都由React底层的Java和JavaScript代码来完成,你所需要做的就是通过`propTypes`来描述属性的类型。
+
+```js
+// ImageView.js
+
+import { PropTypes } from 'react';
+import { requireNativeComponent, View } from 'react-native';
+
+var iface = {
+ name: 'ImageView',
+ propTypes: {
+ src: PropTypes.string,
+ borderRadius: PropTypes.number,
+ resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
+ ...View.propTypes // 包含默认的View的属性
+ },
+};
+
+module.exports = requireNativeComponent('RCTImageView', iface);
+```
+
+`requireNativeComponent`通常接受两个参数,第一个参数是原生视图的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的`name`,用来在调试信息中显示;组件接口还必须声明`propTypes`字段,用来对应到原生视图上。这个`propTypes`还可以用来检查用户使用View的方式是否正确。
+
+注意,如果你还需要一个JavaScript组件来做一些除了指定`name`和`propTypes`以外的事情,譬如事件处理,你可以把原生组件用一个普通React组件封装。在这种情况下,`requireNativeComponent`的第二个参数变为用于封装的组件。这个在后文的`MyCustomView`例子里面用到。
+
+_译注_:和原生模块不同,原生视图的前缀RCT不会被自动去掉。
+
+# 事件
+
+现在我们已经知道了怎么导出一个原生视图组件,并且我们可以在JS里很方便的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动?当一个原生事件发生的时候,它应该也能触发JavaScript端视图上的事件,这两个视图会依据getId()而关联在一起。
+
+```java
+class MyCustomView extends View {
+ ...
+ public void onReceiveNativeEvent() {
+ WritableMap event = Arguments.createMap();
+ event.putString("message", "MyMessage");
+ ReactContext reactContext = (ReactContext)getContext();
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
+ getId(),
+ "topChange",
+ event);
+ }
+}
+```
+
+这个事件名`topChange`在JavaScript端映射到`onChange`回调属性上(这个映射关系在`UIManagerModuleConstants.java`文件里)。这个回调会被原生事件执行,然后我们通常会在封装组件里构造一个类似的API:
+
+```js
+// MyCustomView.js
+
+class MyCustomView extends React.Component {
+ constructor() {
+ this._onChange = this._onChange.bind(this);
+ }
+ _onChange(event: Event) {
+ if (!this.props.onChangeMessage) {
+ return;
+ }
+ this.props.onChangeMessage(event.nativeEvent.message);
+ }
+ render() {
+ return ;
+ }
+}
+MyCustomView.propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onChangeMessage: React.PropTypes.func,
+ ...
+};
+
+var RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`, MyCustomView, {
+ nativeOnly: {onChange: true}
+});
+```
+
+注意上面用到了`nativeOnly`。有时候有一些特殊的属性,想从原生组件中导出,但是又不希望它们成为对应React封装组件的属性。举个例子,`Switch`组件可能在原生组件上有一个`onChange`事件,然后在封装类中导出`onValueChange`回调属性。这个属性在调用的时候会带上Switch的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上`nativeOnly`选项。
diff --git a/docs/docs/0.43/native-component-ios.md b/docs/docs/0.43/native-component-ios.md
new file mode 100644
index 0000000..2251594
--- /dev/null
+++ b/docs/docs/0.43/native-component-ios.md
@@ -0,0 +1,381 @@
+在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如`ScrollView`和`TextInput`,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
+
+和原生模块向导一样,本向导也是一个相对高级的向导,我们假设你已经对iOS编程颇有经验。本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中`MapView`组件的具体实现。
+
+## iOS MapView样例
+
+假设我们要把地图组件植入到我们的App中——我们用到的是[`MKMapView`](https://developer.apple.com/library/prerelease/mac/documentation/MapKit/Reference/MKMapView_Class/index.html),而现在只需要让它可以被Javascript重用。
+
+原生视图都需要被一个`RCTViewManager`的子类来创建和管理。这些管理器在功能上有些类似“视图控制器”,但它们本质上都是单例 - React Native只会为每个管理器创建一个实例。它们创建原生的视图并提供给`RCTUIManager`,`RCTUIManager`则会反过来委托它们在需要的时候去设置和更新视图的属性。`RCTViewManager`还会代理视图的所有委托,并给JavaScript发回对应的事件。
+
+提供原生视图很简单:
+
+- 首先创建一个子类
+- 添加`RCT_EXPORT_MODULE()`标记宏
+- 实现`-(UIView *)view`方法
+
+```objective-c
+// RNTMapManager.m
+#import
+
+#import
+
+@interface RNTMapManager : RCTViewManager
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+- (UIView *)view
+{
+ return [[MKMapView alloc] init];
+}
+
+@end
+```
+
+接下来你需要一些Javascript代码来让这个视图变成一个可用的React组件:
+
+```javascript
+// MapView.js
+
+var { requireNativeComponent } = require('react-native');
+
+// requireNativeComponent 自动把这个组件提供给 "RNTMapManager"
+module.exports = requireNativeComponent('RNTMap', null);
+```
+
+现在我们就已经实现了一个完整功能的地图组件了,诸如捏放和其它的手势都已经完整支持。但是现在我们还不能真正的从Javascript端控制它。(╯﹏╰)
+
+## 属性
+
+我们能让这个组件变得更强大的第一件事情就是要能够封装一些原生属性供Javascript使用。举例来说,我们希望能够禁用手指捏放操作,然后指定一个初始的地图可见区域。禁用捏放操作只需要一个布尔值类型的属性就行了,所以我们添加这么一行:
+
+```objective-c
+// RNTMapManager.m
+RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
+```
+
+注意我们现在把类型声明为`BOOL`类型——React Native用`RCTConvert`来在JavaScript和原生代码之间完成类型转换。如果转换无法完成,会产生一个“红屏”的报错提示,这样你就能立即知道代码中出现了问题。如果一切进展顺利,上面这个宏就已经包含了导出属性的全部实现。
+
+现在要想禁用捏放操作,我们只需要在JS里设置对应的属性:
+
+```javascript
+// MyApp.js
+
+```
+
+但这样并不能很好的说明这个组件的用法——用户要想知道我们的组件有哪些属性可以用,以及可以取什么样的值,他不得不一路翻到Objective-C的代码。要解决这个问题,我们可以创建一个封装组件,并且通过`PropTypes`来说明这个组件的接口。
+
+```javascript
+// MapView.js
+import React, { Component, PropTypes } from 'react';
+import { requireNativeComponent } from 'react-native';
+
+var RNTMap = requireNativeComponent('RNTMap', MapView);
+
+export default class MapView extends Component {
+ static propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: PropTypes.bool,
+ };
+ render() {
+ return ;
+ }
+}
+```
+
+_译注_:使用了封装组件之后,你还需要注意到module.exports导出的不再是requireNativeComponent的返回值,而是所创建的包装组件。
+
+现在我们有了一个封装好的组件,还有了一些注释文档,用户使用起来也更方便了。注意我们现在把`requireNativeComponent`的第二个参数从null变成了用于封装的组件`MapView`。这使得React Native的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。
+
+现在,让我们添加一个更复杂些的`region`属性。我们首先添加原生代码:
+
+```objective-c
+// RNTMapManager.m
+RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RNTMap)
+{
+ [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
+}
+```
+
+这段代码比刚才的一个简单的`BOOL`要复杂的多了。现在我们多了一个需要做类型转换的`MKCoordinateRegion`类型,还添加了一部分自定义的代码,这样当我们在JS里改变地图的可视区域的时候,视角会平滑地移动过去。在我们提供的函数体内,`json`代表了JS中传递的尚未解析的原始值。函数里还有一个`view`变量,使得我们可以访问到对应的视图实例。最后,还有一个`defaultView`对象,这样当JS给我们发送null的时候,可以把视图的这个属性重置回默认值。
+
+你可以为视图编写任何你所需要的转换函数——下面就是`MKCoordinateRegion`的转换实现,它通过两个RCTConvert的扩展来完成:
+
+```objective-c
+@implementation RCTConvert(CoreLocation)
+
+RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue);
+RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue);
+
++ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json
+{
+ json = [self NSDictionary:json];
+ return (CLLocationCoordinate2D){
+ [self CLLocationDegrees:json[@"latitude"]],
+ [self CLLocationDegrees:json[@"longitude"]]
+ };
+}
+
+@end
+
+@implementation RCTConvert(MapKit)
+
++ (MKCoordinateSpan)MKCoordinateSpan:(id)json
+{
+ json = [self NSDictionary:json];
+ return (MKCoordinateSpan){
+ [self CLLocationDegrees:json[@"latitudeDelta"]],
+ [self CLLocationDegrees:json[@"longitudeDelta"]]
+ };
+}
+
++ (MKCoordinateRegion)MKCoordinateRegion:(id)json
+{
+ return (MKCoordinateRegion){
+ [self CLLocationCoordinate2D:json],
+ [self MKCoordinateSpan:json]
+ };
+}
+```
+
+这些转换函数被设计为可以安全的处理任何JS扔过来的JSON:当有任何缺少的键或者其它问题发生的时候,显示一个“红屏”的错误提示。
+
+为了完成`region`属性的支持,我们还需要在`propTypes`里添加相应的说明(否则我们会立刻收到一个错误提示),然后就可以像使用其他属性一样使用了:
+
+```javascript
+// MapView.js
+
+MapView.propTypes = {
+ /**
+ * 当这个属性被设置为true,并且地图上绑定了一个有效的可视区域的情况下,
+ * 可以通过捏放操作来改变摄像头的偏转角度。
+ * 当这个属性被设置成false时,摄像头的角度会被忽略,地图会一直显示为俯视状态。
+ */
+ pitchEnabled: React.PropTypes.bool,
+
+ /**
+ * 地图要显示的区域。
+ *
+ * 区域由中心点坐标和区域范围坐标来定义。
+ *
+ */
+ region: React.PropTypes.shape({
+ /**
+ * 地图中心点的坐标。
+ */
+ latitude: React.PropTypes.number.isRequired,
+ longitude: React.PropTypes.number.isRequired,
+
+ /**
+ * 最小/最大经、纬度间的距离。
+ */
+ latitudeDelta: React.PropTypes.number.isRequired,
+ longitudeDelta: React.PropTypes.number.isRequired,
+ }),
+};
+
+// MyApp.js
+
+ render() {
+ var region = {
+ latitude: 37.48,
+ longitude: -122.16,
+ latitudeDelta: 0.1,
+ longitudeDelta: 0.1,
+ };
+ return ;
+ }
+
+```
+
+现在你可以看到region属性的整个结构已经加上了文档说明——将来可能我们会自动生成一些类似的代码,但目前还没有这样的手段。
+
+有时候你的原生组件有一些特殊的属性希望导出,但并不希望它成为公开的接口。举个例子,`Switch`组件可能会有一个`onChange`属性用来传递原始的原生事件,然后导出一个`onValueChange`属性,这个属性在调用的时候会带上`Switch`的状态作为参数之一。这样的话你可能不希望原生专用的属性出现在API之中,也就不希望把它放到`propTypes`里。可是如果你不放的话,又会出现一个报错。解决方案就是带上额外的`nativeOnly`参数,像这样:
+
+```javascript
+var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
+ nativeOnly: { onChange: true }
+});
+```
+
+## 事件
+
+现在我们已经有了一个原生地图组件,并且从JS可以很容易的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动来改变可视区域?关键的步骤是在`RNTMapManager`中声明一个事件处理函数的属性(onChange),来委托我们提供的所有视图,然后把事件传递给JavaScript。最终的代码看起来类似这样(比起完整的实现有所简化):
+
+```objective-c
+// RNTMap.h
+
+#import
+
+#import
+
+@interface RNTMap: MKMapView
+
+@property (nonatomic, copy) RCTBubblingEventBlock onChange;
+
+@end
+```
+
+```objective-c
+// RNTMap.m
+
+#import "RNTMap.h"
+
+@implementation RNTMap
+
+@end
+```
+
+```objective-c
+#import "RNTMapManager.h"
+
+#import
+
+#import "RNTMap.h"
+#import
+
+@interface RNTMapManager()
+@end
+
+@implementation RNTMapManager
+
+RCT_EXPORT_MODULE()
+
+RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
+
+- (UIView *)view
+{
+ RNTMap *map = [RNTMap new];
+ map.delegate = self;
+ return map;
+}
+
+#pragma mark MKMapViewDelegate
+
+- (void)mapView:(RNTMap *)mapView regionDidChangeAnimated:(BOOL)animated
+{
+ if (!mapView.onChange) {
+ return;
+ }
+
+ MKCoordinateRegion region = mapView.region;
+ mapView.onChange(@{
+ @"region": @{
+ @"latitude": @(region.center.latitude),
+ @"longitude": @(region.center.longitude),
+ @"latitudeDelta": @(region.span.latitudeDelta),
+ @"longitudeDelta": @(region.span.longitudeDelta),
+ }
+ });
+}
+```
+
+如你所见,我们刚才通过继承`MKMapView`添加了事件处理函数,然后我们将`onChange`暴露出来,委托`RNTMapManager`代理其创建的所有视图。最后在委托方法`-mapView:regionDidChangeAnimated:`中,根据对应的视图调用事件处理函数并传递区域数据。调用`onChange`事件会触发JavaScript端的同名回调函数。这个回调会被原生事件执行,然后我们通常都会在封装组件里做一些处理,来使得API更简明:
+
+
+```javascript
+// MapView.js
+
+class MapView extends React.Component {
+ static propTypes = {
+ /**
+ * Callback that is called continuously when the user is dragging the map.
+ */
+ onChange: React.PropTypes.func,
+ ...
+ };
+ _onChange = (event: Event) => {
+ if (!this.props.onRegionChange) {
+ return;
+ }
+ this.props.onRegionChange(event.nativeEvent);
+ }
+ render() {
+ return ;
+ }
+}
+
+class MapViewExample extends React.Component {
+ onRegionChange(event: Event) {
+ // Do stuff with event.region.latitude, etc.
+ }
+
+ render() {
+ var region = {
+ latitude: 37.48,
+ longitude: -122.16,
+ latitudeDelta: 0.1,
+ longitudeDelta: 0.1,
+ };
+
+ return (
+
+ );
+ }
+ }
+
+ // Module name
+ +AppRegistry.registerComponent('MapViewExample', () => MapViewExample);
+```
+
+## 样式
+
+因为我们所有的视图都是`UIView`的子类,大部分的样式属性应该直接就可以生效。但有一部分组件会希望使用自己定义的默认样式,例如`UIDatePicker`希望自己的大小是固定的。这个默认属性对于布局算法的正常工作来说很重要,但我们也希望在使用这个组件的时候可以覆盖这些默认的样式。`DatePickerIOS`实现这个功能的办法是通过封装一个拥有弹性样式的额外视图,然后在内层的视图上应用一个固定样式(通过原生传递来的常数生成):
+
+```javascript
+// DatePickerIOS.ios.js
+
+var RCTDatePickerIOSConsts = require('react-native').UIManager.RCTDatePicker.Constants;
+...
+ render: function() {
+ return (
+
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ rkDatePickerIOS: {
+ height: RCTDatePickerIOSConsts.ComponentHeight,
+ width: RCTDatePickerIOSConsts.ComponentWidth,
+ },
+});
+```
+
+常量`RCTDatePickerIOSConsts`在原生代码中导出,从一个组件的实际布局上获取到:
+
+```objective-c
+// RCTDatePickerManager.m
+
+- (NSDictionary *)constantsToExport
+{
+ UIDatePicker *dp = [[UIDatePicker alloc] init];
+ [dp layoutIfNeeded];
+
+ return @{
+ @"ComponentHeight": @(CGRectGetHeight(dp.frame)),
+ @"ComponentWidth": @(CGRectGetWidth(dp.frame)),
+ @"DatePickerModes": @{
+ @"time": @(UIDatePickerModeTime),
+ @"date": @(UIDatePickerModeDate),
+ @"datetime": @(UIDatePickerModeDateAndTime),
+ }
+ };
+}
+```
+
+本向导覆盖了包装原生组件所需了解的许多方面,不过你可能还有很多知识需要了解,譬如特殊的方式来插入和布局子视图。如果你想更深入了解,可以阅读`RNTMapManager`和其它的组件的[源代码](https://github.com/facebook/react-native/blob/master/React/Views)。
+
diff --git a/docs/docs/0.43/native-modules-android.md b/docs/docs/0.43/native-modules-android.md
new file mode 100644
index 0000000..38aeedb
--- /dev/null
+++ b/docs/docs/0.43/native-modules-android.md
@@ -0,0 +1,432 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块包装;或者你需要复用一些Java代码,而不是用Javascript重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+## Toast模块
+
+本向导会用[Toast](http://developer.android.com/reference/android/widget/Toast.html)作为例子。假设我们希望可以从Javascript发起一个Toast消息(Android中的一种会在屏幕下方弹出、保持一段时间的消息通知)
+
+我们首先来创建一个原生模块。一个原生模块是一个继承了`ReactContextBaseJavaModule`的Java类,它可以实现一些JavaScript所需的功能。我们这里的目标是可以在JavaScript里写`ToastAndroid.show('Awesome', ToastAndroid.SHORT);`,来调起一个Toast通知。
+
+```java
+package com.facebook.react.modules.toast;
+
+import android.widget.Toast;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class ToastModule extends ReactContextBaseJavaModule {
+
+ private static final String DURATION_SHORT_KEY = "SHORT";
+ private static final String DURATION_LONG_KEY = "LONG";
+
+ public ToastModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+}
+```
+
+`ReactContextBaseJavaModule`要求派生类实现`getName`方法。这个函数用于返回一个字符串名字,这个名字在JavaScript端标记这个模块。这里我们把这个模块叫做`ToastAndroid`,这样就可以在JavaScript中通过`React.NativeModules.ToastAndroid`访问到这个模块。**译注:RN已经内置了一个名为ToastAndroid的模块,所以如果你在练习时完全照抄,那么运行时会报错名字冲突!所以请在这里选择另外一个名字!**
+
+```java
+ @Override
+ public String getName() {
+ return "ToastAndroid";
+ }
+```
+
+_译注_:模块名前的RCT前缀会被自动移除。所以如果返回的字符串为"RCTToastAndroid",在JavaScript端依然可以通过`React.NativeModules.ToastAndroid`访问到这个模块。
+
+一个可选的方法`getContants`返回了需要导出给JavaScript使用的常量。它并不一定需要实现,但在定义一些可以被JavaScript同步访问到的预定义的值时非常有用。
+
+```java
+ @Override
+ public Map getConstants() {
+ final Map constants = new HashMap<>();
+ constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
+ constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
+ return constants;
+ }
+```
+
+要导出一个方法给JavaScript使用,Java方法需要使用注解`@ReactMethod`。方法的返回类型必须为`void`。React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件(参见下文的描述)。
+
+```java
+ @ReactMethod
+ public void show(String message, int duration) {
+ Toast.makeText(getReactApplicationContext(), message, duration).show();
+ }
+```
+
+### 参数类型
+
+下面的参数类型在`@ReactMethod`注明的方法中,会被直接映射到它们对应的JavaScript类型。
+
+```
+Boolean -> Bool
+Integer -> Number
+Double -> Number
+Float -> Number
+String -> String
+Callback -> function
+ReadableMap -> Object
+ReadableArray -> Array
+```
+参阅[ReadableMap](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java)和[ReadableArray](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java)。
+
+### 注册模块
+
+在Java这边要做的最后一件事就是注册这个模块。我们需要在应用的Package类的`createNativeModules`方法中添加这个模块。如果模块没有被注册,它也无法在JavaScript中被访问到。
+
+```java
+package com.facebook.react.modules.toast;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AnExampleReactPackage implements ReactPackage {
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createNativeModules(
+ ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new ToastModule(reactContext));
+
+ return modules;
+ }
+```
+
+这个package需要在`MainApplication.java`文件的`getPackages`方法中提供。这个文件位于你的react-native应用文件夹的android目录中。具体路径是: `android/app/src/main/java/com/your-app-name/MainApplication.java`.
+
+```java
+protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new AnExampleReactPackage()); // <-- 添加这一行,类名替换成你的Package类的名字.
+}
+```
+
+为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从`NativeModules`中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。
+
+```javascript
+'use strict';
+
+/**
+ * This exposes the native ToastAndroid module as a JS module. This has a function 'show'
+ * which takes the following parameters:
+ *
+ * 1. String message: A string with the text to toast
+ * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or ToastAndroid.LONG
+ */
+import { NativeModules } from 'react-native';
+
+// 下一句中的ToastAndroid即对应上文
+// public String getName()中返回的字符串
+// 练习时请务必选择另外的名字!
+
+export default NativeModules.ToastAndroid;
+```
+
+现在,在别处的JavaScript代码中可以这样调用你的方法:
+
+```javascript
+import ToastAndroid from './ToastAndroid';
+ToastAndroid.show('Awesome', ToastAndroid.SHORT);
+```
+
+## 更多特性
+
+### 回调函数
+
+原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
+
+```java
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Callback errorCallback,
+ Callback successCallback) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+ float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+ float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+ float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+ float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+ successCallback.invoke(relativeX, relativeY, width, height);
+ } catch (IllegalViewOperationException e) {
+ errorCallback.invoke(e.getMessage());
+ }
+ }
+
+...
+```
+
+这个函数可以在JavaScript里这样使用:
+
+```js
+UIManager.measureLayout(
+ 100,
+ 100,
+ (msg) => {
+ console.log(msg);
+ },
+ (x, y, width, height) => {
+ console.log(x + ':' + y + ':' + width + ':' + height);
+ }
+);
+```
+
+原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。
+
+请务必注意callback并非在对应的原生函数返回后立即被执行——注意跨语言通讯是异步的,这个执行过程会通过消息循环来进行。
+
+## Promises
+
+__译注__:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。
+
+原生模块还可以使用promise来简化代码,搭配ES2016(ES7)标准的`async/await`语法则效果更佳。如果桥接原生方法的最后一个参数是一个`Promise`,则对应的JS方法就会返回一个Promise对象。
+
+我们把上面的代码用promise来代替回调进行重构:
+
+```java
+import com.facebook.react.bridge.Promise;
+
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+ @ReactMethod
+ public void measureLayout(
+ int tag,
+ int ancestorTag,
+ Promise promise) {
+ try {
+ measureLayout(tag, ancestorTag, mMeasureBuffer);
+
+ WritableMap map = Arguments.createMap();
+
+ map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0]));
+ map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1]));
+ map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2]));
+ map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3]));
+
+ promise.resolve(map);
+ } catch (IllegalViewOperationException e) {
+ promise.reject(e.getMessage());
+ }
+ }
+
+...
+```
+
+现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了`async`的异步函数内使用`await`关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
+
+```js
+async function measureLayout() {
+ try {
+ var {
+ relativeX,
+ relativeY,
+ width,
+ height,
+ } = await UIManager.measureLayout(100, 100);
+
+ console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+measureLayout();
+```
+
+### 多线程
+
+原生模块不应对自己被调用时所处的线程做任何假设,当前的状况有可能会在将来的版本中改变。如果一个过程要阻塞执行一段时间,这个工作应当分配到一个内部管理的工作线程,然后从那边可以调用任意的回调函数。_译注_:我们通常用AsyncTask来完成这项工作。
+
+### 发送事件到JavaScript
+
+原生模块可以在没有被调用的情况下往JavaScript发送事件通知。最简单的办法就是通过`RCTDeviceEventEmitter`,这可以通过`ReactContext`来获得对应的引用,像这样:
+
+```java
+...
+private void sendEvent(ReactContext reactContext,
+ String eventName,
+ @Nullable WritableMap params) {
+ reactContext
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit(eventName, params);
+}
+...
+WritableMap params = Arguments.createMap();
+...
+sendEvent(reactContext, "keyboardWillShow", params);
+```
+
+JavaScript模块可以通过使用`DeviceEventEmitter`模块来监听事件:
+
+```js
+import { DeviceEventEmitter } from 'react-native';
+...
+componentWillMount: function() {
+ DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) {
+ // handle event.
+ });
+}
+...
+```
+
+### 从`startActivityForResult`中获取结果
+
+如果你使用`startActivityForResult`调起了一个activity并想从其中获取返回结果,那么你需要监听`onActivityResult`事件。具体的做法是继承`BaseActivityEventListener`或是实现`ActivityEventListener`。我们推荐前一种做法,因为它相对来说不太会受到API变更的影响。然后你需要在模块的构造函数中注册这一监听事件。
+
+```java
+reactContext.addActivityEventListener(mActivityResultListener);
+```
+
+现在你可以通过重写下面的方法来实现对`onActivityResult`的监听:
+
+```java
+@Override
+public void onActivityResult(
+ final Activity activity,
+ final int requestCode,
+ final int resultCode,
+ final Intent intent) {
+ // 在这里实现你自己的逻辑
+}
+```
+
+下面我们写一个简单的图片选择器来实践一下。这个图片选择器会把`pickImage`方法暴露给JavaScript,而这个方法在调用时就会把图片的路径返回到JS端。
+
+```java
+public class ImagePickerModule extends ReactContextBaseJavaModule {
+
+ private static final int IMAGE_PICKER_REQUEST = 467081;
+ private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
+ private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
+ private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
+ private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";
+
+ private Promise mPickerPromise;
+
+ private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
+
+ @Override
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
+ if (requestCode == IMAGE_PICKER_REQUEST) {
+ if (mPickerPromise != null) {
+ if (resultCode == Activity.RESULT_CANCELED) {
+ mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
+ } else if (resultCode == Activity.RESULT_OK) {
+ Uri uri = intent.getData();
+
+ if (uri == null) {
+ mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
+ } else {
+ mPickerPromise.resolve(uri.toString());
+ }
+ }
+
+ mPickerPromise = null;
+ }
+ }
+ }
+ };
+
+ public ImagePickerModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+
+ // Add the listener for `onActivityResult`
+ reactContext.addActivityEventListener(mActivityEventListener);
+ }
+
+ @Override
+ public String getName() {
+ return "ImagePickerModule";
+ }
+
+ @ReactMethod
+ public void pickImage(final Promise promise) {
+ Activity currentActivity = getCurrentActivity();
+
+ if (currentActivity == null) {
+ promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
+ return;
+ }
+
+ // Store the promise to resolve/reject when picker returns data
+ mPickerPromise = promise;
+
+ try {
+ final Intent galleryIntent = new Intent(Intent.ACTION_PICK);
+
+ galleryIntent.setType("image/*");
+
+ final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");
+
+ currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST);
+ } catch (Exception e) {
+ mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
+ mPickerPromise = null;
+ }
+ }
+}
+```
+
+### 监听生命周期事件
+
+监听activity的生命周期事件(比如`onResume`, `onPause`等等)和我们在前面实现 `ActivityEventListener`的做法类似。模块必须实现`LifecycleEventListener`,然后需要在构造函数中注册一个监听函数:
+
+```java
+reactContext.addLifecycleEventListener(this);
+```
+
+现在你可以通过实现下列方法来监听activity的生命周期事件了:
+
+```java
+@Override
+public void onHostResume() {
+ // Activity `onResume`
+}
+
+@Override
+public void onHostPause() {
+ // Activity `onPause`
+}
+
+@Override
+public void onHostDestroy() {
+ // Activity `onDestroy`
+}
+```
diff --git a/docs/docs/0.43/native-modules-ios.md b/docs/docs/0.43/native-modules-ios.md
new file mode 100644
index 0000000..0ffa289
--- /dev/null
+++ b/docs/docs/0.43/native-modules-ios.md
@@ -0,0 +1,453 @@
+有时候App需要访问平台API,但React Native可能还没有相应的模块封装;或者你需要复用Objective-C、Swift或C++代码,而不是用JavaScript重新实现一遍;又或者你需要实现某些高性能、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
+
+我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
+
+本文是关于如何封装原生模块的高级向导,我们假设您已经具备Objective-C或者Swift,以及iOS核心库(Foundation、UIKit)的相关知识。
+
+## iOS 日历模块演示
+
+本向导将会用[iOS日历API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html)作为示例。我们的目标就是在Javascript中可以访问到iOS的日历功能。
+
+在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
+
+```objective-c
+// CalendarManager.h
+#import
+#import
+
+@interface CalendarManager : NSObject
+@end
+```
+
+为了实现`RCTBridgeModule`协议,你的类需要包含`RCT_EXPORT_MODULE()`宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。
+
+```objective-c
+// CalendarManager.m
+@implementation CalendarManager
+
+RCT_EXPORT_MODULE();
+
+@end
+```
+
+你必须明确的声明要给Javascript导出的方法,否则React Native不会导出任何方法。声明通过`RCT_EXPORT_METHOD()`宏来实现:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
+{
+ RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
+}
+```
+
+现在从Javascript里可以这样调用这个方法:
+
+```javascript
+import { NativeModules } from 'react-native';
+var CalendarManager = NativeModules.CalendarManager;
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
+```
+
+> **注意**: Javascript方法名
+>
+> 导出到Javascript的方法名是Objective-C的方法名的第一个部分。React Native还定义了一个`RCT_REMAP_METHOD()`宏,它可以指定Javascript方法名。当许多方法的第一部分相同的时候用它来避免在Javascript端的名字冲突。
+
+桥接到Javascript的方法返回值类型必须是`void`。React Native的桥接操作是异步的,所以要返回结果给Javascript,你必须通过回调或者触发事件来进行。(参见本文档后面的部分)
+
+## 参数类型
+
+`RCT_EXPORT_METHOD` 支持所有标准JSON类型,包括:
+
+- string (`NSString`)
+- number (`NSInteger`, `float`, `double`, `CGFloat`, `NSNumber`)
+- boolean (`BOOL`, `NSNumber`)
+- array (`NSArray`) 包含本列表中任意类型
+- object (`NSDictionary`) 包含string类型的键和本列表中任意类型的值
+- function (`RCTResponseSenderBlock`)
+
+除此以外,任何`RCTConvert`类支持的的类型也都可以使用(参见[`RCTConvert`](https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h)了解更多信息)。`RCTConvert`还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。
+
+在我们的`CalendarManager`例子里,我们需要把事件的时间交给原生方法。我们不能在桥接通道里传递Date对象,所以需要把日期转化成字符串或数字来传递。我们可以这么实现原生函数:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)secondsSinceUnixEpoch)
+{
+ NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
+}
+```
+
+或者这样:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString)
+{
+ NSDate *date = [RCTConvert NSDate:ISO8601DateString];
+}
+```
+
+不过我们可以依靠自动类型转换的特性,跳过手动的类型转换,而直接这么写:
+
+```objective-c
+RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSDate *)date)
+{
+ // Date is ready to use!
+}
+```
+
+在Javascript既可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.getTime()); // 把日期以unix时间戳形式传递
+```
+
+也可以这样:
+
+```javascript
+CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.toISOString()); // 把日期以ISO-8601的字符串形式传递
+```
+
+两个值都会被转换为正确的`NSDate`类型。但如果提供一个不合法的值,譬如一个`Array`,则会产生一个“红屏”报错信息。
+
+随着`CalendarManager.addEvent`方法变得越来越复杂,参数的个数越来越多,其中有一些可能是可选的参数。在这种情况下我们应该考虑修改我们的API,用一个dictionary来存放所有的事件参数,像这样:
+
+```objective-c
+#import