Document new asset system

This commit is contained in:
Alex Kotliarskyi 2015-10-20 10:55:02 -07:00
parent 3a8f9e1080
commit e73b08fc06
2 changed files with 61 additions and 36 deletions

View File

@ -1,54 +1,79 @@
## Static Resources
---
id: images
title: Images
layout: docs
category: Guides
permalink: docs/images.html
next: gesture-responder-system
---
Over the course of a project, it is not uncommon to add and remove many images and accidentally end up shipping images you are no longer using in the app. In order to fight this, we need to find a way to know statically which images are being used in the app. To do that, we introduced a marker on require. The only allowed way to refer to an image in the bundle is to literally write `require('image!name-of-the-asset')` in the source.
## Static Image Resources
As of 0.14 release, React Native provides a unified way of managing images in your iOS and Android apps. To add a static image to your app, place it somewhere in your source code tree and reference it like this:
```javascript
<Image source={require('./my-icon.png')} />
```
The image name is resolved the same way JS modules are resolved. In the example above the packager will look for `my-icon.png` in the same folder as the component that requires it. Also if you have `my-icon.ios.png` and `my-icon.android.png`, the packager will pick the file depending on the platform you are running on.
You can also use `@2x`, `@3x`, etc. suffix in the file name to provide images for different screen densities. For example, if you have the following file structure:
```
.
├── button.js
└── img
├── check@2x.png
└── check@3x.png
```
And `button.js` code contains
```javascript
<Image source={require('./img/check.png')} />
```
Packager will bundle and serve the image corresponding to device's screen density, e.g. on iPhone 5s `check@2x.png` will be used, on Nexus 5 `check@3x.png`. If there is no image matching the screen density, the closest best option will be selected.
Here are some benefits that you get:
1. Same system on iOS and Android.
2. Images live in the same folder as your JS code. Components are self-contained.
3. No global namespace, i.e. you don't have worry about name collisions.
4. Only the images that are actually used will be packaged into your app.
5. Adding and changing images doesn't require app recompilation, just refresh the simulator as you normally do.
6. The packager knows the image dimensions, no need to duplicate it in the code.
7. Images can be distributed via [npm](https://www.npmjs.com/) packages.
Note that in order for this to work, the image name in `require` has to be known statically.
```javascript
// GOOD
<Image source={require('image!my-icon')} />
<Image source={require('./my-icon.png')} />
// BAD
var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
<Image source={require('image!' + icon)} />
<Image source={require('./' + icon + '.png')} />
// GOOD
var icon = this.props.active ? require('image!my-icon-active') : require('image!my-icon-inactive');
var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png');
<Image source={icon} />
```
When your entire codebase respects this convention, you're able to do interesting things like automatically packaging the assets that are being used in your app. Note that in the current form, nothing is enforced, but it will be in the future.
NOTE: This system relies on build hooks for [Xcode](https://github.com/facebook/react-native/pull/3523) and [Gradle](https://github.com/facebook/react-native/commit/9dc036d2b99e6233297c55a3490bfc308e34e75f) that are included in new projects generated with `react-native init`. If you generated your projects before that, you'll have to manually add them to your projects to use the new images asset system.
### Adding Static Resources to your iOS App using Images.xcassets
## Images From Hybrid App's Resources
![](/react-native/img/StaticImageAssets.png)
If you are building a hybrid app (some UIs in React Native, some UIs in platform code) you can still use images that are already bundled into the app (via Xcode asset catalogs or Android drawable folder):
> **NOTE**: App build required for new resources
>
> Any time you add a new resource to `Images.xcassets` you will need to re-build your app through Xcode before you can use it - a reload from within the simulator is not enough.
```javascript
<Image source={{uri: 'app_icon'}} style={{width: 40, height: 40}} />
```
*This process is currently being improved, a much better workflow will be available shortly.*
Note that this approach provides no safety checks. It's up to you to guarantee that those images are available in the application. Also you have to specify image dimensions manually.
> **NOTE**: PNG images are required when loading with `require('image!my-icon')`
>
> At this time, only PNG images are supported in iOS. There is an [issue](https://github.com/facebook/react-native/issues/646) that is currently addressing this bug. In the meantime a quick fix is to rename your files to my-icon.png or to use the `uri` property like: `source={{ uri: 'my-icon' }}` instead of `require()`.
### Adding Static Resources to your Android app
Add your images as [bitmap drawables](http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap) to the android project (`<yourapp>/android/app/src/main/res`). To provide different resolutions of your assets, check out [using configuration qualifiers](http://developer.android.com/guide/practices/screens_support.html#qualifiers). Normally, you will want to put your assets in the following directories (create them under `res` if they don't exist):
* `drawable-mdpi` (1x)
* `drawable-hdpi` (1.5x)
* `drawable-xhdpi` (2x)
* `drawable-xxhdpi` (3x)
If you're missing a resolution for your asset, Android will take the next best thing and resize it for you.
> **NOTE**: App build required for new resources
>
> Any time you add a new resource to your drawables you will need to re-build your app by running `react-native run-android` before you can use it - reloading the JS is not enough.
*This process is currently being improved, a much better workflow will be available shortly.*
## Network Resources
## Network Images
Many of the images you will display in your app will not be available at compile time, or you will want to load some dynamically to keep the binary size down. Unlike with static resources, *you will need to manually specify the dimensions of your image.*
@ -61,7 +86,7 @@ Many of the images you will display in your app will not be available at compile
<Image source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}} />
```
## Local Filesystem Resources
## Local Filesystem Images
See [CameraRoll](/react-native/docs/cameraroll.html) for an example of
using local resources that are outside of `Images.xcassets`.
@ -90,7 +115,7 @@ In React Native, one interesting decision is that the `src` attribute is named `
<Image source={{uri: 'something.jpg'}} />
```
On the infrastructure side, the reason is that it allows us to attach metadata to this object. For example if you are using `require('image!icon')`, then we add an `isStatic` attribute to flag it as a local file (don't rely on this fact, it's likely to change in the future!). This is also future proofing, for example we may want to support sprites at some point, instead of outputting `{uri: ...}`, we can output `{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}` and transparently support spriting on all the existing call sites.
On the infrastructure side, the reason is that it allows us to attach metadata to this object. For example if you are using `require('./my-icon.png')`, then we add information about its actual location and size (don't rely on this fact, it might change in the future!). This is also future proofing, for example we may want to support sprites at some point, instead of outputting `{uri: ...}`, we can output `{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}` and transparently support spriting on all the existing call sites.
On the user side, this lets you annotate the object with useful attributes such as the dimension of the image in order to compute the size it's going to be displayed in. Feel free to use it as your data structure to store more information about your image.

View File

@ -4,7 +4,7 @@ title: Style
layout: docs
category: Guides
permalink: docs/style.html
next: gesture-responder-system
next: images
---
React Native doesn't implement CSS but instead relies on JavaScript to let you style your application. This has been a controversial decision and you can read through those slides for the rationale behind it.