251

Is it possible to get the size (width and height) of a certain view? For example, I have a view showing the progress:

<View ref='progressBar' style={{backgroundColor:'red',flex:this.state.progress}} /> 

I need to know the actual width of the view to align other views properly. Is this possible?

10 Answers 10

512

As of React Native 0.4.2, View components have an onLayout prop. Pass in a function that takes an event object. The event's nativeEvent contains the view's layout.

<View onLayout={(event) => {
  const {x, y, width, height} = event.nativeEvent.layout;
}} />

The onLayout handler will also be invoked whenever the view is resized.

The main caveat is that the onLayout handler is first invoked one frame after your component has mounted, so you may want to hide your UI until you have computed your layout.

12
  • 7
    The issue of this approach is when device rotates/view size changes, I do not get onLayout called again.
    – Matthew
    Commented May 19, 2015 at 20:08
  • 4
    onLayout is invoked when the view's frame changes. Perhaps your view does not change its size or position on rotation. Look at the onLayout example in the UIExplorer, where onLayout is invoked upon rotation.
    – ide
    Commented May 19, 2015 at 21:36
  • 4
    Let's say I want to display a View differently depending on the dimensions. I don't understand how I can use the View's onLayout function to change how I display the View. Doesn't that lead to an infinite loop? Commented Feb 3, 2016 at 16:52
  • 2
    @LaneRettig Yes it does so if this is really what you want to do, then you should write your code in a way that reaches static equilibrium. But it sounds like you might just want to customize your view based on the screen dimensions in which case onLayout is unrelated.
    – ide
    Commented Feb 3, 2016 at 20:14
  • 12
    @ide how would you hide the UI until layout is computed ?
    – Irfanlone
    Commented Aug 29, 2017 at 19:52
42

This is the only thing that worked for me:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image
} from 'react-native';

export default class Comp extends Component {

  find_dimesions(layout){
    const {x, y, width, height} = layout;
    console.warn(x);
    console.warn(y);
    console.warn(width);
    console.warn(height);
  }
  render() {
    return (
      <View onLayout={(event) => { this.find_dimesions(event.nativeEvent.layout) }} style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.android.js
        </Text>
        <Text style={styles.instructions}>
          Double tap R on your keyboard to reload,{'\n'}
          Shake or press menu button for dev menu
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('Comp', () => Comp);
32

You can easily get the size of the View by onLayout props.

import React from 'react'
import { View } from 'react-native'

export default function index() {
  const onLayout=(event)=> {
    const {x, y, height, width} = event.nativeEvent.layout;
    
  }
  return (
    <View onLayout={onLayout}>
      <OtherComponent />
    </View>
  )
}

The onLayout handler will also be invoked whenever the view is resized.

The main caveat is that the onLayout handler is first invoked one frame after your component has mounted, so you may want to hide your UI until you have computed your layout.

0
18

Basically if you want to set size and make it change then set it to state on layout like this:

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

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'yellow',
  },
  View1: {
    flex: 2,
    margin: 10,
    backgroundColor: 'red',
    elevation: 1,
  },
  View2: {
    position: 'absolute',
    backgroundColor: 'orange',
    zIndex: 3,
    elevation: 3,
  },
  View3: {
    flex: 3,
    backgroundColor: 'green',
    elevation: 2,
  },
  Text: {
    fontSize: 25,
    margin: 20,
    color: 'white',
  },
});

class Example extends Component {

  constructor(props) {
    super(props);

    this.state = {
      view2LayoutProps: {
        left: 0,
        top: 0,
        width: 50,
        height: 50,
      }
    };
  }

  onLayout(event) {
    const {x, y, height, width} = event.nativeEvent.layout;
    const newHeight = this.state.view2LayoutProps.height + 1;
    const newLayout = {
        height: newHeight ,
        width: width,
        left: x,
        top: y,
      };

    this.setState({ view2LayoutProps: newLayout });
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.View1}>
          <Text>{this.state.view2LayoutProps.height}</Text>
        </View>
        <View onLayout={(event) => this.onLayout(event)} 
              style={[styles.View2, this.state.view2LayoutProps]} />
        <View style={styles.View3} />
      </View>
    );
  }

}


AppRegistry.registerComponent(Example);

You can create many more variation of how it should be modified, by using this in another component which has Another view as wrapper and create an onResponderRelease callback, which could pass the touch event location into the state, which could be then passed to child component as property, which could override onLayout updated state, by placing {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]} and so on.

13

Maybe you can use measure:

measureProgressBar() {
    this.refs.welcome.measure(this.logProgressBarLayout);
},

logProgressBarLayout(ox, oy, width, height, px, py) {
  console.log("ox: " + ox);
  console.log("oy: " + oy);
  console.log("width: " + width);
  console.log("height: " + height);
  console.log("px: " + px);
  console.log("py: " + py);
}
2
  • For the life of me I can't figure out how to properly use NativeMethodsMixin. No matter what I do, measure is always undefined. Any pointers? Commented Aug 24, 2016 at 21:34
  • 2
    You don't need to use NativeMethodsMixin the function is only available on some elements. For example TouchableWithFeedback does have the measure function, but a regular Touchable doesn't. Try to change the type of View you are using, get the ref and check if the measure element is available. I've stumbled on this aswell.
    – Jens
    Commented Jan 17, 2017 at 13:53
3

I create this simple component

import React, {Dispatch, SetStateAction} from 'react';
import {View, ViewProps} from 'react-native';

interface GetDimensionsProps {
  children: React.ReactNode | React.ReactNode[];
  onDimensions: Dispatch<SetStateAction<{height: number; width: number}>>;
  viewProps?: ViewProps;
}

export const GetDimensions: React.FC<GetDimensionsProps> = ({
  children,
  onDimensions,
  ...viewProps
}: GetDimensionsProps) => {
  return (
    <View
      onLayout={event =>
        onDimensions({
          width: Math.round(event.nativeEvent.layout.width),
          height: Math.round(event.nativeEvent.layout.height),
        })
      }
      {...viewProps}>
      {children}
    </View>
  );
};

// ────────────────────────────────────────────────────────────────────────────────
// usage

// const [dimensions, setDimensions] = useState<{
//   height: number;
//   width: number;
// }>({width: 0, height: 0});
//
// <GetDimensions onDimensions={setDimensions}>
//  {children}
// </GetDimensions>
0
1

Yes possible you can achieve this by onLayout prop

const [progress, setProgress] = useState(0.5); // Example progress value
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
  const progressBarRef = useRef(null);

  const onLayout = event => {
    const { width, height } = event.nativeEvent.layout;
    setDimensions({ width, height });
  };

then your view should be like this

 <View style={styles.container}>
      <View
        ref={progressBarRef}
        style={[styles.progressBar, { flex: progress }]}
        onLayout={onLayout}
      />
      <Text>Progress Bar Width: {dimensions.width}</Text>
      <Text>Progress Bar Height: {dimensions.height}</Text>
    </View>

and style like this

container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  progressBar: {
    backgroundColor: 'red',
    height: 20,
    alignSelf: 'stretch',
  },

also you can check the full code in expo snack

Expo link

-9

for me setting the Dimensions to use % is what worked for me width:'100%'

-10

Here is the code to get the Dimensions of the complete view of the device.

var windowSize = Dimensions.get("window");

Use it like this:

width=windowSize.width,heigth=windowSize.width/0.565

1
  • This is okay, but it doesn't answer the question. Commented May 24, 2020 at 13:14
-11

You can directly use the Dimensions module and calc your views sizes. Actually, Dimensions give to you the main window sizes.

import { Dimensions } from 'Dimensions';

Dimensions.get('window').height;
Dimensions.get('window').width;

Hope to help you!

Update: Today using native StyleSheet with Flex arranging on your views help to write clean code with elegant layout solutions in wide cases instead computing your view sizes...

Although building a custom grid components, which responds to main window resize events, could produce a good solution in simple widget components

8
  • 1
    This is what I am looking for. Thank you!
    – Matthew
    Commented Aug 28, 2015 at 21:06
  • 3
    Gah, why isn't this documented more clearly!?! I was trying 'width' and 'height' instead of ('window').width etc.
    – user657199
    Commented Nov 17, 2015 at 17:45
  • 1
    @MarkAmery with window dimensions you can planning how your views will look like Commented Nov 29, 2015 at 17:34
  • 2
    @BrunoGuerra can you show the code to get a certain view (not window) size by Dimensions?
    – Spark.Bao
    Commented May 24, 2016 at 8:31
  • 4
    Dimensions does not get updated on many devices when the device is rotated. This is a known issue and does not seem to be fixed as of react-native 0.32.0-rc.0 Commented Sep 8, 2016 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.