Search code examples
react-nativereact-native-stylesheet

RN: Align items in a row both left and right


Here is RN (0.59) component using sectionList to display an event name in a row. The renderItem renders 3 items in a row, starting with a head image (left image), then event name, ending with another head image (right image).

render() {
       return (
        <View  style={styles.container}>
          <SectionList
              sections={this.state.activeEvents} 
              renderItem={({item, section}) => {return (
                                                <View style={styles.container}>
                                                  <Image style={styles.image} source={{uri: item.image}}/>
                                                  <TouchableOpacity onPress={() => {this._onPress(item.id)}} >
                                                    <Text style={styles.item} key={item.id}>{item.name}</Text>
                                                  </TouchableOpacity>
                                                  <View style={styles.containerRight}>
                                                    <Image style={styles.image} source={{uri: "https://bootdey.com/img/Content/avatar/avatar1.png"}}/>
                                                  </View>
                                                </View>)}}

              renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
              keyExtractor={(item, index) => item + index}
            />
        </View>
      ); 

      }

}

const styles = StyleSheet.create({
    container: {
      flex: 1,
      paddingTop: 22,
      paddingVertical: 12,
      flexDirection: 'row',
      alignItems: 'flex-start',
      flexDirection: 'row',
      alignItems: 'flex-start'
    },
    containerRight: {
      flex: 1,
      paddingTop: 22,
      paddingVertical: 12,
      flexDirection: 'row',
      alignItems: 'flex-end',
      flexDirection: 'row',
      alignItems: 'flex-end' 
    },
    sectionHeader1: {
      paddingTop: 2,
      paddingLeft: 10,
      paddingRight: 10,
      paddingBottom: 2,
      fontSize: 14,
      fontWeight: 'bold',
      backgroundColor: 'rgba(247,247,247,1.0)',
    },
    sectionHeader:{
      backgroundColor : '#64B5F6',
      fontSize : 20,
      padding: 5,
      color: '#fff',
      fontWeight: 'bold'
   },
    item: {
      padding: 10,
      fontSize: 18,
      height: 44,
    },
    image:{
      width:45,
      height:45,
      borderRadius:20,
      marginLeft:20
    },
    imageRight:{
      width:45,
      height:45,
      borderRadius:20,
      marginRight:20
    },
  }) 

Here is the output of the above render:

enter image description here

All row items (left image, event name, right image) should be vertically aligned. The left image and event name are properly aligned to the left side of the row, but the right image should be horizontally aligned to the right side of the row. How can I change my jsx and styling to achieve this UI?


Solution

  • I suppose you'd like something like this:

    You can accomplish this by adding a big container for the row and adding:

    justifyContent: 'space-between'

    Wrap the source code and fix it to your needs or see a working snack: snack.expo.io/@abranhe/stackoverflow-56638124

    import React, { Component } from 'react';
    import {
      SectionList,
      Text,
      Image,
      View,
      TouchableOpacity,
      StyleSheet,
    } from 'react-native';
    
    const events = [
      {
        title: '2019-04-03',
        data: [
          {
            name: 'Event 1',
            imageLeft: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar1.png',
            },
            imageRight: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar2.png',
            },
          },
          {
            name: 'Event 2',
            imageLeft: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar3.png',
            },
            imageRight: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar4.png',
            },
          },
        ],
      },
      {
        title: '2019-04-07',
        data: [
          {
            name: 'Event 2',
            imageLeft: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar5.png',
            },
            imageRight: {
              uri: 'https://bootdey.com/img/Content/avatar/avatar6.png',
            },
          },
        ],
      },
    ];
    
    export default class App extends Component {
      onPressEvent = id => {
        alert(eventName);
      };
    
      render() {
        return (
          <SectionList
            style={styles.selectionList}
            sections={events}
            renderItem={({ item: event, section }) => {
              return (
                <View style={styles.container}>
                  <View style={styles.content}>
                    <Image style={styles.image} source={event.imageLeft} />
                    <TouchableOpacity onPress={() => this.onPressEvent(event.name)}>
                      <Text>{event.name}</Text>
                    </TouchableOpacity>
                    <Image style={styles.image} source={event.imageRight} />
                  </View>
                </View>
              );
            }}
            renderSectionHeader={({ section }) => (
              <Text style={styles.sectionHeader}>{section.title}</Text>
            )}
            keyExtractor={(item, index) => item + index}
          />
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        paddingTop: 22,
      },
      content: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center',
      },
      selectionList: {
        marginTop: 22,
      },
      sectionHeader: {
        backgroundColor: '#64B5F6',
        fontSize: 20,
        padding: 5,
        color: '#fff',
        fontWeight: 'bold',
      },
      image: {
        width: 45,
        height: 45,
        borderRadius: 20,
        margin: 20,
      },
    });
    

    If you have any questions let me know!

    Update after a comment by the question author

    It looks close. But I was not able to do any test since my post because of an error related to AndroidX. Can you move the event.name to the left right after the left image? For the icon on the right, it may be changed to a hamburger menu

    It would be easy just wrap the left icon into a

    <View>
      <Image/>
      <Text>Some Text</Text>
    </View>
    

    then it would look like this:

    See the updated snack: snack.expo.io/@abranhe/stackoverflow-56638124-updated

    <View style={styles.leftIcon}>
      <Image style={styles.image} source={event.imageLeft} />
      <TouchableOpacity onPress={() => this.onPressEvent(event.name)}>
        <Text>{event.name}</Text>
      </TouchableOpacity>
    </View>
    

    And then add the following style:

    leftIcon: {
      flexDirection: 'row',
      justifyContent: 'center',
      alignItems: 'center',
    }