[React Native Android 安利系列]FLEX布局精讲

欢迎大家收看react-native-android系列教程,跟着本系列教程学习,可以熟练掌握react-native-android的开发,你值得拥有:
https://segmentfault.com/blog...

1. FLEX是什么?

flex布局,本是一种新的css解决方案,它是『弹性布局』的缩写。我们上一节讲到过盒子模型,这个模型的值都是定死的,并不具备可伸缩的性质,所以,应对不同屏幕,做到响应式布局,就很困难。
但是flex布局,给了我们一种全新的解决方案,从定位方式,到宽高设置,都可以做到随心所欲。
比如:flex布局可以指定元素宽或者高相对于同级的比例,而不是定值。

2. react-native中的flex

我们先来看看,上一节中提到的,react-native支持的flex布局的一些属性吧:

属性值 含义
alignItems flex布局元素中,子元素沿纵轴排列方式
alignSelf flex元素中,本项元素的纵轴对其方式
flex 这里指代flex-grow,描述了元素的宽度比例值
flexDirection 指代flex元素的排列方向
flexWrap 指代flex元素的换行方式,取值为 nowrap/wrap
justifyContent 指代flex元素在横轴上的排列方式,之后会进行详解

可以说,react-native对于flex布局的支持还是比较全面的,少了几个简写的属性,非常的简洁、使用。而且,排布与css的flex布局基本一致。接下来,我们将对这些属性进行一一讲解与实践。

2.1 flexDirection属性

flex元素的排列方向,取值有:column|row

2.1.1 column排布(默认)

纵轴排列,竖向排列(如图2.1.1所示):

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatar}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />  
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:一筒</Text>
                </View>
            </View>
        );  
    }   
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
    },  
    shadowBlock: {
        height: 100,
        width: 100,
        backgroundColor: '#0f0',
    },  
    back1: {
        elevation: 5,
    },  
    avatarArea: {
        width: 300,
        height: 300,
    },  
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }   
});

clipboard.png
图2.1.1

2.1.2 row排布

横向排列,如图2.1.2所示

container: {
    flex: 1,
    flexDirection: 'row',
    backgroundColor: '#fff',
}, 

clipboard.png
图2.1.2

2.2 flexWrap属性

flex布局的换行行为,取值有:nowrap | wrap

2.2.1 nowrap排布

不换行(默认),效果如图 2.2.1所示:

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatar}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />  
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:一筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:一筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:一筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:一筒</Text>
                </View>
            </View>
        );  
    }   
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#fff',
    },
    shadowBlock: {
        height: 100,
        width: 100,
        backgroundColor: '#0f0',
    },
    back1: {
        elevation: 5,
    },
    avatarArea: {
        width: 300,
        height: 300,
    },
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }
});

clipboard.png
图 2.2.1
我们看到,使用了此取值,就算元素宽度超出,也未对元素进行换行。

2.2.2 wrap 换行,效果如图2.2.2所示:

container: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap',
    backgroundColor: '#fff',
},

clipboard.png
图2.2.2

目测react-native对于换行的元素,采取的措施是隐藏。

2.3 alignItems属性

flex布局元素中,子元素沿当前轴的交叉轴的排列方式。取值:'flex-start', 'flex-end', 'center', 'stretch'。请注意,这里说的是『当前轴的交叉轴』,flexDirection的值为row的话,元素为横向排列,则alignItems控制元素的上下对齐方式。flexDirection的值为column的话,alignItems控制元素的左右最起方式。

2.3.1 flex-start(默认)

所有子元素排列在主轴开始处,flexDirection为row时效果如图2.3.1.1所示:

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatar}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:1筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text>姓名:2筒</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#fff',
    },
    shadowBlock: {
        height: 100,
        width: 100,
        backgroundColor: '#0f0',
    },
    back1: {
        height: 200,
    },
    avatarArea: {
        width: 300,
        height: 300,
    },
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }
});

clipboard.png
图2.3.1.1
flexDirection为column时效果如图2.3.1.2所示:
clipboard.png
图2.3.1.2

2.3.2 flex-end

所有元素按照主轴结尾处排列,flexDirection为row时效果如图2.3.2.1所示:

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'flex-end',
        backgroundColor: '#fff',
    },
    .....

clipboard.png
图2.3.2.1
flexDirection为column时效果如图2.3.2.2所示:
clipboard.png
图2.3.2.2

2.3.3 center

所有元素居中对齐,如图2.3.3所示:

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'center',
        backgroundColor: '#fff',
    },
.....

clipboard.png
图2.3.3

2.3.4 stretch属性

在当前轴的交叉轴上,进行拉伸。如果元素没有设置宽度或者高度的话,则使用该值时,将会被拉伸。
我们将上述例子的alignItems换位stretch,效果如图2.3.4.1所示(flexDirection为row):

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatarArea}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text1}>姓名:1筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text2}>姓名:2筒</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'stretch',
        backgroundColor: '#fff',
    },
    shadowBlock: {
        backgroundColor: '#0f0',
    },
    back1: {
    },
    text1: {
        height: 100,
    },
    text2: {
        height: 200,
    },
    avatarArea: {
        backgroundColor: '#000'
    },
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }
});

clipboard.png
图2.3.4.1
我们看到,几个子元素,高度均被拉伸。
flexDirection换为column的话,则元素被横向拉伸(如图2.3.4.2):
clipboard.png
图2.3.4.2

2.4 justifyContent属性

justifyContent控制了元素在当前轴上的排列方式,当前轴有可能是column也有可能是row,下面以当前轴为row的情况做例子,column的情况,读着可以自己试着做做例子。另外注意,这个属性是设置在所有想排列的子元素的父级元素上的。
justifyContent可选的值有

属性值 含义
flex-start 在当前轴开始处按序排列(默认)
flex-end 在当前轴结尾处,开始按序排列
center 在当前轴居中位置,两侧伸展排列
space-between 所有元素打散,填充满整个当前轴,两侧无留白。
space-around 所有元素打散,填充满整个当前轴,两侧有留白。

2.4.1 flex-start布局

效果如图2.4.1所示
clipboard.png
图2.4.1

2.4.2 flex-end布局

如图2.4.2所示,元素都聚集到了当前轴(row)的结尾处:
clipboard.png
图2.4.2

2.4.3 center布局

在当前轴居中,并两侧伸展排列,justifyContent: 'center', 如图2.4.3所示
clipboard.png
图2.4.3

2.4.4 space-between布局

所有元素,填充满整个屏幕,元素与元素间的留白,平均分布,并且最左边的元素与最右边的元素两侧不加留白。justifyContent: 'space-between'如图2.4.4所示:
clipboard.png
图2.4.4

2.4.5 space-around布局

与space-between类似,只不过,使用此属性时,排列元素两侧也会有留白,最终效果会使所有元素的左右两侧留白均一致。
clipboard.png
图2.4.5

2.5 alignSelf属性

该属性其实与alignItems的属性锁表达的意义一致,是不过alignItems应用于父级元素上,决定了所有子元素的排布方式,而alignSelf应用于单个子元素上,决定了子元素自己的对其方式。
其取值与alignItems一样,也有 'flex-start', 'flex-end', 'center', 'stretch'。只是多了一个值'auto',此值意味着,采用父级元素的alignItems所定义的对其方式。
如,我们在父级元素上,定义了alignItems为center,于是我们看到,这个center被"雨露均沾"到各个子元素上(如图2.5.1所示):

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatarArea}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text1}>姓名:1筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text2}>姓名:2筒</Text>
                </View>
            </View>
        );
    }
}
const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'center',
        backgroundColor: '#fff',
    },
    shadowBlock: {
        backgroundColor: '#0f0',
    },
    back1: {
        height: 100,
        width: 100,
    },
    text1: {
        height: 100,
        width: 100,
    },
    text2: {
        height: 200,
    },
    avatarArea: {
        width: 100,
        height: 100,
        backgroundColor: '#000'
    },
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }
});

clipboard.png
图2.5.1
可是有个子元素非是不听呢,它设置了alignSelf为flex-start(self这个词彰显了个性),于是他就"独得恩宠",跑到上面去了,如图2.5.2所示:

    avatarArea: {
        width: 100,
        height: 100,
        //子元素设置了此属性
        alignSelf: 'flex-start',
        backgroundColor: '#000'
    },

clipboard.png
图2.5.2

同样的,我们可以指定单个元素对其到开始、结尾、中间....,这就是alignSelf的用法了。

2.6 flex属性

这个属性可谓是flex布局中,非常重要的属性了。之前的开发方式中,我们会指定元素的宽度与高度,这样的写死的方式,无法适应各种屏幕下的适配。而指定元素的flex,则可以达到,元素的宽高,按照比例排布。
flex可以这样用,当我们拥有三个元素时,可以指定三个元素的比例关系,达到自适应的效果,代码如下(效果如图2.6.1所示):    

class hellowReact extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <View style={styles.container}>
                <View style={styles.avatarArea}>
                    <Image
                        source={myAvatar}
                        style={styles.avatar}
                    />
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text1}>姓名:1筒</Text>
                </View>
                <View style={[styles.shadowBlock, styles.back1]}>
                    <Text style={styles.text2}>姓名:2筒</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'flex-start',
        backgroundColor: '#fff',
    },
    shadowBlock: {
        backgroundColor: '#0f0',
    },
    back1: {
        // 指定后两个元素的flex值为2
        flex: 2,
    },
    text1: {
    },
    text2: {
        height: 200,
    },
    avatarArea: {
        // 指定第一个元素的flex值为1
        flex: 1,
        backgroundColor: '#000'
    },
    avatar: {
        resizeMode: Image.resizeMode.contain,
    }
});

clipboard.png
图2.6.1

我们可以看到,此时元素的比例化为了1:2:2,这样布局,换了大屏幕的手机也依然会保持,妈妈再也不用担心我的屏幕适配了。

3. 今日作业

请使用flex布局完成一个类似于手机百度首页FEED流布局的界面。

这一章,我们一起学习了flex布局的所有属性,下一章我们一起来做个例子,实现的就是今天的作业--手机百度上面新闻流的布局。
形式大概就是这样:

clipboard.png

原创文章,版权所有,转载请注明出处

阅读 2.9k

推荐阅读
前端小站
用户专栏

讲解前端知识的小站,讲解你不知道的前端

593 人关注
19 篇文章
专栏主页