基于Android實現(xiàn)顏色漸變動畫效果
1. 前言
今天來試一個顏色變化的效果,有個控件點擊后,背景的顏色就逐漸變成另一個顏色。類似這樣的一個效果
這個如果用自定義View是有一萬種方法去實現(xiàn),但是我們要考慮到希望所有控件都能做到,所以就不用自定義View的方式去實現(xiàn)這種效果,比如之前你的同事做了一個控件,你的產(chǎn)品讓你給這個控件的點擊事件加個酷炫的效果,大概上邊演示的效果。
2. 場景分析
可以先分析一下怎么去實現(xiàn)這個效果,首先,顏色的變化,是一個過程,那這個過程中,兩個顏色之間銜接,不能太生硬,比如你x位置還是顏色A,x+1的位置馬上變成顏色B,那這樣的變化就太生硬了,要做一個顏色變化的過程,我想到的就是用漸變做。
漸變又分3種類型,線性、放射、掃描,具體用哪種,根據(jù)你的需求,比如我想變化從左到右,那就用線性,如果想像水波紋一樣從右下角去變化,那就用放射,抱歉不是你想,是產(chǎn)品想[狗頭]。這里做演示就用線性來演示吧。
顏色銜接的問題是解決了,用漸變能讓顏色的變化過程看起來不會很突兀,那如何去實現(xiàn)顏色變化的過程,怎么去實現(xiàn)顏色A到顏色B的變化。顏色是這個控件的一個屬性,所以是不是就能馬上想到可以用屬性動畫來實現(xiàn)。
3. 實現(xiàn)效果
ok,通過上面的分析,我們要做兩個技術(shù)點,一個是漸變,一個是屬性動畫。
(1)漸變的實現(xiàn)
首先漸變我們平時做,都是用xml去做,這里因為要配合屬性動畫,所以我們要動態(tài)去寫代碼,動態(tài)實現(xiàn)漸變色的效果可以使用GradientDrawable
我們先寫一個demo看看效果,這里就用兩種顏色來演示,基佬紫和猛男粉
private fun setBg(){ val colors = intArrayOf( Color.parseColor("#9932CC"), Color.parseColor("#FF69B4") ) val drawable = GradientDrawable() drawable.gradientType = GradientDrawable.LINEAR_GRADIENT drawable.orientation = GradientDrawable.Orientation.LEFT_RIGHT drawable.colors = colors tvTest?.background = drawable }
可以看到代碼很簡單,最終實現(xiàn)的效果(我就不貼全代碼了,控件就一個TextView)
ok,我們要做的是中間漸變的那段區(qū)域從左邊屏幕外移動到右邊的屏幕外,那就能實現(xiàn)一個顏色變化的過程,這個思路應(yīng)該能不難理解吧。
那么要怎么移動呢,GradientDrawable我也不熟,沒關(guān)系,那就去看官方文檔嘛,能發(fā)現(xiàn)有個方法level,我們試著寫個輪詢?nèi)ピ囋囘@個level的效果,官方有說這個Level的范圍是0-10000(這里開始上動畫也行,為了方便也可以先用輪詢測效果)
var level = 0 private fun startLooper() { handler.postDelayed({ if (level < 10000) { level += 100 setBg() startLooper() } }, 10) } private fun setBg(){ val colors = intArrayOf( Color.parseColor("#9932CC"), Color.parseColor("#FF69B4") ) val drawable = GradientDrawable() drawable.gradientType = GradientDrawable.LINEAR_GRADIENT drawable.orientation = GradientDrawable.Orientation.LEFT_RIGHT drawable.useLevel = true drawable.level = level drawable.colors = colors tvTest?.background = drawable }
看最后的效果
看得出這顏色變化只能變一半,沒辦法全部變完,level為0的效果就是單色的效果,最終的1000的level效果就是原始的樣子。那我嘗試把level設(shè)超過10000會怎樣,我設(shè)個10W
能看出好像是實現(xiàn)了這個效果。其實不然,首先這個最終也并沒有完全是單色(只要你把其中一個顏色換成白色就能很容易看出),其次后半段的速度和前面的不同
所以不能勉強用這個方法去做,那為什么要寫這個失敗的demo出來呢,因為我覺得用Level應(yīng)該也能有辦法實現(xiàn)這個效果的,只是我沒時間去認真研究,就簡單的使用的話是做不到,但是通過一些奇技淫巧肯定還是能做到的。
既然level實現(xiàn)不了我們想要的效果,沒關(guān)系,我們再看看文檔,發(fā)現(xiàn)其實setColors方法是有一個參數(shù)的,也有兩個參數(shù)的,雙參的方法中是一個offsets數(shù)組,那我感覺這個就是我要找的方法了,把代碼改一下。
var x = 0f private fun startLooper() { handler.postDelayed({ if (x < 1.1f) { x += 0.1f setBg() startLooper() } }, 1000) } private fun setBg() { val colors = intArrayOf( Color.parseColor("#9932CC"), Color.parseColor("#FF69B4") ) val offsets = floatArrayOf( x - 0.1f, x ) val drawable = GradientDrawable() drawable.gradientType = GradientDrawable.LINEAR_GRADIENT drawable.orientation = GradientDrawable.Orientation.LEFT_RIGHT if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { drawable.setColors(colors, offsets) } // drawable.colors = colors tvTest?.background = drawable }
看看最終的效果
有點意思,怎么搞得像個進度條一樣,無所謂,總之這樣就能實現(xiàn)顏色漸變的這個功能,實現(xiàn)第一個目標。
(2)顏色變化過程的實現(xiàn)
讓上面的效果更加絲滑,我們使用屬性動畫。按理來說這個過程也應(yīng)該要用屬性動畫來實現(xiàn),這樣才符合屬性動畫的定義。
我們寫一個動畫
private var mValueAnimator1: ValueAnimator? = null fun startToStopChange() { if (mValueAnimator1 == null) { mValueAnimator1 = ValueAnimator.ofFloat(0f, 1.1f) mValueAnimator1?.addUpdateListener { x = it.animatedValue as Float setBg() } } mValueAnimator1?.setDuration(1000)?.start() }
整體的代碼結(jié)合起來就是
var tvTest: TextView? = null var x = 0f private var mValueAnimator1: ValueAnimator? = null @SuppressLint("MissingInflatedId") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.test_main) tvTest = findViewById(R.id.tv_test) setBg() tvTest?.setOnClickListener { startToStopChange() } } private fun setBg() { val colors = intArrayOf( Color.parseColor("#9932CC"), Color.parseColor("#FF69B4") ) val offsets = floatArrayOf( x - 0.1f, x ) val drawable = GradientDrawable() drawable.gradientType = GradientDrawable.LINEAR_GRADIENT drawable.orientation = GradientDrawable.Orientation.LEFT_RIGHT if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { drawable.setColors(colors, offsets) } // drawable.colors = colors tvTest?.background = drawable } fun startToStopChange() { if (mValueAnimator1 == null) { mValueAnimator1 = ValueAnimator.ofFloat(0f, 1.1f) mValueAnimator1?.addUpdateListener { x = it.animatedValue as Float setBg() } } mValueAnimator1?.setDuration(2000)?.start() }
加了個點擊事件,看看最終的效果
ok,看得出最終的效果非常的絲滑。當然我這個是demo,所以這樣簡單寫,主要是為了說明怎么實現(xiàn),但真實要運用到項目中的話了,肯定還是需要在這代碼的基礎(chǔ)上做些優(yōu)化、封裝操作的。
4. 總結(jié)
簡單來說,實現(xiàn)這樣的一個動畫漸變的效果很簡單,只需要兩步,第一步用GradientDrawable實現(xiàn)兩個顏色之間的漸變效果,第二步用屬性動畫實現(xiàn)顏色變化的過程。
這其實也就是一些很簡單的基礎(chǔ)知識,基礎(chǔ)知識就是你的武器庫,一個復(fù)雜的效果,如果你基礎(chǔ)牢固的話,你會把這個復(fù)雜的效果去拆分成粒度更小的效果,你知道用哪些基礎(chǔ)知識能實現(xiàn)這樣的效果,這才是一個真正的開發(fā)過程,而不是說產(chǎn)品讓你實現(xiàn)一個你沒做過的效果,你第一反應(yīng)就是去搜索抄別人的代碼,第一反應(yīng)應(yīng)該是看看你的武器庫,有沒有能實現(xiàn)這個目標的武器。我有時也會看別人的代碼,但也主要是為了看實現(xiàn)的思路。
再復(fù)雜的效果,也是由很多個很簡單的原理去實現(xiàn)的。比如這里的效果如果放到recyclerView的item中,還要從recyclerView的那塊角度加點東西,才能兼容。
以上就是Android實現(xiàn)顏色漸變動畫效果的詳細內(nèi)容,更多關(guān)于Android顏色漸變的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
外層豎向ScrollView,里層橫向ScrollView滑動沖突的解決方法
下面小編就為大家?guī)硪黄鈱迂Q向ScrollView,里層橫向ScrollView滑動沖突的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04Android獲取arrays.xml里的數(shù)組字段值實例詳解
這篇文章主要介紹了Android獲取arrays.xml里的數(shù)組字段值實例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04android編程實現(xiàn)sd卡讀取數(shù)據(jù)庫的方法
這篇文章主要介紹了android編程實現(xiàn)sd卡讀取數(shù)據(jù)庫的方法,涉及Android權(quán)限控制及針對sd卡與數(shù)據(jù)庫的相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動實現(xiàn)返回功能
這篇文章主要介紹了Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動實現(xiàn)返回功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04Android獲取網(wǎng)絡(luò)圖片并顯示的方法
這篇文章主要為大家詳細介紹了Android獲取網(wǎng)絡(luò)圖片并顯示的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-11-11Anroid四大組件service之本地服務(wù)的示例代碼
本篇文章主要介紹了Anroid四大組件service之本地服務(wù)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10