如何堆叠绝对位置的卡片?

时间:2018-01-31 02:29:18

标签: react-native flexbox

事先,这个问题包含图片,我不熟悉如何发布图片的最佳做法。如果我的帖子做得不好,我没有问题重构。

我正在尝试为实践目的创建设计。而且我对卡的定位有点困难。我相信使用绝对位置应该创建所需的效果并手动调整“顶部”,但它会切断卡的上半部分。

我想要达到的目的是:

我拥有的是:

我使用的代码是:

 <Animated.View style={animatedStyles}>
          <View style={styles.phoneContainer}>
            <View style={{ position: "absolute" }}>
              <Deck deckColor="#ED29F9" />
              <View
                style={{
                  position: "absolute",
                  bottom: 15
                }}
              >
                <Deck deckColor="red" />
              </View>
              <View
                style={{
                  position: "absolute",
                  bottom: 5,
                  left: 2
                }}
              >
                <Deck deckColor="#FFF5AB" />
              </View>
              <View
                style={{
                  position: "absolute"
                }}
              >
                <Deck deckColor="#78BDF0" />
              </View>
            </View>

          </View>
        </Animated.View>

非常感谢任何帮助或线索。

The component's code is:

const Deck = () => {
  return (
    <View>
      <View style={styles.head} />
      <View style={styles.body}>
        <View style={styles.bodyContents}>
          <View style={styles.circle} />
          <View style={styles.text} />
          <View style={styles.text} />
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  bodyContents: {
    flexDirection: "column",
    flex: 0.8,
    justifyContent: "space-around",
    alignItems: "center"
  },
  text: {
    height: 30,
    borderRadius: 5,
    width: 100,
    backgroundColor: "#d2d2d2"
  },
  circle: {
    borderRadius: 50,
    backgroundColor: "#d2d2d2",
    height: 50,
    width: 50,
    marginTop: 20
  },
  head: {
    backgroundColor: "#ED29F9",
    flex: 0.2,
    width: 250
  },
  body: {
    flex: 0.7,
    width: 250,
    borderRadius: 4,
    borderWidth: 0.5,
    borderColor: "#d6d7da",
    backgroundColor: "#F7F7F7"
  }
});

1 个答案:

答案 0 :(得分:0)

这只是建议你找到做你计划的最佳方式。


    // this code bellow I was testing in the App.js

    import React, { Component } from 'react';
    import {View} from 'react-native';

    import Deck from './components/Deck';
    import ButtonReject from './components/ButtonReject';
    import ButtonAccept from './components/ButtonAccept';
    import TopBar from './components/Topbar';


    export default class App extends Component {

        constructor(props){
            super(props);
            this.state={
            //array of decks
                decks: [
                    {
                        headColor: '#00FA9A',
                    },
                    {
                        headColor: '#8A2BE2',
                    },
                    {
                        headColor: '#1E90FF',
                    },
                    {
                        headColor: '#FFFF00'
                    },
                    {
                        headColor: '#FF6171'
                    }
                ],
            }
            // it's a Map that refer to the Decks Components in the container
            this.refDecks = new Map();
        }

        // Rejects a card
        reject(){
            // Calls the reject function in the last card in the deck 
            this.refDecks.get(this.state.decks.length-1).reject();
            this.removeCard();
        }

        // Accepts a card
        accept(){
            // Calls the accept function in the last card in the deck
            this.refDecks.get(this.state.decks.length-1).accept();
            // Calls the accept function in the topBar Component (it changes the heart color)
            this.topBar.accept();
            this.removeCard();

        }

        // Waits the time of the animation and remove the card
        removeCard(){
            setTimeout(()=>{
                decks = this.state.decks; 
                decks.splice(0, 1);
                this.setState({decks:decks});
            },250);
        }

        renderDeck(){
            // render the cards starting of the end (it changes the position props in the Decks, when a card is removed, so all others cards updates their positions in the deck)
            return this.state.decks.slice(0).reverse().map((deck,index) =>{
                return (
                     (this.refDecks.set(index, ref))} />
                )
            })
        }

        render() {
            return (
                <View>
                    <TopBar onRef = {ref =>{this.topBar = ref}} />
                    <View>
                        {this.renderDeck()}
                    </View>
                    <View style={{justifyContent:'flex-end'}}>
                        <ButtonReject reject={this.reject.bind(this)} />
                        <ButtonAccept accept={this.accept.bind(this)} />
                    </View>
                </View>
            );
        }
    }



// fim do App.js

Component => ButtonReject.js



        import React, { Component } from 'react';
        import {
            StyleSheet,
            View,
            Text,
            TouchableOpacity,
            Dimensions
        } from 'react-native';

        export default class ButtonReject extends Component {
            constructor(props){
                super(props);
            }

            onPress() {
                this.props.reject();
            }

            render(){
                return (
                    <View style={styles.circle}>
                        <TouchableOpacity
                            onPress={this.onPress.bind(this)}
                        >
                            <Text style={styles.textButton}> X 
                        </TouchableOpacity>
                    </View>
               );
           }
       };

       const styles = StyleSheet.create({
           circle: {
              position: 'absolute',
              top: Dimensions.get('window').height - 150,
              left: Dimensions.get('window').width -280,
              borderRadius: 60,
              backgroundColor: "#888888",
              height: 60,
              width: 60,
              marginTop: 20,
              alignItems:'center',
              justifyContent: 'center'
          },
          textButton:{
              fontSize: 30,
              color: '#FFF'
          }
      });
      //fim do ButtonReject.js

Component => TopBar.js



import React, { Component } from 'react';
import {
      StyleSheet,
      View,
      Dimensions
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

export default class TopBar extends Component {

    constructor(props){
        super(props);
        this.state = {
            heartColor:'#FFF'
        }
    }


    accept(){
        this.setState({heartColor:'#FF1493'});
        _this = this;
        setTimeout(()=>{
            _this.setState({heartColor:'#FFF'});
        },1000);
    }

    changeColor(color){
        this.setState({heartColor:color});
    }

    componentDidMount() {
        this.props.onRef(this)
    }

    componentWillUnmount() {
        this.props.onRef(undefined)
    }

    render(){
        return (
            <View style={styles.topBar}>
                <Icon name="md-heart" style={{left:Dimensions.get('window').width-50,top:20}} size={30} color={this.state.heartColor} />
            </View>
        );
    }
};

const styles = StyleSheet.create({
    topBar: {
        position: 'absolute',
        width: Dimensions.get('window').width,
        height: 70,      
        backgroundColor: "#8A2BE2",
    },
    textButton:{
        fontSize: 30,
        color: '#FFF'
    }
});

Deck.js

import React, { Component } from 'react'; import { StyleSheet, View, Text, Animated, Dimensions, TouchableWithoutFeedback } from 'react-native'; const animationDuration = 250; export default class Deck extends Component { constructor(props){ super(props); this.state= { headColor:'', // show or hide the X to close the card, when the card is maximize maximized: false, left: new Animated.Value((Dimensions.get('window').width/2)-(150-(this.props.position*7.5))), top: new Animated.Value((Dimensions.get('window').height/2)-140-(this.props.position*15)), height: new Animated.Value(300), width: new Animated.Value(300-(this.props.position*15)) } } componentWillReceiveProps (nextProps){ this.initialSize(nextProps); } componentDidMount() { this.props.onRef(this) } componentWillUnmount() { this.props.onRef(undefined) } initialSize(props){ Animated.parallel([ Animated.timing(this.state.left, { toValue: (Dimensions.get('window').width/2)-(150-(props.position*7.5)), duration: animationDuration }), Animated.timing(this.state.top, { toValue: (Dimensions.get('window').height/2)-140-(props.position*15), duration: animationDuration }), Animated.timing(this.state.height, { toValue: 300, duration: animationDuration }), Animated.timing(this.state.width, { toValue: 300-(props.position*15), duration: animationDuration }), ]).start(); } reject(){ Animated.parallel([ Animated.timing(this.state.top, { toValue: Dimensions.get('window').height-20, duration: animationDuration }), Animated.timing(this.state.height, { toValue: 3, duration: animationDuration }), Animated.timing(this.state.width, { toValue: 300-(this.props.position*15)+50, duration: animationDuration }), ]).start(); } accept(){ Animated.parallel([ Animated.timing(this.state.left, { toValue: Dimensions.get('window').width-50, duration: animationDuration }), Animated.timing(this.state.top, { toValue: 20, duration: animationDuration }), Animated.timing(this.state.height, { toValue: 20, duration: animationDuration }), Animated.timing(this.state.width, { toValue: 20, duration: animationDuration }), ]).start(); } maximize(){ if(this.props.position==1){ Animated.parallel([ Animated.timing(this.state.left, { toValue: 0, duration: animationDuration }), Animated.timing(this.state.top, { toValue: 0, duration: animationDuration }), Animated.timing(this.state.height, { toValue: Dimensions.get('window').height, duration: animationDuration }), Animated.timing(this.state.width, { toValue: Dimensions.get('window').width, duration: animationDuration }), ]).start(); this.setState({maximized:true}); } } minimize(){ this.initialSize(this.props); this.setState({maximized:false}); } render(){ return ( <Animated.View style={[styles.container,{top:this.state.top,left: this.state.left,height:this.state.height,width:this.state.width}]}> <TouchableWithoutFeedback onPress={this.maximize.bind(this)}> <View style={[styles.head,{backgroundColor: this.props.headColor}]}> {this.state.maximized && <View style={styles.containerCloseButton}> <TouchableWithoutFeedback onPress={this.minimize.bind(this)}> <Text style={styles.closeButton}>X </TouchableWithoutFeedback> </View> } </View> </TouchableWithoutFeedback> <View style={styles.body}> <View style={styles.bodyContents}> <View style={styles.circle} /> <View style={styles.text} /> <View style={styles.text} /> </View> </View> </Animated.View> ); } }; const styles = StyleSheet.create({ container: { position: "absolute", }, bodyContents: { flexDirection: "column", flex: 0.8, justifyContent: "space-around", alignItems: "center" }, text: { height: 30, borderRadius: 5, width: 100, backgroundColor: "#d2d2d2" }, circle: { borderRadius: 50, backgroundColor: "#d2d2d2", height: 50, width: 50, marginTop: 20 }, head: { flex:1 }, body: { flex:4, borderRadius: 4, borderWidth: 0.5, borderColor: "#d6d7da", backgroundColor: "#F7F7F7" }, containerCloseButton:{ left: Dimensions.get('window').width-30, top: 20 }, closeButton:{ fontSize: 30, color: '#FFF' } });

您可以让自己很舒服地向我询问有关代码的任何信息。 最诚挚的问候。