Как я могу создать несколько каруселей изображений? - PullRequest
0 голосов
/ 31 марта 2020

Я немного новичок в React Native, и я пытаюсь создать список карточек с Flatlist, я хочу показать несколько изображений для каждой карточки в виде карусели, и я пытаюсь сделать это с реакцией карусель, проблема в том, что когда я прокручиваю карту, индексы всех карт перемещаются.

Как получить отдельный индекс для каждой карты?

import React, { useState, useRef } from 'react';
import { View, Text, Dimensions } from 'react-native';
import Carousel, { Pagination } from 'react-native-snap-carousel';

const { width: screenWidth, height: screenHeight } = Dimensions.get('window');

const myCarousel = () => {
  const [activeSlide, setActiveSlide] = useState(0);
  const carousel = useRef();
  const entries = [
    {
      title: 'card1',
    },
    {
      title: 'card2',
    },
    {
      title: 'card3',
    },
    {
      title: 'card4',
    },
  ];

  var slides = [];

  const entriesSplitter = () => {
    let size = 1; //Based on the size you want
    while (entries.length > 0) {
      slides.push(entries.splice(0, size));
    }
  };

  // render every single slide
  const _renderItem = ({ item, index }) => {
    return (
      <View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>
        {item.map(item => {
          return <Text key={index}>{item.title}</Text>;
        })}
      </View>
    );
  };

  return (
    <View>
      {entriesSplitter()}
      <Carousel
        ref={carousel}
        data={slides}
        renderItem={_renderItem}
        onSnapToItem={index => setActiveSlide(index)}
        sliderWidth={screenWidth}
        sliderHeight={screenHeight}
        itemWidth={screenWidth}
      />
      <Pagination
        dotsLength={4} // also based on number of sildes you want
        activeDotIndex={activeSlide}
        containerStyle={{ backgroundColor: 'red', borderWidth: 2 }}
        dotStyle={{
          width: 10,
          height: 10,
          borderRadius: 5,
          marginHorizontal: 8,
          backgroundColor: 'black',
        }}
        inactiveDotStyle={{
          backgroundColor: 'pink',
        }}
        inactiveDotOpacity={0.4}
        inactiveDotScale={0.6}
      />
      <Carousel
        ref={carousel}
        data={slides}
        renderItem={_renderItem}
        onSnapToItem={index => setActiveSlide(index)}
        sliderWidth={screenWidth}
        sliderHeight={screenHeight}
        itemWidth={screenWidth}
      />
      <Pagination
        dotsLength={4} // also based on number of sildes you want
        activeDotIndex={activeSlide}
        containerStyle={{ backgroundColor: 'red', borderWidth: 2 }}
        dotStyle={{
          width: 10,
          height: 10,
          borderRadius: 5,
          marginHorizontal: 8,
          backgroundColor: 'black',
        }}
        inactiveDotStyle={{
          backgroundColor: 'pink',
        }}
        inactiveDotOpacity={0.4}
        inactiveDotScale={0.6}
      />
    </View>
  );
};

export default myCarousel;

Индекс имеет стиль кругов, при котором go к следующему изменяет цвет, чтобы указать, сколько осталось, все они двигаются одновременно

Ответы [ 2 ]

0 голосов
/ 02 апреля 2020

В конце концов мне удалось сделать то, что я хотел, хотя индекс движется слишком медленно, я делюсь своим кодом на случай, если он может кому-то помочь.

Состояние:

constructor(props) {
  super(props);

  this.state = {
    activeSlide: [],
  };
}

Визуализация:

  render() {
    const {cards} = this.props;
    return (
      <View>
        <FlatList
          data={cards}
          numColumns={2}
          renderItem={({item, index}) => this._renderItemCarousel(item, index)}
        />
      </View>
    );
  }

_renderItemCarousel:

  _renderItemCarousel = (card, index) => (
    <View style={styles.card}>
      <Carousel
        data={card.picks}
        renderItem={this._renderItem}
        onSnapToItem={indexC => this.setIndex(indexC, {index})}
        sliderWidth={screenWidth}
        sliderHeight={screenHeight}
        itemWidth={screenWidth}
      />

      <Pagination
        dotsLength={card.picks.length}
        activeDotIndex={this.getIndex({index})}
        containerStyle={styles.circleDiv}
        dotStyle={styles.whiteCircle}
        inactiveDotOpacity={0.4}
        inactiveDotScale={0.6}
      />
    </View>
  );

setIndex, getIndex:

    setIndex = (indexC, indexF) => {
    let activeSlide = [...this.state.activeSlide];
    activeSlide[indexF.index] = indexC;
    this.setState({activeSlide});
  };
  getIndex = index => {
    if (this.state.activeSlide[index.index] == undefined) {
      this.state.activeSlide.push(0);
    }
    return this.state.activeSlide[index.index];
  };

_renderItem:

  _renderItem = ({item, index}) => {
    return (
      <View>
        <Image
          key={item.url}
          source={item.image}
          style={{height: '100%', width: CARD_WIDTH}}
        />
      </View>
    );
  };
0 голосов
/ 31 марта 2020

Вы используете два cousel с одинаковым референсом и одной и той же переменной, поэтому вам нужно разделить их

Working example: https://snack.expo.io/@msbot01/joyous-carrot
import React, {useState, useRef} from 'react';
import { Text, View, StyleSheet, Dimensions, Image } from 'react-native';
import Constants from 'expo-constants';

// You can import from local files
import AssetExample from './components/AssetExample';
import Carousel, {Pagination} from 'react-native-snap-carousel';

const screenWidth = Math.round(Dimensions.get('window').width);
const screenHeight = Math.round(Dimensions.get('window').height);

// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';

export default function App() {
  const [activeSlide, setActiveSlide] = useState(0);
  const [activeSlide2, setActiveSlide2] = useState(0);

  const entries = [
    { 
      title: 'card1',
    },
    {
      title: 'card2',
    },
    { 
      title: 'card3',
    },
    {
      title: 'card4',
    },
  ];
  const entries2 = [
    {
      title: 'card1',
    },
    {
      title: 'card2',
    },
    { 
      title: 'card3',
    },
    {
      title: 'card4',
    },
  ];

  var slides = [];

  const entriesSplitter = () => {
    let size = 1; //Based on the size you want
    while (entries.length > 0) {
      slides.push(entries.splice(0, size));
    }
  };

  // render every single slide
  const _renderItem = ({item, index}) => {
    return (
          <View style={{backgroundColor:'green', justifyContent:'center', alignItems:'center'}}>
            <Image
                style={{height:screenHeight/2, width:screenWidth-100}}
                source={{
                  uri: 'https://reactnative.dev/img/tiny_logo.png',
                }}
              />
        </View>

    );
  }

  const _renderItem2 = ({item, index}) => {
    return (
          <View style={{backgroundColor:'yellow', justifyContent:'center', alignItems:'center'}}>
            <Image
                style={{height:screenHeight/2, width:screenWidth-100}}
                source={{
                  uri: 'https://reactnative.dev/img/tiny_logo.png',
                }}
              />
        </View>

    );
  }

  return (
    <View style={styles.container}>
      <Carousel
        ref={(c) => { this._carousel = c}}
        data={entries}
        renderItem={_renderItem}
        onSnapToItem={index => setActiveSlide(index)}
        sliderWidth={screenWidth-20}
        sliderHeight={(screenHeight-100)}
        itemWidth={screenWidth-50}
      />
      {<Pagination
        dotsLength={4} // also based on number of sildes you want
        activeDotIndex={activeSlide}
        containerStyle={{backgroundColor: 'red', borderWidth: 2}}
        dotStyle={{
          width: 10,
          height: 10,
          borderRadius: 5,
          marginHorizontal: 8,
          backgroundColor: 'black',
        }}
        inactiveDotStyle={{
          backgroundColor: 'pink',
        }}
        inactiveDotOpacity={0.4}
        inactiveDotScale={0.6}
      />}
      <Carousel
        ref={(c) => { this._carousel2 = c}}
        data={entries2}
        renderItem={_renderItem2}
        onSnapToItem={index => setActiveSlide2(index)}
        sliderWidth={screenWidth-20}
        sliderHeight={(screenHeight-100)}
        itemWidth={screenWidth-50}
      />

      {<Pagination
        dotsLength={4} // also based on number of sildes you want
        activeDotIndex={activeSlide2}
        containerStyle={{backgroundColor: 'red', borderWidth: 2}}
        dotStyle={{ 
          width: 10,
          height: 10,
          borderRadius: 5,
          marginHorizontal: 8,
          backgroundColor: 'black',
        }}
        inactiveDotStyle={{
          backgroundColor: 'pink',
        }}
        inactiveDotOpacity={0.4}
        inactiveDotScale={0.6}
      />}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  }
});
...