Создание и изменение пользовательских анимационных поведений в Java

Обзор

Пользовательские анимационные поведения позволяют управлять отдельными операциями внутри анимационного эффекта, такими как изменение цвета, вращение фигуры или следование по редактируемой траектории движения. В этом руководстве показано, как создавать и комбинировать поведения, настраивать их синхронизацию, просматривать и изменять существующие анимации, а также проверять, сохраняются ли их свойства при сохранении и повторном открытии презентации.

Для предустановленных эффектов и триггеров клика см. Анимация фигур.

Понимание модели анимации

Анимация организована как Timeline → Sequence → Effect → Behaviors:

  • Метод getTimeline возвращает таймлайн слайда, который содержит его основную последовательность и интерактивные последовательности.
  • ISequence содержит эффекты, потенциально направленные на разные фигуры.
  • IEffect определяет целевую фигуру, предустановку, подтип и синхронизацию эффекта.
  • Коллекция, возвращаемая IEffect.getBehaviors, содержит операции, реализующие эффект: изменение цвета, перемещение, вращение, установка свойства и т.д.

Создание отдельных поведений

Вызовите ISequence.addEffect для создания эффекта и доступа к коллекции getBehaviors. Предустановка может автоматически заполнить эту коллекцию. Сохраните её операции при расширении предустановки или используйте clear при сознательной замене.

IBehaviorFactory создаёт восемь типов поведений, показанных ниже. Движение рассматривается в разделе Создание траектории движения. Каждый фрагмент кода включает свои импорты; размещайте исполняемые инструкции внутри метода. В примерах последующего редактирования указано, какой файл‑вывод они используют.

Вращение

Используйте createRotationEffect для создания вращения. getBy указывает относительный угол в градусах; getFrom и getTo задают конечные точки.

Пример начинается с эффекта Spin, заменяет его предустановленные операции одним поведением вращения и задаёт этому поведению длительность два секунды. Относительный угол 90 градусов представляет четверть оборота от исходной ориентации фигуры, поэтому явный начальный угол не требуется.

import com.aspose.slides.*;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Spin, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IRotationEffect rotation = factory.createRotationEffect();
    rotation.setBy(90f);
    rotation.getTiming().setDuration(2f);

    effect.getBehaviors().add(rotation);

    presentation.save("rotation.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

rotation.pptx содержит одну фигуру и одно поведение вращения. Коллекция, синхронизация и примеры редактирования вращения ниже используют этот файл.

Масштаб

Используйте createScaleEffect с процентами X/Y: getFrom и getTo описывают начальный и конечный размер, а getBy описывает относительное изменение. Здесь 100 означает исходный размер.

Пример увеличивает обе измерения с 100 % до 125 % за две секунды. Использование одинаковых горизонтальных и вертикальных процентов сохраняет пропорции фигуры; разные проценты растягивают одну из сторон сильнее.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.GrowShrink, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IScaleEffect scale = factory.createScaleEffect();
    scale.setFrom(new Point2D.Float(100, 100));
    scale.setTo(new Point2D.Float(125, 125));
    scale.getTiming().setDuration(2f);

    effect.getBehaviors().add(scale);

    presentation.save("scale.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Цвет

Используйте createColorEffect для изменения заливки с синего на оранжевый. getFrom и getTo – это цвета; getBy – смещение цвета. IBehavior.getProperties определяет атрибут, который анимируется.

Заливка фигуры изначально установлена в синий, что соответствует начальному цвету анимации. Выбор атрибута заливки указывает поведению, какую часть фигуры менять; сами конечные цвета атрибут не определяют. Сохранённый эффект описывает двухсекундный переход к оранжевому.

import com.aspose.slides.*;
import java.awt.Color;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
    shape.getFillFormat().setFillType(FillType.Solid);
    shape.getFillFormat().getSolidFillColor().setColor(Color.BLUE);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.ChangeFillColor, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IColorEffect color = factory.createColorEffect();
    color.getProperties().add(BehaviorProperty.getFillColor().getValue());
    color.getFrom().setColor(Color.BLUE);
    Color orange = new Color(255, 165, 0);
    color.getTo().setColor(orange);
    color.getTiming().setDuration(2f);

    effect.getBehaviors().add(color);

    presentation.save("color.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Фильтр

Используйте createFilterEffect для выбора стирания. getType, getSubtype, и getReveal задают тип фильтра, направление и то, будет ли фигура раскрыта или скрыта.

Этот пример конфигурирует двухсекундный стирающий эффект, который раскрывает фигуру с направлением «вправо». Параметры фильтра принадлежат поведению внутри эффекта, поэтому они настраиваются после удаления оригинальных операций предустановки.

import com.aspose.slides.*;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Wipe, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IFilterEffect filter = factory.createFilterEffect();
    filter.setType(FilterEffectType.Wipe);
    filter.setSubtype(FilterEffectSubtype.Right);
    filter.setReveal(FilterEffectRevealType.In);
    filter.getTiming().setDuration(2f);

    effect.getBehaviors().add(filter);

    presentation.save("filter.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Свойство

Используйте createPropertyEffect для анимации непрозрачности. getFrom, getTo, и getBy – строки, интерпретируемые с помощью getValueType и getCalcMode. Выбирайте конечные значения или относительное смещение, а не задавайте все три без разбора.

Здесь выбранный атрибут – непрозрачность, а числовые строки представляют изменение от 25 % к полной непрозрачности. Линейная интерполяция описывает постепенное изменение между этими значениями. При адаптации примера к другому атрибуту выберите тип значения и конечные значения, соответствующие этому атрибуту.

import com.aspose.slides.*;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IPropertyEffect property = factory.createPropertyEffect();
    property.getProperties().add(BehaviorProperty.getStyleOpacity().getValue());
    property.setValueType(PropertyValueType.Number);
    property.setCalcMode(PropertyCalcModeType.Linear);
    property.setFrom("0.25");
    property.setTo("1");
    property.getTiming().setDuration(2f);

    effect.getBehaviors().add(property);

    presentation.save("property.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Установка

Используйте createSetEffect для задания видимости через getTo. Поведение «set» не интерполирует между конечными точками.

Пример выбирает атрибут видимости и присваивает строку visible при выполнении поведения. Прямоугольник уже видим в этой минимальной презентации, поэтому присваивание может не вызвать заметного визуального изменения само по себе. Такая операция полезна как часть более крупного эффекта, который также управляет моментом скрытия или отображения фигуры.

import com.aspose.slides.*;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Appear, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    ISetEffect set = factory.createSetEffect();
    set.getProperties().add(BehaviorProperty.getStyleVisibility().getValue());
    set.setTo("visible");

    effect.getBehaviors().add(set);

    presentation.save("set.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Команда

Используйте createCommandEffect и настройте getType, getCommandString, и getShapeTarget. Поместите WAV‑запись sample.wav в рабочий каталог. Этот пример внедряет её с помощью addAudioFrameEmbedded и привязывает команду воспроизведения к аудиофрейму.

Аудиофрейм является одновременно целью эффекта и целью команды. Это связывает запрос воспроизведения с внедрённой записью; сама строка команды не указывает, какой медиа‑объект контролировать. Эффект настроен на запуск по щелчку во время показа.

import com.aspose.slides.*;
import java.io.FileInputStream;
import java.io.IOException;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    try (FileInputStream audioStream = new FileInputStream("sample.wav")) {
        IAudioFrame audioFrame = slide.getShapes().addAudioFrameEmbedded(100, 100, 40, 40, audioStream);

        IEffect effect = slide.getTimeline().getMainSequence().addEffect(audioFrame, EffectType.MediaPlay, EffectSubtype.None, EffectTriggerType.OnClick);
        effect.getBehaviors().clear();

        IBehaviorFactory factory = new BehaviorFactory();
        ICommandEffect command = factory.createCommandEffect();
        command.setType(CommandEffectType.Call);
        command.setCommandString("play");
        command.setShapeTarget(audioFrame);

        effect.getBehaviors().add(command);

        presentation.save("command.pptx", SaveFormat.Pptx);
    } catch (IOException exception) {
        System.out.println("Unable to read sample.wav: " + exception.getMessage());
    }
} finally {
    presentation.dispose();
}

Сохранение сохраняет команду в command.pptx; она не воспроизводит запись. Воспроизведение требует проигрывателя слайдов, поддерживающего данную команду и её медиа‑цель.

Управление коллекцией поведений

IBehaviorCollection поддерживает add, insert, remove, и removeAt. Этот пример открывает rotation.pptx, добавляет масштабирование, перемещает его перед вращением и удаляет вращение. Удаление и повторная вставка того же объекта меняют его сохранённую позицию без создания копии.

Последовательность правок меняет коллекцию с rotation–scale на scale–rotation, затем оставляет только масштаб. Индексы относятся к текущей коллекции, поэтому удаление использует новый индекс вращения после переупорядочения. Финальный перебор подтверждает, какое поведение будет сохранено.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation("rotation.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
    IBehaviorCollection behaviors = effect.getBehaviors();

    IBehaviorFactory factory = new BehaviorFactory();
    IScaleEffect scale = factory.createScaleEffect();
    scale.setTo(new Point2D.Float(125, 125));
    scale.getTiming().setDuration(2f);

    behaviors.add(scale);

    behaviors.remove(scale);
    behaviors.insert(0, scale);
    behaviors.removeAt(1);

    for (IBehavior behavior : behaviors)
        System.out.println(behavior.getClass().getSimpleName());

    presentation.save("collection-edited.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результатом является ScaleEffect: остаётся только масштабирование. Порядок в коллекции сам по себе не задаёт последовательное воспроизведение поведений. Очищать коллекцию следует только при полном замещении её операций.

Настройка синхронизации поведения

IBehavior.getTiming раскрывает ITiming, независимо от IEffect.getTiming. Синхронизация эффекта планирует весь эффект, а синхронизация поведения описывает операцию внутри него.

Установка длительности, задержки, повторений и ускорения

Откройте rotation.pptx и задайте длительность (getDuration) и задержку триггера (getTriggerDelayTime) в секундах, затем настройте количество повторов через setRepeatCount. getAccelerate и getDecelerate – доли от общей длительности; их сумма не должна превышать 1.

Входной файл – тот, что был создан в примере вращения, где первое поведение известно как вращение. Этот пример меняет только синхронизацию этого поведения; угол в 90 градусов остаётся неизменным. Разделение угла и синхронизации упрощает настройку темпа без переработки всей анимации.

import com.aspose.slides.*;

Presentation presentation = new Presentation("rotation.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);

    IRotationEffect rotation = (IRotationEffect)effect.getBehaviors().get_Item(0);
    rotation.getTiming().setDuration(2f);
    rotation.getTiming().setTriggerDelayTime(0.5f);
    rotation.getTiming().setRepeatCount(3f);
    rotation.getTiming().setAccelerate(0.2f);
    rotation.getTiming().setDecelerate(0.2f);

    presentation.save("timing.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Поведение использует длительность две секунды, задержку полсекунды и количество повторов = 3. Первые и последние 20 % длительности отводятся ускорению и замедлению.

Другие политики повторов включают getRepeatDuration, getRepeatUntilEndSlide, и getRepeatUntilNextClick; выбирайте одну политику, а не включайте их все одновременно. getAutoReverse воспроизводит анимацию в обратном направлении после прямого прохода. Ускорение и замедление применяются к непрерывным изменениям, а не к дискретным присваиваниям или командам.

Создание траектории движения

Используйте createMotionEffect для создания движения. Его getFrom, getTo, и getBy описывают координаты или смещения в процентах. Для редактируемого маршрута создайте MotionPath и назначьте его с помощью IMotionEffect.setPath. IMotionPath хранит команды пути.

MotionCommandPathType выбирает операцию:

Команда Точки Значение
MoveTo Одна Устанавливает начальную позицию.
LineTo Одна Движется по прямому отрезку к его конечной точке.
CurveTo Три Следует кубической кривой, определяемой двумя контрольными точками и конечной точкой.
CloseLoop Нет Возвращается к начальной позиции.
End Нет Завершает путь.

MotionPathPointsType описывает характер редактирования точек, например угловые или гладкие точки. Это не заменяет тип команды. Для кривой используйте тип точек curve, а для прямых сегментов – тип corner.

Координаты пути нормализованы по размерам слайда: смещение X = 0.25 соответствует одной четверти ширины слайда, а не 0.25 пунктам. Положительный Y идёт вниз. Абсолютные команды указывают позиции в системе координат пути; относительные – смещения от текущей позиции. Это отдельный параметр от getOrigin, который выбирает референтную систему пути, и от getPathEditMode, управляющего тем, как путь перемещается вместе с фигурой.

Создание прямого пути

Создайте поведение движения с начальной точкой, одним прямым сегментом и командой завершения. IMotionPath.add принимает тип команды, её точки, тип точек и флаг относительных координат.

Начальная команда задаёт (0, 0), а линия заканчивается в (0.25, 0), давая маршруту горизонтальное смещение в одну четверть ширины слайда. Команда завершения не имеет координатных точек. После назначения пути добавление поведения движения к эффекту связывает этот маршрут с прямоугольником.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);

    IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.PathRight, EffectSubtype.None, EffectTriggerType.OnClick);
    effect.getBehaviors().clear();

    IBehaviorFactory factory = new BehaviorFactory();
    IMotionEffect motion = factory.createMotionEffect();
    motion.setOrigin(MotionOriginType.Layout);
    motion.getTiming().setDuration(2f);

    IMotionPath path = new MotionPath();
    path.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0, 0) }, MotionPathPointsType.Auto, false);
    path.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.25f, 0) }, MotionPathPointsType.Corner, false);
    path.add(MotionCommandPathType.End, new Point2D.Float[0], MotionPathPointsType.None, false);

    motion.setPath(path);
    effect.getBehaviors().add(motion);

    presentation.save("motion.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

motion.pptx содержит одно движение с тремя командами пути. Далее приведённые примеры редактирования файлов используют эту известную структуру.

Сравнение абсолютных и относительных координат

Эти два объекта пути описывают один и тот же маршрут. Абсолютная команда заканчивается в (0.3, 0.1); относительная команда прибавляет (0.1, 0.1) к текущей позиции, получая (0.2, 0).

Оба пути начинаются из одной позиции. Для относительной линии добавьте её смещения X и Y к текущей позиции, чтобы получить конечную точку; для абсолютной – читайте конечную точку напрямую. Переключение флага без преобразования координат даст иной маршрут.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

MotionPath absolutePath = new MotionPath();
absolutePath.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0) }, MotionPathPointsType.Auto, false);
absolutePath.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.3f, 0.1f) }, MotionPathPointsType.Corner, false);

MotionPath relativePath = new MotionPath();
relativePath.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0) }, MotionPathPointsType.Auto, false);
relativePath.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.1f, 0.1f) }, MotionPathPointsType.Corner, true);

Назначьте любой из путей поведению движения, чтобы использовать его в презентации. Последний логический аргумент выбирает относительные координаты для этой команды.

Замена линии кривой

Откройте motion.pptx и замените её команду линии кубической кривой. Сначала укажите две контрольные точки, затем конечную точку.

Начальная позиция задаётся предыдущей командой. Первые две точки формируют кривую, а третья – её конечную точку; они не являются тремя последовательными конечными точками. Одновременное обновление типа команды, типа редактирования точек и массива точек сохраняет согласованность сегмента с новой геометрией.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation("motion.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
    IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);

    IMotionPath path = motion.getPath();
    path.get_Item(1).setCommandType(MotionCommandPathType.CurveTo);
    path.get_Item(1).setPointsType(MotionPathPointsType.CurveSmooth);
    path.get_Item(1).setPoints(new Point2D.Float[] { new Point2D.Float(0.1f, 0), new Point2D.Float(0.2f, 0.1f), new Point2D.Float(0.3f, 0.1f) });

    presentation.save("curve.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Путь в curve.pptx по‑прежнему имеет три команды; теперь его средняя команда определяет кривую.

Просмотр и редактирование сохранённого пути

Каждый IMotionCmdPath раскрывает getPoints, getCommandType, getPointsType, и isRelative. Ниже приведённые примеры используют известный трёхкомандный путь в motion.pptx. Для произвольного ввода сначала найдите нужный эффект и проверьте типы команд и количество точек перед редактированием по индексу.

Чтение команд и координат

Чтение пути без его изменения. Команды End и CloseLoop не требуют точек, поэтому допускайте массив точек, равный null.

Вывод сопоставляет каждый числовой тип команды с её флагом относительных координат перед перечислением точек. Это позволяет различать конечную точку и смещение перед изменением пути. Кривая будет перечислять три точки, тогда как прямая линия в этом файле – только одну.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation("motion.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
    IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);

    IMotionPath path = motion.getPath();
    for (IMotionCmdPath segment : path)
    {
        System.out.println(segment.getCommandType() + ", relative: " + segment.isRelative());
        if (segment.getPoints() != null)
            for (Point2D.Float point : segment.getPoints())
                System.out.println("X=" + point.x + ", Y=" + point.y);
    }
} finally {
    presentation.dispose();
}

Список содержит начальную точку, абсолютную линию, заканчивающуюся в (0.25, 0), и команду End.

Изменение конечной точки

Откройте motion.pptx и замените массив точек линии, переместив её конечную точку.

В входном файле индекс 0 – начальная команда, индекс 1 – линия. Замена единственной точки линии меняет её пункт назначения без изменения типа команды, синхронизации или позиции в коллекции. Поскольку команда использует абсолютные координаты, новая пара указывает позицию, а не добавочный смещение.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation("motion.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);

    IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);
    motion.getPath().get_Item(1).setPoints(new Point2D.Float[] { new Point2D.Float(0.4f, 0.1f) });

    presentation.save("motion-endpoint.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Линия в motion-endpoint.pptx заканчивается в (0.4, 0.1); оригинальный файл остаётся без изменений.

Замена сегмента

Используйте insert и removeAt для замены линии в motion.pptx. Вставка сдвигает старую линию к индексу 2.

Это демонстрирует замену объекта команды, а не редактирование его текущих координат. После вставки коллекция временно содержит начальную команду, новую линию, старую линию и команду End. Удаление индекса 2 отбрасывает старую линию, оставляя новый маршрут на месте.

import com.aspose.slides.*;
import java.awt.geom.Point2D;

Presentation presentation = new Presentation("motion.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
    IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);

    IMotionPath path = motion.getPath();
    path.insert(1, MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0.1f) }, MotionPathPointsType.Corner, false);
    path.removeAt(2);

    presentation.save("motion-edited.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Сохранённый путь всё ещё содержит три команды, новая линия заканчивается в (0.2, 0.1), а команда End остаётся последней.

Изменение и проверка существующего поведения

Когда индекс поведения неизвестен, выберите его по типу. Этот пример открывает rotation.pptx, ищет IRotationEffect, меняет угол и проверяет сохранённое значение после повторного открытия.

Проверка типа позволяет пропустить поведения, не являющиеся вращениями. Второй загрузка читает сохранённый файл в отдельный объект презентации, поэтому сравнение проверяет устойчивые данные, а не значение, оставшееся в памяти. Пример по‑прежнему предполагает, что известный эффект первый в основной последовательности; выбор поведения по типу не находит нужный эффект в произвольной презентации.

import com.aspose.slides.*;

Presentation presentation = new Presentation("rotation.pptx");
try {
    IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);

    for (IBehavior behavior : effect.getBehaviors())
    {
        if (behavior instanceof IRotationEffect) {
            IRotationEffect rotation = (IRotationEffect) behavior;
            rotation.setBy(180f);
        }
    }

    presentation.save("rotation-edited.pptx", SaveFormat.Pptx);

    Presentation reopened = new Presentation("rotation-edited.pptx");
    try {
        IEffect savedEffect = reopened.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);

        for (IBehavior behavior : savedEffect.getBehaviors())
        {
            if (behavior instanceof IRotationEffect) {
                IRotationEffect rotation = (IRotationEffect) behavior;
                System.out.println("Rotation preserved: " + (Math.abs(rotation.getBy() - 180f) < 0.001f));
            }
        }
    } finally {
        reopened.dispose();
    }
} finally {
    presentation.dispose();
}

Вывод: Rotation preserved: true. Применяйте такой же паттерн проверки типа к другим поведениям. Для полного контроля сравните целевую фигуру, эффект, типы и порядок поведений, синхронизацию и команды пути. Используйте числовой допуск для значений с плавающей точкой. Для презентаций с неизвестной структурой анимации см. Чтение анимаций фигур для обхода основных и интерактивных последовательностей.

Порядок поведений, предустановки и воспроизведение

Порядок в IBehaviorCollection – это сохранённый порядок операций эффекта. Это не плейлист, в котором каждое поведение автоматически ждёт предыдущее. Синхронизация и окружающий эффект определяют планирование. Поведения могут накладываться, а операции над одним и тем же свойством могут взаимодействовать через getAdditive и getAccumulate. Не используйте простое переупорядочивание коллекции для планирования «сдвиг, затем вращение»; применяйте явную синхронизацию или отдельные эффекты, как описано в Анимация фигур.

IEffect.getType и IEffect.getSubtype описывают предустановку эффекта. Это не полное описание отредактированного дерева поведений. Выбирайте предустановку и подтип до кастомизации поведений: изменение предустановки может перестроить коллекцию и удалить ваши пользовательские операции. Например, изменение настроенного эффекта Spin на Fade может заменить его поведение вращения на поведения set и filter. После изменения предустановки или подтипа снова проверьте коллекцию. Очистка предустановленных поведений может также удалить операции видимости или инициализации, необходимые предустановке. Примеры сознательно используют видимые фигуры и заменяют поведения; они не перестраивают полную реализацию каждой предустановки.

Совместимость форматов

Сохранённое дерево поведений не гарантирует идентичное воспроизведение во всех средствах просмотра или экспортных рендерерах. Проверяйте сохранённые данные и отрендеренный вывод отдельно.

Формат или вывод Что проверять
PPTX Используйте как основной формат для этих примеров. Откройте файл повторно, чтобы проверить редактируемое дерево поведений, затем проверьте воспроизведение в целевой версии PowerPoint.
PPT Устаревшее бинарное представление может отличаться от PPTX. Выполните отдельный цикл сохранения‑повторного открытия и проверьте воспроизведение; не делайте выводы о поддержке каждой пользовательской комбинации исключительно по успешному PPTX‑выводу.
PDF, PNG, JPEG и другие статические изображения слайдов Содержат статическое представление слайда, а не проигрываемую временную линию поведения или гарантированный конечный кадр анимации.
HTML5 Может воспроизводить поддерживаемые анимации, когда в параметрах экспорта включена анимация фигур. Тестируйте пользовательские комбинации в браузере.
Animated GIF Сохраняет отрендеренные кадры, а не редактируемые поведения или интерактивные триггеры. Проверяйте фактическое отрендеренное движение.
Video Рендерит кадры анимации и кодирует их в видео. Поддержка ограничена поддерживаемыми анимациями и эффектами; команды и интерактивные события не становятся редактируемой временной линией.

FAQ

Почему мой эффект уже содержит поведения, хотя я ничего не добавлял?

Создание предустановленного эффекта может создать его внутренние операции. Просмотрите их, прежде чем решать, расширять предустановку или заменять её поведения.

Если перенести поведение в начало, будет ли оно воспроизводиться первым?

Не обязательно. Порядок в коллекции не заменяет синхронизацию. Проверьте задержки, длительности и взаимодействия операций над одним и тем же свойством.

Почему у команды End нет точек?

Она обозначает конец пути и не требует координат. При просмотре пути, считанного из файла, проверяйте наличие массива точек, равного null.

Достаточно ли успешного кругового прохода, чтобы подтвердить воспроизведение?

Нет. Повторное открытие подтверждает сохранность проверенных свойств. Тестируйте проигрыватель слайдов или экспорт анимации отдельно, чтобы подтвердить визуальное поведение.