如何在React Native中调整字体大小以适应Android视图?

47

如何在React Native中使视图内文本大小自动更改?

我的文本长度不同,其中一些长度不适合视图,所以需要缩小字体大小。我已查看文档并找到这个 但是它只适用于iOS,而我需要它适用于Android。

它是否适用于其他组件,比如按钮和touchableopacity?


可能是 React Native 可响应字体大小 的重复。 - Pir Shukarullah Shah
9
这不是那个问题的重复。之前的问题是关于根据屏幕尺寸设置字体大小的,而这个问题是关于使特定文本组件的字体大小根据文本内容自适应其父视图的大小。想象一下从 Web 服务获取动态文本的使用情况,你希望它填充到一个特定大小的框中,但无法预测字符串的长度。 - Joe Lafiosca
可能是 https://dev59.com/bVYN5IYBdhLWcg3wR2k-#49381215 的重复问题。 - Florin Dobre
9个回答

42

将这两个属性组合在一起,可在Android和iOS上使用:

adjustsFontSizeToFit={true}
numberOfLines={1}

adjustsFontSizeToFit可以确保字体不超出容器,numberOfLines可以确保文本只显示一行。

如果没有adjustsFontSizeToFit,numberOfLines会显示省略号;如果没有numberOfLines,adjustsFontSizeToFit会减小字体的高度或宽度以适应包含视图的固定高度或宽度。


不错的发现,还添加了 fontSize 作为 RN 尝试适应的基本大小,然后再将大小调整到合适的大小。 - devonj

29

稍作改进的Jeffy Lee代码适用于我

const AdjustLabel = ({
  fontSize, text, style, numberOfLines
}) => {
  const [currentFont, setCurrentFont] = useState(fontSize);

  return (
    <Text
      numberOfLines={ numberOfLines }
      adjustsFontSizeToFit
      style={ [style, { fontSize: currentFont }] }
      onTextLayout={ (e) => {
        const { lines } = e.nativeEvent;
        if (lines.length > numberOfLines) {
          setCurrentFont(currentFont - 1);
        }
      } }
    >
      { text }
    </Text>
  );
};


adjustsFontSizeToFit 在安卓上完美运行。 - Mitesh K
2
@miteshkalal 并不总是有效。只适用于一些较新的版本。在旧版本中,除了无法更改字体大小外,还可能会导致应用程序冻结,并且如果存在最大宽度,则不会应用省略号。 - Henrique Bruno

5
尝试这种方法。根据屏幕宽度设置字体大小,如下所示:
width: Dimensions.get('window').width

因此,在您的样式中,尝试进行百分比计算以使字体大小适合屏幕

style={
  text:{
     fontSize:0.05*width
  }
}

这将适用于所有屏幕(包括Android和IOS)。

1
0.05 是从哪里来的? - c4k
@c4k 这只是一个比例,将其设置为适合您的屏幕,您就可以让此解决方案在所有屏幕上运行。 - Allloush
34
对于较长的文本,该功能不能自动减小字体大小以适配特定视图宽度,而只是根据屏幕宽度将所有字体设置为特定大小。这并不是问题的答案。 - Jenever
2
同意@Jenever的观点-这并没有回答OP的问题。它解决了一个完全不同的问题。 - Wil Moore III
1
这很有用,但并没有回答 OP 所问的问题。 - Vencovsky
不幸的是,这将独立于所包含文本的长度设置字体大小。 - JustTrying

1

自 React Native 0.62 开始,文本组件的 adjustsFontSizeToFit 属性已经支持 Android。请查看文档


1

编辑

最近我面临了一个更具挑战性的任务。任务是将多个长度不同的单词(例如:Plane和Truck具有相同的字符数,但在相同字体大小下,Truck比Plane更长)适合于相同大小的视图(每个视图一个单词)。我使用React Native Animated库来实现这一点。 输入单词-> Plane,Truck,Bus,Car,Cab

  1. 使用Text组件渲染所有给定的单词,使用固定的、最好更大的字体大小,超过最长单词所需的宽度。
  2. 使用Text组件的onLayout函数找到最长单词的宽度和高度(高度已经相似)。
  3. 计算沿X轴和Y轴所需的缩放因子(由于步骤1中的假设,这些因子将小于1),以使最大单词适合于固定的View,并取其中较小的一个。
  4. 然后在每个单词中呈现一个Text组件(具有相同的字体大小),并使用包裹Text的View组件呈现每个View,并使用变换属性使用相同的缩放因子对每个View进行缩放。

我实现了上述想法,使用onLayout不断减小字体大小直到单词适合View,这样用户就可以在屏幕上看到它,无论我在算法运行期间使用哪种技巧来隐藏它。我已经发布了一个npm包: https://www.npmjs.com/package/@chamodanethra/react-native-fitted-text


1

尝试这个方法。

我使用了onLayout方法来实现这个功能。

首先,我将我的文本视图包裹在一个固定大小的视图中,然后我为两个视图实现了onLayout方法,这样我就可以得到固定大小视图的高度和文本视图的高度。

接下来,如果文本视图所需的高度大于我们的视图高度,我们会减小文本视图的字体大小,直到高度适合我们的视图为止。

在这个测试代码中,我制作了两个视图,一个是粉色背景,另一个是黄色背景,粉色视图内部的文本字体大小将被调整以适应视图,而黄色文本的字体大小将保持不变。

import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  const [size, setSize] = useState(20)
  const [viewHeight, setViewHeight] = useState(0)
  const [textHeight, setTextHeight] = useState(0)

  useEffect(() => {
    if (textHeight > viewHeight) {
      setSize(size - 1) // <<< You may adjust value 1 to a smaller value so the text can be shrink more precisely
    }
  }, [textHeight])

  return (
    <View style={styles.container}>
      <View
        style={{
          margin: 20,
          backgroundColor: 'pink',
          width: 200,
          height: 200
        }}
        onLayout={(event) => {
          var { x, y, width, height } = event.nativeEvent.layout;
          setViewHeight(height)
        }}
      >
        <Text
          style={{
            fontSize: size,
          }}
          onLayout={(event) => {
            var { x, y, width, height } = event.nativeEvent.layout;
            setTextHeight(height)
          }}
        >
          Gemma is a middle grade novel that follows a curious explorer and her ring-tailed lemur, Milo, 
          as they hunt for the “most greatest treasure in the world”. Solving riddles, battling a bell-wearing 
          jaguar, and traveling the Eight Seas, Gemma’s adventures take her from a young girl to a brave captain, 
          whose only limits are the stars.
        </Text>
      </View>

      <View
        style={{
          margin: 20,
          backgroundColor: 'yellow',
          width: 200,
          height: 200
        }}
      >
        <Text
          style={{
            fontSize: 20
          }}
        >
          Gemma is a middle grade novel that follows a curious explorer and her ring-tailed lemur, Milo, 
          as they hunt for the “most greatest treasure in the world”. Solving riddles, battling a bell-wearing 
          jaguar, and traveling the Eight Seas, Gemma’s adventures take her from a young girl to a brave captain, 
          whose only limits are the stars.
        </Text>
      </View>
    </View>
  );
}

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

你可能注意到当字体大小减小时,粉色文字的字体会有收缩动画。我建议您可以将文字的不透明度初始化为0,在字体调整完成后将其设置为1,这样用户就不会看到丑陋的动画效果。


0

不用煩惱,您可以使用一個小型庫來為每個設備維護字體比例。

npm i --save react-native-responsive-fontsize

import RF from "react-native-responsive-fontsize"

fontSize: RF(2)

但別忘記將allowFontScaling={false}屬性添加到文本中。因為iOS具有自動字體縮放能力,所以字體大小有時可能與您的預期不同。


2
这似乎无法将文本缩小以适应<View>元素。 - kojow7

0

快速回答:使用Text属性的adjustsFontSizeToFit


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

0

我在我的React Native应用程序中遇到了与文本数量调整视图(用户将字符串输入到当前限制为30个字符的输入字段中)类似的问题。 我注意到iOS已经实现了一些属性:adjustsFontSizeToFit minimumFontScale={.4},但是Android目前没有这样的方法可用。

注意:这对我有效,但可能不是“最佳”解决方案!

目前,我正在使用嵌套的三元运算符:

fontSize: this.props.driverName.length > 12 && 
this.props.driverName.length < 20 ? heightPercentageToDP('2%') : 
this.props.driverName.length > 20 && this.props.driverName.length < 40 
? heightPercentageToDP('1.75%') : heightPercentageToDP('2.25%')

通俗地说,上述三元运算符检查所使用的字符范围,并根据范围将fontSize修改为视图中的“%”。方法:heightPercentageToDP是一个函数,我正在使用它将大小转换为基于移动屏幕的DP的“%”(这样它就可以在平板电脑或手机上响应)。 heightPercentageToDP 代码片段:
    import { Dimensions, PixelRatio } from "react-native";
    const widthPercentageToDP = widthPercent => {
    const screenWidth = Dimensions.get("window").width;
    // Convert string input to decimal number
    const elemWidth = parseFloat(widthPercent);
    return PixelRatio.roundToNearestPixel((screenWidth * elemWidth) / 100);
    };
    const heightPercentageToDP = heightPercent => {
    const screenHeight = Dimensions.get("window").height;
    // Convert string input to decimal number
    const elemHeight = parseFloat(heightPercent);
    return PixelRatio.roundToNearestPixel((screenHeight * elemHeight) / 100);
    };
    export { widthPercentageToDP, heightPercentageToDP };

heightPercentageToDP 的信用和来源归功于:https://medium.com/react-native-training/build-responsive-react-native-views-for-any-device-and-support-orientation-change-1c8beba5bc23


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接