Get size of a View in React Native
Asked Answered
H

9

249

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?

Holzman answered 12/5, 2015 at 23:28 Comment(0)
L
508

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.

Lonee answered 13/5, 2015 at 5:36 Comment(12)
The issue of this approach is when device rotates/view size changes, I do not get onLayout called again.Holzman
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.Lonee
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?Shoshanashoshanna
@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.Lonee
@Lonee how would you hide the UI until layout is computed ?Gelatinate
This is just perfect!Harday
hello , i am coding a PopMenu , is there any way i can get a Component's margin(marginTop | marginLeft ...)'s value when onPress or onLayout be called? thank you...Earmark
reiterating @Irfanlone's comment, which never got answered: How do you calculate 'potential' size of a view? Any attempt to hide the view will result in onLayout giving 0 values for dimensions, since the view is not visibleGimp
@Gelatinate @Felipe, need to embed desired content in View that has onLayout. If onLayout method called, setState width and height. Desired content need to check to render only if width and height are not undefined.Milky
Since View is placed in render function, is there an issue with calling setState() within the onLayout event?Weinhardt
I am trying to use this to automatically size text to fit a View. It is working good for most of the text, but some of the text keeps jumping back and forth between two different font sizes. I think it is because onLayout is called from within Render, but then in turn it is calling setState. Any ideas how to overcome this issue?Weinhardt
For me using onLayout cause onPress not to work :( - React 16.9Conidium
I
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);
Impeditive answered 30/12, 2016 at 15:50 Comment(0)
F
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.

Flung answered 30/3, 2021 at 11:21 Comment(0)
E
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.

Electrify answered 26/1, 2017 at 17:50 Comment(0)
H
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);
}
Hesperus answered 13/5, 2015 at 18:58 Comment(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?Calendra
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.Sundstrom
P
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>
Priestess answered 4/10, 2022 at 10:40 Comment(0)
E
-9

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

Efflux answered 29/6, 2019 at 18:20 Comment(0)
H
-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

Hoberthobey answered 21/6, 2019 at 12:25 Comment(1)
This is okay, but it doesn't answer the question.Spontoon
W
-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

Whitton answered 16/8, 2015 at 4:1 Comment(8)
This is what I am looking for. Thank you!Holzman
Gah, why isn't this documented more clearly!?! I was trying 'width' and 'height' instead of ('window').width etc.Subaqueous
@MarkAmery with window dimensions you can planning how your views will look likeWhitton
@BrunoGuerra can you show the code to get a certain view (not window) size by Dimensions?Stabilize
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.0Herold
I would argue that if you're using height and width frequently to construct views you probably aren't leveraging flex adequately. This also become an issue because it shows window dimensions and NOT usable space. So if your child view only has 50% of space (as restricted by the parent), this approach will cause the screen to overflow.Cacka
@MJStudio It's useful in fullscreen scenarios. It's always better using modern solutions, this is old answer, but represents one more freely solution. But today using flex or even grid components it's a better solutionWhitton
I would second the @Stabilize comment that this is the window, not the view dimensions. As for why to get this information? I would like to have some of my views change their appearance (i.e. leave some things out) when they are in a small space. I was thinking of using a different style sheet based on the width of the component, but have not managed to figure out a way to do this.Kaffir

© 2022 - 2024 — McMap. All rights reserved.