Giter Site home page Giter Site logo

idibidiart / react-native-responsive-grid Goto Github PK

View Code? Open in Web Editor NEW
380.0 13.0 42.0 389 KB

Bringing the Web's Responsive Design to React Native

License: Other

JavaScript 100.00%
react-native responsive responsive-layout grid layout orientation-changes responsive-design universal flexbox react ios android

react-native-responsive-grid's Introduction

NPM

Backers on Open Collective Sponsors on Open Collective

React Native Library for Responsive and Universal Apps

Pending Proposals

All issues that are not bugs are appropriately labeled and closed.

For now we have three kinds of non-bug issues that are open:

Install

In your project folder, yarn add react-native-responsive-grid

*For best results, use React Native 0.50 or later

Predictable Responsive Layout

This grid is based on row and column components that can be nested in an alternating pattern to build a responsive and adaptive 'tree of Views' of any shape and depth. It eschews complicated Flexbox-based size constraints in favor of simple percentage-based size constraints. And it does so while using Flexbox-based vertical and horizontal alignment constraints.

A Column may contain one or more Rows, each of which may contain one or more Columns, each of which may contain one or more Rows, and so on. Both Rows and Columns can be styled using predictable, percentage-based dimensions and, in case of Columns, percentage-based horizontal offset.

Rows can be aligned inside Columns, vertically (along main axis,) and aligned and stretched horizontally (along cross axis.) Columns can be aligned inside Rows, horizontally (along main axis), and and aligned and stretched vertically (along cross axis.) Additionally, the lines created within a Row that wraps may be aligned and stretched vertically relative to a parent Column.

With these basic features, we can build the entire UI component tree (or an individual component's subtree) as a consistent, repeatable and recursive pattern, one that has predictable and dynamic --not only static-- responsiveness and the ability to trigger specific adaptive behavior.

When To Use Flexbox Sizing:

In some cases when having an absolutely sized view followed (vertically or horizontally) by a view that must take up the remaining space, we'll need to use a wrapping grid element -- Column (to wrap vertical layout) or Row (to wrap horizontal layout) -- with style={{flex: 1}} and same on the Flex sized element that it wraps along with the absolutely sized element. However, such mixing of absolute and Flex sizing is not recommended as it won't lead to a fully responsive UI layout.

The only other reason to use Flexbox grow/shrink sizing with this Grid is for grow-and-shrink-in-place UI (aka "squishy" UI) where elements shrink and grow in elastic fashion and relative to each other instead of undergoing dynamic layout change and/or staying in proportion to screen width.

Examples

You may use this grid to build responsive 2D layouts that maintain their relative proportions, change their basic structure in a predictable way and dynamically decide what content to display, based on screen size, aspect ratio, and orientation.

>> universal pinterest layout <<

>> universal tiles demo <<

>> aspectRatio demo <<

>> responsive break points demo <<

>> FlatList Demo <<

The demos in the videos above show some of the possibilities, but this grid is capable of more complex responsive and adaptive behavior.

Example 1: Universal, Responsive Pinterest Layout

This examples showcases 2-dimensional Constraint-Based Layout using a custom layout in a few lines of code. Flexbox fails us here in that it does not support a 2-dimensional constraint layout. This is precisely why React Native needs native support for display:'grid' Until then you may use this grid with your own constraint-based layout. This example shows a simplified Pinterest-like layout. You may extend it to build a masonry effect using a box packing algorithm and Flexbox's 1-dimensional constraint-based elastic layout. One thing this grid is not designed to do is to implement transitions but it can be forked and extended to do that (would happy take a PR.)

Source Code for Example 1

Example 2: Reponsive Tiles for Universal Apps

This examples showcases the grid's 1-dimensional Constraint-Based Layout using Flexbox wrapping behavior.

The problem it solves is how to make a tiled screen layout that looks consistent across all screen sizes and aspect ratios, It involves the following:

  1. How to size tiles such that they change size relative to the size of the screen as well as retain their shape (width/height aspect ratio)

  2. How do we hide/show tiles on demand and fill the void left by hidden tiles.

The goal is how to do the above in an elegant and declarative way that allows the average user to work without all the tedious implementation details of doing it in row Flexbox and JS.

This example also showes how to use alignLines='stretch' for wrapped row content to have the wrapped lines fill the whole screen. It's the right way to partition a Row vertically in 1/n tall lines where n is the number of wrapping-stacked fullWidth columns.

Source Code for Example 2

Example 3: Selecting an image with the right aspect ratio

In this demo, the grid picks the image with the closest aspect ratio to the device aspect ratio, dynamically, taking into account the current device orientation. The images themselves must be sized and cropped by the designer so that they match the common device aspect ratios (see below) while also showing the part of the image that the designer intends to show for each aspect ratio. Since there could be many aspect ratios that correspond to different devices we should have multiple such images (and, optionally, their rotated versions.)

The following table maps some common device aspect ratios to the ratio of width/height of devices known to this developer, for both landscape and portrait device orientations. The physical device aspect ratio does not change with device rotation (i.e. a device with 16:9 aspect ratio does not become one with a 9:16 aspect ratio when it's rotated, although it does mathematically), but since the width and height get flipped when changing orientation from portrait to lanscape and vice versa, we need to have two images per each physical device aspect ratio, one for portrait mode and the other for landscape. However, if our app only supports portrait or landscape mode then we only need to have the one corresponding to that orientation.

Aspect Ratio Width Height Width/Height Ratio (landscape) Devices
'16:9' 568 320 1.77 iPhone 5
'16:9' 667 375 1.77 iPhone 6 & 7
'16:9' 736 414 1.77 iPhone 6 Plus & 7 Plus
'16:10' ? ? 1.6 ?
'3:2' 480 320 1.5 iPhone 4
'4:3' 1024 768 1.33 iPad Mini, iPad Air and small iPad Pro
'4:3' 1366 1024 1.33 Large iPad Pro
'1:1' 1 ? ? ?
Aspect Ratio Width Height Width/Height Ratio (portrait) Devices
'16:9' 320 568 0.56 iPhone 5
'16:9' 375 667 0.56 iPhone 6 & 7
'16:9' 414 736 0.56 iPhone 6 Plus & 7 Plus
'16:10' ? ? 0.625 ?
'3:2' 320 480 0.66 iPhone 4
'4:3' 768 1024 0.75 iPad Mini, iPad Air and small iPad Pro
'4:3' 1024 1366 0.75 Large iPad Pro
'1:1' 1 ? ? ?
<Grid>{(state, setState) => (
    <Row fullHeight aspectRatio={{ratio: '3:2', orientation: "portrait"}}>
        <Image source={require('./assets/homepage hero-3-2-portrait.jpg')} style={styles.homeImage}></Image>
    </Row>

    <Row fullHeight aspectRatio={{ratio: '3:2', orientation: "landscape"}}>
        <Image source={require('./assets/homepage hero-3-2-landscape.jpg')} style={styles.homeImage}></Image>
    </Row>

    <Row fullHeight aspectRatio={{ratio: '16:9', orientation: "portrait"}}>
        <Image source={require('./assets/homepage hero-16-9-portrait.jpg')} style={styles.homeImage}></Image>
    </Row>

    <Row fullHeight aspectRatio={{ratio: '16:9', orientation: "landscape"}}>
        <Image source={require('./assets/homepage hero-16-9-landscape.jpg')} style={styles.homeImage}></Image>
    </Row>
  )}
</Grid>

Example 4: Responsive Break Points (Row Wrapping)

A more basic example of he grid's 1-Dimensional Constraint-Based Layout using Flexbox.

In the second demo, the grid folds columns in rows based on the screen-device-depebdent xxSize prop provided on the column (which can be percentage based, e.g. smSize, or point based, e.g. smSizePoints. This means that different break points can be supplied for the different screen sizes in both absolute and relative terms. This example demonstrates how to get Row content (e.g. child Columns) to wrap at certain break points (which can be supplied per screen width)

The following are the preset screen widths (in points) at which breaks maybe specified (where row wraps columns within it into new horozintal lines):

  • SMALL_Width: 375 (0-375)

  • MEDIUM_Width: 767 (376-767)

  • LARGE_Width: 1023 (768-1023)

  • XLARGE_Width: 1024+

  • SMALL_Height: 667 (0-667)

  • MEDIUM_Height: 1023 (668-1023)

  • LARGE_Height: 1365 (1024-1365)

  • XLARGE_Height: 1366+

The preset values may be overridden with setBreakPoints which merges the parameter object with the defaults. Each cutoff specifies the upper end for that range. XLARGE_Width is inferred from anything above LARGE_Width. BreakPoints should be set early in the app such as in index.js. An example overriding the SMALL_Width, MEDIUM_Width, and LARGE_Width break points:

import { setBreakPoints } from 'react-native-responsive-grid';

setBreakPoints({
  SMALL_Width: 414,
  MEDIUM_Width: 600,
  LARGE_Width: 1024
})
  <Row  style={{paddingTop: '6%', paddingBottom: '6%', backgroundColor: 'white', borderBottomColor: 'lightgray', borderBottomWidth: 1}}>
      <Col size={80} offset={6}>
        <Row>
          <Col size={50} smSize={100}>      
            <Text style={{fontSize: 15, color: '#BD1206', fontWeight:'bold'}}>March 9, 2017</Text>
            <Row>
              <Col size={5}>
                <FontAwesome name='cutlery' size={17} color='gray'/>
              </Col>
              <Col size={60} offset={2.5}>
                <Text style={{fontSize: 12, color: 'gray', lineHeight: 20}}>TAKEOUT ORDER</Text>
              </Col>
            </Row>
          </Col>
          <Col size={50} smSize={100}>
            <Text style={{fontSize: 16, color: '#0a0a0a'}}>Double Cheese Burger</Text>                                                                          
          </Col>
        </Row>
      </Col>
      <Col size={14} offset={-6} hAlign='right'>
            <MaterialIcons name="keyboard-arrow-right" size={28} color="#BD1206" style={{left: 5}} />
      </Col>
  </Row>

Example 5: FlatList + Row & Column Wrapping

FlatList is a virtualized replacement for React Native's old ListView component. Using FlatList as a container is supported by this grid. This example also demonstrate wrapping Column content based on screen size. See ('size' prop under the Props section.) It also demonstrates who to wrap Row content (e.g. child columns) based on screen size (also see Example 4)

import React, { Component } from 'react';
import {
  FlatList,
  Text,
  ScrollView
} from 'react-native';

import { Row, Column as Col, Grid} from 'react-native-responsive-grid'
import { MaterialIcons } from '@expo/vector-icons';
import faker from 'faker';

let j = 0
const randomUsers = (count = 10) => {
  const arr = [];
  for (let i = 0; i < count; i++) {
    arr.push({
      key: faker.random.uuid(),
      date: faker.date.weekday(),
      name: faker.name.firstName(),
      job: faker.name.jobTitle(),
      index: j++
    })
  }
  return arr
}

export default class Home extends Component {
  state = {
    refreshing: false,
    data: randomUsers(10),
  };

  onEndReached = () => {
    const data = [
        ...this.state.data,
        ...randomUsers(10),
      ]

    this.setState(state => ({
      data
    }));
  };

  onRefresh = () => {
    this.setState({
      data: randomUsers(10),
    });
  }

  render() {
    return (
        <FlatList
          data={this.state.data}
          initialNumToRender={10}
          onEndReachedThreshold={1}
          onEndReached={this.onEndReached}
          refreshing={this.state.refreshing}
          onRefresh={this.onRefresh}
          renderItem={
            ({ item }) => {
              return (
                <Row key={item.key} style={{paddingTop: '6%', paddingBottom: '6%', backgroundColor: 'white', borderBottomColor: 'lightgray', borderBottomWidth: 1}}>
                  <Col size={80} offset={6} >
                    <Row>
                      <Col size={60} smSize={100}>
                        <Text style={{fontSize: 15, color: '#BD1206', fontWeight:'bold'}}>{String(item.date)}</Text>
                        <Row>
                          <Col size={10}>
                            <MaterialIcons name='person' size={17} color='gray'/>
                          </Col>
                          <Col smSize={60} size={87.5} offset={2.5}>
                            <Text style={{fontSize: 12, color: 'gray', lineHeight: 20}}>{item.job}</Text>
                          </Col>
                        </Row>
                      </Col>
                      <Col size={40} smSize={100}>
                        <Text style={{fontSize: 16, color: '#0a0a0a'}}>{item.name}</Text>
                      </Col> 
                    </Row>    
                  </Col>
                  <Col size={8} offset={-6} hAlign='right'>
                        <Text>{item.index}</Text>
                  </Col>
                </Row>
              )
            }}
        />
    )
  }
}

Components

  • Row: Flexbox View with flexDirection set to 'row' with convenient props and dynamic behavior.

  • Col: Flexbox View with flexDirection set to 'column' with convenient props and dynamic behavior.

  • Grid: an optional, stateful, component with style={{flex: 1}}. The Grid uses the children-as-funnction pattern and passes its state to its children, and allows state to be declared in its props, which will have the latest screen and grid info after orientation changes. It also passes it's render-triggering async setState method to its children.

Important:

Grid component is required if you need to re-run the render() function in response to orientation change (many examples here)

Grid component is also required if you use aspectRatio prop on Rows or Columns since the selection of content of the closest aspect ratio requires re-running the render function after orientation change.

Below is an example:

export const Home = () => (
  <Grid state={
    {
      someState: 'yyz', 
      anotherState: 'abc'
    }}>
  {({state, setState}) => (
       {/*  possibly other JSX here */}
        <Col fullWidth style={{backgroundColor: 'lightgray'}}> 
          <ScrollView removeClippedSubviews={true} >
            <Row fullHeight>
              {layout(state)}
            </Row>
          </ScrollView>
        </Col>
      )}
  </Grid>)

Utils

import { Row, Column as Col, ScreenInfo, Grid} from './grid'

ScreenInfo() This will return the following data:

{
  mediaSize: mediaSizeWidth,
  mediaSizeWidth,
  mediaSizeHeight, 
  width: SCREEN_WIDTH, 
  height: SCREEN_HEIGHT, 
  aspectRatio: {currentNearestRatio, currentOrientation}
}
  • mediaSize is one of sm, md, lg, xl screen width categories and is aliased to mediaSizeWidth
  • mediaSizeHeight is the same but for screen height. It's used for hiding/showing Rows wit hidden prop based on screen height category and for Row size props.

if sizeOnly is true it will drop aspectRatio and its 'nearest match' calculation (shaves a few ms)

Methods

Row and Column both have .hide() and .show() instance methods. The instance reference you get from a ref callback will have these methods. See Example #1 for usage.

Instance Variables

These are provided mainly for unit tests, except for componentInstance.hidden and componentInstance.shown which can be used to tell the state of the component.

Props

All props are case sensitive.

aspectRatio (see Example 3)

size may be supplied as prop to Column (width) or Row (height). This number defines the width of the column or height of a row as a percentage of its parent view's computed or explicit width or height, respectively.

smSize, mdSize, lgSize and xlSize are device-dependent size values that are applied to Columns (which map to width percent) and Rows (which map to height percent.) In addition to their utility in deciding the size of content based on screen size (width in case of Columns and height in case of Rows), they may are also used for defining column wrapping behavior based on screen size. For example, Columns in as Row will wrap if Row width becomes smaller at smaller screen sizes.

sizePoints may be supplied as prop to Column (which map to width points) or Row (which map to height points). This number defines the width of the column or height of a row as an asolute value in points.

smSizePoints, mdSizePoints, lgSizePoints, and xlSizePoints are like their percentage-based equivalents but use point values.

offset may be applied to Column. This number defines the marginLeft (or marginRight in csase of RTL mode) for the column as a percentage of its parent view's computed or explicitly set width. Offset values can also be negative. Default is 0.

smOffset, mdOffset, lgOffset and xlOffset are device-dependent offset values that are applied to columns.

offsetPoints, mdOffsetPoints, lgOffsetPoints, and xlOffsetPoints are like their percentage-based equivalents (i.e. applied to Column to produce offset) but use value in points instead of value in percent.

Using offset values in RTL mode moves things from right to left. Using them in normal LTR mode moves things from left to right. It's pretty normal to expect that. If you're working in both directions, this makes offsets more useful than using marginLeft or marginRight directly.

Specifying an offset value in normal LTR mode means marginLeft (if specified in style prop) will be overwritten by offset value. However, marginRight (if specified in style prop) will not be overwritten by the offset value. Specifying offset value in RTL mode means marginRight (if specified in style prop) will be overwritten by offset value. However, marginLeft (if specified in style prop) will not be overwritten by offset value.

smHidden, mdHidden, lgHidden and xlHidden - may be applied to Column or Row which tells the parent Row or Column, respectively, to hide the affected child Column or child Row based on the current width (for child Columns) or height (for child Rows) of the screen.

The screen-size-specific size and hidden props refer to the current screen width in case of Columns and current screen height in case of Rows, which changes with orientation. The offset props only apply to Columns so they refer to the current screen width.

The following are the device width (for Columns) and height (for Rows) thresholds for these props:

The preset values may be overridden with setBreakPoints which merges the parameter object with the defaults. Each cutoff specifies the upper end for that range. XLARGE_Width is inferred from anything above LARGE_Width. BreakPoints should be set early in the app such as in index.js. An example overriding the SMALL_Width, MEDIUM_Width, and LARGE_Width break points:

import { setBreakPoints } from 'react-native-responsive-grid';

setBreakPoints({
  SMALL_Width: 414,
  MEDIUM_Width: 600,
  LARGE_Width: 1024
})

vAlign may be supplied as prop to Column to vertically align the elements and/or rows within it. Possible values are: middle | center, top, bottom, space and distribute. Default is top.

vAlign may also be supplied as prop to Row to align the columns within it in the vertical direction. Possible values are: top, middle | center, bottom, baseline and stretch. Default is stretch.

hAlign may be supplied as prop to Row to align its child Columns and/or elements within it in the horizontal direction. Possible values are: center | middle, left, right, space and distribute. Default is left.

hAlign may also be supplied as prop to Column to align its child Rows and/or elements within it in the horizontal direction. Possible values are: center | middle, left, right, and stretch. Default is stretch.

rtl may be supplied as prop to Row to both reverse the order of columns (or elements) inside a row as well as to set hAlign to 'right.' This is useful for right-to-left layouts.

fullHeight may be supplied as prop to Row in place of size={100} or style={{height: '100%'}} -- note that Rows have 0 height and width by default, but a fullHeight Row inside of a fullWidth Column will have height and width of 100%

fullWidth may be supplied as prop to Column in place of size={100} or style={{width: '100%'}} -- note that Columns have 0 height and width by default, but a fullWidth Column inside of a fullHeight Row will have height and width of 100%

alignLines may be supplied as prop to Row to vertically align the wrapped lines within the Row (not to be confused with the items that are inside each line.) Possible values are: top, middle, bottom, space, distribute, stretch. (See section on Aligning Wrapped Lines within Rows)

alignSelf maybe supplied as prop to Row to override the hAlign prop of the parent Column for that Row. Possible values are: auto, left, right, center | middle, stretch

alignSelf maybe supplied as prop to Column to override the vAlign prop of the parent Row for that Column. Possible values are: auto, top, bottom, middle | center, stretch, baseline

noWrap may be supplied as prop to Row prevent child elements from wrapping.

Nesting

If you're nesting a column inside a row which is inside another column that is inside another row as below:

  <Row>
      <Col size={50}>
        <Row>
          <Col size={50}>
            <Text>
              This column is 25% of the outer view's width (or 25% of the screen width if
              the top level Row has no parent)
            </Text>
          </Col>
        </Row>
      </Col>
  </Row>

The nested column's size will be the column size value (size, sm, md, lg, xl) as a percentage of the width of the preceding column in the hierarchy .

This nested percentages model applies to offsets, too.

RTL Support

This is intended for right-to-left (RTL) layouts and apps that have their text in any of the following languages:

  • Arabic
  • Aramaic
  • Azeri
  • Dhivehi/Maldivian
  • Hebrew
  • Kurdish (Sorani)
  • Persian/Farsi
  • Urdu

Notice the reversed order of the Text relative to the physical order in the markup. Also notice that columns are justified as flex-end within the row and their content is rightAligned (except for the second column which is explicitly leftAligned to mimic the rightAligned behavior in normal ltr layout)

Normal LTR Markup

    <Row style={{paddingTop: '11%', paddingBottom: '4%', backgroundColor: '#f3f3f3', borderBottomColor: 'lightgray', borderBottomWidth: 1}}>
        <Col size={60} offset={6} >
          <Text style={{fontWeight: 'bold', fontSize: 18, color: 'black'}}>
          PREVIOUS ORDERS
          </Text>
        </Col>
        <Col size={30} hAlign='right'>
          <Text style={{ fontSize: 16, color: '#BD1206'}}>
            SEE ALL
          </Text>
          </Col>
    </Row>

RTL Markup

Notice the offset values work in RTL direction now. The addition of .7 offset is to mimic the fact that the left margin in the LTR layout is smaller than the right margin in that layout, whereas it's the opposite in the RTL direction. So the .7 offset is used in RTL layout instead of the 1 offset, so alignment is identical.

    <Row rtl style={{paddingTop: '11%', paddingBottom: '4%', backgroundColor: '#f3f3f3', borderBottomColor: 'lightgray', borderBottomWidth: 1}}>
        <Col size={60} offset={4} >
          <Text style={{fontWeight: 'bold', fontSize: 18, color: 'black'}}>
          PREVIOUS ORDERS
          </Text>
        </Col>
        <Col size={30} hAlign='left'>
          <Text style={{ fontSize: 16, color: '#BD1206'}}>
            SEE ALL
          </Text>
        </Col>
    </Row>

Utils

You may import ScreenInfo from grid and invoke inside of render() of your component to get current screen diemsnions and orientation.

Predictable, Dynamic Layout Behavior

Being able to readt to layout changes, including changes due to device rotation (for apps that allow it), is a key aspect of responsive design. This grid is designed to enable dynamic response to layout changes (see the demos at the start of this Readme)

Columns and Rows have position: 'relative' by default to keep them within the layout flow, but they can have position: 'absolute' specified in style prop, for overlays and such.

The Grid component is a stateful top-level component (at root, above ScrollView, ListView, FlatList et al but below a Modal and Drawer) Grid should not be inside another Grid and it is only needed if you wish to respond to orientation and layout changes by re-running the render() function. It uses the children-as-funnction pattern to pass its state, including its dimensions and any user-defined state, along with screen dimensions, to its children. The user may define Grid state in its props. The Grid also passes it's async render-causing setState method to its children.

More Examples

import {Column as Col, Row} from 'react-native-responsive-grid';

<Row>
    <Col smSize={50} mdSize={33.333} lgSize={25}>
        <Text>First Column</Text>
    </Col>
</Row>

In the example above, on a phone in portrait mode, the Column would take up 50% of the row's computed width. On a phone in landscape nmode or a normal tablet the Column would take up 33.333% of the row's width. On a big tablet the Column would take up 25% of the row's width.

import {Column as Col, Row} from 'react-native-responsive-grid';

<Row style={{height: 20}}>
  <Col smOffset={0} mdOffset={10} lgOffset={20} xlOffset={40}>
    <Text>test</Text>
  </Col>
</Row>

In the example above, the text "test" will move further to the right with larger screen sizes.

import {Column as Col, Row} from 'react-native-responsive-grid';

<Row>
    <Col smHidden>
        <Text>Column displayed when width is <= 480</Text>
    </Col>
    <Col mdHidden lgHidden xlHidden>
        <Text>Column displayed when width is > 480</Text>
    </Col>
</Row>

In the example above, the column and all of it's children will be hidden on small screens like phones, but it will appear on bigger screens like tablets. The size-prefixed 'hidden' props may be applied to columns. Hidden props are all booleans. They default to false.

More Examples

History

Before React Native v0.42 we didn't have a performant, declarative way of specifying percentage-based dimensions. Then came React Native v0.42 which gave us that ability. Since then several open source contributors have made responsive grids that take advantage of this new capability. This "grid" takes one of the simplest and most well-thought-out ones, namely, react-native-flexbox-grid (by @rundmt), and modifies it heavily to produce a simple yet powerful layout model that we can use to implement responsive and adaptive behavior.

Gridism

When I first made a grid I happened to be thinking of the innocence of trees and then this grid came into my mind and I thought it represented innocence, and I still do, and so I painted it and then I was satisfied. I thought, this is my vision. --Agnes Martin

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! šŸ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

react-native-responsive-grid's People

Contributors

asood123 avatar idibidiart avatar iroachie avatar kp666 avatar peacechen avatar skyblue avatar skylinezum avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-responsive-grid's Issues

Keeping state when Grid is unmounted (for nested Grids)

I've not used this grid in any project recently.

However, the fact that some of you are using it has prompted me to think more about extending its dynamics and patterns, with special thanks to @peacechen

Proposal to enable Nested Grids

The Grid component is responsible for encapsulating state and updating the children. Children can read state as well as setState on Grid allowing them to re-render the component tree. In addition, layout changes captured on the Grid component via the React Native onLayout event cause re-rendering of the Grid children with updated layout information.

The Grid component pattern was borrowed from a tweet by Tanner Lindsay and then I toyed with the idea of exposing lifecycle methods as props (that reference the lifecycle handlers) so that you can tell the Grid what to do when it mounts, unmounts, etc, just as Ryan Florence does in his Component component pattern (which is also based in part on what Tanner had originally shared) but realizing that when Grids are nested a child Grid may get unmounted in which case it will lose state, and when it loses state it will do everything you tell it to do in those life cycles starting from scratch, so if it had fetched some data in component did mount then that data will be gone (all state will be gone) when it's unmounted and it has to get that data again. More importantly, it will lose other state, like visual state. So I opted to keep the Grid as the root component and I had even introduced logic to prevent nesting of Grids (removed later)

To make a long story short, what I'm proposing is to store the state in an outer scope where each nested Grid has a lens into the part of global in-memory state that belongs to it. This way when a child Grid is unmounted it can check its state and rehydrate from it or updated it with live data when needed.

Just putting this out in case I'm missing something. I'll get to it at some point.

Also, happy to take PRs for any of the proposals.

vAlign for Row contains wrong enums

Using <Row vAlign="bottom">...</Row> displays a warning:

Warning: Failed prop type: Invalid prop vAlign of value bottom supplied to Row, expected one of ["stretch","middle","right","left"].

On closer inspection of the /src/component/Row.js code, it has:
62: vAlign: PropTypes.oneOf(['stretch', 'middle', 'right', 'left']),

which doesn't follow the Docs:

vAlign may also be supplied as prop to Row to align the columns within it in the vertical direction. Possible values are: top, middle, bottom, baseline and stretch. Default is top.

Fix, update enum list to:
62: vAlign: PropTypes.oneOf(['top', 'middle', 'bottom', 'baseline', 'stretch']),

Errors on Column 'fullWidth' and on vAlign['stretch']

There appears to be an issue in the source code

   // Column.js
   vAlign: PropTypes.oneOf(['space', 'distribute', 'middle', 'center', 'bottom', 'top']),
   fullWidtht: PropTypes.bool,

perhaps the following is correct,

   // Column.js
   vAlign: PropTypes.oneOf(['space', 'distribute', 'middle', 'center', 'bottom', 'top', 'stretch']),
   fullWidth: PropTypes.bool,

Unable to resolve module `prop-types`

Why are you using 'prop-types' instead of React.PropTypes?

"dependencies": {
	"react": "16.0.0-alpha.6",
	"react-native": "0.44.0",
	"react-native-responsive-grid": "^0.21.0"
}

Col doesn't work as expected with breakpoints

When using the following code;

<Row>
    <Col style={{ backgroundColor: 'green' }} smSize={50} mdSize={33.333} lgSize={25}>
        <Text>First Column</Text>
    </Col>
    <Col style={{ backgroundColor: 'green' }} smSize={50} mdSize={33.333} lgSize={25}>
        <Text>Second Column</Text>
    </Col>
    <Col style={{ backgroundColor: 'green' }} smSize={50} mdSize={33.333} lgSize={25}>
        <Text>Third Column</Text>
    </Col>
    <Col style={{ backgroundColor: 'green' }} smSize={50} mdSize={33.333} lgSize={25}>
        <Text>Fourth Column</Text>
    </Col>
</Row>

The third and fourth column are not visible on iphone portrait, and the fourth column is not visible on iphone landscape.

I expect that this behaviour needs to be the same as the bootstrap way..?

How to handle Font Scaling

Its not issue I am just asking for advice!

I have attached the screenshot, where you can see I have achieved responsive design, thank you. But problem that I am facing is with Text/Font. How you handle font scaling?
screenshot from 2017-05-04 13-45-30

Infinite scrolling and other questions

Hi guys,

Thanks for these examples, a grid with dynamic columns is a very important component for mobile apps. I have some questions with the second example (Reponsive Tiles for Universal Apps):

  1. Is possible implement infinite scrolling like the FlatList component?
  2. What's props.state.layout? because it's undefined and I'm getting issues with the props.state.layout.grid

Thanks in advance, Nicholls

Problem on scrollview if layout has navigation bar

Hello Guys

I'm having an issue in this grid library if my layout has navigation bar. When I scroll at the end of the page, the content is cut, but if I remove the navigation bar I can see the whole content of my layout.
I'm using nativebase navigation UI.

Has anyone encounter this?

Bringing Pseudo Elements to RN

@peacechen

<Row slot-before={someComponent} slot-after={anotherComponent}>
Some content...
</Row>

Applies to Col, too, and rule that Row can't have Row as child and Col can't have Col as child applies to slots, too.

It would place the output of someComponent before "Some content" and the output of anotherComponent after "Some content"

If "Some content" is null then content from "slot-before" component would be inserted at top and content from "slot-after" after component would be inserted below it. If only slot-after is given and "Some content" is null then content from slot-after would be inserted at top.

It does two things:

  1. gives us something similar to CSS' ::before and ::after pseudo elements
  2. allows us to break down large trees of Row/Col into sub-trees that can be composed as we like, i.e, modular construction and reuse

I understand you can do bullet no. 2 today by creating SomeComponent that contains a reusable Row/Col sub-tree but that prevents us from enforcing the Row/Col alternating nesting pattern (as child won't be of type Row or Col but of type SomeComponent so we can't check) and more importantly it obfuscate the consistent pattern of a tree of alternating Row/Col that makes it easy to infer layout from just looking the JSX (as opposed to having SomeComponent and SomeOtherComponent obfuscate/interrupt that visual pattern)

Definitely a visually oriented enhancement to reinforce the pattern and keep the JSX visually simple fro a cognitive point of view. Not introducing any new functionality.

I'm tempted to add it and play with it but would like your educated opinion as someone who is actually using this library.

Thank you :)

Overlay?

This looks like an awesome library!

One thing I am wondering is how I would place an overlay over a certain row. Position absolute feels weird because I want it as an overlay for that specific row view.

Here is a simple example:

      <Row size={50} style={{backgroundColor: 'green'}}>
        <WebView source={{uri: "https://google.com"}} />
      </Row>

Say I want something on top of the webview, how would you go about it?

Thanks!

crashes expo with simple example

I am using

"react": "16.0.0-alpha.12",
"react-native-responsive-grid": "^0.32.4",

The following just crashes my CRNA (uses expo) setup:

      <Row>
        <Col size={20} offset={5}>
          <Text style={styles.text}>
            asdfas
          </Text>
        </Col>
        <Col size={20} offset={5}>
          <Text style={styles.text}>
            asdfasdfs
          </Text>
        </Col>
        <Col size={20} offset={5}>
          <Text style={styles.text}>
           asdfasdfasdfa
          </Text>
        </Col>
        <Col size={20} offset={5}>
          <Text style={styles.text}>
            adsfasdfasdfasd
          </Text>
        </Col>
      </Row>

Any idea? I am sorry but I am not able to supply much more info :|

Column heights and row widths

Hello, Iā€™m having setting the width of rows and the height of columns. Iā€™d like for all columns to stretch to match the height of their containing row and for all rows to match the width of their containing column. It appears the height of a column is determined by content. I like to have the min-height set to match the height of its parent row

Question not an issue

I'm curious, have you compared this library to other responsive-grid libraries, particularly "react-native-easy-grid"? It appears this system is much more comprehensive (according the api) but I am wondering to what end. Can you share a few notes on how they compare? Can you explain your motivation for writing this packaged instead of going with "easy-grid"?

React 16.x causes exception with setState on unmounted component

Changes in React 16.x lifecycle can result in an exception during unmount. <Grid> calls cancelAnimationFrame in componentWillUnmount, however there is a race condition with either runAfterInteractions or requestAnimationFrame that allow setState() to run even though it was attempted to be canceled.

I'm testing a fix which sets an unmounted flag in componentWillUnmount. The callback checks for the flag and bails if it's set, closing the loop on the race condition.

Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in Grid (at myComponent.js:...)

Usage example

Hi, the docs look great and very informative. But is there any example of how to do a photo grid of images of varying sizes? Like an image collage?

diffrent sizes grid doesn't work good

Hi
I am try'n to make a FlatList with react-native-responsive-grid to have items with diffrent sizes , but it doesn't work the way it must.
this is the code
`import React from 'react';

import {
View,
Text,
Image,
StyleSheet,
ScrollView,
ImageBackground,
FlatList,
Dimensions,
} from 'react-native';

import {Row, Column, ScreenInfo, Grid} from 'react-native-responsive-grid';

const screenWidth = Math.round(Dimensions.get('window').width);
const screenWidthL = screenWidth / 2.1;
// column width (relative to screen size)
const sizes = {sm: 100, md: 50, lg: 25, xl: 20};

const layout = (state) => {
const numCols = Math.floor(100 / sizes[ScreenInfo().mediaSize]);
const numRows = Math.ceil(data.length / numCols);
const colWidth = state.layout.grid ? screenWidthL : 0;

let layoutMatrix = [],
layoutCols = [];

for (let col = 0; col < numCols; col++) {
layoutMatrix.push([]);
for (let row = 0, i = col; row < numRows; row++, i += numCols) {
if (data[i])
layoutMatrix[col].push(
,
);
}
layoutCols.push(
<Column
key={col}
smSize={state.layout.grid ? sizes.sm : 0}
mdSize={state.layout.grid ? sizes.md : 0}
lgSize={state.layout.grid ? sizes.lg : 0}
xlSize={state.layout.grid ? sizes.xl : 0}>
{layoutMatrix[col]}
,
);
}

return layoutCols;
};
const dd = [];
const Item = (props) => {
if (!props.colWidth) return null;

dd.push({
key_: props.key,
id_: props.id,
urlimg: props.url,
height_: props.height,
width_: props.width,
margin_: props.margin,
colWidth_: props.colWidth,
});

return (
<FlatList
numColumns={2}
data={dd}
renderItem={({item, index}) => {
return (
<Row
style={{
backgroundColor: 'white',
margin: item.margin_,
borderRadius: 15,
borderWidth: 1,
borderColor: 'black',
height: item.height_,
}}>

<ImageBackground
source={{uri: item.urlimg}}
style={{
width: item.colWidth_,
height:
item.height_ +
((item.colWidth_ - item.width_) * item.height_) /
item.width_,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{fontSize: 48, marginTop: 5}}>{item.id_}



);
}}>
);
};

export const Home = () => (

{({state, setState}) => (
<Row fullHeight style={{backgroundColor: 'lightgray'}}>

{layout(state)}


)}

);

const data = [
{
url:
'https://i.pinimg.com/236x/d8/3a/9b/d83a9b6faf2e58ff895342242bd62214.jpg',
pixelHeight: screenWidthL + 30,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/61/35/93/613593ea3d5537c7f85f7365f0d72f45.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/52/7c/66/527c66879c1bbbeaf53938e467ee8927.jpg',
pixelHeight: screenWidthL + 10,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/16/8e/1e/168e1e2ba9e74baf37e1c64df576b79c.jpg',
pixelHeight: screenWidthL + 5,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/22/0f/01/220f016c154044a51abca097f7ecc4ea.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/14/3a/8c/143a8c283ecaecbf90058ac0f914a1ed.jpg',
pixelHeight: screenWidthL + 20,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/3d/65/6f/3d656f63189290a84d906b92d0d1565d.jpg',
pixelHeight: screenWidthL + 15,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/7a/2c/f2/7a2cf28357e37a95dfac3d273ef9cb0a.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/d8/3a/9b/d83a9b6faf2e58ff895342242bd62214.jpg',
pixelHeight: screenWidthL + 15,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/61/35/93/613593ea3d5537c7f85f7365f0d72f45.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/52/7c/66/527c66879c1bbbeaf53938e467ee8927.jpg',
pixelHeight: screenWidthL + 10,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/16/8e/1e/168e1e2ba9e74baf37e1c64df576b79c.jpg',
pixelHeight: screenWidthL + 5,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/22/0f/01/220f016c154044a51abca097f7ecc4ea.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/14/3a/8c/143a8c283ecaecbf90058ac0f914a1ed.jpg',
pixelHeight: screenWidthL + 20,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/3d/65/6f/3d656f63189290a84d906b92d0d1565d.jpg',
pixelHeight: screenWidthL + 15,
pixelWidth: screenWidthL,
},
{
url:
'https://i.pinimg.com/236x/7a/2c/f2/7a2cf28357e37a95dfac3d273ef9cb0a.jpg',
pixelHeight: screenWidthL,
pixelWidth: screenWidthL,
},
];
`
and
photo_2020-09-21_01-38-44

what I'm doing wrong?

Is ImageBackground supported?

I have a background image that has a textual logo on it. When I set the image to stretch, the text gets stretched and looks terrible. My thinking is to export the background at several aspect ratios and have those loaded dynamically. I see that <Image> is supported. Is <ImageBackground> also supported?

'Hidden' props not working

<Row> and <Col> are not respecting the props smHidden, mdHidden, lgHidden and xlHidden.

Inspecting the code, isHidden is looking for the props on the children, not the Row/Column itself.

web support

hi!

sorry if this question is stupid, but I keep reading the word 'universal' does that mean this library can be used with react-native-web?

Is it tested for web-applications?

Thanks!

Feature request: variable sizes

I've come across situations where a flexible size is necessary. In the web world this is known as CSS Liquid Layout. Take this 3-column example:

|  Col A  |       Col B        |   Col C  |

The desire is to fix the widths for Columns A & C, and to let Col B take up the remaining space. The grid code might look something like:

<Row>
  <Col sizePoints ={100}>
    // A: Fixed size content
  </Col>
  <Col sizePoints ={*}>
    // B: Variable sized content
  </Col>
  <Col sizePoints ={80}>
    // C: Fixed size content
  </Col>
</Row>

Is this possible in the current code or will changes need to be made?

setScreenInfo() recalculates unnecessarily

setScreenInfo always calculates values for mediaSize, etc. On a layout with hundreds of columns / rows, this causes redundant recalculations for every component.

A simple optimization would be to store the previous screen Dimensions and check whether it's changed since the last call. If not, use the previously calculated values. I'll submit a PR.

Row.js update a mounted or mounting component

I use FlatList render many items, FlatList wrapped by Row.

<Row fullWidth fullHeight style={{ backgroundColor: "#f3f3f3", padding: 20 }}>
                <FlatList
                    data={this.dataItems}
                    keyExtractor={(item, index) => item.id + ''}
                    renderItem={this.renderListItem}
                />
</Row>

When pop this screen will get a warning:

Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.

Please check the code for the Row component.

I check Row.js find warning code 78 line

this.setState({layoutTriggered: +new Date()})

Uncaught TypeError: e.persist is not a function

@idibidiart hi,

i want to use it with react-native-web,
but looks like have same error when render children.

Grid.js:47 Uncaught TypeError: e.persist is not a function
    at onLayout (Grid.js:47)
    at index.js:131
    at index.js:41

in here :

and i check the react-native docs,

https://facebook.github.io/react-native/docs/view.html#onlayout

{nativeEvent: { layout: {x, y, width, height}}}

on persist here.

could you tell me why use this func?

Parameterize cutoff points

The hard-coded cutoff points aren't a good fit for our use case.
https://github.com/idibidiart/react-native-responsive-grid/blob/master/src/lib/ScreenInfo.js#L54

The code evaluates screen sizes <= 375 as small, 376-767 as medium, 768-1023 as large, etc. Medium tends to be the toughest, as it bleeds into the small range as well as large.
The logic is a bit inconsistent since SMALL_Width is the upper cutoff point for small, but MEDIUM_Width sits in the middle of medium. LARGE_Width sits on the lower end of large.

I propose making the cutoffs consistent (all on the lower end or the upper end) and adding them as props. The change would be backwards compatible of course. Would a PR be accepted?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    šŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. šŸ“ŠšŸ“ˆšŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ā¤ļø Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.