تطبيق الرسوم المتحركة للأشكال في العروض التقديمية على Android

نظرة عامة

للعمل مع السلوكيات الفردية داخل تأثير أو تحرير مقاطع مسار الحركة، راجع الرسوم المتحركة المخصصة لـ Java.

Aspose.Slides for Android via Java تمثل الرسوم المتحركة للشرائح كـ effects في مخطط زمني للشرائح. يحتوي effect على شكل هدف، نوع الرسوم المتحركة والنوع الفرعي، مشغل، إعدادات التوقيت، وخصائص اختيارية مثل الصوت أو سلوك ما بعد الرسوم المتحركة.

المخطط الزمني يحتوي على نوعين من التسلسلات:

  • السلسلة الرئيسية تُشغل عندما تتقدم الشريحة.
  • السلسلة التفاعلية تبدأ عندما يُنقر على الشكل المشغل.

نظرًا لأن صناديق النصوص، الصور، المخططات، الجداول، وغيرها من كائنات الشريحة تُنفّذ IShape، يمكنك استخدام نفس طريقة ISequence.addEffect لمعظم محتوى الشريحة. تُدرج التأثيرات المتاحة في الفئة EffectType.

إضافة رسوم متحركة للأشكال

لإضافة رسوم متحركة، احصل على السلسلة الرئيسية للشرحة واستدعِ ISequence.addEffect مع شكل الهدف، نوع effect، النوع الفرعي، والمشغل. لتأثير يبدأ عندما يُنقر على شكل آخر، أنشئ سلسلة تفاعلية يكون مشغلها ذلك الشكل الآخر.

المثال التالي يخلق كلا نوعي الرسوم المتحركة ويحفظ النتيجة إلى shape-animations.pptx.

import com.aspose.slides.*;

public class AddShapeAnimations {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);

            IAutoShape targetShape = slide.getShapes().addAutoShape(ShapeType.RoundCornerRectangle, 120, 100, 320, 80);
            targetShape.addTextFrame("Click to animate this shape");

            ISequence mainSequence = slide.getTimeline().getMainSequence();
            IEffect entranceEffect = mainSequence.addEffect(targetShape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
            entranceEffect.getTiming().setDuration(1.5f);

            IAutoShape triggerShape = slide.getShapes().addAutoShape(ShapeType.Bevel, 20, 20, 100, 40);
            triggerShape.addTextFrame("Move");

            ISequence interactiveSequence = slide.getTimeline().getInteractiveSequences().add(triggerShape);
            interactiveSequence.addEffect(targetShape, EffectType.PathFootball, EffectSubtype.None, EffectTriggerType.OnClick);

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

المشغل يتحكم بموعد بدء effect:

لتحريك صورة أو مخطط أو نوع شكل آخر، مرّر ذلك الكائن إلى ISequence.addEffect بدلاً من targetShape. لخيارات تجميع خاصة بالمخططات، طالع Animated Charts.

قراءة رسوم متحركة للأشكال

استخدم ISequence.getEffectsByShape عندما تعرف شكل الهدف. لتفقد كل effect، استعرض السلسلة الرئيسية وكل سلسلة تفاعلية. الاستعراض يُجنّب الافتراض بأن السلسلة تحتوي على effect في الفهرس 0.

المثال التالي يُنشئ شكلًا يحتوي على تأثيرات في السلسلة الرئيسية وتفاعلية، يحصل على الـ effects التي تستهدف الشكل، ثم يستعرض كل سلسلة على الشريحة.

import com.aspose.slides.*;

public class ReadShapeAnimations {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);
            IAutoShape targetShape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 120, 100, 320, 80);
            targetShape.addTextFrame("Animated shape");

            ISequence mainSequence = slide.getTimeline().getMainSequence();
            mainSequence.addEffect(targetShape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);

            IAutoShape triggerShape = slide.getShapes().addAutoShape(ShapeType.Bevel, 20, 20, 100, 40);
            triggerShape.addTextFrame("Move");

            ISequence interactiveSequence = slide.getTimeline().getInteractiveSequences().add(triggerShape);
            interactiveSequence.addEffect(targetShape, EffectType.PathFootball, EffectSubtype.None, EffectTriggerType.OnClick);

            IEffect[] targetEffects = mainSequence.getEffectsByShape(targetShape);
            System.out.println("The main sequence contains " + targetEffects.length + " effect(s) for " + targetShape.getName() + ".");

            printSequence("Main sequence", mainSequence);

            int interactiveIndex = 1;
            for (ISequence sequence : slide.getTimeline().getInteractiveSequences()) {
                String triggerName = sequence.getTriggerShape() == null ? "unknown" : sequence.getTriggerShape().getName();
                String sequenceLabel = "Interactive sequence " + interactiveIndex + ", trigger: " + triggerName;
                printSequence(sequenceLabel, sequence);
                interactiveIndex++;
            }
        } finally {
            presentation.dispose();
        }
    }

    private static void printSequence(String label, ISequence sequence) {
        System.out.println("  " + label + ": " + sequence.getCount() + " effect(s)");

        for (IEffect effect : sequence) {
            String targetName = effect.getTargetShape() == null ? "unknown" : effect.getTargetShape().getName();
            String typeName = EffectType.getName(EffectType.class, effect.getType());
            String subtypeName = EffectSubtype.getName(EffectSubtype.class, effect.getSubtype());
            String triggerName = EffectTriggerType.getName(EffectTriggerType.class, effect.getTiming().getTriggerType());
            String effectDescription = typeName + " " + subtypeName + "; target: " + targetName + "; trigger: " + triggerName;
            System.out.println("    " + effectDescription);
        }
    }
}

إذا كنت تحتاج فقط إلى الـ effects لشكل واحد، حدّد الشكل أولاً بالاسم أو نوع العنصر النائب أو خاصية ثابتة أخرى؛ ثم استدعِ ISequence.getEffectsByShape. لا تفترض أن IShapeCollection.get_Item في الفهرس 0 هو دائمًا الكائن المقصود.

العمل مع تأثيرات العناصر النائبة الموروثة

يمكن للعنصر النائب على شريحة عادية أن يرث سلوك الرسوم المتحركة من العنصر النائب المقابل على شريحة التخطيط والشريحة الرئيسية. IShape.getBasePlaceholder يُرجع ذلك العنصر النائب الأب، أو null عندما لا يكون هناك أب.

في عرض الشرائح التالي، يحتوي التذييل على Random Bars على الشريحة العادية، Split على شريحة التخطيط، وFly In على الشريحة الرئيسية.

تأثير حركة تذييل على الشريحة العادية

تأثير حركة عنصر نائب للتذييل على شريحة التخطيط

تأثير حركة عنصر نائب للتذييل على الشريحة الرئيسية

المثال التالي يستخدم تسلسلًا هرميًا لعناصر نائب من عرض تقديم جديد. يضيف تأثيرات إلى عنصر نائب رئيسي، عنصر نائب تخطيط، والعنصر النائب المقابل على شريحة عادية. كل استدعاء لـ IShape.getBasePlaceholder يُفحص قبل استخدام الشكل المُرجع.

import com.aspose.slides.*;

public class InheritedPlaceholderAnimations {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ILayoutSlide layoutSlide = presentation.getLayoutSlides().getByType(SlideLayoutType.TitleAndObject);
            IShape layoutPlaceholder = findPlaceholderWithBase(layoutSlide);

            if (layoutPlaceholder == null) {
                throw new IllegalStateException("The layout slide does not contain a placeholder linked to its master slide.");
            }

            IShape masterPlaceholder = layoutPlaceholder.getBasePlaceholder();
            layoutSlide.getMasterSlide().getTimeline().getMainSequence().addEffect(masterPlaceholder, EffectType.Fly, EffectSubtype.Bottom, EffectTriggerType.OnClick);
            layoutSlide.getTimeline().getMainSequence().addEffect(layoutPlaceholder, EffectType.Split, EffectSubtype.VerticalIn, EffectTriggerType.OnClick);

            ISlide slide = presentation.getSlides().addEmptySlide(layoutSlide);
            IShape slidePlaceholder = findPlaceholderWithBase(slide, layoutPlaceholder);

            if (slidePlaceholder == null) {
                throw new IllegalStateException("The slide does not contain a placeholder linked to its layout slide.");
            }

            slide.getTimeline().getMainSequence().addEffect(slidePlaceholder, EffectType.RandomBars, EffectSubtype.Horizontal, EffectTriggerType.OnClick);
            printEffects("Normal slide", slide.getTimeline().getMainSequence().getEffectsByShape(slidePlaceholder));

            IShape baseLayoutPlaceholder = slidePlaceholder.getBasePlaceholder();
            if (baseLayoutPlaceholder != null) {
                printEffects("Layout slide", layoutSlide.getTimeline().getMainSequence().getEffectsByShape(baseLayoutPlaceholder));

                IShape baseMasterPlaceholder = baseLayoutPlaceholder.getBasePlaceholder();
                if (baseMasterPlaceholder != null) {
                    printEffects("Master slide", layoutSlide.getMasterSlide().getTimeline().getMainSequence().getEffectsByShape(baseMasterPlaceholder));
                }
            }

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

    private static IShape findPlaceholderWithBase(ILayoutSlide layoutSlide) {
        for (IShape shape : layoutSlide.getShapes()) {
            if (shape.getBasePlaceholder() != null) {
                return shape;
            }
        }

        return null;
    }

    private static IShape findPlaceholderWithBase(ISlide slide, IShape expectedBase) {
        for (IShape shape : slide.getShapes()) {
            if (shape.getBasePlaceholder() == expectedBase) {
                return shape;
            }
        }

        return null;
    }

    private static void printEffects(String source, IEffect[] effects) {
        System.out.println(source + ": " + effects.length + " effect(s)");

        for (IEffect effect : effects) {
            String typeName = EffectType.getName(EffectType.class, effect.getType());
            String subtypeName = EffectSubtype.getName(EffectSubtype.class, effect.getSubtype());
            System.out.println("  " + typeName + " " + subtypeName);
        }
    }
}

تغيير توقيت الحركة

حوار PowerPoint Timing يتطابق مع خصائص ITiming.

حوار توقيت PowerPoint لتأثير حركة

هذا المثال المستقل يضيف effect، يغير توقيته عبر الكائن المُرجع من ISequence.addEffect، ويحفظ النتيجة. الحفاظ على مرجع IEffect المُرجع يجنب الحاجة إلى فهرس تجميع غير ضروري.

import com.aspose.slides.*;

public class ChangeAnimationTiming {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);
            IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 120, 100, 320, 80);
            shape.addTextFrame("Timed animation");

            IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
            effect.getTiming().setTriggerType(EffectTriggerType.OnClick);
            effect.getTiming().setDuration(2.0f);
            effect.getTiming().setTriggerDelayTime(0.5f);
            effect.getTiming().setRepeatUntilNextClick(false);
            effect.getTiming().setRepeatUntilEndSlide(false);
            effect.getTiming().setRepeatCount(2.0f);
            effect.getTiming().setRewind(true);

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

استخدم وضعية تكرار واحدة فقط. الجمع بين عدد التكرارات وعلم “until” قد ينتج عنه نتائج مربكة في مشغّلات مختلفة. عند تغيير أوضاع التكرار، عيّن ITiming.setRepeatUntilNextClick وITiming.setRepeatUntilEndSlide قبل ITiming.setRepeatCount، لأن ضبط أي علم يغيّر وضعية التكرار النشطة.

إضافة واستخراج أصوات الحركة

يمكن لتأثير حركة أن يشير إلى صوت مضمّن عبر IEffect.getSound. IEffect.setStopPreviousSound يُخبر الـ effect بإيقاف الصوت الذي بدأه تأثير سابق.

إضافة صوت إلى تأثير

المثال التالي يتوقع ملف صوت محلي اسمه animation-sound.wav. يخلق تأثيرين، يضمّن ذلك الملف كصوت للتأثير الأول، ويضبط التأثير الثاني لإيقاف الصوت. يستخدم الكائنات التي تُرجعها ISequence.addEffect، لذلك لا يُطلب فهرس سلسلة.

import com.aspose.slides.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class AddAnimationSound {
    public static void main(String[] args) throws IOException {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);
            IAutoShape firstShape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 80, 100, 240, 80);
            IAutoShape secondShape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 400, 100, 240, 80);
            firstShape.addTextFrame("Starts sound");
            secondShape.addTextFrame("Stops sound");

            ISequence sequence = slide.getTimeline().getMainSequence();
            IEffect firstEffect = sequence.addEffect(firstShape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
            IEffect secondEffect = sequence.addEffect(secondShape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);

            byte[] audioData = Files.readAllBytes(Paths.get("animation-sound.wav"));
            IAudio effectSound = presentation.getAudios().addAudio(audioData);
            firstEffect.setSound(effectSound);
            secondEffect.setStopPreviousSound(true);

            presentation.save("shape-animation-sound.pptx", SaveFormat.Pptx);
        } finally {
            presentation.dispose();
        }
    }
}

استخراج أصوات التأثير المضمنة

المثال التالي يتوقع عرض تقديم محلي اسمه presentation-with-animation-sounds.pptx. يُمسح كل من السلسلتين الرئيسيتين والتفاعليتين ويكتب كل صوت تأثير مضمّن إلى دليل extracted-animation-sounds. الامتداد يُحدَّد من نوع MIME الصوتي الذي تُعيده IAudio.getContentType.

import com.aspose.slides.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;

public class ExtractAnimationSounds {
    public static void main(String[] args) throws IOException {
        Path inputPath = Paths.get("presentation-with-animation-sounds.pptx");
        Path outputDirectory = Paths.get("extracted-animation-sounds");

        Files.createDirectories(outputDirectory);

        Presentation presentation = new Presentation(inputPath.toString());
        try {
            int soundIndex = 1;

            for (ISlide slide : presentation.getSlides()) {
                soundIndex = saveSounds(slide.getTimeline().getMainSequence(), outputDirectory, soundIndex);

                for (ISequence sequence : slide.getTimeline().getInteractiveSequences()) {
                    soundIndex = saveSounds(sequence, outputDirectory, soundIndex);
                }
            }

            System.out.println("Extracted " + (soundIndex - 1) + " sound file(s) to " + outputDirectory.toAbsolutePath() + ".");
        } finally {
            presentation.dispose();
        }
    }

    private static int saveSounds(ISequence sequence, Path outputDirectory, int soundIndex) throws IOException {
        for (IEffect effect : sequence) {
            if (effect.getSound() == null) {
                continue;
            }

            String extension = getAudioExtension(effect.getSound().getContentType());
            Path outputPath = outputDirectory.resolve("effect-sound-" + soundIndex + extension);
            Files.write(outputPath, effect.getSound().getBinaryData());
            soundIndex++;
        }

        return soundIndex;
    }

    private static String getAudioExtension(String contentType) {
        String normalizedType = contentType == null ? "" : contentType.toLowerCase(Locale.ROOT);

        if (normalizedType.equals("audio/mpeg")) {
            return ".mp3";
        }

        if (normalizedType.equals("audio/mp4")) {
            return ".m4a";
        }

        if (normalizedType.equals("audio/ogg")) {
            return ".ogg";
        }

        if (normalizedType.equals("audio/wav") || normalizedType.equals("audio/x-wav")) {
            return ".wav";
        }

        return ".bin";
    }
}

للكائنات الصوتية الكبيرة، استخدم IAudio.getStream وانسخ الدفق إلى ملف بدلاً من تحميل الكائن بالكامل في مصفوفة بايت.

تعيين سلوك ما بعد الحركة

خيار After animation يتحكم بما يحدث للشكل بعد انتهاء تأثيره.

حوار خيارات تأثير PowerPoint يظهر إعدادات ما بعد الحركة

تدعم الفئة AfterAnimationType ترك الشكل دون تغيير، تغيير لونه، إخفائه بعد الحركة، أو إخفائه عند النقرة التالية. عندما يكون النوع هو AfterAnimationType.Color، اضبط أيضًا IEffect.getAfterAnimationColor.

هذا المثال المستقل يخلق effect، يضبط سلوك ما بعد الحركة عبر كائن الـ effect المُرجع، ويحفظ النتيجة.

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

public class SetAfterAnimationBehavior {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);
            IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 120, 100, 320, 80);
            shape.addTextFrame("Dim after animation");

            IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
            effect.setAfterAnimationType(AfterAnimationType.Color);
            effect.getAfterAnimationColor().setColor(Color.LTGRAY);

            presentation.save("shape-animation-after-effect.pptx", SaveFormat.Pptx);
        } finally {
            presentation.dispose();
        }
    }
}

تغيير النوع بعيدًا عن AfterAnimationType.Color يمسح إعداد لون ما بعد الحركة.

تحريك النص

لتحريك النص هناك تحكمان مرتبطان:

  • ITextAnimation.getBuildType يتحكم فيما إذا كانت الفقرات تظهر معًا أو على مستوى الفقرة.
  • IEffect.getAnimateTextType يتحكم فيما إذا كان النص يظهر دفعة واحدة، كلمةً كلمةً، أو حرفًا بحرف. IEffect.getDelayBetweenTextParts يحدد التأخير بين الكلمات أو الأحرف. القيمة الموجبة هي نسبة مئوية من مدة الـ effect؛ القيمة السالبة هي تأخير بالثواني.

المثال المستقل التالي يحرك الكلمات داخل صندوق نص. BuildType.AsOneObject يُعطّل بناء الفقرة-بالفقرة بحيث يُطبق إعداد الكلمة على كامل إطار النص.

import com.aspose.slides.*;

public class AnimateTextByWord {
    public static void main(String[] args) {
        Presentation presentation = new Presentation();
        try {
            ISlide slide = presentation.getSlides().get_Item(0);
            IAutoShape textBox = slide.getShapes().addAutoShape(ShapeType.Rectangle, 80, 80, 560, 100);
            textBox.addTextFrame("Aspose.Slides animates this sentence word by word.");

            IEffect effect = slide.getTimeline().getMainSequence().addEffect(textBox, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
            effect.getTextAnimation().setBuildType(BuildType.AsOneObject);
            effect.setAnimateTextType(AnimateTextType.ByWord);
            effect.setDelayBetweenTextParts(20.0f);

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

لبناء صندوق نص وفقًا للفقرة، اضبط BuildType.ByLevelParagraphs1 (أو مستوى فقرة آخر). لاستهداف فقرة واحدة بتأثير خاص بها، استخدم نسخة ISequence.addEffect التي تقبل IParagraph. راجع Animated Text لأمثلة على مستوى الفقرة.

ملاحظات التصدير والتوافق

  • الحفظ إلى PPT أو PPTX يحافظ على نموذج الرسوم المتحركة، لكن التشغيل النهائي يتحكم فيه عارض العرض.
  • PDF والصور الثابتة لا تشغل الرسوم المتحركة. استخدم HTML5 export، GIF متحرك، أو تحويل الفيديو عندما يجب إظهار الحركة.
  • بالنسبة إلى HTML5، فعّل Html5Options.setAnimateShapes وعند الحاجة Html5Options.setAnimateTransitions.
  • تحويل الفيديو يدعم العديد من تأثيرات الدخول، التركيز، الخروج، ومسار الحركة الشائعة، لكن ليس كل تأثير PowerPoint مدعوم. راجع جدول supported animations and effects الحالي واختبر العروض الحرجة مع نسخة Aspose.Slides المستهدفة.
  • قد تُحافظ التأثيرات المخصصة المتقدمة أو المستوردة من صيغ عرض أخرى في الملف لكنها تُعرض بشكل مختلف في PowerPoint أو HTML5 أو الفيديو. تحقق من النتيجة المصدرة بدلاً من الاعتماد فقط على اسم التأثير.

الأسئلة المتكررة

لماذا يظهر تأثير في PowerPoint ولا يظهر في PDF؟

PDF تنسيق ثابت، لذا لا تُشغل الرسوم المتحركة وانتقالات الشرائح. صدّر إلى HTML5 أو GIF متحرك أو فيديو عندما يجب حفظ الحركة.

لماذا يُشغَّل تأثير بصورة مختلفة في الفيديو؟

تصدير الفيديو يُعيد رسم الرسوم المتحركة بدلًا من حفظ سلوك PowerPoint الأصلي. بعض التأثيرات المتقدمة غير مدعومة أو تُقرب. راجع جدول التأثيرات المدعومة واختبر العرض الفعلي قبل الاستخدام في الإنتاج.

هل تغيير موضع الشكل إلى الأمام أو الخلف يغيّر ترتيب الرسوم المتحركة؟

لا. ترتيب الـ z لل shape يتحكم في التراكب، بينما ترتيب السلسلة والمشغلات يتحكم في تشغيل الرسوم المتحركة. غيّر المخطط الزمني إذا احتجت ترتيب تشغيل مختلف.