react native字体大小自适应布局

需求背景:

最近遇到一个问题,就是在FlatList中显示一行行抄表数据,每行的左侧文本是抄表时间,右侧文本是抄表值。抄表时间是固定格式、固定宽度的 ,但是右侧的抄表值是变长的,从个位数到8、9位数不等,值的结尾还显示单位,所以数据过长时会出现换行或是省略号显示的效果。

产品经理要求是抄表值一行显示不要换行,也不要显示省略号,完整显示。当抄表值过大在布局中显示不下时,则动态缩小字体大小,来适应布局宽度,在一行内完整显示抄表值。

实现效果如下:

下图demo中文本的宽度填充屏幕,点击按钮会动态追加文本。

限制一行显示效果:

一行内动态适应字体大小

限制两行显示效果:

两行内动态适应字体大小

上代码:

import React, { useState } from 'react';
import type { Node } from 'react';
import {
  Button,
  Platform,
  SafeAreaView,
  Text,
  NativeSyntheticEvent,
  TextLayoutEventData,
} from 'react-native';

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen';

export interface AdjustTextProps {
  children: any;
  initFontSize: number;
  numberOfLines: number;
}

const AdjustText: () => Node = (props: AdjustTextProps) => {
  const {
    children, numberOfLines, initFontSize,
  } = props;
  const [currentFontSize, setCurrentFontSize] = useState(initFontSize);

  AdjustText.defaultProps = {
    numberOfLines: 1,
  };

  const onTextLayout = (e: NativeSyntheticEvent<TextLayoutEventData>) => {
    const { lines } = e.nativeEvent;
    if (lines.length > numberOfLines) {
      setCurrentFontSize(currentFontSize - 0.5);
    }
  };

  return (
      <Text
          {...props}
          style={[props?.style, { fontSize: currentFontSize }]}
          numberOfLines={numberOfLines}
          adjustsFontSizeToFit={Platform.OS === 'ios'}
          onTextLayout={Platform.OS === 'ios' ? null : onTextLayout}
      >
        {children}
      </Text>
  );
};

const App: () => Node = () => {
  const [text, setText] = useState('Hello World.');

  return (
      <SafeAreaView style={{ height: '100%', justifyContent: 'center', backgroundColor: Colors.darker }}>
        <AdjustText
            initFontSize={20}
            numberOfLines={1}
            style={{ color: 'black', backgroundColor: 'pink', marginBottom: 20 }}
        >
          {text}
        </AdjustText>
        <Button
            title={'Append Text'}
            onPress={() => setText(`${text} Hello World.`)}
        />
      </SafeAreaView>
  );
};

export default App;

代码解析:

App函数组件是页面容器。

AdjustText是封装的字体大小自适应函数组件,是对Text组件做了一层再包裹。其属性同Text组件,但是多了一个initFontSize 属性,是文本的默认字体大小,当文本在指定行数中放不下时,文本会基于这个字体大小向下缩小。

因为在iOS上自带属性adjustsFontSizeToFit已经实现了字体自动适配,不需要我们自己处理,所以判断为iOS时,该值为true

Android上则没有提供类似属性,所以用到了onTextLayout来监听文本行数的变化,当要显示的行数超过指定行数使,则触发字体大小减少0.5的逻辑直至实现指定行数显示(这个值可以自己设置,比如1也可以)。

onTextLayout中的属性值lines是一个数组,当文本为两行显示时,数组长度就为2了。

还有react native的bug需要注意,在安卓上,当设置adjustsFontSizeToFit={true}时,会造成一直触发onTextLayout,文本将无限的更改布局。这个问题在react-native 0.67.3上得到修复。



思路参考地址

DEMO代码地址
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值