⑴ 知識體系四:android動畫工作原理
1.Android 動畫的工作原理?
在android系統中動畫分為兩種分別是幀動畫和屬性動畫。對於動畫的工作原理主要涉及到的是幀動畫的實現。
幀動畫主要有旋轉RotatleAnimation,縮放ScaleAnimation,透明AlphaAnimation,平移TranslateAnimation等都是Animation的子類。Animation控制動畫的效果,Transformation 對動畫進行計算。
對於動畫的原理簡單說就是從一個動畫的啟動狀態,到動畫結束狀態,和動畫持續總時間,在這段時間中任一時間點動畫的狀態計算和顯示的過程。
計算 :是通過Animation的getTransformation()方法首先對時間進行歸一化時間讓時間在0~1之間,進行計算。滿足條件之後就會調用applyTransformation()方法處理實現動畫類型的計算。當前時間點的轉換狀態保存到Transformation 的Matrix中等待顯示的時候使用。
顯示 :動畫顯示工作主要依賴於Choreograther類,此類是線程唯一的,Choreograther和Handler用法類似,都是通過post一個Runnable對象到隊列中等待VSYSC屏幕垂直同步信號刷新(16ms)刷新一次,然後觸發ViewRootImpl的view的遍歷工作,回調到view.draw()方法時就會把之前applyTransformation 計算的此時刻的Transformation 的Matrix賦值到Canvas上, 這也就是為什麼我們使用幀動畫時候我們的view的屬性並沒有改變,這就是根源因為計算得到的Matrix被Canvas使用了,並沒有直接賦值到我們的view上。 對於屬性動畫來說主要使用animator實現看下面解析:
2.Animation 和 Animator 的區別?
Animation和Animator都是抽象類,都有子類,Animation通過Transformation對動畫進行Matrix轉換來作用到Canvas上實現動畫效果。而Animator只是一個工具類,主要是用來控制在一段時間內某一個值的變化過程,然後我們再根據這個值來作用到view的屬性上,以此來實現動畫效果。為了讓這個變化的過程能達到加速減速等變化效果系統提供了插值器Interpolator。他們的實現思想都是一致的。
3.幀動畫 和 屬性動畫的區別?
⑵ 如何給Imageview 設置水波紋效果
水波紋效果:
1.標准正餘弦水波紋;
2.非標准圓形液柱水波紋;
雖說都是水波紋,但兩者在實現上差異是比較大的,一個通過正餘弦函數模擬水波紋效果,另外一個會運用到圖像的混合模式(PorterDuffXfermode);
先看效果:
自定義View根據實際情況可以選擇繼承自View、TextView、ImageView或其他
這次的實現我們都選擇繼承view,在實現的過程中我們需要關注如下幾個方法:
1.onMeasure():最先回調,用於控制項的測量;
2.onSizeChanged():在onMeasure後面回調,可以拿到view的寬高等數據,在橫豎屏切換時也會回調;
3.onDraw():真正的繪制部分,繪制的代碼都寫到這裡面;
既然如此,我們先復寫這三個方法,然後來實現如上兩個效果;
一:標准正餘弦水波紋
這種水波紋可以用具體函數模擬出具體的軌跡,所以思路基本如下:
1.確定水波函數方程
2.根據函數方程得出每一個波紋上點的坐標;
3.將水波進行平移,即將水波上的點不斷的移動;
4.不斷的重新繪制,生成動態水波紋;
有了上面的思路,我們一步一步進行實現:
正餘弦函數方程為:
y=Asin(wx+b)+h,這個公式里:w影響周期,A影響振幅,h影響y位置,b為初相;
根據上面的方程選取自己覺得中意的波紋效果,確定對應參數的取值;
然後根據確定好的方程得出所有的方程上y的數值,並將所有y值保存在數組里:
//將周期定為view總寬度
mCycleFactorW=(float)(2*Math.PI/mTotalWidth);
//根據view總寬度得出所有對應的y值
for(inti=0;i<mTotalWidth;i++){
mYPositions[i]=(float)(STRETCH_FACTOR_A*Math.sin(mCycleFactorW*i)+OFFSET_Y);
}
根據得出的所有y值,則可以在onDraw中通過如下代碼繪制兩條靜態波紋:
for(inti=0;i<mTotalWidth;i++){
//減400隻是為了控制波紋繪制的y的在屏幕的位置,大家可以改成一個變數,然後動態改變這個變數,從而形成波紋上升下降效果
//繪制第一條水波紋
canvas.drawLine(i,mTotalHeight-mResetOneYPositions[i]-400,i,
mTotalHeight,
mWavePaint);
//繪制第二條水波紋
canvas.drawLine(i,mTotalHeight-mResetTwoYPositions[i]-400,i,
mTotalHeight,
mWavePaint);
}
這種方式類似於數學裡面的細分法,一條波紋,如果橫向以一個像素點為單位進行細分,則形成view總寬度條直線,並且每條直線的起點和終點我們都能知道,在此基礎上我們只需要循環繪制出所有細分出來的直線(直線都是縱向的),則形成了一條靜態的水波紋;
接下來我們讓水波紋動起來,之前用了一個數組保存了所有的y值點,有兩條水波紋,再利用兩個同樣大小的數組來保存兩條波紋的y值數據,並不斷的去改變這兩個數組中的數據:
privatevoidresetPositonY(){
//mXOneOffset代表當前第一條水波紋要移動的距離
intyOneInterval=mYPositions.length-mXOneOffset;
//使用System.array方式重新填充第一條波紋的數據
System.array(mYPositions,mXOneOffset,mResetOneYPositions,0,yOneInterval);
System.array(mYPositions,0,mResetOneYPositions,yOneInterval,mXOneOffset);
intyTwoInterval=mYPositions.length-mXTwoOffset;
System.array(mYPositions,mXTwoOffset,mResetTwoYPositions,0,
yTwoInterval);
System.array(mYPositions,0,mResetTwoYPositions,yTwoInterval,mXTwoOffset);
}
如此下來只要不斷的改變這兩個數組的數據,然後不斷刷新,即可生成動態水波紋了;
刷新可以調用invalidate()或postInvalidate(),區別在於後者可以在子線程中更新UI
整體代碼如下:
packagecom.csdn.csdnblog2.ui;
importcom.csdn.csdnblog2.utils.UiUtils;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.DrawFilter;
importandroid.graphics.Paint;
importandroid.graphics.Paint.Style;
importandroid.graphics.PaintFlagsDrawFilter;
importandroid.util.AttributeSet;
importandroid.view.View;
{
//波紋顏色
privatestaticfinalintWAVE_PAINT_COLOR=0x880000aa;
//y=Asin(wx+b)+h
_FACTOR_A=20;
privatestaticfinalintOFFSET_Y=0;
//第一條水波移動速度
_X_SPEED_ONE=7;
//第二條水波移動速度
_X_SPEED_TWO=5;
privatefloatmCycleFactorW;
privateintmTotalWidth,mTotalHeight;
privatefloat[]mYPositions;
privatefloat[]mResetOneYPositions;
privatefloat[]mResetTwoYPositions;
privateintmXOffsetSpeedOne;
privateintmXOffsetSpeedTwo;
privateintmXOneOffset;
privateintmXTwoOffset;
privatePaintmWavePaint;
privateDrawFiltermDrawFilter;
publicDynamicWave(Contextcontext,AttributeSetattrs){
super(context,attrs);
//將dp轉化為px,用於控制不同解析度上移動速度基本一致
mXOffsetSpeedOne=UiUtils.dipToPx(context,TRANSLATE_X_SPEED_ONE);
mXOffsetSpeedTwo=UiUtils.dipToPx(context,TRANSLATE_X_SPEED_TWO);
//初始繪制波紋的畫筆
mWavePaint=newPaint();
//去除畫筆鋸齒
mWavePaint.setAntiAlias(true);
//設置風格為實線
mWavePaint.setStyle(Style.FILL);
//設置畫筆顏色
mWavePaint.setColor(WAVE_PAINT_COLOR);
mDrawFilter=newPaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
}
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
//從canvas層面去除繪制時鋸齒
canvas.setDrawFilter(mDrawFilter);
resetPositonY();
for(inti=0;i<mTotalWidth;i++){
//減400隻是為了控制波紋繪制的y的在屏幕的位置,大家可以改成一個變數,然後動態改變這個變數,從而形成波紋上升下降效果
//繪制第一條水波紋
canvas.drawLine(i,mTotalHeight-mResetOneYPositions[i]-400,i,
mTotalHeight,
mWavePaint);
//繪制第二條水波紋
canvas.drawLine(i,mTotalHeight-mResetTwoYPositions[i]-400,i,
mTotalHeight,
mWavePaint);
}
//改變兩條波紋的移動點
mXOneOffset+=mXOffsetSpeedOne;
mXTwoOffset+=mXOffsetSpeedTwo;
//如果已經移動到結尾處,則重頭記錄
if(mXOneOffset>=mTotalWidth){
mXOneOffset=0;
}
if(mXTwoOffset>mTotalWidth){
mXTwoOffset=0;
}
//引發view重繪,一般可以考慮延遲20-30ms重繪,空出時間片
postInvalidate();
}
privatevoidresetPositonY(){
//mXOneOffset代表當前第一條水波紋要移動的距離
intyOneInterval=mYPositions.length-mXOneOffset;
//使用System.array方式重新填充第一條波紋的數據
System.array(mYPositions,mXOneOffset,mResetOneYPositions,0,yOneInterval);
System.array(mYPositions,0,mResetOneYPositions,yOneInterval,mXOneOffset);
intyTwoInterval=mYPositions.length-mXTwoOffset;
System.array(mYPositions,mXTwoOffset,mResetTwoYPositions,0,
yTwoInterval);
System.array(mYPositions,0,mResetTwoYPositions,yTwoInterval,mXTwoOffset);
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
//記錄下view的寬高
mTotalWidth=w;
mTotalHeight=h;
//用於保存原始波紋的y值
mYPositions=newfloat[mTotalWidth];
//用於保存波紋一的y值
mResetOneYPositions=newfloat[mTotalWidth];
//用於保存波紋二的y值
mResetTwoYPositions=newfloat[mTotalWidth];
//將周期定為view總寬度
mCycleFactorW=(float)(2*Math.PI/mTotalWidth);
//根據view總寬度得出所有對應的y值
for(inti=0;i<mTotalWidth;i++){
mYPositions[i]=(float)(STRETCH_FACTOR_A*Math.sin(mCycleFactorW*i)+OFFSET_Y);
}
}
}
二:非標准圓形液柱水波紋
前面的波形使用函數模擬,這個我們換種方式,採用圖進行實現,先用PS整張不像波紋的波紋圖;
為了銜接緊密,首尾都比較平,並高度一致;
思路:
1.使用一個圓形圖作為遮罩過濾波形圖;
2.平移波紋圖,即不斷改變繪制的波紋圖的區域,即srcRect;
3.當一個周期繪制完,則從波紋圖的最前面重新計算;
全部代碼如下
//初始化bitmap
privatevoidinitBitmap(){
mSrcBitmap=((BitmapDrawable)getResourceswww.yingtaow.com?getDrawable(R.drawable.wave_2000))
.getBitmap();
mMaskBitmap=((BitmapDrawable)getResources().getDrawable(
R.drawable.circle_500))
.getBitmap();
}
//初始化畫筆paint
privatevoidinitPaint(){
mBitmapPaint=newPaint();
//防抖動
mBitmapPaint.setDither(true);
//開啟圖像過濾
mBitmapPaint.setFilterBitmap(true);
mPicPaint=newPaint(Paint.ANTI_ALIAS_FLAG);
mPicPaint.setDither(true);
mPicPaint.setColor(Color.RED);
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
mTotalWidth=w;
mTotalHeight=h;
mCenterX=mTotalWidth/2;
mCenterY=mTotalHeight/2;
mSrcRect=newRect();
mDestRect=newRect(0,0,mTotalWidth,mTotalHeight);
intmaskWidth=mMaskBitmap.getWidth();
intmaskHeight=mMaskBitmap.getHeight();
mMaskSrcRect=newRect(0,0,maskWidth,maskHeight);
mMaskDestRect=newRect(0,0,mTotalWidth,mTotalHeight);
}
}
⑶ android開發中如何實現播放聲音時根據聲音大小做一個動態能量條
音量變化是比較頻繁的,通常是低於50毫秒。
所以你取得的音量大小是一條密集的點組成的曲線,要動態的展示這些密集的點,有兩種不同的實現方式,效果也不一致。
把這些點分成不同的區間。比如5個區間,每個區間對應一張圖片(也可以是動態的圖片AnimationDrawable),取得音量後判斷是哪個區間,設置對應的圖片。打個比方,如果是用格數來表示,就有五張圖片表示1-5格,音量最大值可以通過mediaRecorder.getMaxAmplitude()獲得。分成五個區間,每個區間顯示對應格數的圖片。當然,這個圖片也可以是類似水波在盪漾的動態圖片,用AnimationDrawable來播放。
平滑的處理這些點。把上一次的位置與這一次的位置做一個動畫,如果採集頻率為50毫秒,動畫的ration就是50ms。比如是做一個圓圈,隨著音量大小變化,那麼可以參照如下的屬性動畫:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", lastScale, scale);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", lastScale, scale);
valumeAnimator = ObjectAnimator.ofPropertyValuesHolder(speakVolumeImageV, pvhX, pvhY);
valumeAnimator.setDuration(MIN_TIME).start();
通過放大和縮小speakVolumeImageV來展示當前音量。其中scale是此次的縮放比,lastScale是上次的縮放比。縮放比初始為1.0f,如果最大隻能放大到speakVolumeImageV的兩倍大,那麼可以這樣計算
Float scale = 1.0f;
if (volume == 0) {
scale = 1.0f;
} else {
scale = 1.0f + (volume / MAX_VOLUME * 1.0f);
}
⑷ Android 中的動畫有哪幾類,它們的特點和區別是什麼
1.View Animation(Tween Animation):補間動畫,給出兩個關鍵幀,通過一些演算法將給定屬性值在給定的時間內在兩個關鍵幀間漸變。
View animation只能應用於View對象,而且只支持一部分屬性,這種實現方式可以使視圖組件移動、放大、縮小以及產生透明度的變化.
2.Frame動畫,傳統的動畫方法,通過順序的播放排列好的圖片來實現,類似電影補間動畫和幀動畫。
補間動畫和Frame動畫的定義:
所謂補間動畫,是指通過指定View的初末狀態和變化時間、方式,對View的內容完成一系列的圖形變換來實現動畫效果。主要包括四種效果:Alpha、Scale、Translate和Rotate。
幀動畫就是Frame動畫,即指定每一幀的內容和停留時間,然後播放動畫。。
3.屬性動畫
只是一個動畫效果,組件其實還在原來的位置上,xy沒有改變
###位移:
第一個參數target指定要顯示動畫的組件
第二個參數propertyName指定要改變組件的哪個屬性
第三個參數values是可變參數,就是賦予屬性的新的值
傳入0,代表x起始坐標:當前x + 0
傳入100,代表x終點坐標:當前x + 100
//具有get、set方法的成員變數就稱為屬性
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "translationX", 0, 100) ;
4.四種基本的動畫 ,透明/伸縮/移動/旋轉。
(1)XML中
alpha 漸變透明度動畫效果
scale 漸變尺寸伸縮動畫效果
translate畫面轉換位置移動動畫效果
rotate畫面轉移旋轉動畫效果
(2) javaCode中
AlphaAnimation漸變透明度動畫效果
ScaleAnimation漸變尺寸伸縮動畫效果
TranslateAnimation畫面轉換位置移動動畫效果
RotateAnimation畫面轉移旋轉動畫效果
(3)Android動畫模式
Animation主要有兩種動畫模式:
一種是tweened animation(漸變動畫)
一種是frame by frame(畫面轉換動畫)
Tween動畫,這種實現方式可以使視圖組件移動、放大、縮小以及產生透明度的變化;
Frame動畫,傳統的動畫方法,通過順序的播放排列好的圖片來實現,類似電影。
⑸ Android 動畫詳解
android中酷炫的效果,都離不開動畫的支持。這里我們詳細介紹一下android中動畫的分類。android的中動畫分為幀動畫、補間動畫、屬性動畫。原理各不相同,實現的效果也大不相同。下面一一講解三種動畫。
幀動畫顧名思義就是通過順序一幀一幀播放圖片從而產生動畫效果,效果類似放電影。該動畫缺點比較明顯,就是如果圖片過大過多會導致OOM。幀動畫xml文件放置在drawable目錄下而非anim文件夾下。
補間動畫是通過對view進行旋轉、縮放、漸變、透明度變化,而達到的一種動畫效果。是一種漸進式動畫。並且可以通過組合以上四種操作,完成復雜的自定義動畫效果。缺點就是只是改變的view的展示狀態,但是不會改變view的位置。例如我們將一個button通過位移想左移動100dp,然後停留在終點。但是我們可以發現展示的位置button點擊無效果,不可以交互。而在button原始位置空白的地方點擊會觸發button的點擊效果。也就是button本質還是在原來位置,只是展示左移了100dp。
透明度動畫,通過改變view的透明度展示動畫。對應AlphaAnimation和<alpha>xml標簽
縮放動畫,通過修改view的大小展示動畫。對應ScaleAnimation類和<scale>xml表情
通過旋轉view展示動畫。對應RotateAnimation類和<rotate>xml標簽
平移動畫,更改view的展示位置展示動畫。對應TranslateAnimation類和<translate>xml表情
應用動畫xml配置
使用java類配置動畫,具體參數類同xml參數,建議使用xml配置動畫
屬性動畫本質是通過改變對象的屬性(例如:x,y等屬性),來實現動畫的,所以基本上是無所不能的,只要對象有這個屬性,就能實現動畫效果。屬性動畫是在api11的新特性,通過動態的改變view的屬性從而達到動畫效果。雖然可以使用nineoldandroid庫向下兼容,但是兼容本質是使用補間動畫完成,也就是說不會更改view的屬性,也不會更改view的位置。屬性動畫比較常用的類: ValueAnimator、ObjectAnimator、AnimationSet,其中ObjectAnimator是ValueAnimator的子類,而AnminationSet是動畫集合
動畫配置同樣可以使用xml配置,參數類似,這里不做詳細說明。
根據時間流逝百分比計算當前屬性改變百分比。同xml配置動畫中的 android:interpolator 屬性配置,常見有LinearInterpolator(線性差值器)、(加速減速差值器)
等。自定義需要實現 Interpolator 或者 TimeInterpolator 。Interpolator介面繼承TimeInterpolator。
根據當前屬性改變百分比計算改變後的屬性值。屬性動畫特有的屬性。自定義估值器需要實現 TypeEvaluator 介面。
可以對任意屬性做屬性動畫,屬性動畫要求動畫作用的對象提供該屬性的get()和set()方法。因為屬性動畫本質就是根據外界傳遞的對象屬性的初始值和終點值,然後根據估值器和差值器計算屬性值,不斷調用屬性的set方法,通過時間的推移所傳遞的值,越來越近終點值。
注意:
使用ValueAnimator通過監聽動畫過程,自己改變對象屬性完成動畫
⑹ Carson帶你學Android:常見的三種動畫類型
Android 動畫主要分為分為兩大類(三種):
下面。我將簡單介紹這兩大類、三種 Android 常用動畫
根據不同的動畫效果,補間動畫分為4種動畫:
具體效果分別如下:
較為復雜的個性化動畫效果。
將動畫拆分後的圖片幀
在 Android 3.0 ( API 11 )後才提供的一種全新動畫模式
與屬性相關、更加復雜的動畫效果。
不定期分享關於 安卓開發 的干貨,追求 短、平、快 ,但 卻不缺深度 。