内容简介:需要注意的是为了看起来稍微好看点,加了一点样式,不加也可以。style.js别忘了在route里配置新的路由,完整代码如下:
还是摘自L小庸的文章,加入了一点个人的实践和理解
经过第一部分 开发 React Native APP —— 从改造官方 Demo 开始(1) 介绍,App 框架基本构建完成,这部分主要关注 UI/交互、App 发布前的准备工作及如何发布,具体内容包括:
- 在使用 react navigation 的前提下, iOS 实现单个页面从下往上(modal)的进入动画
- 尺寸自适应
- 设置启动页,更换桌面图标、app 展示名称、appID
- 打包发布
一 扩展 react navigation
这部分在android下无效…… ,个人是win,所以后面没有展示效果图,有mac的可以尝试下效果复制代码
官方标注:modal - Make the screens slide in from the bottom which is a common iOS pattern. Only works on iOS, has no effect on Android.
这里的扩展指的是实现 可单独配置页面的进入方式 (react navigation 默认只支持全局配置,要么 card
,要么 modal
,配置后所有页面进入动画相同)。
关于card和modal,个人还并不是很理解,后续理解了再补上
实现上述效果需要做两方面修改: createStackNavigator
API(在 route.js
中使用)和进入某个页面是的调用方式。
1.1 修改 StackNavigator API
..navigate('ScreenSome1')
;如果要使某个页面进入方式为 modal 只需要在路径上加上 Modal 比如:
..navigate('ScreenSome2Modal')
。
需要注意的是 如果页面进入方式为 modal,需要自定义 header,因为默认 header 样式失效,都叠在一块了 。(还没有实际遇到,先mark着)
1.2 页面中调用
首先我们新建页面 ScreenSome2
,接下来就让它以 modal 的形式进入(从屏幕下面进入),作为对比 ScreenSome1
以 card
的形式进入(默认进入方式,从屏幕右侧进入)。
因为以 modal 形式进入的页面需要自定义 header,一般只是一个关闭按钮,以 ScreenSome2
为例:
/** * ScreenSome2/view.js * 自定义 header(关闭按钮) */ import React from 'react'; import { TouchableHighlight,Text,View } from 'react-native' import pxToDp from '../../config/pxToDp'; <View> <TouchableHighlight onPress={() => self.navigation.goBack()} underlayColor="transparent" style={{ display: "flex", justifyContent: "center", marginTop: pxToDp(30), width: pxToDp(150), height: pxToDp(90), backgroundColor: "yellow" }} > <Text style={{ marginLeft: pxToDp(24) }}>关闭</Text> </TouchableHighlight> <Text style={{ fontSize: pxToDp(36) }}>some2,以 modal 的形式进入</Text> </View>复制代码
ScreenSome2
代码:
/** * ScreenSome2/view.js * 自定义 header(关闭按钮) */ import React from 'react'; import { TouchableHighlight,Text,View } from 'react-native' import pxToDp from '../../config/pxToDp'; export default self => ( <View> <TouchableHighlight onPress={() => self.navigation.goBack()} underlayColor="transparent" style={{ display: "flex", justifyContent: "center", marginTop: pxToDp(30), width: pxToDp(150), height: pxToDp(90), backgroundColor: "yellow" }} > <Text style={{ marginLeft: pxToDp(24) }}>关闭</Text> </TouchableHighlight> <Text style={{ fontSize: pxToDp(36) }}>some2,以 modal 的形式进入</Text> </View> );复制代码
为了看起来稍微好看点,加了一点样式,不加也可以。style.js
import { StyleSheet } from 'react-native'; export default StyleSheet.create({ buttonContainer: { margin: 20 }, });复制代码
别忘了在route里配置新的路由,完整代码如下:
// 引入依赖 import React from 'react'; import { createStackNavigator, createAppContainer } from 'react-navigation' // 引入页面组件 import ScreenBottomTab from '../screens/ScreenBottomTab'; import ScreenHome from '../screens/ScreenHome'; import ScreenSome1 from '../screens/ScreenSome1'; import ScreenSome2 from '../screens/ScreenSome2'; import ScreenTab1 from '../screens/ScreenTab1'; import ScreenTab2 from '../screens/ScreenTab2'; import ScreenTab3 from '../screens/ScreenTab3'; /** * 自定义 StackNavigator,可以选择 screen 进入方式 * 默认状态为 card,只需要输入对应页面,比如 ..navigate('ScreenSome1') * 如果要使某个页面进入方式为 modal 只需要在路径上加上 Modal * 比如:..navigate('ScreenSome2Modal') */ const StackModalNavigator = (routeConfigs, navigatorConfig) => { const CardStackNavigator = createStackNavigator(routeConfigs, navigatorConfig); const modalRouteConfig = {}; const routeNames = Object.keys(routeConfigs); for (let i = 0; i < routeNames.length; i++) { modalRouteConfig[`${routeNames[i]}Modal`] = routeConfigs[routeNames[i]]; } const ModalStackNavigator = createStackNavigator( { CardStackNavigator: { screen: CardStackNavigator }, ...modalRouteConfig, }, { // 如果页面进入方式为 modal,需要自定义 header(默认 header 样式失效,都叠在一块了) mode: 'modal', headerMode: 'none', }, ); return ModalStackNavigator; }; // 配置路由 const AppNavigator = StackModalNavigator({ ScreenBottomTab: ScreenBottomTab, //下面几个配置的是测试Navigator不同使用场景用,只需要tab的话,只要ScreenBottomTab: ScreenBottomTab即可 ScreenHome: ScreenHome, ScreenSome1: ScreenSome1, ScreenSome2: ScreenSome2, ScreenTab1: ScreenTab1, ScreenTab2: ScreenTab2, ScreenTab3: ScreenTab3, }); const App = createAppContainer(AppNavigator) export default App 复制代码
this.props.navigation有很多方法,demo中(ScreenHome,ScreenSome1)只用到.navigate,.push,.goBack,具体可参考https://reactnavigation.org/docs/zh-Hans/navigation-prop.html
二 自适应
自适应主要包括两方面:尺寸根据屏幕大小自适应,包括 fontSize
, width
等;图片分辨率根据屏幕分辨率自适应,也就常说的二倍图、三倍图等。
2.1 尺寸自适应
copy自@L小庸的代码片段
尺寸自适应的原理是通过获取手机屏幕的宽度,尺寸做相应比例的调整,为此封装了一个 工具 函数,放在了 config/pxToDp.js
中。
-
config/pxToDp.js
尺寸转换的工具函数
1)编写自适应尺寸工具函数
因为所有涉及尺寸的数据都要转换( fontSize
, width
等),所以对转换后的数据要做处理,保证:1.大于等于 1 的数字向上取整;2.小于 1 的数字,如果是 ios 平台统一设为 0.5;如果是安卓平台统一设为 1(因为安卓平台分辨率千差万别万别,低分辨率的屏幕显示 0.5 的尺寸会有锯齿状)。工具函数完整代码如下:
/** * 自适应布局 * @param uiElementPx: ui给的原始尺寸 */ import { Dimensions, Platform } from 'react-native'; // app 只有竖屏模式,所以可以只获取一次 width const deviceWidthDp = Dimensions.get('window').width; // UI 默认给图是 750 const uiWidthPx = 750; function pxToDp(uiElementPx) { const transferNumb = uiElementPx * deviceWidthDp / uiWidthPx; if (transferNumb >= 1) { // 避免出现循环小数 return Math.ceil(transferNumb); } else if (Platform.OS === 'android') { // 如果是安卓,最小为1,避免边框出现锯齿 return 1; } return 0.5; } export default pxToDp; 复制代码
Dimensions.get('window').width
获取的屏幕宽度和自己想象的可能有出入,比如,iphone7 屏幕 4.7'',获取到的宽度是
375
,华为 P9 是 5.2',但获取到的宽度却是是
360
!有点坑,这个工具函数还有待优化。个人还没有遇到这么多场景,也还没有更好的方案,如果踩坑,后续更新。
2.3 图片分辨率自适应
手机分辨率越来越多,尤其安卓,React Native 可以根据不同分辨率加载不同尺寸的图片,只需在图片命名上面加以区分。
- 提供不同分辨率的图片
比如我们有张图片叫 test.png
,尺寸为 40 x 40
(单位像素),为了做到自适应屏幕分辨率,我们还需要提供它的 2 倍图,3 倍图,这样,一张图片就对应 3 个尺寸,如下:
# 一张图片提供 3个尺寸 test.png # 尺寸 40 x 40 test@2x.png # 尺寸 80 x 80 test@3x.png # 尺寸 120 x 120复制代码
name@nx
是 n (n > 1) 倍图命名规范,React Native 也是根据命名判断图片尺寸的。
- 使用
在引用图片的时候直接使用 不加倍率后缀的图片名 ,比如,直接使用 test.png
,如下:
/** * ScreenTab3/view.js */ <Image source={require("../../assets/images/test.png")} style={{ height: pxToDp(80), width: pxToDp(80) }} />复制代码
三 修改桌面图标、App 展示名称,设置启动页
修改桌面图标、App 展示名称相对简单,设置启动页稍微麻烦。
IOS的设置并没有mac去尝试,可参考@L小庸的https://juejin.im/post/5a9602c45188257a7262e3fb尝试,
踩坑: 开发要连真机调试,尤其是涉及原生功能的部分,切记。
3.1 设置桌面图标
因为 App 图标对应多个尺寸,手动改写太麻烦,这个网站可以自动生成MakeAppIcon。
并不是所有尺寸的图片都需要,见下文。
- 安卓
安卓的 app 图标相对简单,只需要设置桌面图标。设置位置在 yourApp/android/app/src/main/res/
目录下,
这个目录默认有5个文件夹,里面各对应放置了一种尺寸的桌面图标图片,图片尺寸不同,但名称相同,统一为 ic_launcher.png
,具体如下所示:
文件夹名称 | 含义 | 文件夹内部图片尺寸 | 文件夹内部图片名称 |
---|---|---|---|
mipmap-ldpi | Low Density Screen | 36x36 | ic_launcher.png |
mipmap-mdpi | Medium Density Screen | 48x48 | ic_launcher.png |
mipmap-hdpi | High Density Screen | 72x72 | ic_launcher.png |
mipmap-xhdpi | Extra-high density screen | 96x96 | ic_launcher.png |
mipmap-xxhdpi | xx-high density screen | 144x144 | ic_launcher.png |
mipmap-xxxhdpi | xxx-high density screen | 192x192 | ic_launcher.png |
如果你使用了 MakeAppIcon 的服务,直接将对应文件夹全部放入 res/
目录下就好,不然就手动替换图标。
可以根据实际需求删除不必要的文件,比如,120 DPI 的屏幕很少了,那么这个文件夹就可以不要
3.2 修改 App 展示名称
IOS的参考@L小庸的https://juejin.im/post/5a9602c45188257a7262e3fb尝试
- 安卓
安卓修改 App 展示名称在这个文件中 yourApp/android/app/src/main/res/values/strings.xml
。
strings.xml
这个文件很简单,全部内容如下:
<resources> <string name="app_name">你的app名称</string> </resources> 复制代码复制代码
替换 你的app名称
为你想要的名字就好。
安卓的话,还要修改默认包名( applicationId
),如果不修改,如果系统监测到当前应用的 applicationId
和已安装的某个应用相同而签名不同,会报错:“签名不一致 该应用可能已被恶意篡改”。
在这个文件中修改包名: yourApp/android/app/build.gradle
:
// ... defaultConfig { applicationId "com.yourAppId" // ... } // ...复制代码
3.3 设置启动页
这里使用了第三方插件 react-native-splash-screen ,官网教程已经很详细,这里做简要介绍。
- 项目中安装依赖
1)下载依赖
yarn add react-native-splash-screen复制代码
2)添加到项目中
react-native link react-native-splash-screen复制代码
3)在 React Native 配置
这里指的是设置启动页什么时候消失,下面的代码是首页加载完 5s 后启动页消失。
export default class ScreenHome extends Component { // ...other code componentDidMount() { // 隐藏启动页,如果不设置消失时间,在组件加载完启动页自动隐藏 setTimeout(() => { SplashScreen.hide(); }, 5000); } // ...other code }复制代码
- iOS 设置参考@L小庸的https://juejin.im/post/5a9602c45188257a7262e3fb尝试
- 安卓配置
1)更新 MainActivity.java(yourApp/android/app/src/main/java/com/yourApp/MainActivity.java)
:
import android.os.Bundle; // here import com.facebook.react.ReactActivity; // react-native-splash-screen >= 0.3.1 import org.devio.rn.splashscreen.SplashScreen; // here // react-native-splash-screen < 0.3.1 import com.cboy.rn.splashscreen.SplashScreen; // here public class MainActivity extends ReactActivity { @Override protected void onCreate(Bundle savedInstanceState) { SplashScreen.show(this); // here super.onCreate(savedInstanceState); } // ...other code }复制代码
2)新建 launch_screen.xml
在 app/src/main/res/layout
中创建 launch_screen.xml
(如果没有 layout
目录,新建),内容如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/launch_screen"> </LinearLayout>复制代码
3)准备不同尺寸的启动页图片并放到项目中
安卓是通过文件夹路径寻找启动页面的,所以,多张尺寸的启动页名称相同,都为 launch_screen.png
,但要放在不同文件夹中,文件夹放置目录为 yourApp/android/app/src/main/res/
,名称及对应放置的图片尺寸如下:
文件夹名称 | 含义 | 文件夹内部图片尺寸 | 文件夹内部图片名称 |
---|---|---|---|
drawable-ldpi | Low Density Screen | 240x320 | launch_screen.png |
drawable-mdpi | Medium Density Screen | 320x480 | launch_screen.png |
drawable-hdpi | High Density Screen | 480x800 | launch_screen.png |
drawable-xhdpi | Extra-high density screen | 720x1280 | launch_screen.png |
drawable-xxhdpi | xx-high density screen | 960x1600 | launch_screen.png |
drawable-xxxhdpi | xxx-high density screen | 1280x1920 | launch_screen.png |
480x800
起步放置 4 张图片就好。
文件必须是 png 格式的图片,开始随便找了一张图片,结果打包各种报错 ,命名需对应尺寸
4)优化启动页出现前的短暂白屏(copy,踩坑填坑)
到这里,启动页功能已经 ok,但如果仔细看,可以看到启动页出现前会有短暂白屏,此时可通过更改 android/app/src/main/res/values/styles.xml
解决:
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <!--设置透明背景--> <item name="android:windowIsTranslucent">true</item> </style> </resources>复制代码
这种方案实际没有根本解决问题:会发现这样设置以后点击图片不能立即弹出应用,而有短暂的等待时间,待填坑。
5) 解决安卓 6.0,7.0 安装配置完成后出现闪退 ,参考下面设置:(copy,踩坑填坑)
在 android/app/src/main/res/values
下面新建 colors.xml
文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- this is referenced by react-native-splash-screen and will throw an error if not defined. its value does nothing, just here to avoid a runtime error. --> <color name="primary_dark">#000000</color> </resources>复制代码
primary_dark
的颜色值作为状态栏的颜色。
3.4 最终效果图
设置完桌面图标、修改 APP 展示名称及设置启动页之后的效果图如下:
demo里后续添加了自己练习的部分,所以效果图和代码稍有差别,需要的只用care文章里的步骤就好
四 打包发布
4.1 安卓打包发布
- 生成签名
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
- 设置 gradle 变量
1)首先将签名文件 my-release-key.keystore
放在目录 yourApp/android/app/
下
2)修改文件 yourApp/android/gradle.properties
添加下面代码 (替换 *****
为正确的 keystore 密码、别名、和 key 密码):
注意这里的 MYAPP_RELEASE_STORE_PASSWORD和 MYAPP_RELEASE_KEY_PASSWORD一定要和生成签名时的密码保持一致
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore MYAPP_RELEASE_KEY_ALIAS=my-key-alias MYAPP_RELEASE_STORE_PASSWORD=***** MYAPP_RELEASE_KEY_PASSWORD=*****复制代码
3)添加签名信息到 app 的 gradle 配置中
编辑文件 yourApp/android/app/build.gradle
加入签名信息
android { ... defaultConfig { ... } signingConfigs { release { if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) { 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 } } }复制代码
- 打包
在终端输入下面命令
cd android && ./gradlew assembleRelease复制代码
等待构建完成,便可以在 yourApp/android/app/build/outputs/apk/release/app-release.apk
中找到编译后的发布版本。
NOTE:如果遇到这个错误: Execution failed for task ':app:processReleaseResources'
,做下述修改:,个人没有遇到,mark先~
在 yourApp/android/gradle.properties
文件最后添加下面代码:
classpath 'com.android.tools.build:gradle:3.0.0' distributionUrl=https://services.gradle.org/distributions/gradle-4.1-all.zip android.enableAapt2=false复制代码
NOTE:如果遇到Execution failed for task ':app:bundleReleaseJsAndAssets'.不幸的遇到了这个错…………
删除 android/app/build
and android/build
folders and run react-native run-android
again
五 小结
到目前为止,从改造官方 demo 开始,一个比较完整的 React Native App 完成了,在此基础上可以不断扩展完善。
后面如果有有空会在各部分加入更多详细的demo和使用场景,以及踩坑分享。
当然,从生产角度来说,这个 demo 的完成度不高,比如,很多样式还是最原始的状态、比如 WebView(App 中嵌入 H5)、下拉刷新等也没有涉及。其中 WebView、下拉刷新等常用功能会逐步集成到这个 demo 中,但样式并不打算做过多优化,因为从使用角度来讲,样式的完成度越高意味着可定制性越差,并且,那样也会导致代码的可读性变差。希望这个 demo 可以成为完整、普适但不臃肿的脚手架。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 开发 React Native APP —— 从改造官方Demo开始
- 告别 Windows 终端的难看难用,从改造 PowerShell 的外观开始
- 项目容器化改造心得
- 遗留系统改造-开篇
- 全链路压测改造
- 单体应用微服务改造实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Elements of Information Theory
Thomas M. Cover、Joy A. Thomas / Wiley-Blackwell / 2006-7 / GBP 76.50
The latest edition of this classic is updated with new problem sets and material The Second Edition of this fundamental textbook maintains the book's tradition of clear, thought-provoking instr......一起来看看 《Elements of Information Theory》 这本书的介绍吧!