React:Cross-Platform Application Development with React Native
上QQ阅读APP看书,第一时间看更新

LocationPin

In this section, we will focus on building the pinpointing to the center of the map to visually confirm the pickup location. This pin also contains a button, which can be used to trigger a pickup request:

/** * src/components/LocationPin.js ** */

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

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

export default class LocationPin extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.banner}>
          <Text style={styles.bannerText}>SET PICKUP LOCATION</Text>
<TouchableOpacity
            style={styles.bannerButton}
            onPress={this.props.onPress}
          >
            <Text style={styles.bannerButtonText}>{'>'}</Text>
          </TouchableOpacity>
        </View>
        <View style={styles.bannerPole} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
top: height / 2 - 60,
    left: width / 2 - 120,
  },
  banner: {
flexDirection: 'row',
    alignSelf: 'center',
    justifyContent: 'center',
    borderRadius: 20,
    backgroundColor: '#333',
    padding: 10,
    paddingBottom: 10,
shadowColor: '#000000',
    shadowOffset: {
      width: 0,
      height: 3,
    },
    shadowRadius: 5,
    shadowOpacity: 1.0,
  },
  bannerText: {
    alignSelf: 'center',
    color: 'white',
    marginRight: 10,
    marginLeft: 10,
    fontSize: 18,
  },
  bannerButton: {
    borderWidth: 1,
    borderColor: '#ccc',
    width: 26,
    height: 26,
    borderRadius: 13,
  },
  bannerButtonText: {
    color: 'white',
    textAlign: 'center',
backgroundColor: 'transparent',
    fontSize: 18,
  },
  bannerPole: {
    backgroundColor: '#333',
    width: 3,
    height: 30,
    alignSelf: 'center',
  },
});

This component is again very light in terms of functionality, but has a lot of custom style. Let's dive into some of the style details.

flexDirection

By default, React Native and Flexbox stack elements vertically:

flexDirection

For the banner in our pin, we want to stack every element horizontally after each other as follows:

flexDirection

This can be achieved by adding the following styles to the containing element flexDirection: 'row'. The other valid options for flexDirection are:

  • row-reverse
  • column (default)
  • column-reverse

Dimensions

One of the first lines of code in this component extracts the height and the width from the device into two variables:

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

Obtaining the height and width of the device enables us developers to absolute position some elements being confident they will show properly aligned. For example, we want the banner of our pin to be aligned in the center of the screen, so it points to the center of the map. We can do this by adding {top: (height/2), left: (width/2)} to the banner style in our style sheet. Of book, that would align the upper-left corner, so we need to subtract half the size of the banner to each property to ensure it gets centered in the middle of the element. This trick can be used whenever we need to align an element that is not relative to any other in the components tree although it is recommended to use relative positioning when possible.

Shadows

Let's set focus on our banner's style, specifically on the shadows properties:

banner: {
  ...
  shadowColor: '#000000',
  shadowOffset: {
    width: 0,
    height: 3
  },
  shadowRadius: 5,
  shadowOpacity: 1.0
}

In order to add a shadow to a component, we need to add four properties:

  • shadowColor: This adds the hexadecimal or RGBA value of the color we want for our component
  • shadowOffset: This shows how far we want our shadow to be casted
  • shadowRadius: This shows the value of the radius in the corner of our shadow
  • shadowOpacity: This shows how dark we want our shadow to be

That's it for our LocationPin component.