native react 相对定位_react-native 相对定位 - CSDN
  • 1 概述 在React Native中,flexbox定位和position定位可以同时使用,同时生效(关于flexbox定位的相关知识...2 relative——相对定位 以元素本来的位置为基准进行偏移。 示例: export default class Test ext...

    1 概述

    在React Native中,flexbox定位和position定位可以同时使用,同时生效(关于flexbox定位的相关知识请自行查阅资料,这里不再赘述)。

    positon有两个取值:relative(默认值)和absolute。

    2 relative——相对定位

    以元素本来的位置为基准进行偏移。

    示例

    export default class Test extends Component {
        render() {
            return (
                <View style={styles.container}>
                    <View style={styles.p1}/>
                    <View style={styles.p2}/>
                    <View style={styles.p3}/>
                    <View style={styles.p4}/>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            flexDirection: 'column',
            alignItems: 'center',
            backgroundColor:'#33ffff'
        },
        p1: {
            width: 50,
            height: 50,
            backgroundColor: 'red',
        },
        p2: {
            width: 50,
            height: 50,
            backgroundColor: 'yellow',
        },
        p3: {
            width: 50,
            height: 50,
            backgroundColor: 'blue',
        },
        p4: {
            width: 50,
            height: 50,
            backgroundColor: '#666',
            position: 'relative',
            left: 50,
            top: 50
        }
    });

    灰色方块本来的位置应该是靠在蓝色方块的下方并与蓝色方块左右对齐,通过position: 'relative',left: 50,top: 50使得灰色方块以其本来的位置为基准,向右、向下分别偏移了50个单位,效果如上图所示。

    3 absolute——绝对定位

    以父元素的边框为基准进行偏移。

    示例

    export default class Test extends Component {
        render() {
            return (
                <View style={styles.container}>
                    <View style={styles.p1}/>
                    <View style={styles.p2}/>
                    <View style={styles.p3}/>
                    <View style={styles.p4}/>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            flexDirection: 'column',
            backgroundColor:'#33ffff'
        },
        p1: {
            width: 50,
            height: 50,
            backgroundColor: 'red',
            position: 'absolute',
            left: 50,
            top: 50
        },
        p2: {
            width: 50,
            height: 50,
            backgroundColor: 'yellow',
            position: 'absolute',
            right: 50,
            bottom: 50
        },
        p3: {
            width: 50,
            height: 50,
            backgroundColor: 'blue',
            position: 'absolute',
            bottom: 50,
        },
        p4: {
            width: 50,
            height: 50,
            backgroundColor: '#666',
            position: 'absolute',
            bottom: 50,
            alignSelf: 'center'
        }
    });

    • 红色方块:以父元素的左边框、上边框为基准,分别向右、向下偏移了50个单位。
    • 黄色方块:以父元素的右边框、下边框为基准,分别向左、向上偏移了50个单位。
    • 蓝色方块:以父元素的下边框为基准,向上偏移了50个单位。
    • 灰色方块:以父元素的下边框为基准,向上偏移了50个单位。左右位置由flexbox定位决定,即水平居中。
    展开全文
  • 在浏览器中,我们用div作为基本容器,在RN中,我们使用View作为基本容器,它们的功能几乎是一样的,主要不同的是容器的定位(position)和布局(display)规则不一样。本篇博客主要就是分析一下它们之间的差异,以及在RN...

    在浏览器中,我们用div作为基本容器,在RN中,我们使用View作为基本容器,它们的功能几乎是一样的,主要不同的是容器的定位(position)和布局(display)规则不一样。本篇博客主要就是分析一下它们之间的差异,以及在RN开发中如何使用定位和布局。

    容器定位

    定位,用position属性表示,其可准确地定义元素出现的位置的规则。

    在浏览器中(即PC端),position属性主要包含有4个属性值,分别为static、relative、absolute、fixed。

    属性值 描述 所属类别
    static 默认值,元素遵循默认的文档流。 默认
    relative

    元素遵循默认的文档流。

    相对于其父级元素的原位置进行定位,周围元素忽略该元素的移动。

    需要设置top、bottom、left、right值进行定位。

    相对定位
    absolute

    元素脱离正常文档流。

    相对于包含该元素的最近一级的非静态定位(即非static)的元素进行定位,若不满足条件,则会根据最外层的window进行定位。

    需要设置top、bottom、left、right值进行定位。

    绝对定位
    fixed

    元素脱离正常文档流。

    相对于最外层的window进行定位,固定在屏幕上的某个位置,不因屏幕滚动而消失。

    需要设置top、bottom、left、right值进行定位。

    绝对定位

    在RN中,position属性只有relative(默认值)和absolute。记住这一点很重要。因为在RN开发中,意味着View容器在不设置position(默认)的情况下,通过top、bottom、left、right值进行定位时,是不会影响周围的元素的。我们用代码证明一下:

    import React, { Component } from 'react';
    import { View, StyleSheet } from 'react-native';
    
    class MainView extends Component {
        render(){
            return (
                <View>
                    <View style={styles.redViewStyle}  />
                    <View style={styles.greenViewStyle}  />
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        redViewStyle: {
            height: 50,
            backgroundColor: 'red',
            top: 10
        },
        greenViewStyle: {
            height: 50,
            backgroundColor: 'green'
        }
    });
    
    export default MainView;

    代码中定义了一个组件MainView,组件中有两个分别为红色和绿色背景色的View容器,并且红色容器距离顶部10dp(设备独立像素),关于单位的理解,在移动设备中用的尺寸单位并不是浏览器中常用的物理像素,后面会写一篇博客再详细介绍。最终显示效果如下:

    事实证明,我们对RN的默认定位理解是正确的。当然,如果要测试绝对定位(absolute)也是没问题的,只需要把背景色为green绿色的容器设置定位为position: absolute,并给该容器添加一个100%的宽度,最终呈现的效果是:绿色容器和红色容器重叠在一起且遮住了红色容器,这个大家可以手动修改上面这段代码试一下。

    这点知识在RN开发中是必须要懂的,即定位默认值的差异,初学者在这一点上会很容易混淆从而造成不必要的麻烦。

     

    布局规则

    布局规则要比定位更加重要。

    布局,在样式表中用display表示,用于定义建立布局时容器的显示类型。在浏览器中,常用的几种布局类型有:

    属性 描述
    block 默认值,表示元素的宽度占满了整个浏览器的宽度,且每一行只允许容纳一个block类型元素
    inline 表示元素的宽度只等于内容所在的宽度,设置width无效
    inline-block 当没设置宽度时与inline效果相同,但设置width后,以width为准,与vertical-align:middle配合使用可实现内容垂直居中
    inherit 规定应该从父元素继承 display 属性的值
    flex 该元素按比例自动扩展宽度或高度,扩展的宽高取决于flexDirection设置的主从轴方向
    none 元素将不会被显示

    在RN中,display属性只有flex和none,默认值为flex,我们称之为弹性布局。这里要注意一点,在RN中的弹性布局主轴方向(属性flexDirection)默认值是column,而在浏览器中则相反,其主轴方向默认值为row。那么怎么理解这个主、从轴方向呢?以RN为例,我们看下面这个图:

    alignItems属性是指父组件设置其在从轴方向的元素的位置,这里可先不管。以左图为例,其定义了一个父组件parent,根据RN对默认布局的定义可知,容器的布局均为flex弹性布局,并且默认主轴方向为flexDirection:column,换算成坐标系来说主轴就是纵向的Y轴,那么从轴就是X轴。按照弹性布局规则:弹性布局中子组件将在从轴方向自动拉伸,这意味着如果子组件Button在不设置固定宽度width值时,其宽度将自动延伸为100%,但要正确显示出来还需为其设置一个高度值height。反之,如右图,flexDirection:row,则主轴方向为横向的X轴,其高度会延伸为100%,要正确显示同样需为其设置一个宽度值width。

    根据上面的图例,可能有朋友会说,既然子组件会在从轴方向自动延伸为100%,那么我想要主轴方向也为100%怎么办,那么这时只需要设置flex:1即可实现,它表示让子组件的尺寸size沿着其父组件设置的主轴方向拉伸,直到在主轴方向上填满父组件。效果如下图:

    如果两个同层级的子组件都把flex:1会怎么样?大家可以试一下噢!你会发现两个子组件将会平分父组件的主轴方向的剩余空间。另外在RN使用弹性布局中,我们经常会用到两个属性来管理其子组件的对齐方式,这两个属性为:justifyContent和alignItems,前者表示对其子组件在主轴方向上的位置管理,后者表示对其子组件在从轴方向上的位置管理。我们举个例子,假设以默认布局方向flexDirection:column为例,这时主轴为Y轴,从轴为X轴。

     justifyContent管理主轴的对齐方式:

    属性 描述
    flex-start 从最顶部开始布局所有子元素
    flex-end 从最底部开始布局所有子元素
    center 居中布局所有子元素
    space-between 将第一个元素布局在最顶部,最后一个子元素布置在最底部,将空白部分平均分配在所有子元素之间。
    space-around 将空白部分平均分配到所有子元素之间,包括上下边界也分配空白。

    alignItems管理从轴的对齐方式:

    属性 描述
    flex-start 从最左边开始布局所有子元素
    flex-end 从最右边开始布局所有子元素
    center 居中布局所有子元素

    我们用代码证明一下:

    import React, { Component } from 'react';
    import { View, StyleSheet } from 'react-native';
    
    class MainView extends Component {
        render(){
            return (
                <View style={styles.containerStyle}>
                    <View style={styles.redViewStyle}  />
                    <View style={styles.greenViewStyle}  />
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        containerStyle: {
            flex: 1,
            justifyContent: 'flex-end',
            alignItems: 'center'
        },
        redViewStyle: {
            backgroundColor: 'red',
            width: 50,
            height: 50
        },
        greenViewStyle: {
            backgroundColor: 'green',
            width: 100,
            height: 100
    
        }
    });
    
    export default MainView;

    最终显示效果如下:

    主轴方向对齐方式为flex-end,表示在最底部;从轴方向对齐方式为center,表示水平居中,证明我们的理解是正确的。

    以上就是RN入门必须懂的容器定义与布局规则的全部内容,这点在RN开发中很重要,因为这些很细节的知识会贯穿整个RN的开发过程,最好都能牢记。

    展开全文
  • react-native 之布局总结

    2017-01-17 22:25:44
    前言之前我们讲了很多react-native的基础控件,为了方便大家的理解,我们来对react-native的布局做一个总结,观看本节知识,你将看到。 宽度单位和像素密度 flex的布局 图片布局 绝对定位和相对定位 padding和margin...

    前言

    之前我们讲了很多react-native的基础控件,为了方便大家的理解,我们来对react-native的布局做一个总结,观看本节知识,你将看到。

    • 宽度单位和像素密度
    • flex的布局
    • 图片布局
    • 绝对定位和相对定位
    • padding和margin的区别和应用场合
    • 文本元素

    宽度单位和像素密度

    我们知道在Android中是用设备像素来作为单位的(后面又出现了百分比这么 一个概念),ios中后面也有了Auto Layout和1倍图,二倍图等概念(xib+storyboard)。然而react的宽度不支持百分比,那么React怎么提供尺寸的呢?PixelRatio,PixelRatio及像素密度,可以看看官方的介绍。

     var image = getImage({
       width: 200 * PixelRatio.get(),
       height: 100 * PixelRatio.get()
     });
     <Image source={image} style={{width: 200, height: 100}} />

    flex的布局

    我们知道一个div如果不设置宽度,默认的会占用100%的宽度, 为了验证100%这个问题, 做三个实验:

    1. 根节点上方一个View, 不设置宽度
    2. 固定宽度的元素上设置一个View, 不设置宽度
    3. flex的元素上放一个View宽度, 不设置宽度
     <Text style={[styles.text, styles.header]}>
          根节点上放一个元素,不设置宽度
      </Text>        
    
      <View style={{height: 20, backgroundColor: '#333333'}} />
    
      <Text style={[styles.text, styles.header]}>
          固定宽度的元素上放一个View,不设置宽度
      </Text> 
    
      <View style={{width: 100}}>
        <View style={{height: 20, backgroundColor: '#333333'}} />
      </View>
    
      <Text style={[styles.text, styles.header]}>
          flex的元素上放一个View,不设置宽度
      </Text> 
    
      <View style={{flexDirection: 'row'}}>
        <View style={{flex: 1}}>
          <View style={{height: 20, backgroundColor: '#333333'}} />
        </View>
        <View style={{flex: 1}}/>
      </View>

    来看一下运行的结果:
    这里写图片描述

    水平垂直居中

    css 里边经常会将一个文本或者图片水平垂直居中,如果使用过css 的flexbox当然知道使用alignItems 和 justifyContent ,那如果用React Native如何实现呢?

    <Text style={[styles.text, styles.header]}>
            水平居中
        </Text>
    
        <View style={{height: 100, backgroundColor: '#333333', alignItems: 'center'}}>
          <View style={{backgroundColor: '#fefefe', width: 30, height: 30, borderRadius: 15}}/>
        </View>
    
         <Text style={[styles.text, styles.header]}>
            垂直居中
        </Text>
        <View style={{height: 100, backgroundColor: '#333333', justifyContent: 'center'}}>
          <View style={{backgroundColor: '#fefefe', width: 30, height: 30, borderRadius: 15}}/>
        </View>
    
        <Text style={[styles.text, styles.header]}>
            水平垂直居中
        </Text>
        <View style={{height: 100, backgroundColor: '#333333', alignItems: 'center', justifyContent: 'center'}}>
          <View style={{backgroundColor: '#fefefe', width: 30, height: 30, borderRadius: 15}}/>
        </View>

    这里写图片描述

    网格布局

    通常页面不是很复杂的时候,我们可以使用flex布局等分做到网格,复杂的那么就要用ListView实现,或者第三方控件。

    等分的网格

    <View style={styles.flexContainer}>
          <View style={styles.cell}>
            <Text style={styles.welcome}>
              cell1
            </Text>
          </View>
          <View style={styles.cell}>
            <Text style={styles.welcome}>
              cell2
            </Text>
          </View>
          <View style={styles.cell}>
            <Text style={styles.welcome}>
              cell3
            </Text>
          </View>
        </View>
    
        styles = {
            flexContainer: {
                // 容器需要添加direction才能变成让子元素flex
                flexDirection: 'row'
            },
            cell: {
                flex: 1,
                height: 50,
                backgroundColor: '#aaaaaa'
            },
            welcome: {
                fontSize: 20,
                textAlign: 'center',
                margin: 10
            },
        }

    这里写图片描述
    另一种方式可以参照我之前的实现: React Native实现九宫格效果

    图片布局

    <Text style={styles.welcome}> 100px height </Text>
      <Image style={{height: 100}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />

    100px 高度, 可以看到图片适应100高度和全屏宽度,背景居中适应未拉伸但是被截断也就是cover。

      <Text style={styles.welcome}> 100px height with resizeMode contain </Text>
      <View style={[{flex: 1, backgroundColor: '#fe0000'}]}>
          <Image style={{flex: 1, height: 100, resizeMode: Image.resizeMode.contain}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />
      </View>

    contain 模式容器完全容纳图片,图片自适应宽高。

      <Text style={styles.welcome}> 100px height with resizeMode cover </Text>
      <View style={[{flex: 1, backgroundColor: '#fe0000'}]}>
          <Image style={{flex: 1, height: 100, resizeMode: Image.resizeMode.cover}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />
      </View>

    stretch模式图片被拉伸适应屏幕

     <Text style={styles.welcome}> set height to image container </Text>
      <View style={[{flex: 1, backgroundColor: '#fe0000', height: 100}]}>
          <Image style={{flex: 1}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />
      </View>

    绝对定位和相对定位

    <View style={{flex: 1, height: 100, backgroundColor: '#333333'}}>
        <View style={[styles.circle, {position: 'absolute', top: 50, left: 180}]}>
        </View>
      </View>
      styles = {
        circle: {
        backgroundColor: '#fe0000',
        borderRadius: 10,
        width: 20,
        height: 20
        }
      }

    这里写图片描述
    和css的标准不同的是, 元素容器不用设置position:’absolute|relative’ 。

    <View style={{flex: 1, height: 100, backgroundColor: '#333333'}}>
        <View style={[styles.circle, {position: 'relative', top: 50, left: 50, marginLeft: 50}]}>
        </View>
      </View>

    padding和margin

    我们知道在css中区分inline元素和block元素,既然react-native实现了一个超级小的css subset。那我们就来实验一下padding和margin在inline和非inline元素上的padding和margin的使用情况。
    padding

     <Text style={[styles.text, styles.header]}>
        在正常的View上设置padding 
      </Text>
    
      <View style={{padding: 30, backgroundColor: '#333333'}}>
        <Text style={[styles.text, {color: '#fefefe'}]}> Text Element</Text>
      </View>
    
      <Text style={[styles.text, styles.header]}>
        在文本元素上设置padding
      </Text>
      <View style={{padding: 0, backgroundColor: '#333333'}}>
        <Text style={[styles.text, {backgroundColor: '#fe0000', padding: 30}]}>
          text 元素上设置paddinga
        </Text>
      </View>

    这里写图片描述

    margin

     <Text style={[styles.text, styles.header]}>
        在正常的View上设置margin 
      </Text>
    
      <View style={{backgroundColor: '#333333'}}>
        <View style={{backgroundColor: '#fefefe', width: 30, height: 30, margin: 30}}/>
      </View>
    
      <Text style={[styles.text, styles.header]}>
        在文本元素上设置margin
      </Text>
      <View style={{backgroundColor: '#333333'}}>
        <Text style={[styles.text, {backgroundColor: '#fe0000', margin: 30}]}>
          text 元素上设置margin
        </Text>
        <Text style={[styles.text, {backgroundColor: '#fe0000', margin: 30}]}>
          text 元素上设置margin
        </Text>
      </View>

    这里写图片描述

    文本元素

    先看看文字有哪些支持的style属性:

     Attributes.style = {
        color string
        containerBackgroundColor string
        fontFamily string
        fontSize number
        fontStyle enum('normal', 'italic')
        fontWeight enum("normal", 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900')
        lineHeight number
        textAlign enum("auto", 'left', 'right', 'center')
        writingDirection enum("auto", 'ltr', 'rtl')
      }

    Text的样式继承

    实际上React-native里边是没有样式继承这种说法的, 但是对于Text元素里边的Text元素是可以继承的。到底是继承的最外层的Text的值呢,还是继承父亲Text的值呢?肯定是继承父亲Text的值。

     <Text style={[styles.text, styles.header]}>
          文本样式继承
      </Text>
    
      <View style={{backgroundColor: '#333333', padding: 10}}>
        <Text style={{color: 'white'}}>
          <Text style={{color: 'red'}} onPress={this.onPressTitle}>
             文本元素{'\n'}
            <Text>我是white还是red呢?{'\n'} </Text>
          </Text>
          <Text>我应该是white的</Text>
        </Text>
      </View>

    这里写图片描述

    总结

    针对上面的实例,我们做一个总结。

    • react 宽度基于pt为单位, 可以通过Dimensions 来获取宽高,PixelRatio 获取密度。
    • 基于flex的布局:
      view默认宽度为100%
      水平居中用alignItems, 垂直居中用justifyContent
      基于flex能够实现现有的网格系统需求,且网格能够各种嵌套无bug
    • 图片布局
      通过Image.resizeMode来适配图片布局,包括contain, cover, stretch 三种模式
      默认不设置模式等于cover模式
      contain模式自适应宽高,给出高度值即可
      cover铺满容器,但是会做截取
      stretch铺满容器,拉伸
    • 绝对定位和相对定位
      定位相对于父元素,父元素不用设置position也行
      padding 设置在Text元素上的时候会存在bug。所有padding变成了marginBottom

    • 文本元素
      文字必须放在Text元素里边
      Text元素可以相互嵌套,且存在样式继承关系
      numberOfLines 需要放在最外层的Text元素上,且虽然截取了文字但是还是会占用空间

    展开全文
  • react-native层级的设置还是和PC、移动端h5不一样的 如下图所示(博主指的是右上角的“待审核状态”绝对定位层级被卡片TouchableOpacity覆盖): 以如下代码为例,如果将source对应的Image放在<...

    react-native层级的设置还是和PC、移动端h5不一样的

    如下图所示(博主指的是右上角的“待审核状态”绝对定位层级被卡片TouchableOpacity覆盖):

    以如下代码为例,如果将source对应的Image放在<TouchableOpacity>中,就会被TouchableOpacity覆盖层级,因为在RN中所有子元素都不会超过父元素的层级

    这个时候只需要在他们外层加一个容器进行相对定位,就能使得Image的层级回复正常!

    <View style={{ flex: 1, position: 'relative' }}>
          {source ? (
            <Image
              style={{
                position: 'absolute',
                zIndex: 10,
                top: OASize(5),
                right: OASize(20),
                width: OASize(imgWidth),
                height: OASize(16),
              }}
              // resizeMode="contain"
              source={source}
            />
          ) : null}
          <TouchableOpacity
            style={{
              flexDirection: 'column',
              justifyContent: 'center',
              marginBottom: OASize(10),
              marginHorizontal: OASize(15),
            }}
            onPress={onPress}
            activeOpacity={0.7}
          >
            <View style={{ padding: OASize(1) }}>
              <View
                style={{
                  // paddingHorizontal: OASize(15),
                  paddingTop: OASize(15),
                  paddingBottom: OASize(15),
                  backgroundColor: OAColor.white,
                  ...taskStyles,
                }}
              >
                <View style={[OAStyles.row, { flexWrap: 'wrap' }]}>
                  <View
                    style={{
                      position: 'absolute',
                      left: 0,
                      top: 3,
                      backgroundColor: OAColor.success,
                      opacity: opacitySize,
                      paddingVertical: 1.5,
                      paddingHorizontal: 2,
                      borderRadius: 2,
                    }}
                  >
                    <Text
                      style={{
                        lineHeight: OASize(13),
                        textAlign: 'center',
                        color: OAColor.white,
                        fontSize: OASize(12),
                      }}
                    >
                      {item && item.type === 0
                        ? '投票'
                        : item && item.type === 1 && '任务'}
                    </Text>
                  </View>
                  <Text
                    style={{
                      ...OAStyles.font,
                      fontSize: OASize(16),
                      color: OAColor.barTitle,
                      lineHeight: OASize(22),
                      opacity: opacitySize,
                    }}
                    numberOfLines={2}
                  >
                    {'     ' + item.title}
                  </Text>
                </View>
                <View
                  style={[
                    OAStyles.row,
                    { marginTop: OASize(15), alignItems: 'flex-start' },
                  ]}
                >
                  {!!item.department && (
                    <Text
                      style={[
                        {
                          ...OAStyles.font,
                          flexDirection: 'row',
                          alignItems: 'center',
                          fontSize: OASize(12),
                          lineHeight: OASize(16.5),
                          color: OAColor.txSecondary,
                          marginRight: OASize(10),
                          maxWidth: '70%',
                          opacity: opacitySize,
                        },
                      ]}
                      numberOfLines={1}
                    >
                      {item.department}
                    </Text>
                  )}
                  <Text
                    style={{
                      ...OAStyles.font,
                      flexDirection: 'row',
                      alignItems: 'center',
                      fontSize: OASize(12),
                      lineHeight: OASize(16.5),
                      color: OAColor.txSecondary,
                      opacity: opacitySize,
                    }}
                  >
                    {fTimeFormat(item.date, 'Y-M-D')}
                  </Text>
                </View>
              </View>
            </View>
          </TouchableOpacity>
        </View>

     

    展开全文
  • react native定位的下拉选择框 在实际开发过程中,下拉选择应该是比较常用的功能。我在项目开发中先后使用了以下两种第三方插件: react-native-popup-menu ...

    react-native-selfadapt-modal

    在实际开发过程中,下拉选择应该是比较常用的功能。我在项目开发中先后使用了以下两种第三方的下拉选择框插件:

    react-native-popup-menu
    react-native-modal-dropdown

    但是这两款插件对我来说都不是特别理想。

    首先react-native-popup-menu自定义样式是比较自由的,但是编码相当繁复,而且代码复用率太低了,尤其是使用该组件需要在最外层使用MenuProvider替换View

    其次react-native-modal-dropdown自定义样式不是很友好,举个栗子?:因为该组件的背景色是透明的,在需要设置背景色为半透明的情况下,令人抓狂?!此外,如果想令弹框自适应高度也不太好使。

    所以,在下希冀通过封装react native自有的Modal组件,实现复用率较高且能自定义样式的可定位下拉框组件。

    先看看效果:

    获取定位参数

    先说下基本思路吧:要使Modal在特定的位置展开,就必须获取到一些定位参数,在Modal中使用绝对布局,并按照一定的规则传入这些参数,才能正确的定位弹窗位置,除此之外还需要判断Modal到底应该是向上展开还是向下展开。

    示意图:

    根据上述思路可知,必要参数是Y轴坐标(y)、Modal控制按钮的高度(height)和屏幕高度。弹框的起点位置

    首先,我想的是如何获取到Modal的展开位置,并需要根据这个位置判断应该向下展开还是向上展开。

    一开始我准备使用onLayout方法,但是发现了几个问题,现总结如下:

    1.onLayout是 y 轴起点是根据父布局来计算的。也就是说如果不以根布局为父布局则无法获取到绝对y轴坐标。
    2. 如果onLayout用于第二级元素,Android 和 iOS 的 y 轴的起点位置是不同的,Android是从状态栏以下开始计算的,而iOS是从屏幕顶端开始计算的。

    关于第二点,有示例图如下:

    左边为Android,右边为iOS。

    经过一番查阅,发现使用react native提供API —— NativeMethodsMixin 中的 measure 方法可以获取到某组件在屏幕中的绝对位置。该方法通过ref调用。具体是使用示例如下:

    this.listRow&&this.listRow.measure((x, y, width, height, left, top) => {
        console.log('===x===',x); //组件相对父布局的X坐标??
        console.log('===y===',y); //组件相对父布局的Y坐标??
        console.log('===width===',width); //组件的宽度
        console.log('===height===',height); //组件的高度
        console.log('===left===',left); //组件在屏幕中的X坐标
        console.log('===top===',top); //组件在屏幕中的Y坐标
    });
    

    根据查阅API,我们知道该方法有6个回调参数,在这里我们需要使用的就是 topheight。至于前两个参数,我不太确定是啥意思,有点小尴尬。欢迎有了解的童鞋进行补充。
    在这里插入图片描述

    关键代码

    接下来就是实际的编码了。核心技术点如下:

    第一步,通过measure获取到Modal的y轴坐标和点击组件(可点击的组件较多,例如Button、TouchableOpacity等,这里和下文都将此类组件笼统的成为“点击组件”)的高度,需要注意的measure是一个异步方法,因此在这里需要传入一个回调参数,示例如下:

    getPosition = (callback) => {
    	this.listRow&&this.listRow.measure((x, y, width, height, left, top) => {
    	    this.yaxis = top;
    	    this.itemHeight = height;
    	    callback&&callback();
    	});
    }
    

    第二步,判断Modal是向上展开还是向下展开,当y轴坐标大于屏幕高度的一半时,向上展开,反之向下展开。

    /** 获取默认的弹出位置,通过样式的形式返回 */
    getPositionStyle = () => {
        let positionStyle = {};
        if (parseInt(this.state.yNumber) > parseInt(screenHeight / 2)) {
            positionStyle = {bottom: screenHeight - (this.state.yNumber + AndroidStatusBar) };
        } else {
            positionStyle = {top: this.state.yNumber + this.state.itemHeight};
        }
        return positionStyle;
    }
    

    在这一步中,需要注意的是,因为Android的Y轴坐标是从状态栏以下开始计算的,而屏幕高度是包含了状态栏在内的,因此如果遇到向上展开的情况,就需要减去相应的高度。

    Android可以通过 StatusBarcurrentHeight 方法获取到状态栏高度。示例:

    const AndroidStatusBar = Platform.OS == 'android'? StatusBar.currentHeight: 0;
    

    最终效果如下所示:

    扩展点

    上文提到如何获取到Android端状态栏的高度,但是这一方法在iOS端却是无效的。经过一番查阅,我找到了以下方法:

    import { NativeModules } from 'react-native';
    
    const { StatusBarManager } = NativeModules;
    
    componentWillMount = () => {
        if (Platform.OS == 'ios') {
            StatusBarManager.getHeight((statusBarHeight) => {
                this.iosHeight = statusBarHeight && statusBarHeight.height;
            });
        }
    }
    

    getHeight方法是只对iOS端有效,调用时请务必加上平台判断,不然会报错。

    其它问题

    在开发过程可能会遇到measure的回调参数全部为undefined的情况,这时你可能需要在创建ref的元素上添加collapsable={false}

    <View 
        collapsable={false}
        ref={(o) => this.listRow = o}>
        ……
    </View>
    

    然后,经过试验,发现使用measureInWindow比起measure更适合本地开发的需求,使用示例:

    this.listRow&&this.listRow.measureInWindow((x, y, width, height) => {
       console.log('===x===',x);
       console.log('===y===',y);
       console.log('===width===',width);
       console.log('===height===',height);
    });
    

    总结

    在本次开发中学习和使用了一些平时没有使用过的API和方法,例如measuremeasureInWindowcollapsableStatusBarManager等。

    发现了onLayout方法的使用局限以及其获取到的参数的意义。

    熟悉了对于异步函数(例如measure)的处理方法。

    备注

    我已经将该组件发布到npm,欢迎有需要的童鞋引用。

    npm install react-native-selfadapt-modal --save
    

    同时代码库也同步到github,希望各位不吝Star

    react-native-selfadapt-modal

    展开全文
  • 一款好的APP离不了一个漂亮的布局,本文章将向大家分享React Native中的布局方式FlexBox。  在React Native中布局采用的是FleBox(弹性框)进行布局。 FlexBox提供了在不同尺寸设备上都能保持一致的布局方式。...
  • position布局 position:enum('absolute','relative')。先简单的看一下示例图 ...相对布局。这个和html的position有很大的不同,他的相对布局不是相对于父容器,而是相对于兄弟节点。position:
  • Flutter 与React Native 对比 [关于性能] 跨平台开发第一个考虑的就是性能问题 RN的效率由于是将View编译成了原生View,所以效率上要比基于Cordova的HTML5高很多,但是它也有效率问题,RN的渲染机制是基于前端框架的...
  • React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却寥寥无几。 本文分为两个部分:上半部分用通俗的语言解释了相关的名词...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • 写了这么多篇Android React Native的博文,基本上把复杂的东西都搞定了,接下来来看看一些轻松的东西,和布局有关,就是css样式,那么一个View可以设置哪些css样式呢,是和web中的css样式完全一样呢,还是有所不同呢...
  • 常规想法是写一个View做标题栏的容器,里面有一个文本控件,一个图片控件,再对相应的控件做居中和向右对齐,但是在相对布局中发现没有这种属性可以支持。 常规方法还是一个容器组件中有一个空View组件为占位视图,...
  • React Native 实现瀑布流列表页,分组+组内横向的列表页….. 随着React Native的更新,因为其跨平台的优越性,越来越多的公司和项目采用其作为其快速开发和迭代的基础语言. 但是其并不是任何控件其都已经涵盖了,就拿...
  • react-native link react-native-camera 发现在编译的时候会碰到各种各样的问题,依次解决但最后还是放弃了(尽力了,问题太多了!!!), 最后试着找不同的导入方式 npm install react-native-camera@...
  • 写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。 项目开始 HomePage.js PS 可以先拖动到底部看下效果图 新建一个reactnative项目 ,底部因为有四个tab 选项卡 那么 我使用一个第三方组件...
  • 源码已开源到Github,详细代码可以查看:《React Native 触摸事件代码实践》。 在基础篇,对RN中的触摸事件做了详细的介绍。相信大家对于触摸事件流程机制有了更为清晰的认识。没有浏览的可以先看看基础篇:《 ...
  • React Native中主要使用FlexBox来布局。什么是FlexBox布局? 弹性盒模型(The Flexible Box Module),又叫Flexbox,意为“弹性布局”,旨在通过弹性的方式来对齐和分布容器中内容的空间,使其能适应不同屏幕,为...
  • react-native 之布局篇

    2019-11-11 16:01:08
    react的宽度不支持百分比,设置宽度时不需要带单位 {width: 10}, 那么10代表的具体宽度是多少呢? 不知道是官网文档不全还是我眼瞎,反正是没找到,那做一个实验自己找吧: 默认用的是iPhone6的模拟器结果是: ...
  • ReactNative混合开发,Facebook官网文档比较精简,坑比较多,根据此文档,作为初学者并不能顺利的将ReactNative引入Android项目,且不能了解ReactNative是以一种怎样的形式存在Native项目中。 此为开篇,解说官方...
  • 我自然就开始进行各种技术选型的调研,这里重点想说的是我最后挑选出的2款hybrid app开发技术方案:RN(react native),HBuilder。React Native是大名鼎鼎的Facebook的开源技术框架,而HBuilder是国内的H5工具开发公 ...
1 2 3 4 5 ... 20
收藏数 1,839
精华内容 735
关键字:

native react 相对定位