【Android】屬性動畫

在屬性動畫出現之前,Android 系統提供的動畫只有幀動畫和 View 動畫。View 動畫我們都了解,它提供了 AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation 這4種動畫方式,并提供了 AnimationSet 動畫集合來混合使用多種動畫。隨著屬性動畫的推出,View 動畫不再風光。

相比屬性動畫,View 動畫一個非常大的缺陷突顯,其不具有交互性。當某個元素發生 View 動畫后,其響應事件的位置依然在動畫進行前的地方,所以 View 動畫只能做普通的動畫效果,要避免涉及交互操作。但是它的優點也非常明顯:效率比較高,使用也方便。由于之前已有的動畫框架 Animation 存在一些局限性,也就是動畫改變的只是顯示,但 View 的位置沒有發生變化,View 移動后并不能響應事件,所以谷歌推出了新的動畫框架,幫助開發者實現更加豐富的動畫效果。在 Animator 框架中使用最多的就是 AnimatorSet 和 ObjectAnimator,配合使用 ObjectAnimator 進行更精細化的控制,控制一個對象和一個屬性值,而使用多個 ObjectAnimator 組合到 AnimatorSet 形成一個動畫。屬性動畫通過調用屬性 get、set 方法來真實地控制一個 View 的屬性值,因此,強大的屬性動畫框架基本可以實現所有的動畫效果。

一、ObjectAnimator

ObjectAnimator 是屬性動畫最重要的類,創建一個 ObjectAnimator 只需通過其靜態工廠類直接返還一個 ObjectAnimator 對象。參數包括一個對象和對象的屬性名字,但這個屬性必須有 get 和 set 方法,其內部會通過 Java 反射機制來調用 set 方法修改對象的屬性值。下面看看平移動畫是如何實現的,代碼如下所示:

<?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"><Viewandroid:id="@+id/test_view"android:layout_width="100dp"android:layout_height="100dp"android:background="@android:color/holo_red_light"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val objectAnimator = ObjectAnimator.ofFloat(testView, "translationX", 200F)objectAnimator.setDuration(3000)objectAnimator.start()}
}

運行程序,效果如圖1所示:
請添加圖片描述

圖1

通過 ObjectAnimator 的靜態方法,創建一個 ObjectAnimator 對象,查看 ObjectAnimator 的靜態方法 ofFloat(),源碼如下所示:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {ObjectAnimator anim = new ObjectAnimator(target, propertyName);anim.setFloatValues(values);return anim;
}

從源碼可以看出第一個參數是要操作的 Object;第二個參數是要操作的屬性;最后一個參數是一個可變的 float 類型數組,需要傳進去該屬性變化的取值過程,這里設置了一個參數,變化到200。與 View 動畫一樣,也可以給屬性動畫設置顯示時長、插值器等屬性。下面就是一些常用的可以直接使用的屬性動畫的屬性值。

  • translationX 和 translationY:用來沿著 X 軸或者 Y 軸進行平移。
  • rotation、rotationX、rotationY:用來圍繞 View 的支點進行旋轉。
  • PrivotX 和 PrivotY:控制 View 對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理。默認該支點位置就是 View 對象的中心點。
  • alpha:透明度,默認是1(不透明),0代表完全透明。
  • x 和 y:描述 View 對象在其容器中的最終位置。

需要注意的是,在使用 ObjectAnimator 的時候,要操作的屬性必須要有 get 和 set 方法,不然 ObjectAnimator 就無法生效。如果一個屬性沒有 get、set 方法,也可以通過自定義一個屬性類或包裝類來間接地給這個屬性增加 get 和 set 方法。現在來看看如何通過包裝類的方法給一個屬性增加 get 和 set 方法,代碼如下所示:

class MyView(private val view: View) {fun getWidth(): Int {return view.layoutParams.width}fun setWidth(width: Int) {view.layoutParams.width = widthview.requestLayout()}
}

使用時只需要操作包類就可以調用 get、set 方法了:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val myView = MyView(testView)ObjectAnimator.ofInt(myView, "width", 500).setDuration(3000).start()}
}

運行程序,效果如圖2所示:
請添加圖片描述

圖2

二、ValueAnimator

ValueAnimator 不提供任何動畫效果,它更像一個數值發生器,用來產生有一定規律的數字,從而讓調用者控制動畫的實現過程。通常情況下,在 ValueAnimator 的 AnimatorUpdateListener 中監聽數值的變化,從而完成動畫的變換,代碼如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val valueAnimator = ValueAnimator.ofFloat(0F, 100F)valueAnimator.setTarget(testView)valueAnimator.setDuration(3000).start()valueAnimator.addUpdateListener { animation ->val animatedValue = animation.animatedValue}}
}

三、動畫的監聽

完整的動畫具有 start、Repeat、End、Cancel 這4個過程,代碼如下所示:

val animator = ObjectAnimator.ofFloat(testView, "alpha", 1.5F)
animator.addListener(object : AnimatorListener {override fun onAnimationStart(animation: Animator) {}override fun onAnimationEnd(animation: Animator) {}override fun onAnimationCancel(animation: Animator) {}override fun onAnimationRepeat(animation: Animator) {}
})

大部分時候我們只關心 onAnimationEnd 事件,Android 也提供了 AnimatorListenterAdaper 來讓我們選擇必要的事件進行監聽。

val animator = ObjectAnimator.ofFloat(testView, "alpha", 1.5F)
animator.addListener(object : AnimatorListenerAdapter() {override fun onAnimationEnd(animation: Animator) {super.onAnimationEnd(animation)}
})

四、組合動畫(AnimatorSet)

AnimatorSet 類提供了一個 play() 方法,如果我們向這個方法中傳入一個 Animator 對象(ValueAnimator 或 ObjectAnimator),將會返回一個 AnimatorSet.Builder 的實例。AnimatorSet 的 play() 方法源碼如下所示:

public Builder play(Animator anim) {if (anim != null) {return new Builder(anim);}return null;
}

很明顯,在 play() 方法中創建了一個 AnimatorSet.Builder 類,這個 Builder 類是 AnimatorSet 的內部類。我們來看看這個 Builder 類中有什么,代碼如下所示:

public class Builder {private Node mCurrentNode;Builder(Animator anim) {mDependencyDirty = true;mCurrentNode = getNodeForAnimation(anim);}public Builder with(Animator anim) {Node node = getNodeForAnimation(anim);mCurrentNode.addSibling(node);return this;}public Builder before(Animator anim) {Node node = getNodeForAnimation(anim);mCurrentNode.addChild(node);return this;}public Builder after(Animator anim) {Node node = getNodeForAnimation(anim);mCurrentNode.addParent(node);return this;}public Builder after(long delay) {ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);anim.setDuration(delay);after(anim);return this;}
}

從源碼中可以看出,Builder 類采用了建造者模式,每次調用方法時都返回 Builder 自身用于繼續構建。AnimatorSet.Builder 中包括以下4個方法:

  • with(Animator anim):將現有動畫和傳入的動畫同時執行。
  • before(Animator anim):將現有動畫插入到傳入的動畫之前執行。
  • after(Animator anim):將現有動畫插入到傳入的動畫之后執行。
  • after(long delay):將現有動畫延遲指定毫秒后執行。

AnimatorSet 正是通過這幾種方法來控制動畫播放順序的。這里再舉一個例子,代碼如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val animator1 = ObjectAnimator.ofFloat(testView, "translationX", 0.0F, 200.0F, 0F)val animator2 = ObjectAnimator.ofFloat(testView, "scaleX", 1.0F, 2.0F)val animator3 = ObjectAnimator.ofFloat(testView, "rotationX", 0.0F, 90.0F, 0.0F)val set = AnimatorSet()set.setDuration(3000)set.play(animator1).with(animator2).after(animator3)set.start()}
}

首先我們創建3個 ObjectAnimator,分別是 animator1、animator2 和 animator3,然后創建 AnimatorSet。在這里先執行 animator3,然后同時執行 animator1 和 animator2(也可以調用 set.playTogether(animator1,animator2) 來使這兩種動畫同時執行)。

運行程序,效果如圖3所示:
請添加圖片描述

圖3

五、組合動畫(PropertyValuesHolder)

除了上面的 AnimatorSet 類,還可以使用 PropertyValuesHolder 類來實現組合動畫。不過這個組合動畫就沒有上面的豐富了,使用 PropertyValuesHolder 類只能是多個動畫一起執行。當然我們得結合 ObjectAnimator.ofPropertyValuesHolder(Object target,PropertyValuesHolder…values) 方法來使用。其第一個參數是動畫的目標對象;之后的參數是 PropertyValuesHolder 類的實例,可以有多個這樣的實例。具體代碼如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0F, 1.5F)val valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0F, 90.0F, 0.0F)val valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0F, 0.3F, 1.0F)val objectAnimator = ObjectAnimator.ofPropertyValuesHolder(testView,valuesHolder1,valuesHolder2,valuesHolder3)objectAnimator.setDuration(3000).start()}
}

運行程序,效果如圖4所示:
請添加圖片描述

圖4

六、在 xml 中使用屬性動畫

和 View 動畫一樣,屬性動畫也可以直接寫在 xml 中。在 res 文件中新建 animator 文件夾,在里面新建一個 scale.xml,其內容如下所示:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:duration="3000"android:propertyName="scaleX"android:valueFrom="1.0"android:valueTo="2.0"android:valueType="floatType" />

在程序中引用 xml 定義的屬性動畫也很簡單,代碼如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView = findViewById<View>(R.id.test_view)val animator = AnimatorInflater.loadAnimator(this, R.animator.scale)animator.setTarget(testView)animator.start()}
}

運行程序,效果如圖5所示:
請添加圖片描述

圖5

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/711000.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/711000.shtml
英文地址,請注明出處:http://en.pswp.cn/news/711000.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

35. 【Linux教程】Linux 修改用戶組

前面小節介紹了如何添加用戶組&#xff0c;本小節介紹如何給已經添加的新用戶組修改信息&#xff0c;從 /etc/group 文件信息可以看到&#xff0c;用戶組的信息比用戶信息項少&#xff0c;和 usermod 命令類似&#xff0c;用戶組的信息可以使用 groupmod 命令修改。 1. groupmo…

為了董宇輝,老婆跟我打起來了!寫下一份深刻檢討

兩個月前&#xff0c;因為討論董宇輝小作文事件&#xff0c;跟老婆吵起來了。起因就為了兩句話&#xff0c;寫了這份檢討&#xff01;給大家分享一下。 老婆在網上刷了兩晚關于董宇輝小作文的視頻&#xff0c;一直為董宇輝喊冤、打抱不平。起初&#xff0c;我跟老婆的想法&…

類型字段定義影響WebApi傳值及SqlSugar調用Select創建新對象

ASP.NET Core編寫的WebApi&#xff0c;由于輸入參數較多&#xff0c;專門定義了輸入參數類并設置[FromBody]方式傳值&#xff0c;但測試時始終無法通過postman將輸入參數值傳遞給WebApi&#xff0c;condition對象的所有屬性值一直都為空。同時在WebApi內部調用SqlSugar查詢數據…

怎樣消除視頻上的字幕和文字?3個方法值得推薦

怎樣消除視頻上的字幕和文字&#xff1f;消除視頻上的字幕和文字不僅是一個常見的需求&#xff0c;更是一個對視頻內容質量提升的關鍵步驟。特別是在處理從網絡下載的帶有水印或標識的視頻時&#xff0c;這些額外的文字和信息往往會干擾觀眾的觀看體驗&#xff0c;甚至可能影響…

three.js環境及使用教程

開發環境 npm i three0.156.1 npm i types/three0.156.0入門代碼 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" />…

Pytorch 復習總結 5

Pytorch 復習總結&#xff0c;僅供筆者使用&#xff0c;參考教材&#xff1a; 《動手學深度學習》Stanford University: Practical Machine Learning 本文主要內容為&#xff1a;Pytorch 卷積神經網絡。 本文先介紹了 Pytorch 語法匯總&#xff1a; Pytorch 張量的常見運算、…

【數據結構】順序表和鏈表的對比,在各種情況下如何選擇

順序表詳細內容&#xff1a; 【數據結構】線性表 順序表&#xff08;動態、靜態分配&#xff0c;插入刪除查找基本操作&#xff09;解析完整代碼 單鏈表詳細內容&#xff1a; 【數據結構】單鏈表解析完整代碼&#xff08;插入、刪除、尾插法、頭插法、按值和按位查找、前插和后…

IDEA開發環境的安裝與編寫第一個程序

1.下載 IDEA&#xff08;全稱IntelliJ IDEA&#xff09;是用于Java程序開發的集成環境&#xff08;也可用于其他語言&#xff09;&#xff0c;它在業界被公認是最好的Java開發工具之一&#xff0c;尤其在智能代碼助手、代碼自動提示、重構、J2EE支持、Ant、JUnit、CVS整合、代…

【Java萬花筒】醫學圖像處理的“探索”:探索更多可能性和應用場景

使用 Java 庫打造醫學圖像處理的“神器” 前言 隨著醫學圖像在醫療保健領域中的不斷發展&#xff0c;醫學圖像處理也成為了一項非常重要的研究領域。在此背景下&#xff0c;本文將介紹三個常用的 Java 醫學圖像處理庫&#xff1a;ImageJ、MIPAV 和 ITK。這些庫提供了豐富的圖…

代碼隨想錄算法訓練營day46| 139. 單詞拆分、背包問題總結

139、單詞拆分&#xff1a; class Solution(object):def wordBreak(self, s, wordDict):""":type s: str:type wordDict: List[str]:rtype: bool"""n len(s)dp [False] * (n 1)dp[0] Truemap_word set(wordDict)for j in range(1, n 1):f…

3月1日.開始記錄

今天事項安排 打算今天開始&#xff0c;每天工作日記錄&#x1f4dd;一下當天大致的事項。 有說法是每天開始工作前記錄下自己的清單&#xff0c;可以讓當天做事太過發散。這對于我這種喜歡發散的人是個有用的技巧&#xff08;笑 上午 把昨天的日報交了 30 min 把今天的工作放…

算法日記——前綴和、差分

文章目錄 洛谷 B3612 求區間和洛谷 P1387 最大正方形洛谷 P3397 地毯 洛谷 B3612 求區間和 題目鏈接&#xff1a;洛谷 B3612 求區間和 思路&#xff1a; 一維前綴和的模板題。所謂前綴和&#xff0c;就是對原數組前i個元素求和&#xff0c;這個值作為新元素放在下標i的位置。 …

C++智能指針_C++回顧

發展歷史 C98中產生了第一個智能指針auto_ptr&#xff1b; Cboost給出了更實用的scoped_ptr和shared_ptr和weak_ptr&#xff1b; CTR1&#xff0c;引入了shared_ptr等&#xff0c;不過TR1并不是標準版&#xff1b; C11引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是…

Mamba與MoE架構強強聯合,Mamba-MoE高效提升LLM計算效率和可擴展性

論文題目&#xff1a; MoE-Mamba: Efficient Selective State Space Models with Mixture of Experts 論文鏈接&#xff1a; https://arxiv.org/abs/2401.04081 代碼倉庫&#xff1a; GitHub - llm-random/llm-random 作為大型語言模型&#xff08;LLM&#xff09;基礎架構的后…

新一代科學計算與系統建模仿真平臺MWORKS 2024a震撼發布:產品強勢進化,更新亮點速覽!

2月25日&#xff0c;同元軟控成功舉辦MWORKS 2024產品發布會&#xff0c;會上公布了新版MWORKS的設計理念、關鍵技術、版本亮點、產品特性以及重大改進。當前&#xff0c;科學計算與系統建模仿真平臺MWORKS 2024a已正式上線&#xff0c;開放下載。 MWORKS已成為全球第4個完整的…

全量知識系統問題及SmartChat給出的答復 之6 三套工具之1

Q15. 提出想法和問題 前面說過&#xff0c;DDD在我要設計的全量知識系統中位于中間層&#xff0c;是專門用來解決“知識湯”問題的。 解決的思路就是以將為在特定領域中的公司經營提供一個責任-權限平面為目的&#xff0c;幫助他們調整商業模式以及組建恰當的組織&#xff0c…

C# 高階語法 —— Winfrom鏈接SQL數據庫的存儲過程

存儲過程在應用程序端的使用的優點 1 如果sql語句直接寫在客戶端&#xff0c;以一個字符串的形式體現的&#xff0c;提示不友好&#xff0c;會導致效率降低 2 sql語句寫在客戶端&#xff0c;可以利用sql注入進行攻擊&#xff0c;為了安全性&#xff0c;可以把sql封裝在…

嘉立創專業版導入SW模型的板框

1、SW新建一個需要的模型&#xff0c;例如下圖&#xff0c; 2、點擊另存為.dxf 文件&#xff08;是.dxf文件&#xff09; 3、選擇要保存模型的視圖&#xff0c;如上視圖&#xff0c;確定后出現上視圖板框形狀&#xff0c;然后保存即可。 4、打開嘉立創&#xff0c;點擊文件——…

Linux中的awk命令

AWK是一種在Linux系統中經常使用的文本處理工具&#xff0c;它可以根據指定的模式對文本文件進行處理和分析。下面是一些關于AWK命令的使用說明和舉例&#xff1a; 1. 基本語法&#xff1a; awk pattern { action } file 2. 使用字段分隔符&#xff1a; 默認情況下&#xf…

整數編碼【華為OD機試-JAVAPythonC++JS】

題目描述 實現一種整數編碼方法&#xff0c;使得待編碼的數字越小&#xff0c;編碼后所占用的字節數越小。 編碼規則如下: 編碼時7位一組&#xff0c;每個字節的低7位用于存儲待編碼數字的補碼 字節的最高位表示后續是否還有字節&#xff0c;置1表示后面還有更多的字節&#xf…