wix-incubator / react-native-interactable

Experimental implementation of high performance interactable views in React Native
MIT License
5.18k stars 515 forks source link

CollapsingHeader example with scrolling content #35

Open Ehesp opened 7 years ago

Ehesp commented 7 years ago

In the CollapsingHeader example, the main body (below the header) does not scroll when the content goes off screen. The below example is a copy paste of the example with extra View content. Only 4 boxes are show.

I've tried experimenting with a ScrollView, however it either causes the header to scroll off screen (when a parent of Interactable) or does nothing (a child of Interactable).

If Interactable is wrapped in a ScrollView, it doesn't seem to pick up all of the scroll events (header scales sometimes, sometimes not), but I do see the content.

Is there a way to achieve this?

import React, { Component } from 'react';
import { StyleSheet, ScrollView, View, Animated } from 'react-native';
import Interactable from 'react-native-interactable';

export default class CollapsingHeader extends Component {
  constructor(props) {
    super(props);
    this._deltaY = new Animated.Value(0);
  }
  render() {
    return (
      <View style={styles.container}>

        <View style={{backgroundColor: 'red', height: 250, alignItems: 'center'}}>
          <Animated.View style={{
              transform: [
                {
                  translateY: this._deltaY.interpolate({
                    inputRange: [-150, -150, 0, 0],
                    outputRange: [-58, -58, 0, 0]
                  })
                },
                {
                  scale: this._deltaY.interpolate({
                    inputRange: [-150, -150, 0, 0],
                    outputRange: [0.35, 0.35, 1, 1]
                  })
                }
              ]
            }}>
            <View style={{width: 150, height: 150, backgroundColor: 'blue', borderRadius: 75, marginTop: 50}} />
          </Animated.View>
        </View>

        <Interactable.View
          verticalOnly={true}
          snapPoints={[{y: 0}, {y: -150}]}
          boundaries={{top: -150}}
          animatedValueY={this._deltaY}>
          <View style={{left: 0, right: 0, height: 650, backgroundColor: '#e0e0e0'}}>
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
            <View style={{ backgroundColor: 'grey', height: 100, marginVertical: 8 }} />
          </View>
        </Interactable.View>

      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  }
});
Ehesp commented 7 years ago

I suppose another thing would be having RefreshControl attached onto the main content when the user pulls down. Would require a ScrollView.

talkol commented 7 years ago

This is one of the most complicated features.. We're going to need a vertical ScrollView inside an Interactable.View that moves vertically. The touch events aren't simple to resolve here.

I created an example that we can play with: https://github.com/wix/react-native-interactable/commit/e89a186e29728e77051fb39cbfa407b9e278c6d5

It's not working yet.. I played with events, but it's not smooth. I need to figure out how to make the touch events drive this correctly (games with the gesture recognizers).

Ehesp commented 7 years ago

Thanks for replying. This combined with the onPress issue makes it a bit too experimental for now to use in an app. Will keep an eye on progress, not sure my Java skills are up to scratch to help!

talkol commented 7 years ago

Can you confirm the onPress issue is only with Android, the iOS implementation should be working well. There's an Android developer planned to be dedicated to touch issues all of next week.

Ehesp commented 7 years ago

Sure! It's actually described here: https://github.com/wix/react-native-interactable/issues/30

What happens, is that when I lay my finger down on an element and begin to scroll the content, the content scrolls/moves as expected. However if that element has an onPress handler (TouchableHighlight), it triggers it when lifting the finger.

talkol commented 7 years ago

Awesome thanks, iOS is working well for you in this case?

Ehesp commented 7 years ago

Haven't checked to be honest, I'll get it setup this morning and find out!

Ehesp commented 7 years ago

@talkol The scroll issue is still present on iOS, but the onPress is not present in iOS (works as expected).

talkol commented 7 years ago

Yes, the vertical scroll inside vertical interactable isn't working on iOS. This is on me, difficult problem. I'll figure it out. If the scroll is in a perpendicular direction it would work (horizontal scroll on vertical interactable).

Ehesp commented 7 years ago

Cool thanks for the heads up. Hate asking this but any sort of ETA? Just wondering whether to keep it for now or work on my own crappier implementation :)

talkol commented 7 years ago

Vertical scroll within vertical scroll requires research so no ETA. Fixing Android touch issues will be done next week, so it will be on the same level as iOS is today.

LoyalBlocks-tzachi commented 7 years ago

Hi guys! I fixed most of the Android touch issues in this branch: https://github.com/wix/react-native-interactable/tree/androidFixes

I'll appreciate if you can give feedback before I merge to master

The issue that still remains unresolved (I'm still working on it) is horizontal scroll inside horizontal moving interactable (or anything with horizontal drag like a slider)

If the scroll inside the interactable listens in the same direction the interactable is moving, we also have an issue in iOS. We will probably fix both together by introducing a more hardcore mechanism to deal with this complicated issue. It will probably introduce a few new props or maybe another aux view to mark how touch events in children should behave

Mindaugas-Jacionis commented 7 years ago

Hi, with @rotemmiz we were discussing that maybe one of the quick solution for ScrollView/ListView in Interactable issue could be a prop that allows to define condition when Interactable consumes gestures and when it ignores them and allows ScrollView to consume them.

I.e. Collapsable Filter example: Interactable consumes on (isExpanded && dy < 0) || (!isExpanded && dy > 0) - when expanded and gesture is upwards(to close/colapse) or when colapsed and gesture is downwards(to expand filter), otherwise it just sits there without interfering with rest of the view. :)

nishiltamboli commented 7 years ago

Yes the ScrollView inside Interactable View is not properly working. It picks up gestures for Interactable view. But Scroll doesnt happen. Stuck up with the same problem. Also, my interactable view is scaling automatically. I am not sure why is that happening. But the height keeps on reducing when snap points are hit. I am implementing something similar to Real Life Filters example and I have the same issue. Instead of View, I am using a ScrollView inside the interactable view.

portons commented 7 years ago

+1 to @nishiltamboli 's problem. Using a vertical ScrollView inside a verticalOnly Interactable. Can't scroll in ScrollView on Android, on iOS works fine. Tried the androidFixes branch, didn't help.

nishiltamboli commented 7 years ago

@portons Is your Interactable view using the height it is allowed? My Interactable view keeps on shrinking as the snap points are hit. I think I am doing something wrong there.

Could you share your code? Or even the Interactable View markup?

portons commented 7 years ago

@nishiltamboli A bit problematic, mine is much more complex than just an Interactable with a ListView inside. There's Interactable -> Carousel -> Panel -> ListView hierarchy. But the height works fine. Mb show your code instead and we'll see what's the problem?

LoyalBlocks-tzachi commented 7 years ago

Hi everyone. The "androidFixes" branch is merged to master. In addition, I have an experimental solution to the "scrolling element inside" problem in this branch: https://github.com/wix/react-native-interactable/tree/touchBlockerBranch (Note: this only works on android for now)

What I did is add a new component called "touchBlocker", which can be used to wrap any element that need to receive touch events and not let the Interactable view "steal" them. It has a parameter "blockAllTouch": if set to true, this component will always receive all touch events on its surface. you can see this usage in the "Touches Inside" example, where the webview and the slider are wrapped in it, so they always respond to touch gestures, horizontal or vertical. if "blockAllTouch" is false, this element will only receive touch events when the Interactable view is at the top boundary and the gesture is upwards. This is used in the "Collapsing Header with Scroll" example, where the ScrollView will scroll only when the header is collapsed. Hope that makes sense :) try it and tell me what you think...

talkol commented 7 years ago

I would like your API feedback on the touchBlocker component as well

portons commented 7 years ago

@LoyalBlocks-tzachi @talkol Just tried it out, works great on Android! Thanks!

Regarding the API, mb something like stopTouchPropagation? 'block' is kinda confusing, as we're not really blocking it. But the implementation is great.

Also, maybe add an option for not propagating direction-specific touch events? Like stopVerticalSwipePropagation and -//-Horizontal-//-. Basing on my case, which is very edgy - I'm using the Interactable on top of a carousel, which holds many panels, and inside each panel there's a ListView. Now the lists are scrollable, but the carousel isn't swipeable (if swiping on the list itself). If it were possible to only block vertical swipes, then it could be very helpful.

And last thing - maybe making Blocker return only this.props.children for iOS for now? So people wouldn't need to add platform specific code. Otherwise we get an error.

AAverin commented 7 years ago

Will this also work with a ListView? I have to implement exactly AirBnb case – list of data with this collapsible animated header with some input fields inside

talkol commented 7 years ago

@AAverin it should.. the component is supposed to wrap every scrollable component. If it doesn't work, let's fix that it does. Also, in ListView you can control the internal ScrollView component as well so this could also be a solution if we have issues.

@portons I agree that the API naming needs some polish. Great suggestions. What about renaming the entire component?

AAverin commented 7 years ago

@talkol I good idea would be not to tie API too much to RN ScrollView, because I think it's only a matter of time until proper Android RecyclerView and iOS TableView support will be implemented in RN, and they will probably not use RN ScrollView as a base.

portons commented 7 years ago

@talkol That's a hard one.. I'd lean towards BubblingBlocker/PropagationBlocker or TouchBubblingBlocker/TouchPropagationBlocker.

talkol commented 7 years ago

@AAverin Completely agree.

I had a long discussion with @LoyalBlocks-tzachi before implementing. His solution does not rely on ScrollView. It should work with any native scrollable component. Might require a few tweeks here and there because some of them add some wrapper views in between and we need to make sure it doesn't break anything.

jensneuse commented 7 years ago

@talkol Have you considered using CoordinatorLayout + NestedScrollView + CollapsibleLayout for the Android part or borrow code from them? These components work out of the box with nested scrolls. I know it's going to make things difficult to get a cross platform api. That being said, these components are there for a reason. Nested Scrolls is one of the most complicated UI topics in Android dev space.

henrikra commented 7 years ago

@LoyalBlocks-tzachi This blocker looks like what I am wanting in https://github.com/wix/react-native-interactable/issues/59 Do you agree that I could block the parts I want and only the red area would be the part that actually drags stuff? :)

ButtersHub commented 7 years ago

@jnsone11, i was looking on the CoordinatorLayout & NestedScrollView, and i agree that this the direction that we need to look and not write something from scratch. Currently, I am fixing master branch on Android (the InteractableView intercept unnecessary inner-view's events) and after this ill start testing CoordinatorLayout & NestedScrollView

henrikra commented 7 years ago

Does this https://github.com/wix/react-native-interactable/commit/212a9528f2211abebc164e3865dd56ad891ccf53 fix the ScrollView problem?

antsmo commented 7 years ago

I'd be really interested in getting ScrollView to work with the collapsing header as well, though I'm afraid I'm not knowledgable enough to help :( Has there been any progress for iOS?

talkol commented 7 years ago

@MyGuySi no progress for iOS yet.. since nested touch events is more complicated in Android I prefer to wait until they reach a conclusion of how the API should look like there and then port to iOS. I'm confident we'll be able to do the same fix on iOS without much difficulty (gesture recognizers there exist for these reasons)

RichardLindhout commented 7 years ago

Any updates on this?

npalethorpe commented 7 years ago

This is one great component! - hate to ask but has there been any movement (no pun intended) with the vertical ScrollView inside an Interactable.View that moves vertically issue?

In my project I have three vertical panels inside the Interactable view which snap to position, the bottom panel is a flatlist though and I find myself getting locked when I reach this panel as dragging in a downward motion doesn't kick the Interactable view into scrolling.

williambout commented 7 years ago

@talkol @ButtersHub Is there any progress on iOS?

Noitidart commented 6 years ago

I am using react native v0.48.1 and am testing on Android 6.0. The CollapsingHeaderWithScroll.js is not collapsing the header on scroll. @ButtersHub should I make a separate issue for this, it might be different?

Here is a screencast: https://gfycat.com/ArtisticBrilliantKangaroo

Gif of screencast:

The code is:

https://github.com/wix/react-native-interactable/blob/master/example/src/CollapsingHeaderWithScroll.js

import React, { Component } from 'react';
import { StyleSheet, View, Animated, ScrollView, Dimensions } from 'react-native';
import Interactable from 'react-native-interactable';

const Screen = {
  height: Dimensions.get('window').height - 75
};

export default class CollapsingHeaderWithScroll extends Component {
  constructor(props) {
    super(props);
    this._deltaY = new Animated.Value(0);
    this.state = {
      canScroll: false
    };
  }
  render() {
    return (
      <View style={styles.container}>

          <View style={{backgroundColor: 'red', height: 250, alignItems: 'center'}}>
            <Animated.View style={{
              transform: [
                {
                  translateY: this._deltaY.interpolate({
                    inputRange: [-150, -150, 0, 0],
                    outputRange: [-58, -58, 0, 0]
                  })
                },
                {
                  scale: this._deltaY.interpolate({
                    inputRange: [-150, -150, 0, 0],
                    outputRange: [0.35, 0.35, 1, 1]
                  })
                }
              ]
            }}>
              <View style={{width: 150, height: 150, backgroundColor: 'blue', borderRadius: 75, marginTop: 50}} />
            </Animated.View>
          </View>

          <Interactable.View
            verticalOnly={true}
            snapPoints={[{y: 0}, {y: -150, id: 'bottom'}]}
            boundaries={{top: -150}}
            onSnap={this.onSnap.bind(this)}
            animatedValueY={this._deltaY}>
            <ScrollView
              bounces={false}
              canCancelContentTouches={this.state.canScroll}
              onScroll={this.onScroll.bind(this)}
              style={{left: 0, right: 0, height: Screen.height - 100, backgroundColor: '#e0e0e0'}}>
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
              <View style={styles.placeholder} />
            </ScrollView>
          </Interactable.View>

      </View>
    );
  }
  onSnap(event) {
    const { id } = event.nativeEvent;
    if (id === 'bottom') {
      this.setState({ canScroll: true });
      alert('This implementation is still broken, in progress');
    }
  }
  onScroll(event) {
    const { contentOffset } = event.nativeEvent;
    if (contentOffset.y === 0) {
      this.setState({ canScroll: false });
    }
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  placeholder: {
    backgroundColor: 'yellow',
    flex: 1,
    height: 120,
    marginHorizontal: 20,
    marginTop: 20
  }
});
airqb commented 6 years ago

hi everyone well i was think about this and it seem it is possible so how it work if you add the scrollview inside the intractable.view and create states witch it will spay this event of intractable envent onDrag position and scrollview position so disable and enable the scroll view and it will work by example

`import React, { Component } from 'react'; import {AppRegistry, StyleSheet, View, Animated, ScrollView, Text} from 'react-native'; import Interactable from 'react-native-interactable';

class ProfileScreen extends Component { constructor(props) { super(props); this._deltaY = new Animated.Value(0); this.state={ scrollEnabled: false, currentScrollPT: 0, isOpen: true } } onPanelDrag = ({ y }) => { console.log(y)

if(y<=-150 && this.state.isOpen){ this.setState({ scrollEnabled: true, isOpen: false }) }

}

onScroll = (e)=>{ this.setState({currentScrollPT: e.nativeEvent.contentOffset.y}) if(e.nativeEvent.contentOffset.y<=30 && !this.state.isOpen ){ this.setState({scrollEnabled: false, isOpen: true}) } if(e.nativeEvent.contentOffset.y>10 && this.state.isOpen){ this.setState({scrollEnabled: false, isOpen: false}) } }

render() { return (

this.onPanelDrag(event.nativeEvent)} animatedValueY={this._deltaY}>
        <View style={{left: 0, right: 0, height: 650, backgroundColor: '#e0e0e0'}} >
            <ScrollView onScroll={this.onScroll} scrollEnabled={this.state.scrollEnabled}>
            <View>
            <Text>
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Sed lectus. Donec mollis hendrerit risus. Phasellus nec sem in justo pellentesque facilisis. Etiam imperdiet imperdiet orci. Nunc nec neque. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed aliquam, nisi quis porttitor congue, elit erat euismod orci, ac placerat dolor lectus quis orci. Phasellus consectetuer vestibulum elit. Aenean tellus metus, bibendum sed, posuere ac, mattis non, nunc. Vestibulum fringilla pede sit amet augue. In turpis. Pellentesque posuere. Praesent turpis. Aenean posuere, tortor sed cursus feugiat, nunc augue blandit nunc, eu sollicitudin urna dolor sagittis lacus. Donec elit libero, sodales nec, volutpat a, suscipit non, turpis. Nullam sagittis. Suspendisse pulvinar, augue ac venenatis condimentum, sem libero volutpat nibh, nec pellentesque velit pede quis nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce id purus. Ut varius tincidunt libero. Phasellus dolor. Maecenas vestibulum mollis diam. Pellentesque ut neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In dui magna, posuere eget, vestibulum et, tempor auctor, justo. In ac felis quis tortor malesuada pretium. Pellentesque auctor neque nec urna. Proin sapien ipsum, porta a, auctor quis, euismod ut, mi. Aenean viverra rhoncus pede. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut non enim eleifend felis pretium feugiat. Vivamus quis mi. Phasellus a est. Phasellus magna. In hac habitasse platea dictumst. Curabitur at lacus ac velit ornare lobortis. Curabitur a felis in nunc fringilla tristique. Morbi mattis ullamcorper velit. Phasellus gravida semper nisi. Nullam vel sem. Pellentesque libero tortor, tincidunt et, tincidunt eget, semper nec, quam. Sed hendrerit. Morbi ac felis. Nunc egestas, augue at pellentesque laoreet, felis eros vehicula leo, at malesuada velit leo quis pede. Donec interdum, metus et hendrerit aliquet, dolor diam sagittis ligula, eget egestas libero turpis vel mi. Nunc nulla. Fusce risus nisl, viverra et, tempor et, pretium in, sapien. Donec venenatis vulputate lorem. Morbi nec metus. Phasellus blandit leo ut odio. Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum viverra felis nunc et lorem. Sed magna purus, fermentum eu, tincidunt eu, varius ut, felis. In auctor lobortis lacus. Quisque libero metus, condimentum nec, tempor a, commodo mollis, magna. Vestibulum ullamcorper mauris at ligula. Fusce fermentum. Nullam cursus lacinia erat. Praesent blandit laoreet nibh. Fusce convallis metus id felis luctus adipiscing. Pellentesque egestas, neque sit amet convallis pulvinar, justo nulla eleifend augue, ac auctor orci leo non est. Quisque id mi. Ut tincidunt tincidunt erat. Etiam feugiat lorem non metus. Vestibulum dapibus nunc ac augue. Curabitur vestibulum aliquam leo. Praesent egestas neque eu enim. In hac habitasse platea dictumst. Fusce a quam. Etiam ut purus mattis mauris sodales aliquam. Curabitur nisi. Quisque malesuada placerat nisl. Nam ipsum risus, rutrum vitae, vestibulum eu, molestie vel, lacus. Sed augue ipsum, egestas nec, vestibulum et, malesuada adipiscing, dui. Vestibulum facilisis, purus nec pulvinar iaculis, ligula mi congue nunc, vitae euismod ligula urna in dolor. Mauris sollicitudin fermentum libero. Praesent nonummy mi in odio. Nunc interdum lacus sit amet orci. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Morbi mollis tellus ac sapien. Phasellus volutpat, metus eget egestas mollis, lacus lacus blandit dui, id egestas quam mauris ut lacus. Fusce vel dui. Sed in libero ut nibh placerat accumsan. Proin faucibus arcu quis ante. In consectetuer turpis ut velit. Nulla sit amet est. Praesent metus tellus, elementum eu, semper a, adipiscing nec, purus. Cras risus ipsum, faucibus ut, ullamcorper id, varius ac, leo. Suspendisse feugiat. Suspendisse enim turpis, dictum sed, iaculis a, condimentum nec, nisi. Praesent nec nisl a purus blandit viverra. Praesent ac massa at ligula laoreet iaculis. Nulla neque dolor, sagittis eget, iaculis quis, molestie non, velit. Mauris turpis nunc, blandit et, volutpat molestie, porta ut, ligula. Fusce pharetra convallis urna. Quisque ut nisi. Donec mi odio, faucibus at, scelerisque quis,

            </Text></View>
            </ScrollView>
        </View>
        </Interactable.View>

  </View>
);

} }

const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'white', } });

export default ProfileScreen AppRegistry.registerComponent('ProfileScreen', () => ProfileScreen)`

antsmo commented 6 years ago

@airqb You might want to tidy up your markup so others can read your code more easily :)

airqb commented 6 years ago

hey @MyGuySi sorry :), @Ehesp @talkol @LoyalBlocks-tzachi @Mindaugas-Jacionis @nishiltamboli by the way I was search a lot in the internet to find CollapsingHeader Component and I didn't found it but in final I decided to make may own component witch really working very smooth and fine the Idea of CollapsingHeader very simply by the way I will share this component with you guys I hope it will solve the problem of CollapsingHeader and not need for any other library using normal react native components

airqb commented 6 years ago
import React, { Component } from 'react'
import { AppRegistry, View, Text, StyleSheet, ScrollView, Dimensions } from 'react-native'

// COMPONENT >>>>>-------------------------------------------------------------
class CoordinatorLayout extends Component {

    constructor(props) {
        super(props)
        this.state = {
            scrollPosition: 0,
            prevScrollPosition: 0,
            showFAB: true,
            headerHeight: this.props.headerHeight,
            height_2: Math.abs((this.props.headerHeight / 2) - 1),
        }

    }

    // COMPONENT METHODS ......................................................
    onScrollEndDrag = () => {
        if (this.state.scrollPosition >= 0 && this.state.scrollPosition <= this.state.height_2) {
            this.refs['ScrollView'].getScrollResponder().scrollTo({ x: 0, y: 0, animated: true })
            this.props.onExpanded()
        }
        if (this.state.scrollPosition >= this.state.height_2 && this.state.scrollPosition <= this.state.headerHeight) {
            this.refs['ScrollView'].getScrollResponder().scrollTo({ x: 0, y: (this.state.headerHeight + 1), animated: true })
            this.props.onCollapsed()
        }

    }

    onScroll = (event) => {
        this.setState({ scrollPosition: event.nativeEvent.contentOffset.y })
        var currentOffset = event.nativeEvent.contentOffset.y
        var direction = currentOffset > this.state.prevScrollPosition ? 'down' : 'up'
        this.setState({ prevScrollPosition: currentOffset })
    }

    // COMPONENT TEMPLATE .....................................................
    render() {
        return (
            <View style={{ flex: 1 }}>
                <ScrollView
                    ref="ScrollView"
                    style={{ flex: 1 }}
                    showsVerticalScrollIndicator={false}
                    contentContainerStyle={this.props.contentContainerStyle}
                    onScrollEndDrag={this.onScrollEndDrag}
                    onScroll={this.onScroll}
                    scrollEventThrottle={16}>
                    <View style={{ flex: 1, backgroundColor: 'white', minHeight: ((Dimensions.get('window').height * 2) - (this.state.headerHeight - 43)) }}>
                        {this.props.children}
                    </View>
                </ScrollView>
            </View>
        )
    }
}

// COMPONENT STYLE SHEET >>>>--------------------------------------------------
const Style = StyleSheet.create({
});

// COMPONENT REGISTRY >>>>-----------------------------------------------------
export default CoordinatorLayout
AppRegistry.registerComponent('CoordinatorLayout', () => CoordinatorLayout)
airqb commented 6 years ago

to use it you need to import the component and pass this props headerHeight={?} onExpanded={this.onExpanded} onCollapsed={this.onCollapsed} you can add some other effect from callback methods [onCollapsed, onExpanded] it and it well work fine ;) happy codeing

we have made social media app call PassBy App you can check it as well https://goo.gl/DFzxvp


import CoordinatorLayout form <YouFileLocation>

render() {
        return (
            <View style={Style.container}>

                    <CoordinatorLayout
                        headerHeight={345}
                        onExpanded={this.onExpanded}
                        onCollapsed={this.onCollapsed}>
                        {/*** HEADER ***/}
                        <View
                            storeID={this.state.storeID}
                            storeFullName={this.state.storeFullName}
                            storeBio={this.state.storeBio}
                            storeIsTrust={this.state.storeIsTrust}
                            storeWebSite={this.state.storeWebSite}
                            storeOfficial={this.state.storeOfficial} />

                        {/*** OTHER COMPONENTS ***/}
                        <View></View>.....
                    </CoordinatorLayout>
            </View>
        )
    }
gabrielecirulli commented 6 years ago

Hey, I just wanted to say you did a very good job with the library and it's very high-quality. I've been using it to try to achieve a sort of pop-up card effect. It came out very well. Result video on Imgur.

Unfortunately as other people have noticed in this issue it is not possible to add scrolling within an Interactable element. I tried my best to get it to work, messing around with the gesture responder system, but unfortunately I couldn't get a fluid result (it doesn't seem possible to switch a touch from being handled by the scroll view to moving the Interactable view without having to release the touch first).

I just wanted to ask if you had any recommendation for how to get this to work, or if you know about any other libraries that could help. I obviously can't ask you to add this feature as you've done an incredible job so far, but it goes without saying that it'd be awesome to have it! Thanks!

butchmarshall commented 6 years ago

Any update on this? I attempted to update the touchBlockerBranch to latest master without much success.

erickreutz commented 6 years ago

Is this not achievable using this lib https://github.com/kmagiera/react-native-gesture-handler - it seems as though the whole library could be re-written to take advantage of these native gesture handlers? /cc @talkol

bhd-vasyl commented 6 years ago

Is there any solutions for iOS and Android?

song50119 commented 6 years ago

same issue

hadimostafapour commented 5 years ago

Try this hack, maybe helpful:

Works on both iOS and Android Tested on RN 0.57RC3

TouchableWithoutFeedback will prioritize scrollView touch events than Interactable.View

<ScrollView>
       <TouchableWithoutFeedback>
                <View>{this.props.children}</View>
      </TouchableWithoutFeedback>
</ScrollView>