@remotion/layout-utils 的最佳实践
请注意以下几点,以确保在使用 @remotion/layout-utils 包时测量正确。
🌐 Take note of the following points to ensure correct measurements when using the @remotion/layout-utils package.
这些提示适用于 measureText()、fitText() 和 fillTextBox()。
🌐 These tips apply to all of measureText(), fitText(), and fillTextBox().
等到字体加载完成
🌐 Wait until the font is loaded
只有在字体加载完成后才调用 measureText()。这适用于 Google 字体(下面示例)或任何其他字体加载机制。
🌐 Only call measureText() after the font is loaded. This applies to Google Fonts (example below) or any other font loading mechanism.
包含 useEffect 的示例
🌐 Example with useEffect
MyComp.tsximport {useState ,useEffect } from 'react'; import {Dimensions ,measureText } from '@remotion/layout-utils'; import {loadFont ,fontFamily } from '@remotion/google-fonts/Inter'; const {waitUntilDone } =loadFont ('normal'); constMyComp :React .FC = () => { const [dimensions ,setDimensions ] =useState <Dimensions | null>(null);useEffect (() => { // Wait until the font is loaded before measuring textwaitUntilDone ().then (() => { constmeasurement =measureText ({fontFamily :fontFamily ,fontSize : 14,fontWeight : '400',text : 'Hello world', }); // We don't need to use delayRender() here, because // font loading from @remotion/google-fonts is already wrapped in itsetDimensions (measurement ); }); }, []); return null; };
使用高阶组件的示例
🌐 Example with high-order component
以下逻辑借鉴自 Remotion Recorder。 它通过暴露一个高阶组件来保持代码整洁,该组件只有在字体加载完成时才会挂载其子组件。
🌐 This following logic is borrowed from the Remotion Recorder.
It keeps the code clean by exposing a high-order component which only mounts its children when the font is loaded.
定义了一个加载一些字体的文件:
🌐 A file is defined which loads some fonts:
fonts.tsimport {fontFamily asregularFont ,loadFont asloadRegular } from '@remotion/google-fonts/Inter'; import {fontFamily asmonospaceFont ,loadFont asloadMonospace } from '@remotion/google-fonts/RobotoMono'; import {cancelRender ,continueRender ,delayRender } from 'remotion'; constregular =loadRegular (); constmonospace =loadMonospace (); export constwaitForFonts = async () => { awaitregular .waitUntilDone (); awaitmonospace .waitUntilDone (); }; constdelay =delayRender ('Loading fonts');waitForFonts () .then (() =>continueRender (delay )) .catch ((err ) =>cancelRender (err ));
然后定义了一个高阶组件,只有在字体加载完成时才渲染它的子组件:
🌐 Then a higher order component is defined which only renders it's children when the font is loaded:
WaitForFonts.tsximportReact , {useEffect ,useState } from 'react'; import {cancelRender ,continueRender ,useDelayRender } from 'remotion'; import {waitForFonts } from './fonts'; export constWaitForFonts :React .FC <{children :React .ReactNode ; }> = ({children }) => { const [fontsLoaded ,setFontsLoaded ] =useState (false); const {delayRender ,continueRender } =useDelayRender (); const [handle ] =useState (() =>delayRender ('Waiting for fonts to be loaded'));useEffect (() => { if (fontsLoaded ) { return; }waitForFonts () .then (() => {setFontsLoaded (true); }) .catch ((err ) => {cancelRender (err ); }); }, [fontsLoaded ,handle ,continueRender ,delayRender ]);useEffect (() => { if (fontsLoaded ) {continueRender (handle ); } }, [continueRender ,fontsLoaded ,handle ]); if (!fontsLoaded ) { return null; } return <>{children }</>; };
然后该组件可以封装任何调用文本测量 API 的其他组件:
🌐 Then the component can be wrap any other component that calls text measurement APIs:
MyComp.tsximportReact from 'react'; import {regular } from './fonts'; import {WaitForFonts } from './WaitForFonts'; import {measureText } from '@remotion/layout-utils'; constMyCompInner :React .FC = () => { // Safe to call measureText() here constmeasurement =measureText ({fontFamily :regular ,fontSize : 14,fontWeight : '400',text : 'Hello world', }); return null; }; export constMyComp :React .FC = () => { return ( <WaitForFonts > <MyCompInner /> </WaitForFonts > ); };
使用 validateFontIsLoaded 选项v4.0.136
🌐 Use the validateFontIsLoaded optionv4.0.136
将 validateFontIsLoaded: true 传递给 measureText()、fitText() 和 fillTextBox() 中的任意一个,以验证你传递的字体家族是否已实际加载。
🌐 Pass validateFontIsLoaded: true to any of measureText(), fitText(), and fillTextBox() to validate that the font family you passed is actually loaded.
这将使用备用字体进行第二次测量,如果测量结果相同,它就会假定使用了备用字体并抛出错误。
🌐 This will take a second measurement with the fallback font and if it produces the same measurements, it assumes the fallback font was used and will throw an error.
在 Remotion v5 中,这将成为默认设置。
匹配所有字体属性
🌐 Match all font properties
在测量文本时,确保所有字体属性与你将在视频中使用的字体属性匹配。
这包括 fontFamily、fontSize、fontWeight、letterSpacing 和 fontVariantNumeric。
🌐 When measuring text, ensure that all font properties match the ones you are going to use in your video.
This includes fontFamily, fontSize, and fontWeight, letterSpacing and fontVariantNumeric.
你可以创建可重用的变量,在测量函数和实际组件中都引用它们。
🌐 You could make reusable variables that you reference in both the measuring function and the actual component.
Using variables for font propertiesimport {measureText } from '@remotion/layout-utils'; consttext = 'Hello world'; constfontFamily = 'Inter'; constfontWeight = 'bold'; constfontSize = 16; // Use the variable in the measurement function:measureText ({text ,fontFamily ,fontWeight ,fontSize , }); // As well as in markup <div style ={{fontFamily ,fontWeight ,fontSize }}>{text }</div >;
注意边框和内边距
🌐 Be aware of borders and padding
在一个单词中添加 padding 或 border 会影响测量结果。
完全避免使用 padding,并使用单词之间的自然间距。
不要使用 border,而是使用 outline 在文本外添加一行而不影响布局。
🌐 Adding a padding or a border to a word will skew the measurements.
Avoid using padding altogether and use the natural spacing between words.
Instead of border, use an outline to add a line outside the text without affecting its layout.
空白
🌐 Whitespace
在测量时,布局工具将使用应用了 display: inline-block 和 white-space: pre 的 <span> 来换行文本。
这也会测量空白字符的宽度。
🌐 When measuring, the Layout utils will wrap the text in a <span> with display: inline-block and white-space: pre applied.
This will also measure the width of the whitespace characters.
也将这两个 CSS 属性添加到你的标记中,以使其与测量值匹配。
🌐 Add those two CSS properties to your markup as well to match it with the measurements.
服务器端渲染
🌐 Server-side rendering
布局工具需要在浏览器中运行。
如果你在将进行服务器端渲染的组件中使用它们,那么我们建议你在 useEffect 中调用这些函数,就像本页第一个示例中那样。
🌐 The layout utilities need to be run in a browser.
If you are using them in a component that will be server-side rendered, then we recommend you call the functions in a useEffect, like on the first example on this page.