基于Android實(shí)現(xiàn)顏色漸變動(dòng)畫效果
1. 前言
今天來試一個(gè)顏色變化的效果,有個(gè)控件點(diǎn)擊后,背景的顏色就逐漸變成另一個(gè)顏色。類似這樣的一個(gè)效果
這個(gè)如果用自定義View是有一萬種方法去實(shí)現(xiàn),但是我們要考慮到希望所有控件都能做到,所以就不用自定義View的方式去實(shí)現(xiàn)這種效果,比如之前你的同事做了一個(gè)控件,你的產(chǎn)品讓你給這個(gè)控件的點(diǎn)擊事件加個(gè)酷炫的效果,大概上邊演示的效果。
2. 場(chǎng)景分析
可以先分析一下怎么去實(shí)現(xiàn)這個(gè)效果,首先,顏色的變化,是一個(gè)過程,那這個(gè)過程中,兩個(gè)顏色之間銜接,不能太生硬,比如你x位置還是顏色A,x+1的位置馬上變成顏色B,那這樣的變化就太生硬了,要做一個(gè)顏色變化的過程,我想到的就是用漸變做。
漸變又分3種類型,線性、放射、掃描,具體用哪種,根據(jù)你的需求,比如我想變化從左到右,那就用線性,如果想像水波紋一樣從右下角去變化,那就用放射,抱歉不是你想,是產(chǎn)品想[狗頭]。這里做演示就用線性來演示吧。
顏色銜接的問題是解決了,用漸變能讓顏色的變化過程看起來不會(huì)很突兀,那如何去實(shí)現(xiàn)顏色變化的過程,怎么去實(shí)現(xiàn)顏色A到顏色B的變化。顏色是這個(gè)控件的一個(gè)屬性,所以是不是就能馬上想到可以用屬性動(dòng)畫來實(shí)現(xiàn)。
3. 實(shí)現(xiàn)效果
ok,通過上面的分析,我們要做兩個(gè)技術(shù)點(diǎn),一個(gè)是漸變,一個(gè)是屬性動(dòng)畫。
(1)漸變的實(shí)現(xiàn)
首先漸變我們平時(shí)做,都是用xml去做,這里因?yàn)橐浜蠈傩詣?dòng)畫,所以我們要?jiǎng)討B(tài)去寫代碼,動(dòng)態(tài)實(shí)現(xiàn)漸變色的效果可以使用GradientDrawable
我們先寫一個(gè)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 }
可以看到代碼很簡(jiǎn)單,最終實(shí)現(xiàn)的效果(我就不貼全代碼了,控件就一個(gè)TextView)
ok,我們要做的是中間漸變的那段區(qū)域從左邊屏幕外移動(dòng)到右邊的屏幕外,那就能實(shí)現(xiàn)一個(gè)顏色變化的過程,這個(gè)思路應(yīng)該能不難理解吧。
那么要怎么移動(dòng)呢,GradientDrawable我也不熟,沒關(guān)系,那就去看官方文檔嘛,能發(fā)現(xiàn)有個(gè)方法level,我們?cè)囍鴮憘€(gè)輪詢?nèi)ピ囋囘@個(gè)level的效果,官方有說這個(gè)Level的范圍是0-10000(這里開始上動(dòng)畫也行,為了方便也可以先用輪詢測(cè)效果)
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會(huì)怎樣,我設(shè)個(gè)10W
能看出好像是實(shí)現(xiàn)了這個(gè)效果。其實(shí)不然,首先這個(gè)最終也并沒有完全是單色(只要你把其中一個(gè)顏色換成白色就能很容易看出),其次后半段的速度和前面的不同
所以不能勉強(qiáng)用這個(gè)方法去做,那為什么要寫這個(gè)失敗的demo出來呢,因?yàn)槲矣X得用Level應(yīng)該也能有辦法實(shí)現(xiàn)這個(gè)效果的,只是我沒時(shí)間去認(rèn)真研究,就簡(jiǎn)單的使用的話是做不到,但是通過一些奇技淫巧肯定還是能做到的。
既然level實(shí)現(xiàn)不了我們想要的效果,沒關(guān)系,我們?cè)倏纯次臋n,發(fā)現(xiàn)其實(shí)setColors方法是有一個(gè)參數(shù)的,也有兩個(gè)參數(shù)的,雙參的方法中是一個(gè)offsets數(shù)組,那我感覺這個(gè)就是我要找的方法了,把代碼改一下。
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 }
看看最終的效果
有點(diǎn)意思,怎么搞得像個(gè)進(jìn)度條一樣,無所謂,總之這樣就能實(shí)現(xiàn)顏色漸變的這個(gè)功能,實(shí)現(xiàn)第一個(gè)目標(biāo)。
(2)顏色變化過程的實(shí)現(xiàn)
讓上面的效果更加絲滑,我們使用屬性動(dòng)畫。按理來說這個(gè)過程也應(yīng)該要用屬性動(dòng)畫來實(shí)現(xiàn),這樣才符合屬性動(dòng)畫的定義。
我們寫一個(gè)動(dòng)畫
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() }
加了個(gè)點(diǎn)擊事件,看看最終的效果
ok,看得出最終的效果非常的絲滑。當(dāng)然我這個(gè)是demo,所以這樣簡(jiǎn)單寫,主要是為了說明怎么實(shí)現(xiàn),但真實(shí)要運(yùn)用到項(xiàng)目中的話了,肯定還是需要在這代碼的基礎(chǔ)上做些優(yōu)化、封裝操作的。
4. 總結(jié)
簡(jiǎn)單來說,實(shí)現(xiàn)這樣的一個(gè)動(dòng)畫漸變的效果很簡(jiǎn)單,只需要兩步,第一步用GradientDrawable實(shí)現(xiàn)兩個(gè)顏色之間的漸變效果,第二步用屬性動(dòng)畫實(shí)現(xiàn)顏色變化的過程。
這其實(shí)也就是一些很簡(jiǎn)單的基礎(chǔ)知識(shí),基礎(chǔ)知識(shí)就是你的武器庫,一個(gè)復(fù)雜的效果,如果你基礎(chǔ)牢固的話,你會(huì)把這個(gè)復(fù)雜的效果去拆分成粒度更小的效果,你知道用哪些基礎(chǔ)知識(shí)能實(shí)現(xiàn)這樣的效果,這才是一個(gè)真正的開發(fā)過程,而不是說產(chǎn)品讓你實(shí)現(xiàn)一個(gè)你沒做過的效果,你第一反應(yīng)就是去搜索抄別人的代碼,第一反應(yīng)應(yīng)該是看看你的武器庫,有沒有能實(shí)現(xiàn)這個(gè)目標(biāo)的武器。我有時(shí)也會(huì)看別人的代碼,但也主要是為了看實(shí)現(xiàn)的思路。
再?gòu)?fù)雜的效果,也是由很多個(gè)很簡(jiǎn)單的原理去實(shí)現(xiàn)的。比如這里的效果如果放到recyclerView的item中,還要從recyclerView的那塊角度加點(diǎn)東西,才能兼容。
以上就是Android實(shí)現(xiàn)顏色漸變動(dòng)畫效果的詳細(xì)內(nèi)容,更多關(guān)于Android顏色漸變的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
外層豎向ScrollView,里層橫向ScrollView滑動(dòng)沖突的解決方法
下面小編就為大家?guī)硪黄鈱迂Q向ScrollView,里層橫向ScrollView滑動(dòng)沖突的解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Android獲取arrays.xml里的數(shù)組字段值實(shí)例詳解
這篇文章主要介紹了Android獲取arrays.xml里的數(shù)組字段值實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04android編程實(shí)現(xiàn)sd卡讀取數(shù)據(jù)庫的方法
這篇文章主要介紹了android編程實(shí)現(xiàn)sd卡讀取數(shù)據(jù)庫的方法,涉及Android權(quán)限控制及針對(duì)sd卡與數(shù)據(jù)庫的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能
這篇文章主要介紹了Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android自定義View仿大眾點(diǎn)評(píng)星星評(píng)分控件
這篇文章主要為大家詳細(xì)介紹了Android自定義View仿大眾點(diǎn)評(píng)星星評(píng)分控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03Android中快速便捷的實(shí)現(xiàn)圓角按鈕方法詳解
圓角按鈕在我們現(xiàn)在的界面中常常會(huì)用到,最近在開發(fā)中就又遇到了,所以想著有沒有更快速更便捷的實(shí)現(xiàn)方法呢,所以就有了這篇文章,本文主要給大家介紹了關(guān)于Android中如何快速便捷的實(shí)現(xiàn)圓角按鈕的相關(guān)資料,需要的朋友可以參考下。2017-05-05Android獲取網(wǎng)絡(luò)圖片并顯示的方法
這篇文章主要為大家詳細(xì)介紹了Android獲取網(wǎng)絡(luò)圖片并顯示的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Anroid四大組件service之本地服務(wù)的示例代碼
本篇文章主要介紹了Anroid四大組件service之本地服務(wù)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10