26 พฤศจิกายน 2556

[Android Code] ว่าด้วยเรื่อง Interpolator ใน Animation


        สำหรับเรื่อง Animation ที่เจ้าของบล็อกเคยพูดถึงเมื่อก่อนนู้นนนนนน วันนี้ก็มีเรื่องเพิ่มเติมที่อยากจะเล่าให้ผู้ที่หลงเข้ามาอ่านฟังเสียหน่อย นั่นก็คือเรื่องของคลาส Interpolator ที่ใช้ในคลาส Animation นั่นเอง


        สำหรับ Interpolator ถ้าอธิบายแบบง่ายๆสำหรับ Animation เลย ก็คือการกำหนดการรูปแบบในการ Transition แบบต่างๆของ Animation ไม่ใช่ประเภทเดียวกับ Scale, Alpha, Translate หรือ Rotate นะครับ แต่เป็นรูปแบบหรือลักษณะการ Transition ของ Animation เหล่านี้ สมมติว่าเจ้าของบล็อกใช้ Animation เป็นแบบ Translate Animation ก็คือวัตถุเคลื่อนที่จากตำแหน่งหนึ่งไปยังอีกตำแหน่งหนึ่ง แต่ทีนี้จะเคลื่อนที่ไปในรูปแบบยังไงนั่นเอง เป็นยังไงเดี๋ยวมาดูกัน

        สำหรับ Interpolator จะเป็นคลาสหลัก ที่สืบทอดออกมาเป็นแบบต่างๆดังนี้

                • AccelerateDecelerateInterpolator
                • AccelerateInterpolator
                • AnticipateInterpolator
                • AnticipateOvershootInterpolator
                • BounceInterpolator
                • CycleInterpolator
                • DecelerateInterpolator
                • LinearInterpolator
                • OvershootInterpolator

        ทั้งหมดนี้เป็นคลาสหลักๆที่ใช้สำหรับกำหนด Interpolator ของ Animation

        ก่อนอื่นยกตัวอย่างโค๊ด Animation ง่ายๆก่อน เอา Translate ละกัน เพราะว่าเป็น Animation ที่เห็นภาพของ Interpolator ได้ง่ายดี

main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>


        โดยจะให้ Image View มีชื่อ ID ว่า imageView อยู่ชิดขอบบนและ Relative Layout ก็จะตั้งชื่อ ID ว่า layout แล้วใช้คำสั่งในการเรียกใช้งาน Translate Animation ดังนี้

RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout);
ImageView imageView = (ImageView)findViewById(R.id.imageView);

Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0.7f);
anim.initialize(imageView.getWidth(), imageView.getHeight()
        , layout.getWidth(), layout.getHeight());
anim.setDuration(2000);
anim.setFillAfter(true);
imageView.startAnimation(anim);

        ก็ไม่มีอะไรมาก ถ้าเคยอ่านบทความเรื่อง Translate Animation มาแล้ว ถ้ายังไม่เคยอ่านให้ไปย้อนเรื่องราวกันก่อนได้ที่บทความนี้ [Android Code] สร้างการเคลื่อนไหวง่ายๆ ด้วยคลาส TranslateAnimation

        ตัวอย่างนี้ก็คือให้ Image View เคลื่อนที่ลงมาที่ 70% ของขนาด Relative Layout โดยใช้ระยะเวลา 2 วินาที และค้างสถานะวัตถุไว้ที่ตอนจบ Animation ทีนี้อยากจะกำหนด Interpolator ก็ต้องกำหนดก่อนคำสั่ง startAnimation โดยจะยกตัวอย่างเป็น AccelerateInterpolator ละกันนะ

Interpolator inter = new AccelerateInterpolator();
anim.setInterpolator(inter);

        หรือ

anim.setInterpolator(new AccelerateInterpolator());

        จะได้เป็นดังนี้

RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout);
ImageView imageView = (ImageView)findViewById(R.id.imageView);

Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0f
        , Animation.RELATIVE_TO_PARENT, 0.7f);
anim.initialize(imageView.getWidth(), imageView.getHeight()
        , layout.getWidth(), layout.getHeight());
anim.setDuration(2000);
anim.setFillAfter(true);

anim.setInterpolator(new AccelerateInterpolator());

imageView.startAnimation(anim);

        เท่านี้ก็กำหนด Interpolator ให้กับ Animation เรียบร้อยแล้ว ทีนี้ขออธิบายกันก่อนจะทดลองจริงว่าแต่ละแบบต่างกันอย่างไร โดยจะอธิบายเป็นทฤษฎีคร่าวๆก่อน แล้วค่อยดูตอนทดสอบจริงกัน

        Linear Interpolator เป็น Interpolator ที่มีอัตราเร็วคงที่ ดังนั้นวัตถุจะเคลื่อนที่โดยไม่มีความเร่ง ไปยังปลายทาง


        Accelerate Interpolator เป็น Interpolator ที่มีอัตราเร็วเพิมขึ้น ดังนั้นวัตถุจะเคลื่อนที่แบบมีความเร่งเป็นบวก ไปยังปลายทาง ผลที่ได้ก็จะเห็นว่าวัตถุค่อยๆเคลื่อนที่เร็วขึ้นเรื่อยๆ


        Decelerate Interpolator เป็น Interpolator ที่มีอัตราเร็วลดลง ดังนั้นวัตถุจะเคลื่อนที่แบบมีความเร่งเป็นลบ ไปยังปลายทาง ผลที่ได้ก็จะเห็นว่าวัตถุค่อยๆเคลื่อนที่ช้าลงเรื่อยๆ


        Accelerate Decelerate Interpolator เป็น Interpolator แบบผสมระหว่าง Accelerate Interpolator กับ Decelerate Interpolator โดยช่วงแรกวัตถุจะเคลื่อนที่แบบมีความเร่งเป็นบวก และในช่วงต่อมาวัตถุจะมีความเร่งเป็นลบแทน ผลที่ได้ก็จะเห็นว่าวัตถุค่อยๆเร็วขึ้นเรื่อยๆแล้วค่อยๆช้าลง


        Bounce Interpolator เป็น Interpolator แบบวัตถุกระเด้งกับพื้น โดยตอนแรกวัตถุจะเคลื่อนที่แบบ Linear Interpolator และเมื่อถึงปลายทางก็จะเคลื่อนที่ย้อนกลับแบบ Decelerate Interpolator เมื่อถอยกลับได้ซักพักก็จะเคลื่อนที่แบบ Accelerate Interpolator ซึ่งเคลื่อนที่แบบนี้สลับกันไปเรื่อยๆจนหยุดที่ปลายทาง ผลที่ได้จะเห็นง่ายกับวัตถุที่เคลื่อนที่จากบนลงล่าง จะเห็นว่าวัตถุตกลงพื้นแล้วกระเด้งขึ้นเล็กน้อยคล้ายลูกบอล


        Cycle Interpolator เป็น Interpolator แบบรูปคลื่น Sinusoidal หรือกราฟไซน์ที่สามารถกำหนดพื้นที่ของลูกคลื่นฝั่งบวกและลูกคลื่นฝั่งลบได้ ในตัวอย่างนี้เจ้าของบล็อกกำหนดไว้ที่ 50% ทั้งสองฝั่ง ผลก็คือวัตถุเคลื่อนที่มายังเป้าหมายแล้วกลับไปจุดเริ่มต้น


        Anticipate Interpolator เป็น Interpolator ที่เหมือนการขว้างลูกบอล โดยปกติการขว้างลูกบอลผู้ขว้างจะต้องเหวี่ยงมือไปข้างหลังแล้วขว้าง ถ้าดูรูปกราฟจะเห็นว่าอัตราเร็วมีค่าไปในทางลบเป็นยอดแหลมแล้วจึงเปลี่ยนอัตราเร็วเป็นบวกแบบ Accelerate Interpolator ในทันที วัตถุจะเคลื่อนที่ถอยหลังแล้วเคลื่อนที่ไปข้างหน้าแบบมีความเร่งเป็นบวก


        Overshoot Interpolator เป็น Interpolator ที่คล้ายการรับลูกบอลที่ขว้างมา เมื่อผู้รับรับลูกบอล จะไม่หยุดทันที แต่มือจะถอยหลังไปเล็กน้อยแล้วกลับมาที่เดิม ถ้าดูรูปกราฟจะเห็นว่าอัตราเร็วเป็นแบบ Decelerate Interpolator จากนั้นจะเคลื่อนที่เลยไปเล็กน้อยแล้วถอยกลับมา


        Anticipate Overshoot Interpolator เป็น Interpolator แบบผสมระหว่าง Anticipate Interpolator กับ Overshoot Interpolator โดยในช่วงแรกวัตถุจะเคลื่อนที่แบบ Anticipate Interpolator แล้วในช่วงหลังจะเคลื่อนที่แบบ Overshoot Interpolator ผลที่ได้ก็จะเห็นว่าวัตถุถอยหลังเล็กน้อยแล้วเคลื่อนที่ไปยังเป้าหมาย จากนั้นจะเคลื่อนที่เลยเป้าหมายเล็กน้อยแล้วถอยกลับมา

        สำหรับ Animation แบบอื่นๆให้เปลี่ยน อัตราเร็วเป็นไปตาม Animation นั้นๆ เช่นใช้กับ Alpha ก็เปลี่ยนจากอัตราเร็ว (V) เป็นความโปร่งใสแทน

        เมื่อดูรูปแบบการเคลื่อนที่ของ Interpolate พื้นฐานทั้งหมดแล้ว มาดูตอนทำงานจริงในแบบวีดีโอกันเลยดีกว่า น่าจะเห็นภาพง่ายดี โดยเจ้าของบล็อกเอาแต่ละแบบมารวมกันให้แล้ว จะได้เทียบง่ายๆ


        จะเห็นว่า Interpolator ในแต่ละแบบจะให้ผลแตกต่างกันออกไป และนอกจากนี้ยังสามารถกำหนดค่าบางอย่างเพื่อให้ผลลัพธ์ต่างกันเล็กน้อยได้ โดยจะให้กำหนดค่าระหว่าง 0 ถึง 1 ซึ่ง Interpolator แต่ละแบบจะทำงานต่างกันไป

anim.setInterpolator(new AccelerateInterpolator(0.7f));

        เช่น Accelerate Interpolator การกำหนดค่าดังกล่าว จะมีผลต่อการเคลื่อนที่ในตอนเริ่มต้นและจบ โดยที่ค่าเป็น 1 ความเร็วเริ่มต้นจะเพิ่มขึ้นช้าและความเร็วตอนจบจะเพิ่มขึ้นอย่างเร็ว แต่ถ้ากำหนดเป็น 0.5 ความเร็วเริ่มต้นจะเพิ่มขึ้นเร็วขึ้น และความเร็วตอนจบจะเพิ่มขึ้นอย่างช้า สำหรับ Decelerate Interpolator จะให้ผลลัพธ์ตรงกันข้ามแทน ส่วน Accelerate Decelerate Interporator จะไม่มีให้กำหนด

        สำหรับ Anticipate Interpolator การกำหนดค่าเป็น 1 จะทำให้ถอยหลังนานขึ้น ถ้ากำหนดเป็น 0.3 จะทำให้ถอยหลังเพียงเล็กน้อยแล้วเคลื่อนที่ไปข้างหน้า สำหรับ Overshoot Interpolator ก็จะเหมือนกันแต่มีผลตอนในท้ายแทน ส่วน Anticipate Overshoot Interpolator จะเป็นการกำหนดทั้งสองพร้อมกัน

        สำหรับ Cycle Interpolator จะเป็นการกำหนดอัตราส่วนระหว่างพื้นที่ของลูกคลื่นฝั่งบวกและพื้นที่ของลูกคลื่นฝั่งลบ สมมติว่ากำหนดเป็น 0.7 ผลก็คือพื้นที่ลูกคลื่นฝั่งบวกจะมี 30% และพื้นที่ลูกคลื่นฝั่งลบจะมี 70% ผลคือเคลื่อนที่ถอยหลังมากกว่า ดังนั้นการกำหนด 0.5 จะทำให้เคลื่อนที่ไปข้างหน้าและถอยหลังเท่ากัน

        สำหรับ Bounce Interpolator และ Linear Interpolator จะไม่มีให้กำหนด


Main.java
package app.akexorcist.animationinterpolator;

import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.app.Activity;

public class Main extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout);
        ImageView imageView = (ImageView)findViewById(R.id.imageView);

        Animation anim = new TranslateAnimation(
                Animation.RELATIVE_TO_PARENT, 0f
                , Animation.RELATIVE_TO_PARENT, 0f
                , Animation.RELATIVE_TO_PARENT, 0f
                , Animation.RELATIVE_TO_PARENT, 0.7f);
        anim.initialize(imageView.getWidth(), imageView.getHeight()
                , layout.getWidth(), layout.getHeight());
        anim.setDuration(2000);
        anim.setFillAfter(true);
        imageView.startAnimation(anim);

        anim.setInterpolator(new LinearInterpolator());
        //anim.setInterpolator(new AccelerateInterpolator());
        //anim.setInterpolator(new DecelerateInterpolator());
        //anim.setInterpolator(new AccelerateDecelerateInterpolator());
        //anim.setInterpolator(new BounceInterpolator());
        //anim.setInterpolator(new CycleInterpolator(0.5f));
        //anim.setInterpolator(new AnticipateInterpolator());
        //anim.setInterpolator(new OvershootInterpolator());
        //anim.setInterpolator(new AnticipateOvershootInterpolator());
        
        imageView.startAnimation(anim);
        
    }
}
        (เวลาเปลี่ยนเป็น Interpolator ตัวไหนอย่าลืมแก้เออเรอด้วยการ Import คลาสด้วย)


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app.akexorcist.animationinterpolator"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="app.akexorcist.animationinterpolator.Main"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

        จากนี้ก็ให้ผู้ที่หลงเข้ามาอ่านลองเอาไปประยุกต์เป็นแบบอื่นดูนะ อ้อลืมอีกอย่าง สามารถใช้กับ Animation Resource ได้นะ [Android Code] การสร้าง Animation จาก Animation Resource [Anim]

         และสามารถสร้างเป็น Interpolate Resource ก็ได้นะ เพื่อสร้างรูปแบบของ Interporate เอง ไว้มีเวลาจะพูดให้ฟังล่ะกัน สำหรับผู้ที่หลงเข้ามาอ่านคนใดต้องการไฟล์ตัวอย่าง สามารถดาวน์โหลดได้ที่ Animation-Interpolator [Google Drive]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium