Skip to main content

自定义演示

本页面描述如何为 <TransitionSeries> 创建自定义效果。

概念

演示是一个高阶组件,包裹进入幻灯片和退出幻灯片,并基于三个参数实现效果:

当前的 presentationProgress,受过渡时间的影响


presentationDirection,可以是 enteringexiting


presentationDurationInFrames(从 v4.0.153 版本开始可用)
4
开发者定义的额外 passedProps

样板

自定义演示是一个返回 TransitionPresentation 类型对象的函数。
它是一个包含 React 组件(component)和作为 passedProps 传递给组件的 React props 的对象。

custom-presentation.tsx
tsx
import type {TransitionPresentation} from '@remotion/transitions';
 
type CustomPresentationProps = {
width: number;
height: number;
};
 
export const customPresentation = (
props: CustomPresentationProps,
): TransitionPresentation<CustomPresentationProps> => {
return {component: StarPresentation, props};
};
custom-presentation.tsx
tsx
import type {TransitionPresentation} from '@remotion/transitions';
 
type CustomPresentationProps = {
width: number;
height: number;
};
 
export const customPresentation = (
props: CustomPresentationProps,
): TransitionPresentation<CustomPresentationProps> => {
return {component: StarPresentation, props};
};

component 是一个接收以下 props 的 React 组件:

children: 要包裹的标记


presentationDirection: 可以是 "entering" "exiting"


presentationProgress: 介于 0 1 之间的数字,表示过渡的进度。


passedProps: 传递给演示的自定义 props



StarPresentation.tsx
tsx
import type {TransitionPresentationComponentProps} from '@remotion/transitions';
import {AbsoluteFill} from 'remotion';
 
const StarPresentation: React.FC<
TransitionPresentationComponentProps<CustomPresentationProps>
> = ({children, presentationDirection, presentationProgress, passedProps}) => {
return (
<AbsoluteFill>
<AbsoluteFill>{children}</AbsoluteFill>
</AbsoluteFill>
);
};
StarPresentation.tsx
tsx
import type {TransitionPresentationComponentProps} from '@remotion/transitions';
import {AbsoluteFill} from 'remotion';
 
const StarPresentation: React.FC<
TransitionPresentationComponentProps<CustomPresentationProps>
> = ({children, presentationDirection, presentationProgress, passedProps}) => {
return (
<AbsoluteFill>
<AbsoluteFill>{children}</AbsoluteFill>
</AbsoluteFill>
);
};

示例

A
B

以下示例实现了星形遮罩过渡:

基于 passedProps heightwidth,计算星星的内半径,以完全填充画布。


使用 @remotion/shapes,计算 SVG 路径,并从零增长到画布的全尺寸。
3
使用 presentationProgress 插值形状大小。
4
使用 @remotion/paths 将星星居中在画布中央。


使用 clipPath 剪切进入幻灯片。 在容器内,渲染 children


如果 presentationDirection 设置为 "exiting",则禁用效果。



StarPresentation.tsx
tsx
import {getBoundingBox, translatePath} from '@remotion/paths';
import {makeStar} from '@remotion/shapes';
import type {TransitionPresentationComponentProps} from '@remotion/transitions';
import React, {useMemo, useState} from 'react';
import {AbsoluteFill, random} from 'remotion';
 
export type CustomPresentationProps = {
width: number;
height: number;
};
 
const StarPresentation: React.FC<
TransitionPresentationComponentProps<CustomPresentationProps>
> = ({children, presentationDirection, presentationProgress, passedProps}) => {
const finishedRadius =
Math.sqrt(passedProps.width ** 2 + passedProps.height ** 2) / 2;
const innerRadius = finishedRadius * presentationProgress;
const outerRadius = finishedRadius * 2 * presentationProgress;
 
const {path} = makeStar({
innerRadius,
outerRadius,
points: 5,
});
 
const boundingBox = getBoundingBox(path);
 
const translatedPath = translatePath(
path,
passedProps.width / 2 - boundingBox.width / 2,
passedProps.height / 2 - boundingBox.height / 2,
);
 
const [clipId] = useState(() => String(random(null)));
 
const style: React.CSSProperties = useMemo(() => {
return {
width: '100%',
height: '100%',
clipPath:
presentationDirection === 'exiting' ? undefined : `url(#${clipId})`,
};
}, [clipId, presentationDirection]);
 
return (
<AbsoluteFill>
<AbsoluteFill style={style}>{children}</AbsoluteFill>
{presentationDirection === 'exiting' ? null : (
<AbsoluteFill>
<svg>
<defs>
<clipPath id={clipId}>
<path d={translatedPath} fill="black" />
</clipPath>
</defs>
</svg>
</AbsoluteFill>
)}
</AbsoluteFill>
);
};
StarPresentation.tsx
tsx
import {getBoundingBox, translatePath} from '@remotion/paths';
import {makeStar} from '@remotion/shapes';
import type {TransitionPresentationComponentProps} from '@remotion/transitions';
import React, {useMemo, useState} from 'react';
import {AbsoluteFill, random} from 'remotion';
 
export type CustomPresentationProps = {
width: number;
height: number;
};
 
const StarPresentation: React.FC<
TransitionPresentationComponentProps<CustomPresentationProps>
> = ({children, presentationDirection, presentationProgress, passedProps}) => {
const finishedRadius =
Math.sqrt(passedProps.width ** 2 + passedProps.height ** 2) / 2;
const innerRadius = finishedRadius * presentationProgress;
const outerRadius = finishedRadius * 2 * presentationProgress;
 
const {path} = makeStar({
innerRadius,
outerRadius,
points: 5,
});
 
const boundingBox = getBoundingBox(path);
 
const translatedPath = translatePath(
path,
passedProps.width / 2 - boundingBox.width / 2,
passedProps.height / 2 - boundingBox.height / 2,
);
 
const [clipId] = useState(() => String(random(null)));
 
const style: React.CSSProperties = useMemo(() => {
return {
width: '100%',
height: '100%',
clipPath:
presentationDirection === 'exiting' ? undefined : `url(#${clipId})`,
};
}, [clipId, presentationDirection]);
 
return (
<AbsoluteFill>
<AbsoluteFill style={style}>{children}</AbsoluteFill>
{presentationDirection === 'exiting' ? null : (
<AbsoluteFill>
<svg>
<defs>
<clipPath id={clipId}>
<path d={translatedPath} fill="black" />
</clipPath>
</defs>
</svg>
</AbsoluteFill>
)}
</AbsoluteFill>
);
};

示例用法:

MyComp.tsx
tsx
export const MyComp: React.FC = () => {
const {width, height} = useVideoConfig();
 
return (
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={70}>
<Letter color="orange">A</Letter>
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={customPresentation({width, height})}
timing={springTiming({
durationInFrames: 45,
config: {
damping: 200,
},
durationRestThreshold: 0.0001,
})}
/>
<TransitionSeries.Sequence durationInFrames={60}>
<Letter color="pink">B</Letter>
</TransitionSeries.Sequence>
</TransitionSeries>
);
};
MyComp.tsx
tsx
export const MyComp: React.FC = () => {
const {width, height} = useVideoConfig();
 
return (
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={70}>
<Letter color="orange">A</Letter>
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={customPresentation({width, height})}
timing={springTiming({
durationInFrames: 45,
config: {
damping: 200,
},
durationRestThreshold: 0.0001,
})}
/>
<TransitionSeries.Sequence durationInFrames={60}>
<Letter color="pink">B</Letter>
</TransitionSeries.Sequence>
</TransitionSeries>
);
};

参考

查看已实现的演示文稿的源代码,以获取有用的参考。

另请参阅