使用NavigationCardStack时如何设置标题的对齐方式?

时间:2016-11-09 22:59:13

标签: react-native alignment

我已按照示例here进行操作,然后尝试添加标题。我设法获得了显示密钥和后退导航的标题,以显示堆栈中前一张卡的密钥。

我遇到的问题是我无法弄清楚如何对齐后退动作的图标和文字。如果我将flow: 1添加到样式中,那么它就会消失。如果我添加任何对齐选项,则没有任何变化。 Funnilly足够了,改变flexDirection的工作原理,以及改变左右边距。

现在,图标和文字似乎沿着上边缘对齐。

我不确定它是文本问题还是容器大小问题。请注意,我在文本上尝试textAlignVertical: 'center'无济于事。

我该怎么做?

Example of alignment problem in header

有谁知道如何解决?

有问题的代码:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 *
 * Refer: http://facebook.github.io/react-native/docs/navigation.html
 */

import React, { Component } from 'react';

import { 
  AppRegistry,
  NavigationExperimental, 
  PixelRatio, 
  ScrollView, 
  StyleSheet, 
  View,
  Text, 
  TouchableHighlight 
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons'

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
  Header: NavigationHeader,
} = NavigationExperimental;

export default class BleedingEdgeApplication extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      navigationState: {
        index: 0,
        routes: [{key: 'Home'}]
      }
    }

    this._onNavigationChange = this._onNavigationChange.bind(this);
  }


  _onNavigationChange(type) {
    // extract the navigation state from the current state
    let {navigationState} = this.state;

    switch(type) {
      case 'push':
        // push a new route, which in our case is an object with a key value
        const route = {key: ':' + Date.now()};

        // use the push reducer provided by NavigationStateUtils
        navigationState = NavigationStateUtils.push(navigationState, route);
        break;

      case 'pop':
        // Pop the current route using the pop reducer
        navigationState = NavigationStateUtils.pop(navigationState);
        break;
    }

    if (this.state.navigationState !== navigationState) {
      this.setState({navigationState});
    }
  }

  render() {
    return (
      <MyVerySimpleNavigator
        navigationState={this.state.navigationState}
        onNavigationChange={this._onNavigationChange}
        onExit={this._exit}
        />
    );
  }
}

class TappableRow extends Component {
  render () {
    return (
      <TouchableHighlight
        style={styles.row}
        underlayColor="#D0D0D0"
        onPress={this.props.onPress}>
        <Text style={styles.buttonText}>
          {this.props.text}
        </Text>
      </TouchableHighlight>
    );
  }
}

class MyVeryComplexScene extends Component {
  render() {
    return (
      <ScrollView style={styles.scrollView}>
        <Text style={styles.row}>
          Route: {this.props.route.key}
        </Text>
        <TappableRow 
          text="Tap me to load the next scene"
          onPress={this.props.onPushRoute}
          />
        <TappableRow 
          text="Tap me to go back"
          onPress={this.props.onPopRoute}
          />
      </ScrollView>
    );
  }
}

class MyVerySimpleNavigator extends Component {
  constructor(props, context) {
    super(props, context);

    this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
    this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');

    this._renderScene = this._renderScene.bind(this);
    this._renderHeader = this._renderHeader.bind(this);
    this._renderLeftHeader = this._renderLeftHeader.bind(this);
  }

  render() {
    return (
      <NavigationCardStack
        onNavigateBack={this._onPopRoute}
        navigationState={this.props.navigationState}
        renderScene={this._renderScene}
        renderHeader={this._renderHeader}
        style={styles.navigator}
        />
    );
  }

  _renderHeader(sceneProps) {
    return (
      <NavigationHeader
        {...sceneProps}
        renderTitleComponent={() => (
          <NavigationHeader.Title>
            {sceneProps.scene.route.key}
          </NavigationHeader.Title>
        )}
        renderLeftComponent={this._renderLeftHeader}
        />
    );
  }

  _renderLeftHeader(sceneProps) {
    if(sceneProps.scene.index > 0) {
      return (
        <TouchableHighlight onPress={this._onPopRoute}>
          <View style={styles.backView}>
            <Icon style={styles.navBarIcon} name='ios-arrow-back' size={27} />
            <Text style={styles.backText}>{sceneProps.scenes[sceneProps.scene.index - 1].route.key}</Text>
          </View>
        </TouchableHighlight>
      );
    }

    return (
      <TouchableHighlight>
        <View style={styles.backView}>
          <Icon style={styles.navBarIcon} name='ios-menu' size={27} />
        </View>
      </TouchableHighlight>
    );

  }

  _renderScene(sceneProps) {
    return (
      <MyVeryComplexScene
        route={sceneProps.scene.route}
        onPushRoute={this._onPushRoute}
        onPopRoute={this._onPopRoute}
        onExit={this.props.onExit}
        />
    );
  }
}

const styles = StyleSheet.create({
  navigator: {
    flex: 1,
  },
  scrollView: {
    marginTop: 64
  },
  row: {
    padding: 15,
    backgroundColor: 'white',
    borderBottomWidth: 1 / PixelRatio.get(),
    borderBottomColor: '#CDCDCD',
  },
  backView: {
//    flex: 2,
    height: 50,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'flex-start',
  },
  backText: {
    fontSize: 12,
    textAlign: 'left',
  },
  backChevron: {

  },
  navBarIcon: {
    color: '#1d1d1d',
    marginLeft: 8,
    marginRight: 8,
    justifyContent: 'center',
  },
  rowText: {
    fontSize: 17,
  },
  buttonText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

AppRegistry.registerComponent('BleedingEdgeApplication', () => BleedingEdgeApplication);

我应该注意到我正在使用React Native Vector Icons。这需要将Ionicon字体从字体的目录复制到ios项目中并从xcode中重建。

1 个答案:

答案 0 :(得分:0)

问题不是将样式应用于<TouchableHighlight> flex: 1。这使得组件占用整个空间,让我在保持按钮和文本的<View>上使用flex和alignItems。这使整个造型更加整洁。

最大的困惑是理解<NavigationHeader>中的各种标题组件都是独立的,因此左右都是标题的单独渲染选项。

解决方案如下: enter image description here

代码正常工作(带有彩色背景以显示组件):

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 *
 * Refer: http://facebook.github.io/react-native/docs/navigation.html
 */

import React, { Component } from 'react';

import { 
  AppRegistry,
  NavigationExperimental, 
  PixelRatio, 
  ScrollView, 
  StyleSheet, 
  View,
  Text, 
  TouchableHighlight 
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons'

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
  Header: NavigationHeader,
} = NavigationExperimental;

export default class BleedingEdgeApplication extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      navigationState: {
        index: 0,
        routes: [{key: 'Home'}]
      }
    }

    this._onNavigationChange = this._onNavigationChange.bind(this);
  }


  _onNavigationChange(type) {
    // extract the navigation state from the current state
    let {navigationState} = this.state;

    switch(type) {
      case 'push':
        // push a new route, which in our case is an object with a key value
        const route = {key: ':' + Date.now()};

        // use the push reducer provided by NavigationStateUtils
        navigationState = NavigationStateUtils.push(navigationState, route);
        break;

      case 'pop':
        // Pop the current route using the pop reducer
        navigationState = NavigationStateUtils.pop(navigationState);
        break;
    }

    if (this.state.navigationState !== navigationState) {
      this.setState({navigationState});
    }
  }

  render() {
    return (
      <MyVerySimpleNavigator
        navigationState={this.state.navigationState}
        onNavigationChange={this._onNavigationChange}
        onExit={this._exit}
        />
    );
  }
}

class TappableRow extends Component {
  render () {
    return (
      <TouchableHighlight
        style={styles.row}
        underlayColor="#D0D0D0"
        onPress={this.props.onPress}>
        <Text style={styles.buttonText}>
          {this.props.text}
        </Text>
      </TouchableHighlight>
    );
  }
}

class MyVeryComplexScene extends Component {
  render() {
    return (
      <ScrollView style={styles.scrollView}>
        <Text style={styles.row}>
          Route: {this.props.route.key}
        </Text>
        <TappableRow 
          text="Tap me to load the next scene"
          onPress={this.props.onPushRoute}
          />
        <TappableRow 
          text="Tap me to go back"
          onPress={this.props.onPopRoute}
          />
      </ScrollView>
    );
  }
}

class MyVerySimpleNavigator extends Component {
  constructor(props, context) {
    super(props, context);

    this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
    this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');

    this._onOpenSideNav = this._onOpenSideNav.bind(this);

    this._renderScene = this._renderScene.bind(this);
    this._renderHeader = this._renderHeader.bind(this);
    this._renderLeftHeader = this._renderLeftHeader.bind(this);
  }

  render() {
    return (
      <NavigationCardStack
        onNavigateBack={this._onPopRoute}
        navigationState={this.props.navigationState}
        renderScene={this._renderScene}
        renderHeader={this._renderHeader}
        style={styles.navigator}
        />
    );
  }

  _renderHeader(sceneProps) {
    return (
      <NavigationHeader
        {...sceneProps}
        style={styles.navHeader}
        renderTitleComponent={() => (
          <NavigationHeader.Title style={styles.navheadertitle}>
            <Text style={styles.headerTitle}>
              {sceneProps.scene.route.key}
            </Text>

          </NavigationHeader.Title>
        )}
        renderLeftComponent={this._renderLeftHeader}
        />
    );
  }

  _renderLeftHeader(sceneProps) {
    if(sceneProps.scene.index > 0) {
      return (
        <TouchableHighlight onPress={this._onPopRoute} style={styles.headerBackTouchableHighlight}>
          <View style={styles.headerBackView}>
            <Icon style={styles.headerIcon} name='ios-arrow-back' size={27} />
            <Text style={styles.headerBackText}>{sceneProps.scenes[sceneProps.scene.index - 1].route.key}</Text>
          </View>
        </TouchableHighlight>
      );
    }

    return (
      <TouchableHighlight onPress={this._onOpenSideNav} style={styles.headerBackTouchableHighlight}>
        <View style={styles.headerBackView}>
          <Icon style={styles.headerIcon} name='ios-menu' size={27} />
        </View>
      </TouchableHighlight>
    );

  }

  _renderScene(sceneProps) {
    return (
      <MyVeryComplexScene
        route={sceneProps.scene.route}
        onPushRoute={this._onPushRoute}
        onPopRoute={this._onPopRoute}
        onExit={this.props.onExit}
        />
    );
  }
  _onOpenSideNav() {
    return null;
  }

}

const styles = StyleSheet.create({
  navigator: {

  },
  navHeader: {
    backgroundColor: 'red',
  },
  navheadertitle: {
    backgroundColor: '#00ff0099',
    flex: 3
  },
  headerTitle: {
    color: '#ffffff',
    backgroundColor: 'blue',
  },
  headerBackTouchableHighlight: {
    backgroundColor: 'purple',
    flex: 1,
  },
  headerBackView: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'darkgreen',
  },
  headerBackText: {
    fontSize: 14,
    textAlign: 'left',
    color: '#ffffff',
  },
  headerIcon: {
    color: '#ffffff',
    marginLeft: 8,
    marginRight: 8,
    justifyContent: 'center',
  },
  scrollView: {
    marginTop: 64
  },
  row: {
    padding: 15,
    backgroundColor: 'white',
    borderBottomWidth: 1 / PixelRatio.get(),
    borderBottomColor: '#CDCDCD',
  },
  rowText: {
    fontSize: 17,
  },
  buttonText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

AppRegistry.registerComponent('BleedingEdgeApplication', () => BleedingEdgeApplication);