Create and Measure Hidden Elements with Translate Offsets in React Native

Jason Brown
InstructorJason Brown
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 5 years ago

In this lesson we'll use onLayout to measure elements hidden with opacity. We hide additional elements with overflow: "hidden" and translate visible elements based upon measured layout height.

Instructor: [00:00] To execute a number ticker, there are two phases. The first is to render all of the items that you want hidden. The second is to measure one of those items, and then determine the offsets for each of the characters that we need to scroll to.

[00:15] First, let's render our number range. We have a number range from zero to nine, and we'll just loop over that. We can either use the value provided or the integer, it doesn't really matter, the index. We save this, and we can see that we now have a list of items that are rendering in a column. We'll then supply a key, just so we can quiet our error messages.

[00:53] So that the text is big enough to deal with, we're going to create a text class, create a font size of 80 and a color of gray, and apply that to each of them.

[01:13] In order for these to be hidden, we need to wrap this in another view, and then apply overflow:hidden. On iOS, overflow:hidden is an option. However, on Android, overflow:hidden is the default and the only option for a view. Let's apply a wrapping view. We'll simply give it a hidden class, say overflow:hidden, and then apply that to our wrapping class.

[01:51] Nothing has changed, because the text is actually affecting the layout of this view. Each one of these, rendered in a column on top of each other, is adding to the overall size of this particular view. We need to measure one single character, and then apply that height to this view. That way, our overflow:hidden will actually take affect.

[02:13] If we supply a random height, let's say it's a height of 95, we can see that it is restricting to a single character being shown. Let's remove that, and now, we'll measure the layout of a single one of these characters. To measure, we'll need to apply another text element.

[02:37] We'll give it our style=styles.text, and then we'll put a random character in here that's included in our numbers range. We'll just say zero. Then, we'll also need to apply an opacity of zero to this text element. The reason is we want the layout to be displayed, but we don't want this to actually cause any effect on this particular layout.

[03:04] Let's give it a measure class. We'll say opacity of zero, and we'll apply styles.measure. Now, we need to set up something to receive that layout for this text element. We'll create a handleLayout function that receives an event, and then we'll do a this.setState of measured, if true, we know that we've measured something. We'll set the height of e.nativeEvent.layout.height.

[03:47] Additionally, we'll set up some default states or state=measured false, and height of zero. Now, we can apply our onLayout = this.handleLayout to our text element. Additionally, we'll supply another style here, and say height=this.state.height.

[04:16] Now that we've done that, what's happened is we do a measurement. We eventually set our state here to the height, and then this will go from a zero height, with an overflow:hidden, to a height of whatever this particular character is.

[04:34] We don't necessarily want this particular view to be hidden until stuff is measured, let's clean up our styling a little bit. We'll remove this, and we'll just say const height and measured = this.state. We'll create another variable called constWrapStyle, and if we've measured something, we'll return height as our style. Otherwise, we'll return styles.measure. Styles.measure is just opacity zero.

[05:10] Now, we can apply our wrap style here, save, and nothing is changed. Now that we have this working, we need to fix this so that when we have a specified value, we can figure out at what position it is. One would be here, two would be here.

[05:26] Now that we have access to the height, we can create a function that determines the translate for the transform that we need. The reason we're using translate transform is because it's going to be perfomant and allow us to use the native driver when we're doing our animations.

[05:42] Let's create a function called const getPosition. It'll receive the value and the height, and then we'll do a parseInt on our value, just to be sure. We'll multiply it by the height, and then we'll also multiply it by -1, because translateY, if it's positive, will move the view downwards. Or, if it's negative, it'll move it up.

[06:13] Because our starting value is at this position, we need to move the value upwards to get to the other characters. Finally, we'll create a translate style. We'll say const getTranslateStyle. We'll get our position, and we'll return transform with an array and a single translateY with our position.

[06:48] Now, we need to apply this style. Because this is the overflow:hidden container and there is nothing else inside of here, we need to wrap this in another view that will basically act as a scroll within this particular hidden container.

[07:04] I'll apply our view, and then we'll get our transform style, which is going to be equal to the getPosition of the value that we want. For example, let's say we want five. We'll pass in the height, and then we'll wrap that in our getTranslateStyle. Now, we can apply our transformed style to the view. We'll say style=transformStyle.

[07:41] Once we save, we can see that it is figured out -- based upon the height and the value that we've given it -- which value to select within the range. To show that this is working, let's remove the styles.hidden. We can save it and see that, in the center of the screen, the five is exactly where we wanted it to be.

[08:04] If we change this to, say, nine, it'll scroll all the way to the end, or zero, go all the way to the other side. Let's add our styles.hidden back, and we can add a value to our state, just start at zero. Our componentDidMount will set an interval and do a this.setState to a value of this.state.value +1.

[08:41] We'll do that every 1,000 milliseconds, and then we'll pipe our this.state.value into our transform style, just as an example. Now, we can see that it's actually ticking from zero all the way up, based upon the value that we are setting.

egghead
egghead
~ 25 minutes ago

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today