Android에서 사용자 지정 애니메이션 동작 만들기 및 수정
개요
맞춤 애니메이션 동작을 사용하면 색상 변경, 도형 회전 또는 편집 가능한 모션 경로 따위와 같은 애니메이션 효과의 개별 작업을 제어할 수 있습니다. 이 가이드는 동작을 만들고 결합하는 방법, 타이밍을 구성하는 방법, 기존 애니메이션을 검사·수정하는 방법, 그리고 프레젠테이션을 저장하고 다시 열었을 때 속성이 유지되는지 확인하는 방법을 보여줍니다.
미리 정의된 효과와 클릭 트리거에 대해서는 도형 애니메이션을 참고하십시오.
애니메이션 모델 이해
애니메이션은 Timeline → Sequence → Effect → Behaviors 로 구성됩니다:
- getTimeline 메서드는 슬라이드 타임라인을 반환하며, 여기에는 기본 시퀀스와 인터랙티브 시퀀스가 포함됩니다.
- ISequence 은 다양한 도형을 대상으로 할 수 있는 효과들을 포함합니다.
- IEffect 은 대상 도형, 프리셋, 서브타입 및 효과 타이밍을 식별합니다.
- IEffect.getBehaviors 가 반환하는 컬렉션에는 색상 변경, 이동, 회전, 속성 설정 등 효과를 구현하는 작업이 들어 있습니다.
개별 동작 만들기
ISequence.addEffect 를 호출하여 효과를 만들고 getBehaviors 컬렉션에 접근합니다. 프리셋을 사용하면 이 컬렉션이 자동으로 채워집니다. 프리셋을 확장할 때는 해당 작업을 유지하거나, 의도적으로 교체할 경우 clear 를 사용하십시오.
IBehaviorFactory 는 아래에 나타낸 여덟 가지 동작 유형을 생성합니다. 모션에 대해서는 모션 경로 만들기 를 참고하십시오. 각 스니펫에는 필요한 import 문이 포함되어 있으며, 실행 가능한 구문은 메서드 내부에 배치합니다. 이후 편집 예제에서는 사용한 출력 파일명을 명시합니다. Android에서는 샘플 파일명을 앱이 접근 가능한 디렉터리(예: 앱의 files 디렉터리)의 전체 경로로 교체하십시오.
회전
createRotationEffect 로 회전 효과를 생성합니다. getBy 은 상대 각도를 도(°) 단위로 지정하고, getFrom 과 getTo 은 시작점과 끝점을 지정합니다.
예제는 Spin 효과를 시작점으로 하여 프리셋 작업을 하나의 회전 동작으로 교체하고, 해당 동작에 2초 지속 시간을 부여합니다. 90도라는 상대 각도는 도형의 시작 방향에서 1/4회전임을 의미하므로 명시적인 시작 각도를 지정할 필요가 없습니다.
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에는 하나의 도형과 하나의 회전 동작이 들어 있습니다. 아래의 컬렉션, 타이밍 및 회전 편집 예제는 이 파일을 사용합니다.
크기 조절
[X/Y 백분율]을 사용하려면 createScaleEffect 를 이용합니다. getFrom 와 getTo 은 시작 및 종료 크기를 설명하고, getBy 은 상대 변화를 나타냅니다. 여기서 100은 원래 크기를 의미합니다.
예제는 두 차원을 100%에서 125%까지 2초에 걸쳐 확대합니다. 가로·세로 비율을 동일하게 지정하면 도형의 비율이 유지되며, 비율을 다르게 지정하면 한 차원이 더 늘어나게 됩니다.
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 은 애니메이션되는 속성을 식별합니다.
도형의 단색 채우기는 파랑으로 초기화되며, 이는 애니메이션 시작 색과 일치합니다. 채우기 색 속성을 선택하면 동작이 어떤 부분을 변경해야 하는지 지정할 수 있습니다; 색상 끝점만으로는 해당 속성을 알 수 없습니다. 저장된 효과는 2초에 걸쳐 주황색으로 전환하는 것을 설명합니다.
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 은 각각 필터 종류, 방향, 도형을 나타낼지 숨길지를 지정합니다.
이 예제는 오른쪽 방향 서브타입을 사용하여 2초 동안 도형을 나타내는 와이프를 구성합니다. 필터 설정은 효과 내부 동작에 속하므로 프리셋의 원래 작업을 제거한 뒤에 구성합니다.
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 를 구성합니다. 작업 디렉터리에 sample.wav 라는 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 를 열어 크기 조절을 추가하고, 회전 앞에 삽입한 뒤 회전을 제거합니다. 동일 객체를 제거하고 다시 삽입하면 복사본을 만들지 않고 저장된 위치만 변경됩니다.
편집 순서는 컬렉션을 회전‑크기조절 → 크기조절‑회전 → 크기조절만 남도록 변경합니다. 인덱스는 현재 컬렉션을 기준으로 하므로 재정렬 후 회전의 새로운 인덱스를 사용합니다. 최종 열거는 저장될 동작을 확인합니다.
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 은 IEffect.getTiming 와 독립적으로 ITiming 을 노출합니다. 효과 타이밍은 외부 효과를 예약하고, 동작 타이밍은 그 내부 작업을 설명합니다.
지속 시간, 지연, 반복, 가속 설정
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();
}
이 동작은 2초 지속, 0.5초 지연, 반복 횟수 3을 사용합니다. 지속 시간의 처음과 마지막 20%는 가속 및 감속에 사용됩니다.
다른 반복 정책으로는 getRepeatDuration, getRepeatUntilEndSlide, getRepeatUntilNextClick 가 있으며, 모든 옵션을 동시에 켜는 대신 하나를 선택하십시오. getAutoReverse 은 앞쪽 재생이 끝난 뒤 역방향으로 애니메이션을 재생합니다. 가속·감속은 연속적인 변화에만 적용되며, 이산 할당이나 명령에는 적용되지 않습니다.
모션 경로 만들기
createMotionEffect 로 모션을 생성합니다. getFrom, getTo, getBy 은 백분율 기반 좌표 또는 오프셋을 설명합니다. 편집 가능한 경로를 만들려면 MotionPath 를 생성하고 IMotionEffect.setPath 로 할당합니다. IMotionPath 은 경로 명령을 저장합니다.
MotionCommandPathType 은 작업을 선택합니다:
| Command | Points | Meaning |
|---|---|---|
| MoveTo | One | 시작 위치를 설정합니다. |
| LineTo | One | 직선 구간을 따라 끝점까지 이동합니다. |
| CurveTo | Three | 두 제어점과 끝점으로 정의된 3차 곡선을 따릅니다. |
| CloseLoop | None | 시작 위치로 되돌아갑니다. |
| End | None | 경로를 종료합니다. |
MotionPathPointsType 은 코너 포인트 또는 부드러운 포인트와 같은 점 편집 특성을 설명합니다. 이는 명령 유형을 대체하지 않으며, 아래 곡선 예제에서는 곡선 포인트 유형을, 직선 구간에서는 코너 포인트 유형을 사용하십시오.
경로 좌표는 슬라이드 크기에 정규화됩니다. X 변위 0.25는 슬라이드 너비의 1/4을 의미하고, 0.25 포인트가 아닙니다. Y 좌표는 아래쪽이 양수입니다. 절대 명령은 경로 좌표계의 위치를 지정하고, 상대 명령은 현재 위치에서의 오프셋을 지정합니다. 이는 getOrigin 이 선택하는 경로 기준 프레임 및 getPathEditMode 이 도형 이동 시 경로가 어떻게 움직이는지를 제어하는 것과 별개입니다.
직선 경로 만들기
시작점, 한 개의 직선 구간, 종료 명령으로 구성된 모션 동작을 생성합니다. IMotionPath.add 은 명령 유형, 해당 점들, 점 유형, 상대 좌표 플래그를 받습니다.
시작 명령은 (0, 0) 을 설정하고, 선 명령은 (0.25, 0) 으로 끝나 슬라이드 너비의 1/4 만큼 수평 이동합니다. 종료 명령은 좌표 점이 없습니다. 경로를 할당한 뒤 효과에 모션 동작을 추가하면 해당 경로가 사각형에 연결됩니다.
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 를 열어 선 명령을 3차 곡선으로 교체합니다. 먼저 두 제어점을 제공하고, 이어서 끝점을 지정합니다.
시작 위치는 앞선 명령이 제공합니다. 첫 두 점이 곡선을 형성하고, 세 번째 점이 목적지입니다; 이는 연속적인 목적지가 아니라 하나의 곡선 정의입니다. 명령 유형, 점 편집 유형, 점 배열을 함께 업데이트하면 새 기하학에 맞게 구간이 일관됩니다.
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 의 알려진 세 명령 경로를 사용합니다. 임의 입력의 경우, 편집하기 전에 대상 효과를 찾고 명령 유형과 점 개수를 확인하십시오.
명령 및 좌표 읽기
경로를 변경 없이 읽습니다. 종료 및 닫기 루프 명령은 점이 필요 없으므로 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) 에 끝나는 절대 선, 그리고 종료 명령이 포함됩니다.
끝점 변경
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 로 이동합니다.
이는 기존 좌표를 편집하는 대신 명령 객체 자체를 교체하는 방법을 보여줍니다. 삽입 후 컬렉션은 일시적으로 시작 명령, 새 선, 기존 선, 종료 명령을 포함합니다. 인덱스 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) 에 끝나고 종료 명령이 마지막에 위치합니다.
기존 동작 수정 및 확인
동작 인덱스를 모를 경우 타입으로 선택합니다. 이 예제는 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 로 상호 작용할 수 있습니다. 컬렉션 순서만으로 “이동 후 회전”을 예약하지 말고, 도형 애니메이션 에 설명된 대로 명시적인 타이밍이나 별도 효과를 사용하십시오.
효과의 getType 과 getSubtype 은 프리셋을 설명합니다. 이는 편집된 동작 트리의 전체 설명이 아니므로, 동작을 사용자 정의하기 전에 프리셋과 서브타입을 선택하십시오. 프리셋을 변경하면 컬렉션이 재구성되어 사용자 정의 작업이 사라질 수 있습니다. 예를 들어, 사용자 정의 Spin 효과를 Fade 로 변경하면 회전 동작이 설정·필터 동작으로 교체됩니다. 프리셋이나 서브타입을 변경한 뒤 컬렉션을 다시 검사하십시오. 프리셋 동작을 비우면 프리셋이 필요로 하는 가시성·초기화 작업도 제거될 수 있습니다. 예제에서는 가시적인 도형을 사용하고 동작을 교체했으며, 모든 프리셋 구현을 재구성하지는 않습니다.
포맷 호환성
보존된 동작 트리가 모든 뷰어나 출력 렌더러에서 동일한 재생을 보장하지는 않습니다. 저장된 데이터와 렌더링 결과를 별도로 확인하십시오.
| Format or output | What to verify |
|---|---|
| PPTX | 이 예제의 기본 포맷으로 사용합니다. 파일을 다시 열어 수정 가능한 동작 트리를 확인한 뒤, 원하는 PowerPoint 버전에서 재생을 체크하십시오. |
| PPT | 레거시 바이너리 형식은 PPTX와 다를 수 있습니다. 별도 저장‑재열 사이클과 재생을 테스트하십시오; PPTX 출력이 성공했다고 해서 모든 사용자 정의 조합이 지원된다고 추론하지 마십시오. |
| PDF, PNG, JPEG 및 기타 정적 슬라이드 이미지 | 정적 슬라이드 표현이며, 재생 가능한 동작 타임라인이나 최종 애니메이션 프레임을 보장하지 않습니다. |
| HTML5 | 도형 애니메이션이 내보내기 옵션에서 활성화된 경우 지원되는 애니메이션을 재생할 수 있습니다. 브라우저에서 사용자 정의 조합을 테스트하십시오. |
| Animated GIF | 렌더링된 프레임을 저장하며, 편집 가능한 동작이나 클릭 트리거 인터랙션은 포함하지 않습니다. 실제 렌더링된 모션을 확인하십시오. |
| Video | 애니메이션 프레임을 렌더링하고 비디오로 인코딩합니다. 지원은 렌더러의 지원 애니메이션 및 효과 에 제한되며, 명령 및 인터랙티브 이벤트는 편집 가능한 타임라인이 되지 않습니다. |
FAQ
내 효과에 동작이 없는데도 동작이 포함되어 있는 이유는?
미리 정의된 효과를 생성하면 기본 작업이 자동으로 생성될 수 있습니다. 프리셋을 확장할지 교체할지 결정하기 전에 이를 확인하십시오.
동작을 처음으로 이동하면 먼저 재생되나요?
반드시 그렇지는 않습니다. 컬렉션 순서는 타이밍을 대신하지 못합니다. 지연, 지속 시간 및 같은 속성에 대한 작업 간 상호 작용을 확인하십시오.
끝점 명령에 점이 없는 이유는?
끝점 명령은 경로의 종료를 표시하며 좌표가 필요하지 않습니다. 파일에서 경로를 읽을 때 null 점 배열을 검사하십시오.
라운드 트립이 성공했다고 해서 재생이 보장되나요?
아니요. 재열은 확인한 속성 보존만 입증합니다. 슬라이드쇼 플레이어나 애니메이션 내보내기를 별도로 테스트하여 시각적 동작을 확인하십시오.