oblador / react-native-collapsible

Animated collapsible component for React Native, good for accordions, toggles etc
MIT License
2.43k stars 454 forks source link

Scroll To Bottom (need help) #53

Open FDMatthias opened 7 years ago

FDMatthias commented 7 years ago

Hi,

I've been using your Accordion component inside a scrollview and I'm wondering if there's a way I can scroll to the bottom of the scrollview when a section is active.

I gave a ref to the scrollview so I'm thinking I could use 'this.refs.scrollviewRef.scrollTo' inside the 'onChange' callback but I don't know how to get the full height of the scrollview...

can you help me?

Thanks in advance

FDMatthias commented 7 years ago

As a matter of fact, it would also be nice to be able to scroll to a certain section on active.

It's something I tried figuring out my own, with the scrollTo function inside the scrollview, but the problem is that the section don't have refs (or when they do, it's hard to call the right ref to know the position of it in the scrollview..)

FDMatthias commented 7 years ago

Update: I have found a way. I will PR this weekend or next weekend with some code

bakhansen commented 7 years ago

@MatthiasDebaere did you find a solution to this? I'm looking into the part about "scroll to a certain section on active"

cheers

FDMatthias commented 7 years ago

Yes, I did, but I stopped using this module.

I simply made my own list of 'collapsable' items inside a scrollview. When I click on a header of the item I open/close the content of the collapsible item and I call a function to get the position of the item inside the scrollview. With the position I can call a function which will scroll the scrollview (by using the scrollview's ref) to the position of the item.

Psuedo code:

in my scrollview component:

const UIManager = require('NativeModules').UIManager
...

render() {
    return (
      <ScrollView style={ styles.container }
                  ref="wgw_scrollview">
        { this._renderSections() }
      </ScrollView>
    )
  }

_renderSections() {
  /* in here you render some elements you like. Important is they should all have their unique ref,
 and pass that ref as refAlias to the component. Inside the component you'll be calling 
this.props.scrollToSection with that refAlias, which will be able to look it up in here
 and match the height against the scrollview. */
return childComponents.map((childComponent,index) => {
const componentRef = "something_unique" + index
return (
        <SomeChildComponent key={ index }
                   ref={ componentRef }
                   refAlias={ componentRef }
                   scrollToSection={ this._scrollToSection }>
               <someInfoWrapper info={childComponent} />
        </SomeChildComponent >
      )
   }
}

_scrollToSection = (refAlias) => {
    const scrollviewRef = this.refs.wgw_scrollview
    var childHandle = findNodeHandle(this.refs[refAlias]) // this is the section you're scrolling to
    var scrollViewHandle = findNodeHandle(scrollviewRef) // this is the parent scrollview
    if (childHandle == null) {
      UIManager.measureLayout(
        childHandle, scrollViewHandle, (error) => {
          console.log(error)
        }, (relPosX, relPosY) => {
          scrollviewRef.scrollTo({
            x: 0,
            y: relPosY
          })
        }
      )
    }
  }
Kurt57 commented 7 years ago

how the accordion work for you ? are you able to expand and collapse the elements?

marxsk commented 7 years ago

For those who tries to scroll to a right section, the most simplistic solution that works only for headers of fixed size. This solution scroll the view, so the expanded item starts at the top of visible view.

Take a look at https://github.com/marxsk/zobro2/commit/6ec2b4f46a1ec68cf0b685c281491163f7b40bc2

jfilter commented 6 years ago

My approach:

Use the onLayout event to get the heights of the items (and other Views), save them to state and calculate scroll offset based on them.

https://facebook.github.io/react-native/docs/view.html#onlayout

giantslogik commented 5 years ago

I'm using keyboard-avoiding-scroll-view

On collapsible open i trigger: setTimeout(()=>{this.scrollIntoView(this.collapsibleRef)},COLLAPSIBLE_SPEED);

The COLLAPSIBLE_SPEED constant above is the same one passed to the duration prop of the collapsible.

  scrollIntoView(element){
    this.scroll.props.scrollIntoView(element);
  }

Alternate implementation that could be modified to support other scroll views. scrollcontainer is the view wrapping the scrollview.Its measurements are useful to change the position that is scrolled to.

scrollIntoView=(element)=>{
     this.scrollcontainer.measure((sfx, sfy, swidth, sheight, spx, spy) => {
      element.measure( (fx, fy, width, height, px, py) => {

                            var y=fy-height-_extra_h;
                            if(y<0)
                              y=0;
                            /*alert(sfx+"/"+sfy+"/"+swidth+"/"+sheight+"/"+spx+"/"+spy+"\n"+
                            fx+"/"+fy+"/"+width+"/"+height+"/"+px+"/"+py+"\n"+y);*/
                            this.scroll.props.scrollToPosition(0,y);
                            })
                         });
  } 
tamirhal commented 3 years ago

almost 5 years since then. is there a way to do it? :)