<>前言
在RN开发中仅仅使用flex布局,也满足不了我们日常的需求开发;RN官方也提供了定位布局,flexbox定位和position定位可以同时使用,同时生效;
<>position
RN提供了两种布局方式:absolute和relative
* relative
* 相对于 上一个兄弟节点
* 不可以浮动(尽管偏移了,还是占了一个位置)
* absolute
* 相对于 父视图
* 浮动的
绝对布局是脱离文档流的,不过RN依旧在文档层次结构里面,这个和html的position也很大不一样。另外还有一个和html不一样的是,html中position:absolute要求父容器的position必须是absolute或者relative,如果第一层父容器position不是absolute或者relative,在html会依次向上递归查询直到找到为止,然后居于找到的父容器绝对定位。
如果你之前是搞安卓开发的会觉得RN设计非常怪异,在我们安卓原生开发中,决定用什么布局的是由parent决定的,如:AbsoluteLayout和RelativeLayout,而在RN开发中,决定用什么布局的是有child来决定的。
比如:<Text style={{position:‘absolute’}}>
这样Text组件相对于外层parent组件是相对布局,同理我们可以修改成relative。
可以使用left、top、right、bottom来改变偏移量。如下图:
absolute:
view1的样式: { position:'absolute',left:5,top:5 }. view2的样式: {
position:'absolute',right:10,bottom:10 }.
relative:
view1的样式: { position:'relative',left:5,top:5 }. view2的样式: {
position:'relative',left:50,top:30 }.
<>zIndex层级
zIndex是rn在0.30开始支持的属性,是可以生效的;
一般是zIndex层级大的在上面
对于Android,两个同一层级的定位组件(position:“absolute”)
情况 在z轴的层叠关系
既没有ZIndex属性,又没有elevation 属性 由其摆放位置决定的,放在下面的组件会在上层
两个组件只有zIndex没有elevation属性时 zIndex大的在上层
两个组件有elevation属性 elevation大的在上层
两个组件既有zIndex属性elevation属性 以elevation为准
注:对于IOS,同层级的组件,z轴的层叠关系只与摆放顺序与zIndex有关,与elevation无关
<>Android和iOS position差异
如果使用position:"absolute"想要把子元素浮出到父元素外面一部分,在html中的常规处理可以把偏移量top、left、right、bottom设置成负值即可;此种方案在RN的iOS端可是可行的,但是Android端浮出父元素外面的部分是不显示的;
RN对absolute的官方解释就是:以父元素的边框为基准进行偏移,也就是说只能在父元素包裹的范围内偏移;
一下是iOS和Android上的差异:
iOS
Android
如上图想要给其中的一个模块打上一个推荐位的标,实现代码如下:
priceGroup: { paddingHorizontal: 15, flexDirection: "row", justifyContent:
"space-between", alignItems: "center", marginTop: 25, position: "relative",
zIndex: 99998, elevation: 99998 }, //父级容器 commotView: { width: 109, height:
100, justifyContent: "center", alignItems: "center", borderWidth: 1 }, //推荐logo
recIcon: { width: 38, height: 24, position: "absolute", top: -18, right: -5,
justifyContent: "center", alignItems: "center", zIndex: 99999, elevation: 99999
} let priceDom = list.map((item, index) => { //价格列表数据对象 dealPrice折扣价
originPrice原价 desc标题 let { id, dealPrice, originPrice, desc, recommand } =
item; //是否选中 let isChecked = id == sel.id ? true : false; //是否使能 免费使用不选点击选择 let
dis = discountStatus == "0" ? true : false; return ( <TouchableOpacity
activeOpacity={1} key={index} onPress={() => { if (discountStatus) {
this.setState((pre) => { return { selected: item }; }); } }} style={[
styles.commotView, //选中状态和非选中状态以及免费不能点击状态字体颜色区分 isChecked ?
styles.activePriceView : dis ? styles.disableView : styles.priceView ]}> {/*
折扣状态和全价状态下会显示推荐tag */} {discountStatus && recommand ? ( <Image
source={require("./../img/recommand.png")} style={styles.recIcon} /> ) : null}
{/* 订阅列表标题栏 */} <Text style={{ color: isChecked ? COLOR.ActivetilColor : dis ?
COLOR.disColor : COLOR.priceColor, fontSize: 15 }}> {desc} </Text> {/* 订阅列表当前价格
折扣状态显示折扣之后的价格 免费试用显示全价中间价贯穿线 全价直接展示原始价格 */} <Text style={{ color: isChecked ?
COLOR.ActivetilColor : dis ? COLOR.disColor : COLOR.priceColor, fontSize: 18
}}> ¥ <Text style={[ { fontSize: 36, fontWeight: "700" }, discountStatus ? null
: styles.lineThrough ]}> {discountStatus == 1 ? parseInt(dealPrice) :
parseInt(originPrice)} </Text> </Text> {/* 折扣状态下的原始价格展示 */} {discountStatus ==
1 ? ( <Text style={[ styles.lineThrough, isChecked ? styles.activeDiscountText
: styles.discountText ]}> {parseInt(originPrice)}元 </Text> ) : null}
</TouchableOpacity> ); }); return <View
style={styles.priceGroup}>{priceDom}</View>;
整体思路如下:
此种布局就是常规思路,把要logo作为一个子元素放在要打标的模块里面,作为一个子元素,然后使用定位达到UI设计效果;二父元素的尺寸又是严格按照UI要求的尺寸来固定大小了;此时超出父元素的部分在Android上就不会显示了;
<>解决方案:
//原布局方式 父级标签里面直接渲染当前全部内容,把推荐标签页包裹在内 <View parent> <Image tag/> //渲染内容content
</View> //修改后 <View parent> <Image child1/> <View child2> //渲染内容content </View>
</View>
修改方式:
* 把原父级区块放在一个视图里面 复用原父级样式 成一个新模块 child2
* 把tag推荐图片作为一个兄弟节点 child1
* 把child1和child2放到一个视图里面 parent
* parent布局:
* 如果是如上图所示的需要上浮和右浮出
* parent大小设置 width = child2.width + child1右浮宽度
height = child2.widt + child1上浮高度
* 设置完parent容器大小之后,容器内布局
水平方向:从左往右布局
垂直方向:从下往上布局
* 其余方向同上 自行使用
以上是本人在开发中的一些拙见,有不足支持欢迎指正。
热门工具 换一换