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

Обзор

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

Для предустановленных эффектов и триггеров щелчка см. Shape Animation.

Поймите модель анимации

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

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

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

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

IBehaviorFactory создает восемь типов поведений, показанных ниже. Движение рассматривается в разделе Build a Motion Path. Каждый фрагмент кода включает свои импорты; размещайте исполняемые инструкции внутри метода. Примеры последующего редактирования указывают, какой файл вывода они используют. На Android замените имена файлов образцов полными путями в директории, доступной приложению, например в директории файлов вашего приложения.

Вращение

Используйте 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 android.graphics.PointF;

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 PointF(100, 100));
    scale.setTo(new PointF(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 android.graphics.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);
    int orange = Color.rgb(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. Поведение установки не интерполирует между конечными точками.

Пример выбирает атрибут видимости и присваивает строку 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, а затем только на scale. Индексы относятся к текущей коллекции, поэтому удаление использует новый индекс вращения после переупорядочения. Финальное перечисление подтверждает, какие поведения будут сохранены.

import com.aspose.slides.*;
import android.graphics.PointF;

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 PointF(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 выбирает операцию:

Command Points Meaning
MoveTo One Установить начальную позицию.
LineTo One Перейти по прямому сегменту к его конечной точке.
CurveTo Three Следовать кубической кривой, определённой двумя контрольными точками и конечной точкой.
CloseLoop None Вернуться к начальной позиции.
End None Завершить путь.

MotionPathPointsType описывает характеристики редактируемых точек, такие как угол или плавные точки. Это не заменяет тип команды. Используйте тип точки «кривая» для примера кривой ниже и тип «угол» для прямых сегментов.

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

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

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

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

import com.aspose.slides.*;
import android.graphics.PointF;

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 PointF[] { new PointF(0, 0) }, MotionPathPointsType.Auto, false);
    path.add(MotionCommandPathType.LineTo, new PointF[] { new PointF(0.25f, 0) }, MotionPathPointsType.Corner, false);
    path.add(MotionCommandPathType.End, new PointF[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 android.graphics.PointF;

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

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

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

Замена линии на кривую

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

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

import com.aspose.slides.*;
import android.graphics.PointF;

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 PointF[] { new PointF(0.1f, 0), new PointF(0.2f, 0.1f), new PointF(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 android.graphics.PointF;

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 (PointF 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 android.graphics.PointF;

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 PointF[] { new PointF(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 android.graphics.PointF;

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 PointF[] { new PointF(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. Применяйте тот же шаблон проверки типов к другим поведениям. Для полной проверки сохранения сравните целевую фигуру, эффект, типы и порядок поведений, тайминг и команды пути. Для презентации с неизвестной анимационной структурой см. Read Shape Animations для обхода основных и интерактивных последовательностей.

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

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

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

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

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

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

FAQ

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

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

Делает ли перемещение поведения в начало плейлиста его первым при воспроизведении?

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

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

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

Достаточно ли успешного кругового прохождения для подтверждения воспроизведения?

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