Widget 动画

本文介绍,如何为自定义的 绝对定位 的 Widget,实现从右侧淡入、淡出的动画效果

播放器的 Widget 区域划分为四个固定位置:

  • ⬅️ 左上角
  • ➡️ 右上角
  • ⬇️ 左下角
  • ↘️ 右下角

在用户点击屏幕时,如果这些区域中的 Widget 当前处于显示状态,播放器会自动触发动画使其隐藏。
上述四个位置的动画行为为内置实现,只要 Widget 插入在这些区域内,就会默认遵循该逻辑。

💡 但对于使用 绝对定位 的自定义 Widget,您需要手动适配隐藏/显示的动画逻辑。


Demo:插入绝对定位的 Widget

下面我们将实现一个 Demo,实现以下逻辑:

  1. 在左下角添加一个按钮;
  2. 点击按钮时,插入一个绝对定位的 Widget;
  3. 若该 Widget 已经存在,则再次点击按钮时将其隐藏;
  4. 该绝对定位 Widget 将适配播放器的动画系统,使其在点击屏幕后自动淡出

使用示例

import React, { useEffect, useState } from 'react';
import { View } from '@ray-js/components';
import clsx from 'clsx';
import {
  IPCPlayerIntegration,
  useCtx,
  useComponentHideState,
  ComponentConfigProps,
} from '@ray-js/ipc-player-integration';
import Styles from './index.module.less';
import '@ray-js/ipc-player-integration/iconfont/iconfont.css';

function WidgetAbsolute(props: ComponentConfigProps) {
  const [clickHidden, setClickHidden] = useState(false);
  const [allComponentShouldHidden] = useComponentHideState();
  const listen = () => {
    setClickHidden(prev => !prev);
  };
  useEffect(() => {
    // 监听 WidgetButtonClick 事件
    props.event.on('WidgetButtonClick', listen);
    return () => {
      props.event.off('WidgetButtonClick', listen);
    };
  }, [listen]);
  // ipc-plugin-absolute-move-in-right ipc-plugin-absolute-move-in-right-hide
  // 是预先设置好的 CSS 类型,用于实现右侧的淡入淡出动画
  return (
    <View
      className={clsx('ipc-plugin-absolute-move-in-right', {
        'ipc-plugin-absolute-move-in-right-hide': allComponentShouldHidden || clickHidden,
      })}
      style={{ width: '100px', height: '100px', backgroundColor: '#fff', color: '#ff6700' }}
    >
      1111
    </View>
  );
}

function WidgetButton(props: ComponentConfigProps) {
  const id = 'WidgetAbsolute';
  const handClick = () => {
    // 当点击按钮时,WidgetAbsolute 是否已经存在
    // 若存在就通过事件系统发布 WidgetButtonClick 事件
    // 否则将 WidgetAbsolute 插入到播放器中
    if (props.hasContent('absolute', id)) {
      props.event.emit('WidgetButtonClick');
    } else {
      props.addContent('absolute', {
        id: 'WidgetAbsolute',
        content: WidgetAbsolute,
        // 或者把样式写到 absoluteContentClassName css 类名里
        absolutePosition: {
          position: 'absolute',
          right: '30px',
          top: '50%',
          transform: 'translateY(-50%)',
        },
      });
    }
  };
  return (
    <View onClick={handClick} style={{ color: 'var(--fontColor)' }}>
      Button
    </View>
  );
}

export default function PageHome() {
  const devId = 'devId'; // your deviceId
  const instance = useCtx({
    devId,
  });

  useEffect(() => {
    instance.addContent('bottomLeft', {
      id: 'WidgetButton',
      content: WidgetButton,
    });
  }, []);

  return (
    <View className={Styles.container}>
      <View className={Styles.playerWarp} style={{ marginTop: 300 }}>
        <IPCPlayerIntegration
          style={{ height: '300px' }}
          instance={instance}
          devId={instance.devId}
          playerFit="cover"
        />
      </View>
    </View>
  );
}