Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recalculate collapsible content height issue #420

Open
joseortiz9 opened this issue Nov 16, 2021 · 10 comments
Open

Recalculate collapsible content height issue #420

joseortiz9 opened this issue Nov 16, 2021 · 10 comments

Comments

@joseortiz9
Copy link

Issue

Dynamic content inside the collapsible component have a wrong behavior updating the height, it takes an offset and sometimes just cut to the middle the content, happens always on android and sometimes on IOS.

Expected behavior is to maintain the position of the collapsible and not take offsets, dont cut the content or change the height more than expected.

I tried putting the header and collapsible inside a View but still doesnt work. Help me out here please.

libraries versions

"native-base": "^2.15.2",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-collapsible": "^1.6.0",

code

CollapsibleItem.jsx
<>
        <TitleComp
            handleCollapsible={() => setCollapsed(!collapsed)}
            {...otherProps, containerStyle}
        />
        <Collapsible collapsed={collapsed} align="center" style={{width: "100%", overflow: "visible"}}>
            <Card style={{width: "100%", ...styles}}>
                <CardItem style={[{..styles}, contentStyle]}>
                    {children}
                </CardItem>
            </Card>
        </Collapsible>
</>

ExampleDynamicContent.jsx
<CollapsibleItem
    containerStyle={{marginTop: 16}}
    contentStyle={{flexDirection: "column"}}
    >
        <Touchable onPress={selectItem}/>
         <View style={{width: '100%', marginBottom: 10, flexDirection: 'row', flexWrap: 'wrap'}}>
              {owners.map(chef =>
                  <GoldenItem key={chef.id} text={chef.fullName} onDelete={() => deleteItem(chef)} />)}
         </View>
</CollapsibleItem>

Behavior on Android

video-1637075696.mp4

Expected behavior

video_2021-11-16_10-05-39.mp4
@rajsawhoney
Copy link

Experienced the same issue.

@oussamanm
Copy link

Any Solution , i spend many hours on it

@oussamanm
Copy link

oussamanm commented Jan 9, 2022

💯 i solved that by Calculate the Height the Child view of Collapsible, and create a new state that will hold that height to use it in attribute height of Collapsible Component.

 const [calculatedHieght, setCalculatedHieght] = useState();

declare an event that will Calculate the hieght :

    const onLayout=(event)=> {
        const {x, y, height, width} = event.nativeEvent.layout;
        console.log("~~~~~~ height = ", height);
        setCalculatedHieght(height + 20)
    }

use our state that hold the calculated hieght :

<Collapsible collapsed={!variantes[0].collapsed} style={{width: '100%', height: calculatedHieght}} >

and also set onLayout event in the child view of Collapsible component :

<View style={{width: '100%', padding: 7,}} onLayout={onLayout}>

@oussamanm
Copy link

But if you have Many Collapsible View at same page , you will see a slow motion while the view Collapsing

@AbidKhairyAK
Copy link

i solved this by forcing react to re-render the whole element by putting dependencies on key attributes. eg:

<Collapsible collapsed={isCollapsed} key={searchString}>

if it doesn't work then try to put key attribute on the parent element

@arshiyanaz1
Copy link

@oussamanm can you please describe it in detail, as i tried your method but i guess i am doing it wrong.please share your example with code.

@FrontendTerminator
Copy link

i solved this by forcing react to re-render the whole element by putting dependencies on key attributes. eg:

<Collapsible collapsed={isCollapsed} key={searchString}>

if it doesn't work then try to put key attribute on the parent element

It works with key but without animation on ios

@gregbrinker
Copy link

gregbrinker commented Nov 23, 2022

This took me a while to fully figure out. I tried many different things, and finally found what I believe to be the best solution for this. Hopefully this helps people in the future.

The idea here is to wrap the children in a single view. onLayout of that view, set a currentHeight state. We ignore when the height is 0 - all that means is the cell was collapsed, the children height didn't actually change. If we don't ignore 0, the collapsing animation will not work when expanding.

The currentHeight should then be used as the `' key. This will trigger re-renders properly.


const [currentHeight, setCurrentHeight] = useState<number>(0)

const onLayout = event => {
    const newHeight = event.nativeEvent.layout.height
    
    // Don't do anything for height = 0 (collapsed state)
    if (newHeight === 0) return

    // Only toggle key if the height has changed
    if (newHeight !== currentHeight) {
        setCurrentHeight(newHeight)
    }
}

// Use currentHeight state as the key
<Collapsible collapsed={collapsed} key={currentHeight} renderChildrenCollapsed={true}>
    <View onLayout={onLayout}>
        {children}
    </View>
</Collapsible>

@DiorAbjalilov
Copy link

DiorAbjalilov commented Sep 23, 2023

1695464429377136.mp4
<View>
                <Collapsible
                  duration={1000}
                  collapsed={isCollapsed}
                  collapsedHeight={100}>
                  <HTMLRender source={someText} />
                </Collapsible>
 </View>

error for only Android, help me 🤦‍♂️

@ddnazzah
Copy link

This took me a while to fully figure out. I tried many different things, and finally found what I believe to be the best solution for this. Hopefully this helps people in the future.

The idea here is to wrap the children in a single view. onLayout of that view, set a currentHeight state. We ignore when the height is 0 - all that means is the cell was collapsed, the children height didn't actually change. If we don't ignore 0, the collapsing animation will not work when expanding.

The currentHeight should then be used as the `' key. This will trigger re-renders properly.

const [currentHeight, setCurrentHeight] = useState<number>(0)

const onLayout = event => {
    const newHeight = event.nativeEvent.layout.height
    
    // Don't do anything for height = 0 (collapsed state)
    if (newHeight === 0) return

    // Only toggle key if the height has changed
    if (newHeight !== currentHeight) {
        setCurrentHeight(newHeight)
    }
}

// Use currentHeight state as the key
<Collapsible collapsed={collapsed} key={currentHeight} renderChildrenCollapsed={true}>
    <View onLayout={onLayout}>
        {children}
    </View>
</Collapsible>

You can also stringify what ever value that is dynamic in the collapsible and set it as the key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants