You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native height auto样式失效,连接线组件显示异常求助

问题描述

预期效果

预期效果

实际效果

实际效果

颜色显示正常,核心问题出在LineConnector连接线组件上。问题表现为:每次展开子项时,父组件的主连接线会断开,需要让它持续延伸至最后一个子项而不中断。要求在不安装第三方库的前提下解决。


可复用LineConnector组件代码

import React from "react";
import { StyleSheet, View } from "react-native";

type props ={
    color:any;
    type:string;
    getParentDimensions?: any;
}
const LineConnector = ({color, type, getParentDimensions}:props) =>{
    return (<>
    <View 
    style=
    {{
    borderWidth:0.5,
    backgroundColor: color,
    borderColor:color ,
    zIndex:-2 ,
    opacity:0.6,
    bottom:16.5,
    marginLeft: type === 'area' ? 45 : type == 'asset' ? 82 : 7,
    }}
    >
    </View>
    <View style={{
        borderBottomColor: color,
        borderBottomWidth: 0.5,
        width:'5%',
        opacity:0.6,
        position:'relative',
        alignSelf:'center',
        marginRight:10,
        top:5
    }}>
        <View style={{
            height:4,
            width:4,
            backgroundColor:color,
            position:'absolute',
            right:0,
            borderRadius:100,
            top:-2
            }}>
        </View>
    </View>
    </>
    )
};

export {LineConnector}

BoxLocations组件代码

import React, { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import ChevronDown from '@assets/images/chevron_down.svg';
import CounterAssets from './CounterAssets';
import BoxGradientLayout,{stylesCommon} from './BoxGradientLayout';
import BoxAreas from './BoxAreas';
import { LineConnector } from './LineConnector';

type propsLocations = {
    colors: any;
    locations?: [];
}

const BoxLocations = ({colors,locations}:propsLocations) => {
    const [showAreas, setShowAreas] = useState<number>(-1);
    const styles = StyleSheet.create({ 
        chevronDown:{
            transform:[{rotate: showAreas ? '180deg' : '0deg'}]
        },
    });
    const showViewAreas = (index:number) =>{
       if(index == showAreas){
            setShowAreas(-1);
       }else{
            setShowAreas(index)
       }
    }
    return (
    <>
        {locations?.map((loc:any, index:number)=>(
            <React.Fragment key={loc.id}>
                <View   style={{flexDirection:'row',display:'flex'}}>
                    <LineConnector  color={colors?.site} type='location' />
                        <BoxGradientLayout layoutType='location' colors={ colors?.location}>
                                <Text style={stylesCommon.name}>
                                    {loc?.name}
                                </Text>
                                <CounterAssets count={loc?.assets_counter} />
                        </BoxGradientLayout>
                        <View style={stylesCommon.containerChevron}>
                            <Pressable onPress={() => showViewAreas(index)} style={({ pressed }) => [pressed ? stylesCommon.chevronDownPress : styles.chevronDown]}>
                                        <ChevronDown fill={ colors?.location} fillOpacity={'0.03'} stroke={ colors?.location} />
                            </Pressable>
                        </View>
                </View>
                    {showAreas == index ? (
                        <View style={stylesCommon.childrenBox}>
                        <BoxAreas areas={loc.areas} colors={colors}/>
                        </View>
                    ) : null}
            </React.Fragment>
        ))}
    </>
    );
}

BoxLocations通用样式

export const stylesCommon = StyleSheet.create({
    name:{
        paddingLeft:20,
        right:5
    },
    containerChevron:{
        top:5 ,    
        left:4,           
        alignItems:'center',
        flexDirection:'row', 
        elevation:5
    },
    chevronDownPress:{
        opacity:0.4,
     },
     childrenBox:{
        flexDirection:'column',
        position:'relative',
     }
})

渐变盒子样式

const styles = StyleSheet.create({
        container:{
            flexDirection:'row',
        },
        containerGradient:{
            height:33,
            width:'auto',
            marginTop:10,
            alignSelf:'flex-start',
            alignItems:'center',
            flexDirection:'row',
            backgroundColor: colors,
            borderRadius:10,
            borderWidth:1,
            borderColor: colors,
            elevation:5
        },
        icons:{
            height:20,
            width:20,
            backgroundColor: colors,
            justifyContent:'center',
            alignItems:'center',
            borderRadius:100,
            left:4
        }
    });

解决方案

问题根源在于当前LineConnector是独立挂载在每个父项的行内,高度固定无法跟随子项展开动态延伸。调整布局结构和连接线实现方式即可解决:

1. 重构布局结构

将每个Location项及其子项包裹在相对定位容器中,把主垂直连接线改为容器内的绝对定位元素,让它根据容器高度(含展开的子项)自动延伸。

修改BoxLocations的渲染逻辑:

{locations?.map((loc:any, index:number)=>(
    <View key={loc.id} style={{position: 'relative', marginBottom: 10}}>
        {/* 主垂直连接线 */}
        <View 
            style={{
                position: 'absolute',
                left: 7, // 和原type='location'的marginLeft一致
                top: 0,
                bottom: 0,
                width: 0.5,
                backgroundColor: colors?.site,
                opacity: 0.6,
                zIndex: -2
            }}
        />
        
        {/* 父项行 */}
        <View style={{flexDirection:'row', display:'flex'}}>
            {/* 仅保留横向连接线和圆点 */}
            <View style={{
                borderBottomColor: colors?.site,
                borderBottomWidth: 0.5,
                width:'5%',
                opacity:0.6,
                position:'relative',
                alignSelf:'center',
                marginRight:10,
                top:5
            }}>
                <View style={{
                    height:4,
                    width:4,
                    backgroundColor: colors?.site,
                    position:'absolute',
                    right:0,
                    borderRadius:100,
                    top:-2
                }}>
                </View>
            </View>
            
            <BoxGradientLayout layoutType='location' colors={ colors?.location}>
                <Text style={stylesCommon.name}>
                    {loc?.name}
                </Text>
                <CounterAssets count={loc?.assets_counter} />
            </BoxGradientLayout>
            
            <View style={stylesCommon.containerChevron}>
                <Pressable onPress={() => showViewAreas(index)} style={({ pressed }) => [pressed ? stylesCommon.chevronDownPress : styles.chevronDown]}>
                    <ChevronDown fill={ colors?.location} fillOpacity={'0.03'} stroke={ colors?.location} />
                </Pressable>
            </View>
        </View>
        
        {/* 子项区域 */}
        {showAreas == index ? (
            <View style={stylesCommon.childrenBox}>
                <BoxAreas areas={loc.areas} colors={colors}/>
            </View>
        ) : null}
    </View>
))}

2. 优化LineConnector复用性(可选)

如果要保留组件复用性,修改LineConnector逻辑,根据需求渲染垂直/水平连接线:

import React from "react";
import { View } from "react-native";

type props ={
    color:any;
    type:string;
    isVerticalLine?: boolean;
}
const LineConnector = ({color, type, isVerticalLine}:props) =>{
    const horizontalLine = (
        <View style={{
            borderBottomColor: color,
            borderBottomWidth: 0.5,
            width:'5%',
            opacity:0.6,
            position:'relative',
            alignSelf:'center',
            marginRight:10,
            top:5
        }}>
            <View style={{
                height:4,
                width:4,
                backgroundColor:color,
                position:'absolute',
                right:0,
                borderRadius:100,
                top:-2
            }}>
            </View>
        </View>
    );

    const verticalLine = (
        <View 
            style={{
                position: 'absolute',
                left: type === 'area' ? 45 : type == 'asset' ? 82 : 7,
                top: 0,
                bottom: 0,
                width: 0.5,
                backgroundColor: color,
                opacity: 0.6,
                zIndex: -2
            }}
        />
    );

    return (
        <>
            {isVerticalLine ? verticalLine : horizontalLine}
        </>
    )
};

export {LineConnector}

在BoxLocations中使用优化后的组件:

<View key={loc.id} style={{position: 'relative', marginBottom: 10}}>
    <LineConnector color={colors?.site} type='location' isVerticalLine={true} />
    
    <View style={{flexDirection:'row', display:'flex'}}>
        <LineConnector color={colors?.site} type='location' />
        {/* 其余父项内容不变 */}
    </View>
    
    {/* 子项区域不变 */}
</View>

3. 子项连接线适配

确保子项(BoxAreas)中的LineConnector也采用绝对定位逻辑,让子项连接线与父项垂直长线对齐,保持视觉连贯性。

调整后,父项垂直连接线会随容器高度自动延伸,不会再出现断开问题,完全匹配预期效果。


内容的提问来源于stack exchange,提问作者Guido Gagliardini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 16:37:19