今天要來講的項目叫做Interpolator(插值器)

以前有次去一家公司面試時,我曾經被問到一個問題

面試官:你覺得當工程師,理論學科跟經驗豐富,哪邊比較重要?

 

我回答:我覺得經驗豐富可能只是做得久,遇到問題就可能很快就能有應對方法

但是如果理論學科好,才能夠在這條路上走得又長又遠

 

而今天要講的這一篇,就是我認為能夠應證我這個想法的一篇文章

這篇文章我會講述「如何在Android上完成呼吸燈動畫」

而要完成這一章節的內容,就得了解一些數學理論才能夠完成

麻...無論如何,先來看範例吧

這次的程式很短,所以沒有Github歐!

 


 

1. 呼吸燈與數學公式

 

各位,如果你還是學生的話,或者你有親戚小孩什麼的還在唸書

我這裡只想講一句非常、非常重要的話

數學...不是拿來考試用的,數學很重要....(嘆)

 

首先,關於呼吸燈的實踐,我們必須用積分曲線去完成它

看圖,這是我用desmos所繪製出來的呼吸曲線

截圖 2021-10-02 下午3.00.34

這一整張圖代表的是一個呼吸週期,而我們要控制的就是y軸的變量...在本案中你可以理解為Alpha值,而X軸為時間

而在專案的控制方法中,我們要實現的就是讓這個曲線一直不斷地重複,大致就是如此

那麼,這個是怎麼實現的呢?

首先我們從上升曲線開始看(完整請點此

上升曲線就是綠色(吸氣)的部分,公式為

截圖 2021-10-02 下午3.09.08

截圖 2021-10-02 下午3.20.05

其中,k=1/3,代表上升週期

t=總週期

n為一常數1

 

再來是下降(吐氣)的部分,公式如下

截圖 2021-10-02 下午3.20.50

截圖 2021-10-02 下午3.23.29

 

此外,k的部分則是可以調整吸與吐的斷點,下圖為1/3時吐氣

截圖 2021-10-02 下午3.24.49

我改為1/5

截圖 2021-10-02 下午3.25.18

可以發現,「呼吸」變得急促了!

OK,理解數學公式後,接下來就要來在程式上實現了

 


 

2. 漸變動畫實現

 

接下來就要來就要來把這個東西放到Android上實現

首先是專案結構

截圖 2021-10-02 下午4.49.40

 

Breath.class就是今天專案要用的差值器類別

其他的都很基本,就不在多談

獻上介面

activity_main.xml

截圖 2021-10-02 下午4.50.58

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/layout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="40dp"
        android:background="#000"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

再來寫入呼吸燈動畫

Breath.java

public class Breath implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        float x = 6*input;
        float k = 1f/2;
        int t = 6;
        int n = 1;
        float PI = 3.1415926f;
        float output = 0;
        if (x >= ((n - 1) * t) && x < ((n - (1 - k)) * t)) {
            output = (float) (0.5 * Math.sin((PI / (k * t))
                    * ((x - k * t / 2) - (n - 1) * t)) + 0.5);
        } else if (x >= (n - (1 - k)) * t && x < n * t) {
            output = (float) Math.pow((0.5 * Math.sin((PI / ((1 - k) * t))
                    * ((x - (3 - k) * t / 2) - (n - 1) * t)) + 0.5), 2);
        }
        return output;
    }
}

還記得我們上面的公式嗎?

截圖 2021-10-02 下午3.00.34

綠色部分:

截圖 2021-10-02 下午3.09.08

 

橘色部分

截圖 2021-10-02 下午3.20.50

 

最後模組寫好,將模組套用到主畫面上

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ConstraintLayout show = findViewById(R.id.layout);

        ObjectAnimator animator = ObjectAnimator.ofFloat(show,"alpha",0.5f,1f);
        animator.setDuration(6000);
        animator.setInterpolator(new Breath());
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.start();
    }
}

 

OK,這時候按下操作就可以完成呼吸燈操作囉:D

那最後..

TK

arrow
arrow

    碼農日常 發表在 痞客邦 留言(11) 人氣()