編輯:關於Android編程
主題是關於動畫的,但是不是什麼動畫的內容都包括。先泛泛的介紹一下,然後詳細的介紹一下翻代碼找見的一個好玩的動畫的使用。以下的內容包括Android 3和Android 3.1等引入的API,在使用中請注意版本。
代碼都是用Kotlin寫的。如果你用的是新版的Android Studio。
創建項目之後,按下快捷鍵Shift+Ctrl+Alt+K就會自動把代碼從java轉換成Kotlin。
之後按照說明給項目配置Kotlin的插件即可。很簡單。Kotlin的官網在這裡:http://kotlinlang.org/。
Android 3.0引入了這個動畫。理論上可以支持任意的對象(不限於View)在定義好的timer interval裡修改其屬性值,具體的介紹在這裡。Property Animation的引入很好的改進了之前的Tween Animation的不足。
ObjectAnimator
繼承自ValueAnimator
, ValueAnimator
繼承自Animator
。屬性動畫一般使用ObjectAnimator
來實現動畫。用ValueAnimator
的話需要自己添加AnimatorUpdateListener
來實現動畫中的每一個time interval的增量值。
Animator
說可以添加AnimatorListener
給他,於是我們可以給Animator
和他的子類添加AnimatorListener
。這個listener在動畫的不同階段都會有對應的回調方法。這些在上面提到的那篇文章中都有詳細的敘述,這裡不再多說。
Android 3.1引入了ViewPropertyAnimator
,用這個類可以更加簡單的給View
添加動畫。
animate()
方法返回了調用的view的ViewPropertyAnimator
對象。這個對象可以同時執行多個動畫。而且每一種動畫都提供了一組特定的方法。使用起來非常方便。比如:
view.animate().translationX(100f).translationY(100f).scaleX(2.0f).scaleY(2.0f).withLayer()
這個動畫包括右移(translationX)、下移(translationY)和橫向放大兩倍(scaleX)、縱向放大兩倍(scaleY)。最後的withLayer()
方法可以用start()
代替。只不過withLayer()
會在情況允許的情況下調用硬件加速。
你也可以定義一個Runnable
在動畫開始和結束的時候執行。
// 開始的時候
animLayout.animate().translationX(200f).withStartAction(object : Runnable {
override fun run() {
Toast.makeText(this@MainActivity, "Start Action", Toast.LENGTH_SHORT).show()
}
})
動畫結束的時候執行的Runnable
。
animLayout.animate().alpha(0f).withEndAction {
Toast.makeText(this@MainActivity, "End Action", Toast.LENGTH_SHORT).show()
}
以上用了Kotlin的兩種不同的寫法,但是意思都是一樣的,都是Runnable
對象作為參數傳入方法。第一個寫法:初始化一個Runnable
接口的匿名對象。這個對象用object
關鍵字表明。第二個寫法是,在Kotlin中只有一個方法的接口的實現,可以直接把實現方法放在大括號裡扔給傳入的方法作為參數。
Kotlin是一個很有意思的語言,其與java的互操作非常的方便。他並不是一個運行在JVM上的特例獨行的語言,而是一個擁有腳本語言的便捷特點的Java。而且,這個便捷不是像Java 8那樣的妥協以後的產物。更多Kotlin的內容可以看這裡。
下面舉一個例子。這個例子就是讓一個背景為藍色的view隔幾秒就做寬度(scaleX,scaleY)和位置(translationX,translationY)以及透明度(alpha)的變化。代碼:
fun executeAnim() {
animView.scaleX = getScaleValue()
animView.scaleY = getScaleValue()
animView.translationX = getTransitionValue(animView.width, animView.scaleX)
animView.translationY = getTransitionValue(animView.height, animView.scaleY)
animView.animate()
.scaleX(getScaleValue())
.scaleY(getScaleValue())
.translationX(getTransitionValue(animView.width, animView.scaleX))
.translationY(getTransitionValue(animView.height, animView.scaleY))
.setDuration(300).start()
var animSet = AnimatorSet()
animSet.duration = mFadeInOutMs
animSet.playTogether(
ObjectAnimator.ofFloat(animView, "alpha", 1.0f, 0.0f),
ObjectAnimator.ofFloat(animView, "alpha", 0.0f, 1.0f)
)
animSet.start()
}
為了更容易理解,給出getScaleValue(): Float
和getTransitionValue(value: Int, ratio: Float): Float
的定義。這兩個方法都是產生隨機數的:
fun getScaleValue(): Float {
return minScaleFactor + random.nextFloat() * (maxScaleFactor - minScaleFactor)
}
fun getTransitionValue(value: Int, ratio: Float): Float {
return value * (ratio - 1.0f) * (random.nextFloat() - 0.5f)
}
如前所舒,上面的代碼就是用來讓一個view隔一段時間就執行一次動畫。這個動畫包括寬度、高度和上下的位移。為了不讓view的大小和位置變得沒譜,所以控制寬高和位置的隨機數值是控制在一定的比例范圍內的。
對比一下animView.animate().scaleX(getScaleValue()).scaleY(getScaleValue())...
的多個動畫設置和下面的AnimatorSet
的alpha動畫設置,足見其方便程度。
使用LayoutTransition
類,可以實現在布局容器上添加一個動畫,並且在這個容器內的view樹的變化都會以動畫展現出來。
這部分直接上代碼了,各位跑起來就可以看到運行的結果。點擊按鈕,添加一個view,在添加的過程會有一個alpha動畫。
布局是這樣的(刪去了部分主題無關的內容):
Kotlin的代碼“
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_layout_transition_demo)
val layoutContainer = findViewById(R.id.layout_container) as LinearLayout
// Layout transition animation
val layoutTransition = LayoutTransition()
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
layoutContainer.layoutTransition = layoutTransition
val addViewButton = findViewById(R.id.add_view_button) as Button
addViewButton.setOnClickListener { v ->
layoutContainer.addView(Button(this@LayoutTransitionDemoActivity))
}
}
運行起來以後,點擊“Add View”按鈕使勁往上添加視圖,你會看到具體的效果。如果交互上沒有什麼特殊的要求,給ViewGroup
添加一個LayoutTransition
類動畫可以有效的改善用戶體驗,而且也只需要簡單的幾行代碼就可以完成。
不僅可以給視圖添加動畫,也可以給Activity添加過渡動畫。ActivityOptions
類就是用來干這個的。
val layoutTransAnimButton = findViewById(R.id.layout_trans_button) as Button
layoutTransAnimButton.setOnClickListener { v ->
val i = Intent(this@MainActivity, LayoutTransitionDemoActivity::class.java)
var activityOptions = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.width, v.height)
startActivity(i, activityOptions.toBundle())
}
只需要給startActivity()
方法中添加一個ActivityOptions
類的實例就可以實現這個功能。而且不僅於此,在這個類的API中還包括一些諸如makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)
以及makeThumbnailScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)
等這樣的方法。比如在瀑布流中,從一個item點擊之後跳轉到其他Activity的動畫就可以用這兩個方法來實現。
說完了Activity在說說Fragment的過渡動畫。這部分完全可以另外起一篇博文來細說一下。簡要概括呢,設定動畫的代碼很容易,知識准備動畫內容多一點。下面的內容用到的Property Animation不再是代碼實現,而是使用xml的方式實現。
首先我們來討論一下這個過渡動畫應該是什麼樣子的。在Fragment進入的時候逐漸顯示出來(alpha從0到1),位置從100到0(translation x從100到0),在Fragment退出的時候正好相反。但是,進入和退出分兩個方向。或者需要我們設置兩個方向的進入和退出。分別是從左到右和從右到左的。
下面開始實戰:在res目錄下創建一個animator目錄,專門用來存放上文提到的進入和退出動畫。如果你只想要知道具體的Fragment過渡動畫設置,可以直接略過以下具體的動畫的設置部分。首先要穿件的是從左到右進入和退出的動畫:、
res/animator/fragment_slide_left_enter.xml
res/animator/fragment_slide_left_exit.xml
從右到左的進入和退出:
res/animator/fragment_slide_right_enter.xml
res/animator/fragment_slide_right_exit.xml
這裡在見還要看看Fragment所在的activity的布局和Fragment本身的布局:
activity
fragment
Activity的布局是一個添加Fragment的按鈕,按鈕下面是一個Fragment的容器。Fragment的布局就只包含一個TextView。
fun addFragmentToStack() {
var newFragment = DemoFragemnt.newInstance("fragment $mStackLevel") //as Fragment
var fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.setCustomAnimations(R.animator.fragment_slide_left_enter,
R.animator.fragment_slide_left_exit,
R.animator.fragment_slide_right_enter,
R.animator.fragment_slide_right_exit)
fragmentTransaction.replace(R.id.fragment_container, newFragment)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
}
Fragment的代碼很簡單,這裡直接略了。在Fragment的Transition裡調用方法fragmentTransaction.setCustomAnimations()
來設置左邊的進入和退出,右邊的進入和退出動畫。按鈕點擊以後調用addFragmentToStack()
方法replace Fragemnt,這樣動畫就展現出來了。
這個動畫在Android 5.0出現。也是屬於簡單易用型的。這個動畫能達到的效果是在一個Activity跳轉到另外一個Activity的時候,兩個關聯的view會從第一個的外形轉換到第二個。兩個Activity則分別會fade out和fade in。效果很好,可以省很多事。
先看看兩個Activity的布局,以及他們如何share view的:
shared_text
就是我們准備要和另外一個Activity關聯的view。這裡沒有什麼特別之處。繼續看下一個Activity的布局:
千萬不要被這裡的TextView
迷惑了,他的ID是shared_text1111。下面的Button
就才是關聯view。Button裡有一個屬性android:transitionName
它的值指向了上一個Activity的TextView。android:transitionName
屬性關聯兩個Activity布局中的兩個View。
接下來是Activity的代碼:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shared_view)
var sharedText = findViewById(R.id.shared_text) as TextView
sharedText.setOnClickListener { v ->
var options = ActivityOptions.makeSceneTransitionAnimation(this@SharedViewActivity,
sharedText, "shared_text")
val i = Intent(this@SharedViewActivity, AnotherSharedViewActivity::class.java)
startActivity(i, options.toBundle())
}
}
看代碼,和上文中提到的Activity的過渡動畫非常類似。只不過這裡選擇的是用方法ActivityOptions.makeSceneTransitionAnimation()
並在參數中指定了當前Activity中要share的view對象和這個對象的ID值。那麼另外一個Activity呢?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_another_shared_view)
}
在這個Activity中什麼都沒有做。所以,非常簡單。只需要使用transitionName
這個屬性,並指向其他的Activity的一個View的ID就可以。
作為Android四大組件之一,Activity可以說是最基本也是最常見的組件,它提供了一個顯示界面,從而實現與用戶的交互,作為初學者,必須熟練掌握。今天我們就來通過實驗
前言團隊協作中,盡量保證各自代碼自己維護。這樣既能保證代碼編寫者在邏輯上的一慣性,也能避免修改不熟悉的代碼而引起bug問題。但即使是這樣的規避,也依然無法避免程序員之間代
先給大家展示效果圖,看看是大家想要的效果嗎,如果還滿意,請參考以下代碼:前言 UniversalImageLoader是用於加載圖片的一個開源項目,在其項目介紹中是這麼寫
qq火炬手是騰訊QQ針對今年的巴西裡約奧運會推出的火炬傳遞活動,最近,越來越多的小伙伴參與了QQ火炬手的活動,因此也發現了很多問題,比如QQ掃描沒有出現AR