Reputation: 3357
<View
style={{
flexDirection: "row",
}}
>
<Text
style={{
flex: 1,
}}
>
By continuing, you agree to our{" "}
<Pressable
onPress={...}
>
<Text>
Terms of Service
</Text>
</Pressable>
</Text>
</View>
"Terms of Service" is printed higher than "By continuing, you agree to our". How do I vertically align them?
Or more precisely - how do I get the Pressable
Text to vertically align to the bottom?
Upvotes: 11
Views: 5190
Reputation: 41
A crazy trick that I just did (and if you are not using translations), I used the text as an SVG component that I exported from Figma.
Upvotes: 1
Reputation: 34084
This is a bug in React Native itself. There are several open reports of this bug on React Native's GitHub, but the chances of it being fixed don't look good:
View
s nested in Text
being mis-aligned on Android, and a core contributor responded, but appeared to get derailed and stuck in some details specific to mimicking superscript and subscript.Pressable
and someone posted a PR to fix it, but Facebook closed it because no-one from Facebook got around to reviewing it before it became stale and out of date with the main branch.In React Native >= 0.65, if your inline pressable element uses only text styles, you can work around this issue by using <Text>
with onPress
(and onPressIn
and onPressOut
to style the pressed state). Crude example:
/**
* Like a simplified Pressable that doesn't look broken inline in `Text` on Android
*/
const TextButton = ({ children, onPress, style, ...rest } => {
const [pressed, setPressed] = useState(false)
const onPressIn = () => setPressed(true)
const onPressOut = () => setPressed(false)
return (
<Text
onPress={onPress}
onPressIn={onPressIn}
onPressOut={onPressOut}
style={typeof style === 'function' ? style({ pressed }) : style}
{...rest}
>
{typeof children === 'function' ? children({ pressed }) : children}
</Text>
)
}
Beware, however, that there are also bugs around selecting interactive elements nested inside text using accessibility tools. If you can simply avoid nesting the interactive element in text, and have it on its own line, that's probably better: link-like interactive nested text isn't well supported in React Native currently.
On older versions of React Native before 0.65, Text didn't support onPressIn
or onPressOut
:
Pressable
's pressed
state, use Text
instead of Pressable
(as the asker did: https://stackoverflow.com/a/66590787/568458)Text
doesn't support the required onPressIn/Out
handlers. However, TouchableWithoutFeedback
does support those, and works by injecting props into its child so the Text
will remain Text
with no wrapping View
. Wrap a Text
in TouchableWithoutFeedback
and pass the touchable onPress
with onPressIn
and onPressOut
handlers and store the pressed state yourself./**
* Like a simplified Pressable that doesn't look broken inline in `Text` on Android
*/
const TextButton = ({ children, onPress, style, ...rest } => {
const [pressed, setPressed] = useState(false)
const onPressIn = () => setPressed(true)
const onPressOut = () => setPressed(false)
// TouchableWithoutFeedback modifies and returns its child; this returns `Text`
// plus press in/out events attached that aren't supported by Text directly.
return (
<TouchableWithoutFeedback
onPress={onPress}
onPressIn={onPressIn}
onPressOut={onPressOut}
>
<Text
style={typeof style === 'function' ? style({ pressed }) : style}
{...rest}
>
{typeof children === 'function' ? children({ pressed }) : children}
</Text>
</TouchableWithoutFeedback>
)
}
Warning: if you're also using React Native Web and React Navigation, don't use the TouchableWithoutFeedback
approach on Web, use pure Pressable
on web, because React Navigation's navigate functions don't reliably work when passed to Touchable*
s on Web due to a quirk of how the event handlers are set up (but they do work in Pressable), and this issue doesn't exist on Web.
Upvotes: 14
Reputation: 378
I found a very hackidy-hack solution...
<Text selectable={true}>
<Text>if you click</Text>
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => Linking.openURL("https://www.google.com")}
>
<Text
style={{
alignSelf: 'flex-end',
marginBottom: -4,
}}
>
here
</Text>
</TouchableOpacity>
<Text>, it will open google</Text>
</Text>
Upvotes: 2
Reputation: 331
By default the flexDirection
is column. Change it to flexDirection:"row"
Upvotes: 0
Reputation: 3357
Ended up doing this differently, using the onPress
property of the <Text>
component and finally wrapping all <Text>
components in another <Text>
component to have a proper line break:
<View>
<Text>
<Text>
By continuing, you agree to our{" "}
</Text>
<Text onPress={() => {...}}>
Terms of Service
</Text>
<Text>
{" "}and our{" "}
</Text>
<Text onPress={() => {...}}>
Privacy Policy
</Text>
</Text>
</View>
Upvotes: 3
Reputation: 864
The snippet below should work but hard to understand without giving a shot. If you can provide screenshots I can help more in sake of getting a more proper result.
<View>
<Text style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}>
By continuing, you agree to our{" "}
<Pressable
onPress={() => {
navigate("LegalStack", { screen: "Terms" });
}}
>
<Text style={{margin: 'auto'}}>
Terms of Service
</Text>
</Pressable>
</Text>
</View>
Upvotes: 1