ReactNative学习之常用组件详解
Text组件主要用于显示文本;
具有响应性,可以嵌套,可以继承样式
内部Text组件可以继承外部Text组件的样式
Text组件的特性:
1.onPress
2.numberOfLines 最多显示多少行
3.onLayout
组件的颗粒度设计主要取决于应用的结构设计
1.头部组件 单独封装 独立成一个文件
`module.exports=Header;`
`const Header=require('./header');`
2.列表组件
3.重要新闻 组件
{this.props.news[i]}
警告的处理:数组里面需要key属性 参考:https://fb.me/react-warning-keys
2、TextInput组件
文本输入框:基本组件 自动补全的搜索功能
TextInput的主要属性和事件如下:
autoCapitalize:枚举类型,可选值有none sentences words characters 当用户输入时,用于提示
placeholder:占位符,在输入前显示的文本内容
value:文本输入框的默认值
placeholderTextColor:占位符文本的颜色
password:boolean类型 true表示密码输入显示*
multiline:多行输入
editable:文本框是否可输入
autoFocus:自动聚焦
clearButtonMode:枚举类型,never while-editing unless-editing always 用于显示清除按钮
maxLength:能够输入的最长字符数
enablesReturnKeyAutomatically:如果为true 表示没有文本时键盘是不能有返回键的,其默认值为false
returnKeyType:枚举类型 default go google join next route search send yahoo done emergency-call 表示软键盘返回键显示的字符串
secureTextEntry:隐藏输入内容,默认值为false
onChangeText:当文本输入框的内容变化时,调用改函数;onChangeText接收一个文本的参数对象
onChange:当文本变化时,调用该函数
onEndEditing:当结束编辑时,调用改函数
onBlur:失去焦点触发事件
onFocus:获得焦点时触发事件
onSubmitEditing:当结束编辑后,点击键盘的提交按钮触发该事件
3、Touchable类组件
React Native没有像Web开发那样给元素绑定click事件,前面讲的Text组件有onPress事件回调,View组件是没有的,但是在实际项目开发中,很多其他的组件也是需要可以被点击的,RN提供了3个组件来赋予被点击的能力(去包裹其他组件即可),这3个组件被称为“Touchable类组件”:
1.TouchableHighlight 高亮
属性:activeOpacity(设置透明度)、onHideUnderlay、onShowUnderlay、underlayColor(点击时背景阴影效果的背景颜色)
2.TouchableOpacity 透明度
属性:activeOpacity
3.TouchableWithoutFeedback 无反馈 不会出现任何视觉变化
不建议使用;属性:onLongPress、onPressIn、onPressOut
在app中我们希望点击的时候会有一些视觉上的变化,这个变化会提醒我们已经点击过了,从而避免重复点击
4、Image组件
React Native的Image组件调用的图片途径比较多:网络图片、本地图片、照相机图片
Image组件的属性:
resizeMode:图片适用的模式 cover、contain、stretch
source:图片的引用地址
网络图片:source={{uri:'http://.png'}}
本地图片:source={require('./baidulogo.png')}
静态图片资源:注意:如果你添加图片的时候packager正在运行,则你需要重启packager以便能正确引入新添加的图片。
这样会带来如下的一些好处:
iOS和Android一致的文件系统。 图片和JS代码处在相同的文件夹,这样组件就可以包含自己所用的图片而不用单独去设置。 不需要全局命名。你不用再担心图片名字的冲突问题了。 只有实际被用到(即被require)的图片才会被打包到你的app。 现在在开发期间,增加和修改图片不需要重新编译了,只要和修改js代码一样刷新你的模拟器就可以了。 与访问网络图片相比,Packager可以得知图片大小了,不需要在代码里再声明一遍尺寸。 现在通过npm来分发组件或库可以包含图片了。
注意:为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串。
#使用混合App的图片资源
如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(通过Xcode的asset类目或者Android的drawable文件夹打包)
注意:这一做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸
注意:网络图片,你需要手动指定图片的尺寸
关于图片的尺寸,React Native会自动为你选好。如果没有,则会选择最接近的尺寸进行缩放,但也至少缩放到比所需尺寸大出50%,以使图片看起来仍然足够清晰。这一切过程都是自动完成的,所以你不用操心自己去完成这些繁琐且易错的代码。
5、ProgressBar组件
分平台的:ProgressBarAndroid ProgressViewIOS
styleAttr:进度条的样式 Horizontal Small Large Inverse SmallInverse LargeInverse
progress:当前的进度值(在0到1之间)
6、DrawerLayoutAndroid组件
封装了平台DrawerLayout(仅限安卓平台)的React组件。抽屉(通常用于导航切换)是通过renderNavigationView方法渲染的,并且DrawerLayoutAndroid的直接子视图会成为主视图(用于放置你的内容)。导航视图一开始在屏幕上并不可见,不过可以从drawerPosition指定的窗口侧面拖拽出来,并且抽屉的宽度可以使用drawerWidth属性来指定。
drawerPosition:DrawerLayoutAndroid.positions.Right 左右 默认左
drawerWidth:指定抽屉的宽度,也就是从屏幕边缘拖进的视图的宽度
onDrawerClose
onDrawerOpen
onDrawerSlide:每当导航视图(抽屉)产生交互的时候调用此回调函数
onDrawerStateChanged:idle(空闲) dragging(拖拽中) settling(停靠中)
renderNavigationView:渲染一个可以从屏幕一边拖入的导航视图
drawerLockMode:设置抽屉的锁定模式 有三种模式:
1.unlocked (默认值),意味着此时抽屉可以响应打开和关闭的手势操作
2.locked-closed,意味着此时抽屉将保持关闭,不可用手势打开。
3.locked-open,意味着此时抽屉将保持打开,不可用手势关闭。
无论抽屉处于那种状态,都仍然可以调用openDrawer/closeDrawer这两个方法打开和关闭
7、ViewPagerAndroid组件初探
一个允许在子视图之间左右翻页的容器。每一个ViewPagerAndroid的子容器会被视作一个单独的页,并且会被拉伸填满ViewPagerAndroid。
注意所有的子视图都必须是纯View,而不能是自定义的复合容器
属性:
1.initialPage 初始选中页的下标
2.onPageScroll 当在页间切换时(不论是由于动画还是由于用户在页间滑动/拖拽)执行
回调参数中的event.nativeEvent对象会包含如下数据: position offset 一个在[0,1)(大于等于0,小于1)之间的范围,代表当前页面切换的状态
3.onPageScrollStateChanged idle dragging settling
4.onPageSelected 这个回调会在页面切换完成后(当用户在页面间滑动)调用
回调参数中的event.nativeEvent对象会包含如下的字段: position
5.scrollEnabled boolean
8、ListView组件
原生:mListView mAdapter List集合数据 MVC
ListView组件是React Native中一个比较核心的组件,用途非常的广。该组件设计用来高效的展示垂直滚动的数据列表。最简单的API就是创建一个ListView.DataSource对象,同时给该对象传入一个简单的数据集合。并且使用数据源(data source)实例化一个ListView组件,定义一个renderRow回调方法(该方法的参数是一个数组),该renderRow方法会返回一个可渲染的组件(该就是列表的每一行的item)
由于平台差异性,React Native 中的滚动列表组件 ListView 并没有直接映射为 android 中的 ListView 或 iOS 中的 UITableView,而是在ScrollView 的基础上使用 JS 做了一次封装。这样,滚动体验部分由 Native 负责,而 React 部分则专注于组件何时渲染、如何渲染等问题。
数据源默认的格式有三个维度:
第一个维度是 sectionId ,标识属于哪一段, 可以手动指定或隐式地使用数组索引或对象的 key 值; 第二个维度是 rowId ,标识某个数据段下的某一个行,同样可以手动指定或隐式地使用数组索引或对象的 key 值; 第三个维度是具体的数据对象,根据实际的需要而定。 需要注意的是,上面只是 默认的数据格式 ,如果它不符合实际的需求, 完全可以使用自定义的数据结构 。唯一的区别就是需要额外指定给 ListView 数据源中哪些是 id,哪些是 rowData。
DataSource 的构造函数接收以下4个参数(都是可选): rowHasChanged : 用于在数据变化的时候,计算出变化的部分,在更新时只渲染脏数据; sectionHeaderHasChanged : 同理,在列表带分段标题时需要实现; getRowData/getSectionHeaderData : 如果遵循默认的数据源格式,这两个方法就没有必要实现,用内部默认的即可;而当数据源格式是自定义时,需要手动实现这两个方法。
DataSource 的初始化一般在 constructor 方法中
数据源确定后,下一个工作就是列表的渲染。在渲染时发挥重要作用的是 renderRow 属性,它接收数据源中保存的数据对象,并通过返回值确定该行该如何进行展现。我们可以对所有行统一进行展现,也可以根据里面的字段做出不同的展现。在列表包含 sectionHeader 时,还需要实现 renderSectionHeader 方法。
#注意
要更新datasource中的数据,请(每次都重新)调用cloneWithRows方法(如果用到了section,则对应cloneWithRowsAndSections方法)。数据源中的数据本身是不可修改的,所以请勿直接尝试修改。clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。
#React Native ListView sticky效果实现
dataBlob{The dataBlob is a data structure (generally an object) that holds all the data powering the ListView}:dataBlob 包含ListView所需的所有数据(section header 和 rows),在ListView渲染数据时,使用 getSectionData 和 getRowData 来渲染每一行数据。 dataBlob 的 key 值包含 sectionID + rowId
sectionIDs[]:用于标识每组section
rowIDs[]:用于描述每个 section 里的每行数据的位置及是否需要渲染。在ListView渲染时,会先遍历 rowIDs 获取到对应的 dataBlob 数据。
片段头sticky失效原因:
1.Found this out by accident, but if you put your ListView inside a ScrollView, the headers will not be sticky
2.iOS RCTScrollView implements sticky headers 而android没有
3.ListView的Android版本不支持sticky-header特性
4.用这个替代:https://github.com/emilsjolander/StickyScrollViewItems
##分页
当数据量很大的时候如何分页加载 。这种情形分两种情况考虑:
1.数据一次性拿到,边滚动边加载
2.数据不是一次性拿到,而是有可能分屏取数据
对于第一种情况,在 ListView 内部其实已经做了分页的处理:
ListView 内部通过 curRenderedRowsCount 状态保存已渲染的行数; 初始状态下,要加载的数据条数等于 initialListSize (默认为 10 条); 在滚动时检测当前滚动的位置和最底部的距离,如果小于 scrollRenderAheadDistance (默认为 1000),就更新 curRenderedRowsCount ,在它原有值基础上加 pageSize 个(默认为 1 条); 由于属性变化,触发了 ListView 重新的 render 。在渲染过程中, curRenderedRowsCount 起到截断数据的作用,React 的 diff 算法使得只有新加入的数据才会渲染到了界面上。 整个过程类似于 Web 端懒加载机制,即 每次在和底部的距离达到一个阈值时,加载接下来的 pageSize 个数据 。
对于第二种情况,ListView 提供了相关的属性:
onEndReachedThreshold ,在滚动即将到达底部时触发; onEndReached ,在已经到达底部时触发;
我们可以在这两个方法中调用接口去拿数据,取到数据后再更新数据源。
##滚动
ListView 只是整合了数据和展现,但实际滚动的功能还是由 ScrollView 全权负责。ScrollView 实现完全和平台相关:在 iOS 上,它映射为 RCTScrollView ;在 Android 上,它映射为 RCTScrollView 和 AndroidHorizontalScrollView 。
React Native 让不同端上的技术融合在了一起,同时也给开发人员提出了更高的要求。以 ScrollView 为例,大量的属性其实原封不动映射给了 UIScrollView ,这就意味着如果想再深入地研究下去,必须对客户端相关技术有足够了解。无论是前端还是客户端,跳出自己熟悉的那片领域也许才是更进一步的关键。
谈到滚动,有一点不得不说的就是 列表的无限加载 ,这牵涉到滚动的性能。
Github 上的这个 issue 对此展开了热烈的讨论。其中有人就提到,数据量很大情况下,ListView 在加载时所占用的 CPU 和内存会大大增加,滚动到最后就导致了应用 crash。
为此,ListView 中新添加了一个实验性的属性: removeClippedSubviews ,它能在滚动时及时删掉列表中处于视窗的之外的行,以此达到降低内存消耗的目的。不幸的是,即使设置了这个属性,程序虽然各项占用减少了不少,但还是没避免崩溃的命运。处于好奇,我也在最新版的 ListView 基础上做了简单尝试,不断加载一个无限大的列表,但并没有出现崩溃的情况:
即使加载了 3000、4000 行,Android 真机、iOS 真机和 iOS 模拟器上都没有崩溃; Android 上明显感到数据加载有 阶段性的延时 ,即滚动一定程度后,再次滚动数据始终加载不出来或要等一段时间才加载出来,体验较差;iOS 相比要流畅的多; 但不崩溃并非最终的目的,很多 React Native 使用者都在试图改进 ListView 的性能表现,相比于直接使用 Native 端的组件,ListView 性能还是差强人意,有很大优化空间。
##总结
ListView 并没有创造出新的东西,它只是集各家所长,很好地将 React 的视图渲染和 Native 端很成熟的滚动机制融合在了一起,使用起来和其他组件无差,静态地定义View、动态地组织数据,是给人带来的直观感受。