Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native font outline / textShadow

Tags:

Is it possible to add an outline or textShadow to a font in react native to achieve something like this (white font with a black outline):

enter image description here

In CSS on the web its possible to add a text shadow or an outline to a font, to give the text a border that follows the font, something like this:

h1 {
    color: yellow;
    text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
<h1>Hello World</h1>

Is it possible to do something similar in react native?

I took the CCS snippet example from this stack overflow post on how to do it with CSS: CSS Font Border?

EDIT: Updated question to try and make it clearer

like image 910
Brien Crean Avatar asked Aug 03 '16 23:08

Brien Crean


2 Answers

Yes it is possible through the following properties:

textShadowColor color textShadowOffset ReactPropTypes.shape( {width: ReactPropTypes.number, height: ReactPropTypes.number} ) textShadowRadius ReactPropTypes.number 

https://facebook.github.io/react-native/docs/text.html

Actual completed pull request: https://github.com/facebook/react-native/pull/4975

like image 62
Shivam Sinha Avatar answered Sep 19 '22 21:09

Shivam Sinha


There is at least one way to make it look like this on both ios and android:

iPhone simulator screenshot with outlined text

Idea:

The idea is to use multiple shadows on the Text object. We can do it by wrapping Text component with View and clone the same Text object multiple times with different shadows to make them using different directions.

Implementation:

Here is the code for the wrapper component:

import * as React from "react"; import { StyleSheet, View } from "react-native"; import { Children, cloneElement, isValidElement } from "react";  type Props = {   children: any,   color: string,   stroke: number } const styles = StyleSheet.create({   outline: {     position: 'absolute'   }, });  export class TextStroke extends React.Component<Props> {   createClones = (w: number, h: number, color?: string) => {     const { children } = this.props;     return Children.map(children, child => {       if (isValidElement(child)) {         const currentProps = child.props as any;         const currentStyle = currentProps ? (currentProps.style || {}) : {};          const newProps = {           ...currentProps,           style: {             ...currentStyle,             textShadowOffset: {               width: w,               height: h             },             textShadowColor: color,             textShadowRadius: 1           }         }         return cloneElement(child, newProps)       }       return child;     });   }    render() {     const {color, stroke, children} = this.props;     const strokeW = stroke;     const top = this.createClones(0, -strokeW * 1.2, color);     const topLeft = this.createClones(-strokeW, -strokeW, color);     const topRight = this.createClones(strokeW, -strokeW, color);     const right = this.createClones(strokeW, 0, color);     const bottom = this.createClones(0, strokeW, color);     const bottomLeft = this.createClones(-strokeW, strokeW, color);     const bottomRight = this.createClones(strokeW, strokeW, color);     const left = this.createClones(-strokeW * 1.2, 0, color);      return (       <View>         <View style={ styles.outline }>{ left }</View>         <View style={ styles.outline }>{ right }</View>         <View style={ styles.outline }>{ bottom }</View>         <View style={ styles.outline }>{ top }</View>         <View style={ styles.outline }>{ topLeft }</View>         <View style={ styles.outline }>{ topRight }</View>         <View style={ styles.outline }>{ bottomLeft }</View>         { bottomRight }       </View>     );   } } 

If the text is not big, you can also use only 4 directions instead of 8 to improve performance:

<View>     <View style={ styles.outline }>{ topLeft }</View>     <View style={ styles.outline }>{ topRight }</View>     <View style={ styles.outline }>{ bottomLeft }</View>     { bottomRight } </View> 

The usage:

<TextStroke stroke={ 2 } color={ '#000000' }>   <Text style={ {     fontSize: 100,     color: '#FFFFFF'   } }> Sample </Text> </TextStroke> 

You can also use multiple Text objects inside since the wrapper copies all of them.

Performance:

I haven't checked the performance for this solution yet. Since we're copying text so many times it maybe not great.

Issues:

Need to be careful with the stroke value. With higher values, the edges of the shadows will be visible. If you really need a wider stroke, you can fix this by adding more layers to cover different shadow directions.

sample with wide stroke

like image 39
lub0v Avatar answered Sep 17 '22 21:09

lub0v