FabianoLothor
FabianoLothor

Reputation: 2977

Why onLayout don't triggered in a SubText?

I'm with a issue about the onLayout event

A Code

<View>
  <Text>
    <Text onLayout={e => {console.log("this isn't triggered!")}}>{"foo"}</Text>
  </Text>
</View>

B Code

<View>
  <Text onLayout={e => {console.log("here the event it is called, but I need call in a SubText")}}>{"foo"}</Text>
</View>

Upvotes: 6

Views: 1642

Answers (2)

pachun
pachun

Reputation: 920

Here's an answer for posterity. I rolled through here before I finding my answer so maybe this will help someone else.

In my case, I needed to show attributed text in a scroll view and be able to scroll to different substrings within the text.

Nesting texts within texts creates a single NSAttributedString behind the scenes on iOS and a SpannableString on Android, so trying to add an onLayout prop to a nested text element actually has no effect, since it's not actually represented as it's own text element in the resulting DOM.

In my case the solution was to use the onTextLayout prop of the Text component:

import React from "react"
import { StyleSheet, ScrollView, Text, View } from "react-native"

const App = () => {
  const scrollViewRef = React.useRef<ScrollView>(null)

  const onTextLayout = React.useCallback(event => {
    const scrollLocation = event.nativeEvent.lines.find(
      line => line.text === "6. Hello\n",
    ).y
    if (scrollViewRef.current) {
      scrollViewRef.current.scrollTo({
        x: 0,
        y: scrollLocation,
        animated: true,
      })
    }
  }, [])

  return (
    <View style={styles.container}>
      <View style={{ height: 100 }}>
        <ScrollView
          ref={scrollViewRef}
          style={{
            width: 100,
            height: 100,
            borderColor: "#000",
            borderWidth: 1,
          }}
        >
          <Text onTextLayout={onTextLayout}>
            <Text>1. Hello{"\n"}</Text>
            <Text>2. Hello{"\n"}</Text>
            <Text>3. Hello{"\n"}</Text>
            <Text>4. Hello{"\n"}</Text>
            <Text>5. Hello{"\n"}</Text>
            <Text>6. Hello{"\n"}</Text>
            <Text>7. Hello{"\n"}</Text>
            <Text>8. Hello{"\n"}</Text>
            <Text>9. Hello{"\n"}</Text>
            <Text>10. Hello{"\n"}</Text>
            <Text>10. Hello{"\n"}</Text>
            <Text>10. Hello{"\n"}</Text>
            <Text>10. Hello{"\n"}</Text>
          </Text>
        </ScrollView>
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
})

export default App

As a side note, I am getting Typescript errors on the line which uses the onTextLayout= prop. Googling for solutions doesn't turn anything up, but the prop function is called!

Upvotes: 4

duskandawn
duskandawn

Reputation: 675

I found this related bug on RN repo : https://github.com/facebook/react-native/issues/11650. Still looking for a way to measure nested texts

Upvotes: 1

Related Questions