Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix layout width calculation in onTextLayout (#36222)
Summary: There is a rounding issue in layout calculation when using onTextLayout method in Text component on Android. As you can see in the example below onTextLayout returns 3 lines, but in fact text is rendered in 2 lines: <img width="775" alt="Screenshot 2023-02-19 at 23 48 53" src="https://user-images.githubusercontent.com/8476339/220177419-de183ccd-a250-4131-ad05-907fdb791c75.png"> This happens because `(int) width` casting works like `Math.floor`, but after changing it to `Math.round` we get correct result: <img width="775" alt="Screenshot 2023-02-19 at 23 51 11" src="https://user-images.githubusercontent.com/8476339/220177859-93474c43-ed87-4c1b-986c-2817b29b78be.png"> ## Changelog [ANDROID] [FIXED] - Fix layout width calculation in onTextLayout <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> Pull Request resolved: #36222 Test Plan: This issue can be tricky to reproduce as width calculation depends on device width. I'm attaching code that I used to reproduce it. You need to tap on the screen to run through different sentences and sooner or later you will get the one with this rounding issue. <details> <summary>Code to reproduce</summary> ```js import React, { useState, useEffect } from 'react' import { SafeAreaView, Text, View } from 'react-native' function App() { const [state, setState] = useState({ index: 0, lines: [], sentences: [], }) const onTextLayout = (event) => { const lines = event.nativeEvent.lines console.log(JSON.stringify(lines, null, 2)) setState(state => ({ ...state, lines })) } useEffect(() => { fetch('https://content.duoreading.io/20-the-adventures-of-tom-sawyer/translations/english.json') .then(response => response.text()) .then(response => { setState(state => ({ ...state, sentences: JSON.parse(response) })) }) }, []) return ( <SafeAreaView style={{ flex: 1, padding: 30 }}> <View style={{ flex: 1 }} onTouchStart={() => setState(state => ({ ...state, index: state.index + 1 }))}> <Text style={{ fontSize: 22 }} onTextLayout={onTextLayout}> {state.sentences[state.index]} </Text> {state.lines.map((line, index) => ( <View key={index} style={{ position: 'absolute', top: line.y, left: line.x, width: line.width, height: line.height, opacity: 0.3, backgroundColor: ['red', 'yellow', 'blue'][index % 3], }}> </View> ))} </View> </SafeAreaView> ) } export default App ``` </details> Reviewed By: christophpurrer Differential Revision: D43907184 Pulled By: javache fbshipit-source-id: faef757e77e759b5d9ea26da21c9e2b396dc9ff1
- Loading branch information