前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react-native布局与组件

react-native布局与组件

作者头像
一粒小麦
发布2019-09-17 16:58:01
5.2K0
发布2019-09-17 16:58:01
举报
文章被收录于专栏:一Li小麦

RN布局与样式

布局

一款好的App离不开漂亮的布局,RN中的布局方式采⽤的是FlexBox(弹性布局) 。

经典资料参考:阮一峰flex 布局语法篇:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

FlexBox提供了在不同尺⼨设备上都能保持一致的布局⽅式 。在移动端,在这里不必担心兼容问题。

但是RN的flex布局和真正的css还是有所差别:

  • flexDirection:RN中默认是flexDirection:’column’,Web Css中默认是 flex-direction:’row’,也就是说RN的flex默认就是打竖的。
  • alignItems:RN中默认: ‘stretch’,在Web Css中默认 flex-start’,也就是说RN的flex是强制等高的。
  • RN的flex属性,只能接收一个值
  • 不支持的属性: align-content flex-basis order flex-flow flex-grow flex-shrink (平时也用得少)

样式

在移动端开发中,是没有像素概念的。所有量规无单位,表示的是是1个逻辑像素

代码语言:javascript
复制
<View style={{width:100,height:100,margin:10,backgroundColor:'gray'}}>
  <Text style={{fontSize:16,margin:20}}>尺⼨寸</Text>
</View>

上述代码,运⾏在Android上时,View的⻓宽被解释成:100dp 100dp,字体被解释成16sp,运⾏于 ios上时尺⼨单位被解释成pt,这些单位确保了布局在任何不同DPI的手机屏幕上,显示效果一致。

关于更详细的换算关系,查阅:http://www.woshipm.com/pmd/176328.html

写样式除了可以用传统react的css in js方式,也可以这么写:

代码语言:javascript
复制
<text style={[styles.aaa,{color:'red'}]}></text>

所有文本的样式应该直接加在text上面,如果你在view里面写,就不会生效了。

代码语言:javascript
复制
{/* 错误的实例:不生效 */}
<view style={[styles.aaa,{color:'red'}]}></view>

组件

react native的魅力在于能够使用系统原生的组件。他们和html标签相似,又有不少区别。

如果写过微信小程序,或许理解起来会比较快。因为前者”借用了”这些组件概念。

简单认知的话,组件和UI框架差不多,用什么引什么。以下对某些重要组件进行介绍。

view:万能容器

视图布局容器,可以理解为原生开发中的万能容器。可嵌套多层,支持flex。

一个组件通常是返回一个view包裹的,如果你想返回两个,可以使用[<View>...</View>,<View>...</View>]的形式返回多个兄弟组件。

SafeAreaView:安全区

SafeAreaView 的目的是在一个“安全”的可视区域内渲染内容。具体来说就是因为目前有 iPhone X 这样的带有“刘海”的全面屏设备,所以需要避免内容渲染到不可⻅见的“刘海”范围内。本组件目前仅⽀持 iOS 设备以及 iOS 11 或更高版本。

SafeAreaView 会自动根据系统的各种导航栏、工具栏等预留出空间来渲染内部内容。更重要的 是,它还会考虑到设备屏幕的局限,比如屏幕四周的圆⻆角或是顶部中间不可显示的“非安全”区域。

代码语言:javascript
复制
<SafeAreaView style={{backgroundColor:'red'}}></SafeAreaView>
webview:加载网页容器(即将被移除)

创建一个原生的webview,用于加载网页.我们可结合safeAreaView使用:

代码语言:javascript
复制
      <SafeAreaView style={{flex:1}}>
        <WebView
        source={{uri: 'https://github.com/facebook/react-native'}}
        style={{marginTop: 20}}
        />
      </SafeAreaView>

在官方最新版本需要安装react-native-webview

需要明确的认知是:webview是有可能存在跨域问题的。

Text:文本容器

主要用于显示文本,具有响应之特性(表现为触摸时是否支持高亮)。同时支持多层嵌套,因此样式可继承(内部继承外部)。但是,不同于web css,字体样式(font color等)只有在text组件上才能起效——所以字体样式的实现只能依赖于text组件。

在Text内部的元素不再使⽤flexbox布局,而是采⽤用文本布局。这意味着内部的元素不再是】一个个矩 形,而可能会在行末进⾏折叠。

代码语言:javascript
复制
                <Text
          ellipsizeMode={"tail"} //这个属性通常和下⾯面的 numberOfLines 属性配合使⽤用,⽂文本超出 numberOfLines设定的⾏行行数时,截取⽅方式:head- 从⽂文本内容头部截取显示省略略号。例例如: "...efg",middle - 在⽂文本内容中间截取显示省略略号。例如: "ab...yz",tail - 从⽂文本内容尾 部截取显示省略略号。例例如: "abcd...",clip - 不不显示省略略号,直接从尾部截断。
          numberOfLines={1} //配合ellipsizeMode设置⾏行行数
          onPress={...} //点击事件 selectable={true}//决定⽤用户是否可以⻓长按选择⽂文本,以便便复制和粘贴。
        >123
        </Text>
Image:图片容器

类似img元素。但支持更多但来源,比如网络图片,本机磁盘图片,照相机图片等。

下⾯的例⼦分别演示了如何显示从本地缓存、网络乃至base64拉取图片。

代码语言:javascript
复制
{/* 显示本地图 */}
<Image
  source={require('./img/favicon.png')}
/>

{/* 显示网络图 */}
<Image
    style={{width: 50, height: 50}}
    //网络和 base64 数据的图⽚需要⼿动指定尺⼨
  source={{uri: 'https://facebook.github.io/react-native/docs/assets/favicon.png'}}
/>

{/* 显示base64图 */}
<Image
style={{width: 66, height: 58}} //⽹网络和 base64 数据的图⽚片需要⼿手动指定尺⼨寸
source={{uri:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg=='}}
/>

自从ios9.0之后,官方就一直推荐使用https协议的网络图片。

ImageBackground 背景图

用法和Image差不多:

代码语言:javascript
复制
{/* 显示网络图 */}
<ImageBackground
    style={{width: 50%, height: 50%}}
    //网络和 base64 数据的图⽚需要⼿动指定尺⼨
  source={{uri: 'https://facebook.github.io/react-native/docs/assets/favicon.png'}}>

  <Text>...</Text>
</ImageBackground>
Button:按钮

一个简单的跨平台的按钮组件。可以进行一些简单的定制。如图,前者为安卓,后者为ios。

代码语言:javascript
复制
<Button
  onPress={onPressLearnMore} //⽤户点击此按钮时所调用的处理理函数
  title="Learn More" //按钮内显示的⽂文本
  color="#841584" //文本的颜⾊(iOS),或是按钮的背景⾊(Android)
  disabled={false} //按钮是否可以点击
  accessibilityLabel="Learn more about this purple button"
  //用于给残障人⼠显示的文本(比如读屏应⽤可能会读取这一内容)
/>
ActivityIndicator loading的小菊花

显示一个loading提示符安卓设备时一个谷歌式半圆环,在ios设备上则显示一朵小菊花。

代码语言:javascript
复制
        <ActivityIndicator
          size="large" //指示器器的大⼩,默认为'small'[enum('small', 'large'), number]。⽬前只能在 Android 上设定具体的数值
          animating={true} //是否要显示指示器动画,默认为 true 表示显示,false 则隐藏。
          hidesWhenStopped={false} //在animating为 false 的时候,是否要隐藏指示器(默认为 true)。如果animating和hidesWhenStopped都为 false,则显示⼀一个静⽌止的指示器。
          color="#0000ff" />
ListView:列表

这个组件的性能比较差,尤其是当有大量的数据需要展示的时候,ListView对内存的占⽤用较多,常出现丢帧卡顿现象。

ListView底层实现,渲染组件Item是全量渲染,而且没有复用机制,当渲染较⼤数据量时,会不可避免地卡顿。

第⼀次打开与切换Tab时会出现卡顿或白屏的情况,比如ListView中有100个Item,只能等这 100条Item都渲染完成,ListView中的内容才会展示滑动列表时会出现卡顿。

未来有很⼤大可能性会被移除 。

VirtualizedList: 虚拟列表

替代ListView的主要解决方案就是VirtualizedList。RN0.43版本中引⼊了了FlatList,SectionList和VirtualizedList,其中VirtualizedList是FlatList和SectionList的底层实现。

FlatList 和 SectionList 的底层实现:VirtualizedList通过维护一个有限的渲染窗⼝(其中包含可⻅的元素),并将渲染窗⼝之外的元素全部用合适的定⻓空⽩空间代替的⽅式,极⼤的改善了内存使⽤,提⾼了大量数据情况下的渲染性能。这个渲染窗⼝能响应滚动行为,元素离可视区越远优先级越低,越近优先级越高,当用户滑动速度过快时,会出现短暂空⽩的情况。

代码语言:javascript
复制
<FlatList
    data={[{key: 'a'}, {key: 'b'}]}
    renderItem={({item}) => <Text>{item.key}</Text>}
/>

缺点:

(1)为了优化内存占⽤同时保持滑动的流畅,列表内容会在屏幕外异步绘制。这意味着如果用户滑动的速度超过渲染的速度,则会先看到空白的内容。

(2)不支持分组列列表

扯了那么多理论,如果列表写不了想说自己懂rn是很扯的。是时候开始写一个了。

需求:列表的下拉刷新和上划动加载

看今日头条等新闻列表类app时,都需要用到。

代码语言:javascript
复制
import React,{Component} from 'react';
import {View,Text,StyleSheet,Button,FlatList,RefreshControl} from 'react-native';

const listData=Array(20).fill(1).map((x,i)=>{
    return {
        key:i,
        value:`列表项${i+1}`
    }
});

export default class HotPage extends Component{
    static navigationOptions=({navigation})=>{
        return {
            headerTitle:navigation.getParam('title')
        }
    }

    constructor(props){
        super(props);
        this.state={
            listData,
            isLoading:false
        }
    }

    loadData(refresh){
        if(refresh){
            this.setState({
                isLoading:refresh
            });
        }


        setTimeout(()=>{
            let _listData=[];
            if(refresh){
                for(let i=this.state.listData.length-1;i>=0;i--){
                    _listData.push(this.state.listData[i])
                }
            }else{
                _listData=this.state.listData.concat(listData)
            }

            this.setState({
                listData:_listData,
                isLoading:false
            })
        },2000)
    }

    render(){

        return (
          <View style={styles.container}>
              <FlatList
                data={this.state.listData}
                renderItem={({item}) =>
                    <View style={{
                        justifyContent:'center',
                        alignItems:'center',
                        flex:1,
                        height:60,
                        backgroundColor:'#ccc'
                        }}>
                    <Text>{item.value}</Text>
                    </View>
                    }
                // 分割线:不会出现在第一行之前,也不会出现在第一行之后
                ItemSeparatorComponent={()=>{
                    return <View style={{height:2,backgroundColor:'#eee'}}/>
                }}
                // 列表为空时渲染组件
                ListEmptyComponent={()=>{
                    return <Text style={{textAlign:'center'}}>空空如也</Text>
                }}
                // 顶部组件
                // ListHeaderComponent={()=>{

                // }}
                // 尾部组件
                ListFooterComponent={()=>{
                    return <Text>我也是有底线的</Text>
                }}

                // 刷新相关:
                // 如果设置了此选项,则会在列表头部增加一个标准的RefreshControl控件,
                // 同时也需要正确设置refreshing属性
                refreshControl={
                    <RefreshControl
                      title='loading'
                      colors={['red']}
                      // 如果设置该属性为true,列表将出现一个正在加载的符号
                      refreshing={this.state.isLoading}
                      onRefresh={()=>{
                          this.loadData(true)
                      }}
                      tintColor={'orange'}
                    />
                }

                Threshold='0.4'
                // 当列表滚动到地步距离不足Threshold时调用
                onEndReached={()=>{
                    this.loadData();
                }}
              />
          </View>
        )

    }
}

const styles=StyleSheet.create({
    container:{
        flex:1,
        width:'100%',
        backgroundColor:'#f5f5f5'
    },
    text:{
        fontSize:26,
        marginBottom:20
    }
})
其它组件(Switch/Modal)

可自行查阅api。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一Li小麦 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RN布局与样式
    • 布局
      • 样式
      • 组件
        • view:万能容器
          • SafeAreaView:安全区
            • webview:加载网页容器(即将被移除)
              • Text:文本容器
                • Image:图片容器
                  • ImageBackground 背景图
                    • Button:按钮
                      • ActivityIndicator loading的小菊花
                        • ListView:列表
                          • VirtualizedList: 虚拟列表
                            • 需求:列表的下拉刷新和上划动加载
                          • 其它组件(Switch/Modal)
                          相关产品与服务
                          容器服务
                          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档