React Native布局

react native目录结构解析

工图初始结构如下:


图片1.png
  • android:一个完整的,集成react native的android studio工程,用android studio打开运行可以跑到手机或者模拟器上。
  • ios:一个完整的ios项目,在Mac下可以直接用xcode打开。运行到模拟器或者手机上
  • node_moules:基于node文件依赖系统产生的相关依赖和第三方lib,里面有react native的大部分组件
  • watchmanconfig:Watchman的配置文件,Watchman用于监控文件变化
  • flowconfig:flow的配置文件,flow用于静态代码检查
  • buckconfig:buck的配置文件,buck是Facebook开源的高效编译系统
  • App.js:Android和iOS的应用程序入口
  • package.json:项目基本信息以及依赖信息
  • index.js :app的注入

App.js内容解析

App.js

App.js作为整个程序入口,里面的代码含义相当于Android的

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

//引入 React的抽象组件
import React, {Component} from 'react';
// 引入React具体的组件,比如image,text等
import {AppRegistry, Platform, StyleSheet, Text, View} from 'react-native';
import {name as appName} from "./app";

// 下面根据平台的api展示不同的文字
const instructions = Platform.select({
    ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
    android:
        'Double tap R on your keyboard to reload,\n' +
        'Shake or press menu button for dev menu',
});

type Props = {};
// 这个class 最终是在index.js中调用了AppRegistry.registerComponent(appName, () => App);注入了才得以显示,类似android的setContentView()
export default class App extends Component<Props> {
    // 初始化方法 ---> viewDidLoad ---> 返回具体的组件内容
    // 写结构和内容
    render() {
        // 返回一个View
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>这是第一次运行成功</Text>
                <Text style={styles.instructions}>To get started, edit App.js</Text>
                <Text style={styles.instructions}>{instructions}</Text>
            </View>
        );
    }
}

// View组件的样式
const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
    },
    instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5,
    },
});

index.js文件:

/** @format */

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

// App 这个在App.js中定义,等同于之前版本的AppRegistry.registerComponent('untitled1', () => App);
AppRegistry.registerComponent(appName, () => App);

组件View

JSX的由来

React的核心机制之一就是虚拟DOM:可以在内存中创建的虚拟DOM元素。React利用虚拟DOM来减少对实际DOM的操作从而提升性能。传统的创建方式是:


图片2.png

但这样的代码可读性并不好,于是React发明了JSX,利用我们熟悉的HTML语法来创建虚拟DOM:

  <View style={styles.container}>
                <Text style={styles.welcome}>这是第一次运行成功</Text>
                <Text style={styles.instructions}>To get started, edit App.js</Text>
                <Text style={styles.instructions}>{instructions}</Text>
            </View>

在实际开发中,JSX在产品打包阶段都已经编译成纯JavaScript,JSX的语法不会带来任何性能影响。因此,JSX本身并不是什么高深的技术,可以说只是一个比较高级但很直观的语法糖。

View组件用法

React Native组件View,其作用等同于iOS中的UIView, Android中的android.view,或是网页中的<div>标签,它是所有组件的父组件。下面是具体的用法和需要注意的事项:

// 在下面写注释,必须要 {/*  xxxxx  */}这么写
export default class App extends Component{
    render() {
        return (
            <View style={styles.container}>
                {/*  View组件中必须有东西才可以显示 */}
                <View style={styles.innerViewStyle}>
                    <Text>我是里面的View</Text>
                </View>
                <View style={styles.innerViewStyle2}>
                    <Text>我是里面下面的View</Text>
                </View>
            </View>
        );
    }
}

//  在React Native开发中,更加推荐我们采用StyleSheet来进行组件的布局,这样的话,代码在结构上会更加的清晰、也有利于后期维护。
const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#ffffff',
        padding: 30
    },
    innerViewStyle:{
        backgroundColor:'green',
        width:100
    },
    innerViewStyle2:{
        backgroundColor:'yellow',
        width:100
    }
});

FlexBox布局

在Android中我们有许多的布局,比如线性布局,相对布局等,在react native中FlexBox布局是用的最频繁的,含义是能够伸缩或者很容易变化,以适应外界条件的变化的通用的矩形容器。简称“弹性布局”,旨在通过弹性的方式来对齐和分布容器中内容的空间,使其能适应不同屏幕,为盒装模型提供最大的灵活性。说了那么多就是集合Android线性布局和相对布局等其他布局的一些特征的布局。

Flexbox的排列
  • 在CSS中,常规的布局是基于块和内联流方向,而Flex布局是基于flex-flow流,下图很好解释了Flex布局的思想:
图片3.png

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。项目默认沿主轴排列,单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。

  • 根据伸缩项目排列方式的不同,主轴和侧轴方向也有所变化:
图片4.png
FlexBox常用属性
容器属性
  • flexDirection: row | row-reverse | column | column-reverse

该属性决定主轴的方向(即项目的排列方向)。
row:主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column(默认值):主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。

图片5.png
export default class App extends Component{
    render() {
        return (
            <View style={styles.container}>
                {/*  View组件中必须有东西才可以显示 */}
                <View style={styles.innerViewStyle}>
                    <Text>我是里面的View</Text>
                </View>
                <View style={styles.innerViewStyle2}>
                    <Text>我是中间的View</Text>
                </View>
                <View style={styles.innerViewStyle3}>
                    <Text>我是里面下面的View</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#ffffff',
        padding: 30,
        flexDirection: 'row'  // 横向
    },
    innerViewStyle:{
        backgroundColor:'green',
        width:100
    },
    innerViewStyle2:{
        backgroundColor:'yellow',
        width:100
    },
    innerViewStyle3:{
        backgroundColor:'red',
        width:100
    }
});
  • justifyContent:flex-start | flex-end | center | space-between | space-around

定义了伸缩项目在主轴线的对齐方式
flex-start(默认值):伸缩项目向一行的起始位置靠齐。
flex-end:伸缩项目向一行的结束位置靠齐。
center:伸缩项目向一行的中间位置靠齐。
space-between:两端对齐,项目之间的间隔都相等。
space-around:伸缩项目会平均地分布在行里,两端保留一半的空间

图片6.png
  • alignItems: flex-start | flex-end | center | baseline | stretch

定义项目在交叉轴上如何对齐,可以把其想像成侧轴(垂直于主轴)的“对齐方式”。
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐 。
center:交叉轴的中点对齐。
baseline:项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

图片7.png
  • flexWrap: nowrap | wrap | wrap-reverse
    默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
    nowrap(默认值):不换行。
    图片8.png

    wrap:换行,第一行在上方。
    图片.png

    wrap-reverse:换行,第一行在下方。(和wrap相反)
    图片.png
元素属性
  • flex
    “flex-grow”、“flex-shrink”和“flex-basis”三个属性的缩写, 其中第二个和第三个参数(flex-shrink、flex-basis)是可选参数。
    默认值为“0 1 auto”。
    宽度 = 弹性宽度 * ( flexGrow / sum( flexGorw ) )
    类似Android中的权重
const styles = StyleSheet.create({
    container: {
        backgroundColor: '#ffffff',
        padding: 30,
        flexDirection: 'row',  // 横向
        justifyContent: 'flex-start',
        alignItems: 'center',
    },
    innerViewStyle:{
        backgroundColor:'green',
        flex: 1
    },
    innerViewStyle2:{
        backgroundColor:'yellow',
        flex: 1
    },
    innerViewStyle3:{
        backgroundColor:'red',
        flex: 1
    }
});

  • align-self属性
    align-self属性允许单个项目有与其他项目不一样的侧轴对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
    其值除auto外,其他与align-items完全一致。


    图片9.png

获取屏幕相关参数

获取当前屏幕的宽度、高度、分辨率
// 引入
var Dimensions = require('Dimensions');
var {width, height, scale} = Dimensions.get('window');

class CFlexBoxDemo3 extends Component {
  render() {
    return (
        <View style={styles3.outViewStyle}>
           <Text>当前屏幕的宽度:{Dimensions.get('window').width}</Text>
           <Text>当前屏幕的高度:{Dimensions.get('window').height}</Text>
           <Text>当前屏幕的分辨率:{Dimensions.get('window').scale}</Text>
        </View>
    );
  }
};

const styles3 = StyleSheet.create({
  outViewStyle:{
    // 占满屏幕
    flex:1,
    //  主轴方向居中
    justifyContent:'center',
    // 侧轴方向居中
    alignItems: 'center',
    // 背景
    backgroundColor:'red'
  }
});
绝对定位和相对定位
class CFlexBoxDemo4 extends Component {
    render() {
        return (
            <View style={styles4.outViewStyle}>
                <Text>绝对定位</Text>
                <View style={styles4.topViewStyle}>
                    <View style={styles4.innerViewStyle}></View>
                </View>
                <Text>相对定位</Text>
                <View style={styles4.topViewStyle}>
                    <View style={styles4.innerViewStyle1}></View>
                </View>
            </View>
        );
    }
};


const styles4 = StyleSheet.create({
    outViewStyle:{
        marginTop:20,
        width:width,
        height:200,
        backgroundColor:'red'
    },

    topViewStyle:{
        width:width,
        height:150,
        backgroundColor:'yellow'
    },

    innerViewStyle:{
        width:60,
        height:60,
        backgroundColor:'green',
        // 绝对定位
        position:'absolute',
        top:0,
        right:0
    },

    innerViewStyle1:{
        width:60,
        height:60,
        backgroundColor:'green',
        // 相对定位
        position:'relative',
        top:30,
        right:-30
    }
});

通常情况下设置position和absolute,定位的效果是一样的,但是如果父组件设置了内边距,position会做出相应的定位改变,而absolute则不会。flex的元素如果不设置宽度, 都会百分之百的占满父容器。

  • 水平垂直居中
export default class App extends Component {
    render() {
        return (
            <View style={styles.container}>
                {/*  水平居中 */}
                <View style={{height:100,  alignItems: 'center'}}>
                    <Text style={styles.innerViewStyle}>我是里面的View</Text>
                </View>
                {/*  垂直居中 */}
                <View style={{height:100,  justifyContent: 'center'}}>
                    <Text style={styles.innerViewStyle2}>我是中间的View</Text>
                </View>
                {/*  水平垂直居中 */}
                <View style={{height:100,  alignItems: 'center', justifyContent: 'center',backgroundColor:'black'}}>
                    <Text style={styles.innerViewStyle3}>我是里面下面的View</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#ffffff',
    },
    innerViewStyle: {
        backgroundColor: 'green',
        height: 30,
        width: 100,

    },
    innerViewStyle2: {
        backgroundColor: 'yellow',
        height: 30,
        width: 100,

    },
    innerViewStyle3: {
        backgroundColor: 'red',
        height: 30,
        width: 100,
    }
});
图片.png

注意:一旦设置alignItems属性之后,组件的大小包裹随着内容的尺寸;此外水平居中和垂直居中还要结合FlexDirection进行判断。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容