React-Native-ViewPager icon indicating copy to clipboard operation
React-Native-ViewPager copied to clipboard

DOES NOT WORK IN SCROLLVIEW

Open developer239 opened this issue 8 years ago • 11 comments

Hi, thanks for the library. It was pretty cool before I found out that viewpager does not work in scroll view in ios. Would you please help me out? :)

This does not work (no content is displayed)

<ScrollView style={{ flex: 1 }}>
        <IndicatorViewPager
          pagerStyle={style.viewPager}
          style={style.container}
          initialPage={activeTab === 'products' ? 0 : 1}
          indicator={
            <PagerTitleIndicator
              itemTextStyle={style.pagerTitleText}
              selectedItemTextStyle={style.pagerSelectedText}
              selectedBorderStyle={style.pagerSelectedBorder}
              style={style.pager}
              titles={['Products', 'Brands']}
            />}
        >
          <View>
            <ItemsList navigator={navigator} items={topProducts} type="product" />
          </View>
          <View>
            <ItemsList navigator={navigator} items={topBrands} type="brand" />
          </View>
        </IndicatorViewPager>
      </ScrollView>

This works as expected:

<View style={{ flex: 1 }}>
        <IndicatorViewPager
          pagerStyle={style.viewPager}
          style={style.container}
          initialPage={activeTab === 'products' ? 0 : 1}
          indicator={
            <PagerTitleIndicator
              itemTextStyle={style.pagerTitleText}
              selectedItemTextStyle={style.pagerSelectedText}
              selectedBorderStyle={style.pagerSelectedBorder}
              style={style.pager}
              titles={['Products', 'Brands']}
            />}
        >
          <View>
            <ItemsList navigator={navigator} items={topProducts} type="product" />
          </View>
          <View>
            <ItemsList navigator={navigator} items={topBrands} type="brand" />
          </View>
        </IndicatorViewPager>
      </View>

developer239 avatar Jul 17 '17 23:07 developer239

Could you paste your viewpager style code here ?

zbtang avatar Jul 20 '17 09:07 zbtang

const style = StyleSheet.create({
  container: {
    flex: 1,
  },
  pagerTitleText: {
    color: 'darkgray',
  },
  pagerSelectedText: {
    color: 'black',
  },
  pagerSelectedBorder: {
    backgroundColor: 'black',
  },
  pager: {
    backgroundColor: AppStyles.windowBackground,
    height: 50,
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
  },
  pagerBackground: {
    backgroundColor: 'white',
  },
  viewPager: {
    marginTop: 50,
  },
})

developer239 avatar Jul 24 '17 11:07 developer239

You should specify the height and width in the style sheet of viewpager.

zbtang avatar Jul 24 '17 14:07 zbtang

Cool but how do I do that?

developer239 avatar Jul 24 '17 14:07 developer239

I mean what if I don't know the size of the content in advance?

developer239 avatar Jul 24 '17 14:07 developer239

Or maybe you can set flex:1 in the style sheet of viewpager. Refer this

zbtang avatar Jul 24 '17 14:07 zbtang

Flex does not work.

developer239 avatar Jul 24 '17 14:07 developer239

Even worse is that in order to render the content the view pager NEEDS some height. When I set some initial height manually then it renders its content and only then are onLayout methods executed in the content of the viewer. So I can set the actual height of the viewpager. I don't know what am I gonna do but I am fucked up a lot because of this.

developer239 avatar Jul 24 '17 14:07 developer239

Maybe you can set some initial height, and when the content view's onLayout methods called back, then you change the height of viewpager by setState. Anyway you must think out a way to calc the height of your content.

zbtang avatar Jul 24 '17 14:07 zbtang

I have already done that. I created TabContent component that adds layout height to the total height of the tab but it is not good solution. I have to set initial height in order to set the actual height. Initial height must be bigger that the first element that is supposed to be rendered in the tab. I have to do shitload of unnecessary calculations. For some reason when I made it work ... it worked until I clicked on 2nd+ tab then the component is rerendering indefinitely.

ViewPager:

<IndicatorViewPager
              ref={viewPager => {
                this.viewPager = viewPager
              }}
              pagerStyle={styles.viewPager}
              style={styles.container}
              initialPage={0}
              onPageSelected={eve => {
                this.handleChangeTabIndex(eve.position)
              }}
              indicator={<PagerTitleIndicator
                itemTextStyle={styles.pagerTitleText}
                selectedItemTextStyle={styles.pagerSelectedText}
                selectedBorderStyle={styles.pagerSelectedBorder}
                style={styles.pager}
                onClick={this.handleChangeTabIndex}
                titles={['Information', 'Activity']}
              />}
            >
              <View style={{ flex: 1, padding: 20 }}>
                {productCategory && productCategory.count() > 0 && (
                  <TabContent name="category" addHeight={(key, height) => this.handleAddTabContent('first_tab', key, height)}>
                    <ProductDetailInformation
                      title="Category"
                      value={productCategory.get('name')}
                    />
                  </TabContent>
                )}
                <TabContent name="description" addHeight={(key, height) => this.handleAddTabContent('first_tab', key, height)}>
                  <ProductDetailInformation
                    title={'Product detail'}
                    value={product.get('description')}
                  />
                </TabContent>
              </View>
              <View style={{ paddingTop: 20 }}>
                <TabContent name="second_tab_first_content" addHeight={(key, height) => this.handleAddTabContent('second_tab', key, height)}>
                  <Text>Second tab content</Text>
                </TabContent>
              </View>
            </IndicatorViewPager>

Component methods:

handleAddTabContent(tabName, key, height) {
    const tabsContent = this.state.tabsContent
    tabsContent[tabName][key] = height
    this.setState({ tabsContent })
  }

  getTabContentHeight() {
    const { tab, tabsContent } = this.state

    let activityTabHeight = 0
    let detailTabHeight = 0


    Object.keys(tabsContent.activity).forEach(key => {
      activityTabHeight += tabsContent.activity[key]
    })

    Object.keys(tabsContent.detail).forEach(key => {
      detailTabHeight += tabsContent.detail[key]
    })

    if (!activityTabHeight || !detailTabHeight) {
      return windowHeight
    }

    if (detailTabHeight < windowHeight) {
      detailTabHeight = windowHeight
    }

    if (activityTabHeight < windowHeight) {
      activityTabHeight = windowHeight
    }

    switch (tab) {
      case 0:
        return detailTabHeight
      case 1:
        return activityTabHeight
      default:
        return 0
    }
  }

Tab content component

import React from 'react'
import PropTypes from 'prop-types'
import {
  View,
} from 'react-native'


const TabContent = ({ children, name, addHeight }) => (
  <View
    onLayout={
      event => {
        const layout = event.nativeEvent.layout
        addHeight(name, layout.height)
      }
    }
  >
    {children}
  </View>
)

TabContent.propTypes = {
  children: PropTypes.node,
  name: PropTypes.string,
  addHeight: PropTypes.func,
}

export default TabContent

I am basically fucked.

developer239 avatar Jul 24 '17 14:07 developer239

@developer239 Is there any other way?

ZionChang avatar Aug 16 '17 08:08 ZionChang