編輯:關於Android編程
博主這段時間工作實在是太忙了,全天無尿點……博客一直沒更新,實在對不住大家……
這篇就給大家講setShader的另一個參數,LinearGradient,使用過shape標簽的同學,對這個方法估計都不莫生,就是線性漸變。跟PhotoShop中的線性漸變的原理和作用是一樣的。這篇文章的最終會實現一個閃動文字效果控件:
有關漸變,以前有講過一篇《詳解shape標簽》,其中講述了
//使用LevelListDrawable時就要設置為true。設為false時才有漸變效果
其中的漸變類型有”linear” | “radial” | “sweep”,在代碼中對應的類分別是LinearGradient、RaialGradient、SweepGradient;有關
這篇我們要講就是線性漸變的LinearGradient;
二、LinearGradient基本使用
1、構造函數
我們先來看下LinearGradient的構造函數:
第一個構造函數:
public LinearGradient(float x0, float y0, float x1, float y1,int color0, int color1, TileMode tile)
用過PhotoShop的線性激變工具的同學,應該都知道,線性漸變其實是在指定的兩個點之間填充漸變顏色。
- 參數中的(x0,y0)就是起始漸變點坐標,參數中(x1,y1)就是結束漸變點坐標;
- color0就是起始顏色,color1就是終止顏色;顏色值必須使用0xAARRGGBB形式的16進制表示!表示透明度的AA一定不能少。
- TileMode tile:與BitmapShader一樣,用於指定控件區域大於指定的漸變區域時,空白區域的顏色填充方法。
很顯然!這個方法,只能指定兩種顏色之間的漸變。如果需要多種顏色之間的漸變,就需要使用下面的這個構造函數了。
第二個構造函數:
public LinearGradient(float x0, float y0, float x1, float y1,int colors[], float positions[], TileMode tile)
同樣,(x0,y0)就是起始漸變點坐標,參數中(x1,y1)就是結束漸變點坐標
colors[]用於指定漸變的顏色值數組,同樣,顏色值必須使用0xAARRGGBB形式的16進制表示!表示透明度的AA一定不能少。
positions[]與漸變的顏色相對應,取值是0-1的float類型,表示在每一個顏色在整條漸變線中的百分比位置
2、兩色漸變使用示例
我們先來看看兩色漸變的構造函數是如何來使用的:
public class LinearGradientView extends View {
private Paint mPaint;
public LinearGradientView(Context context) {
super(context);
init();
}
public LinearGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LinearGradientView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
setLayerType(LAYER_TYPE_SOFTWARE,null);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setShader(new LinearGradient(0,getHeight()/2,getWidth(),getHeight()/2,0xffff0000,0xff00ff00, Shader.TileMode.CLAMP));
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
}
}
很簡單,只需要在繪圖的時候構造LinearGradient實例,通過Paint.setShader設置進去即可。
大家注意一下,我這裡設置的漸變范圍是從控件的左邊中點到右邊中點:
mPaint.setShader(new LinearGradient(0,getHeight()/2,getWidth(),getHeight()/2,0xffff0000,0xff00ff00, Shader.TileMode.CLAMP));
最後通過canvas.drawRect把整個控件區域畫出來:
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoNCBpZD0="3多色漸變使用示例">這裡大家注意一下,上面我們也已經提到了,顏色值必須使用0xAARRGGBB的完整16進制的顏色樣式表示,我們這裡的顏色值就是0xffff0000和0xff00ff00;大家自己可以進行嘗試,如果把紅色的透明度值去掉,改寫成0xff00000,是不會有任何顯示的。
效果圖如下:
3、多色漸變使用示例
下面我們來看第二個構造函數,多色漸變的使用方法:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int[] colors = {0xffff0000,0xff00ff00,0xff0000ff,0xffffff00,0xff00ffff};
float[] pos = {0f,0.2f,0.4f,0.6f,1.0f};
LinearGradient multiGradient = new LinearGradient(0,getHeight()/2,getWidth(),getHeight()/2,colors,pos, Shader.TileMode.CLAMP);
mPaint.setShader(multiGradient);
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
}
從這裡可以看出,漸變的開始點同樣是控件左邊中點,漸變的結束點也同樣是控件右邊中點;這裡我們指定了五種漸變顏色,而且指定了每個顏色的位置,前四種顏色是按20%均勻分布的,最後兩種顏色相距40%;最後通過canvas.drawRect把整個控件區域畫出來
效果圖如下:
注意:
colors和pos的個數一定要相等,也就是說必須指定每一個顏色值的位置!如果多或少都會直接報錯:(Signal 11是SO內部錯誤)
2、漸變起始坐標與填充的關系——矩形填充
我們上面的示例中都是從控件左邊中間到控件右邊中點;如果我們改成從左上角到右上角的填充方式,結果會怎樣呢?
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int[] colors = {0xffff0000,0xff00ff00,0xff0000ff,0xffffff00,0xff00ffff};
float[] pos = {0f,0.2f,0.4f,0.6f,1.0f};
LinearGradient multiGradient = new LinearGradient(0,0,getWidth(),getHeight(),colors,pos, Shader.TileMode.CLAMP);
mPaint.setShader(multiGradient);
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
}
漸變線是從控件的左上角到控件的右下角位置:
LinearGradient multiGradient = new LinearGradient(0,0,getWidth(),getHeight(),colors,pos, Shader.TileMode.CLAMP);
效果圖如下:
形成原理如下:
就是說,首先是兩個漸變點之間連線,然後以連線為對角線形成一個矩形,各種顏色都是以這條對角線為矩形的填充的。
3、TileMode重復方式
在講到BitmapShader的時候,我們已經詳細講過TileMode的意義:當控件區域大小漸變區域時,用於填充空白位置的。
下面我們就逐個看一下TileMode不同時,對於線性漸變的有什麼作用。
(1)、X、Y軸共用填充參數
首先,我們再回來看一下LinearGradient的構造函數:
public LinearGradient(float x0, float y0, float x1, float y1,int colors[], float positions[], TileMode tile)
public LinearGradient(float x0, float y0, float x1, float y1,int color0, int color1, TileMode tile)
從構造函數中可以看出,LiearGradient只有一個TileMode參數,這說明X軸與Y軸共用這一個TileMode填充參數,而不能像BitmapShader那樣分別指定X軸與Y軸的填充參數。
(2)、TileMode.CLAMP
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//// 多色漸變
int[] colors = {0xffff0000,0xff00ff00,0xff0000ff,0xffffff00,0xff00ffff};
float[] pos = {0f,0.2f,0.4f,0.6f,1.0f};
LinearGradient multiGradient = new LinearGradient(0,0,getWidth()/2,getHeight()/2,colors,pos, Shader.TileMode.CLAMP);
mPaint.setShader(multiGradient);
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
}
這裡做了一個多色漸變,漸變點是從(0,0)到屏幕的中間點(width/2,height.2);
效果圖如下:
從效果圖中可以看到,效果很好理解,就是以(0,0)到(width/2,height.2)為矩形對角線,來填充各種顏色漸變,對於之外的區域,用邊緣色彩來填充。
(3)、TileMode.REPEAT
同樣是上面的代碼,漸變點是從(0,0)到屏幕的中間點(width/2,height.2),當空白區域填充模式改為TileMode.REPEAT時,效果圖如下:
大家初次看到這個效果,可能一臉懵逼 —_—!!!, 其實也不難理解,我們需要先找到哪塊是我們的漸變,哪塊是空白像素的填充:
在這個圖中,藍色塊是我們原始的漸變圖形,從從(0,0)到屏幕的中間點(width/2,height.2),另外的沒有遮起來的部分是空白位置填充的。
在填充時,結束點做為填充點的起點,即填充的線性漸變的位置為從(width/2,height/2)到(width,height),即從中間點到右下角點位置的填充。
(4)、TileMode.MIRROR
同樣,如果我們把填充模式改為鏡像模式,效果圖如下:
很容易理解,就不再講了。
4、填充方式:從控件左上角開始填充
與BitmapShader一樣,同樣是從控件左上角開始填充整個控件,利用canvas.drawXXX系列函數只是用來指定顯示哪一塊
比如:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//多色漸變
int[] colors = {0xffff0000,0xff00ff00,0xff0000ff,0xffffff00,0xff00ffff};
float[] pos = {0f,0.2f,0.4f,0.6f,1.0f};
LinearGradient multiGradient = new LinearGradient(0,0,getWidth()/2,getHeight()/2,colors,pos, Shader.TileMode.MIRROR);
mPaint.setShader(multiGradient);
canvas.drawRect(100,100,200,200,mPaint);
}
同樣是使用鏡像模式,但我們不再全屏繪制,而只是繪出其中一小部分:
我們再來看看全屏繪制的鏡像模式的效果圖:
很明顯,這裡所繪制的一小塊,跟從全屏繪制的效果圖上摘下來的一塊一樣。
這就說明了:
無論哪種Shader,都是從控件的左上角開始填充的,利用canvas.drawXXX系列函數只是用來指定顯示哪一塊
我們說了如果利用drawXXX系列函數只是用來指定顯示哪一塊,那如果我們利用DrawText來顯示,那是不是就會顯示出彩色文字了?
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//多色漸變
int[] colors = {0xffff0000,0xff00ff00,0xff0000ff,0xffffff00,0xff00ffff};
float[] pos = {0f,0.2f,0.4f,0.6f,1.0f};
LinearGradient multiGradient = new LinearGradient(0,0,getWidth()/2,getHeight()/2,colors,pos, Shader.TileMode.MIRROR);
mPaint.setShader(multiGradient);
mPaint.setTextSize(50);
canvas.drawText("歡迎關注啟艦的blog",0,200,mPaint);
}
效果圖如下:
有沒有感覺很酷炫……看似牛逼的效果其實就是這麼簡單……
如果我們把漸變效果移動起來,就直接實現了我們開篇時說的文字漸變的動畫效果了。
下面我們加入動畫,讓顏色動起來吧
三、閃光字符串實現
這部分我們要實現的效果圖如下:
閃光效果有木有……看起來很碉堡吧,我們就來具體看下原理吧,這個控件只給大家講基本原理,就不再封裝成控件了,博主近期太忙了,大家自己封裝下吧……
我們先來看下原理圖:
1、原理
(1)、初始狀態
首先,我們要有一個漸變的LinearGradient,顏色是從文字顏色的黑色到中間的綠色,然後再到黑色,填充模式為 Shader.TileMode.CLAMP,初始的位置在文字的左側;
對應圖像為:
我這裡為了表述文字效果,特地做了幾個處理;
1.首先我把漸變圖像用紅邊框了起來。由於填充模式是Shader.TileMode.CLAMP,所以右側文字的位置會被填充為邊緣顏色黑色
2.為了表述當前文字的位置,我特地把文字寫成了紅色。而文字真正的顏色應該是其底部LinearGradient的填充色才對的,大家這點注意。
對應代碼為:
mLinearGradient = new LinearGradient(- getMeasuredWidth(),0,0,0,new int[]{
getCurrentTextColor(),0xff00ff00,getCurrentTextColor()},
new float[]{
0,
0.5f,
1
},
Shader.TileMode.CLAMP
);
}
(2)、運動中
下圖顯示的是當漸變的LinearGradient移動到文字部分的時的狀態
由於使用的是Shader.TileMode.CLAMP填充模式,所以兩次空白區域都會被填充為LinearGradient的邊緣顏色,即文字的黑色。
上面我們講了,文字會顯示其下方LinearGradient的填充顏色,所以現在文字的文字就會有一部分變綠了。
(3)、終止狀態
在終止狀態時,LinearGradient移動到文字的右側
同樣是由於Shader.TileMode.CLAMP填充模式,文字會被填充為文字原本的顏色。
從上面的原理中,我們需要理出來幾個點:
第一:創建的LinearGradient漸變的構造方法,前面已經列出來代碼了,初始位置是在文字左側的,而且大小與文字所占位置相同,填充模式使用邊緣填充
第二:從起始位置和終止位置可以看出,LinearGradient漸變的運動長度是兩個文字的長度。
二、代碼實現
其實看了原理之後,實現起來就沒有什麼難度了,我們還是列出完整代碼,然後針對性的講一點就可以了,如果大家還沒看懂,可以把示例源碼下下來,自己再研究研究
public class ShimmerTextView extends TextView {
private Paint mPaint;
private int mDx;
private LinearGradient mLinearGradient;
public ShimmerTextView(Context context) {
super(context);
init();
}
public ShimmerTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ShimmerTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
mPaint =getPaint();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
ValueAnimator animator = ValueAnimator.ofInt(0,2*getMeasuredWidth());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDx = (Integer) animation.getAnimatedValue();
postInvalidate();
}
});
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(2000);
animator.start();
mLinearGradient = new LinearGradient(- getMeasuredWidth(),0,0,0,new int[]{
getCurrentTextColor(),0xff00ff00,getCurrentTextColor()
},
new float[]{
0,
0.5f,
1
},
Shader.TileMode.CLAMP
);
}
@Override
protected void onDraw(Canvas canvas) {
Matrix matrix = new Matrix();
matrix.setTranslate(mDx,0);
mLinearGradient.setLocalMatrix(matrix);
mPaint.setShader(mLinearGradient);
super.onDraw(canvas);
}
}
1、派生自TextView
首先需要注意的是,控件派生自TextView,所以可以使用TextView的自帶方法getCurrentTextColor()來獲取文字顏色。
2、如何移動LinearGradient
然後,上面我們講了如何給文字加上漸變效果,其實讓它動起來辦法很簡單,還記得我們說過Shader有一個setLocalMatrix(Matrix localM) 方法可以設置位置矩陣麼,我們只需要給LinearGradient設置上逐漸平移的矩陣就可以了。
比如:
@Override
protected void onDraw(Canvas canvas) {
Matrix matrix = new Matrix();
matrix.setTranslate(mDx,0);
mLinearGradient.setLocalMatrix(matrix);
mPaint.setShader(mLinearGradient);
super.onDraw(canvas);
}
其中向右偏移的距離mDx,是由ValueAnimator生成的;
3、ValueAnimator的創建
前面我們講了LinearGradient移動距離是從0到兩倍的text距離,我們通過getMeasuredWidth()可以得到TextView的寬度,乘以2就可以了,創建代碼如下:
ValueAnimator animator = ValueAnimator.ofInt(0,2*getMeasuredWidth());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDx = (Integer) animation.getAnimatedValue();
postInvalidate();
}
});
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(2000);
animator.start();
有關ValueAnimator的使用方法,如果有不理解的同學,請先去看《Android自定義三部曲之動畫篇》;
好了,本篇到這裡就結束了,下篇我們再來看最後一個漸變RadialGradient的使用方法與效果吧。
最近根據項目需要,整理了一個相對比較全面的 WheelView 使用控件,借用之前看到的一句話來說,就是站在巨人肩膀上,進行了一些小調整。 這裡先貼上效果圖一般常用的時間
效果圖:看網上的都是兩個view拼接,默認右側的不顯示,水平移動的時候把右側的view顯示出來。但是看最新版QQ上的效果不是這樣的,但給人的感覺卻很好,所以獻丑來一發比較
1,動畫系統配置創建游戲對象並添加Animation組件,然後將動畫文件拖入組件。進入動畫文件的Debug屬性面板選中Legacy屬性 選中游戲對象,打開Ani
1、概述 關於手機圖片加載器,在當今像素隨隨便便破千萬的時代,一張圖片占據的內存都相當可觀,作為高大尚程序猿的我們,有必要掌握圖片的壓縮,緩存等處理,以到達