需求背景分析:
產品和美工給了個根據專輯封面取主題色做背景,并且專輯封面還要融入背景的效果圖,一開始看到取色覺得簡單啊,不就是之前看過的palette嘛,可是專輯封面漸變消失融入背景怎么做呢,我們一步步分析。
1. 首先是背景取色,Palette
這個比較簡單,因為已經有現成的API讓我們調用
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
//todo
}
}
});
palette可以獲取到6種顏色,而且palette還有其他功能,這里就不介紹了,網上有很多案例,我們繼續。
因為背景色是漸變的,由深變淺,所以要這里取出兩個顏色通過paint的shader繪制一張漸變效果的bitmap,具體代碼如下
//......省略一些
Palette.from(resource).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
//記得判空
if(palette==null)return;
//palette取色不一定取得到某些特定的顏色,這里通過取多種顏色來避免取不到顏色的情況
if (palette.getDarkVibrantColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
createLinearGradientBitmap(palette.getDarkVibrantColor(Color.TRANSPARENT), palette.getVibrantColor(Color.TRANSPARENT));
} else if (palette.getDarkMutedColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
createLinearGradientBitmap(palette.getDarkMutedColor(Color.TRANSPARENT), palette.getMutedColor(Color.TRANSPARENT));
} else {
createLinearGradientBitmap(palette.getLightMutedColor(Color.TRANSPARENT), palette.getLightVibrantColor(Color.TRANSPARENT));
}
}
});
//創建線性漸變背景色
private void createLinearGradientBitmap(int darkColor,int color) {
int bgColors[] = new int[2];
bgColors[0] = darkColor;
bgColors[1] = color;
if(bgBitmap==null){
bgBitmap= Bitmap.createBitmap(ivBg.getWidth(),ivBg.getHeight(), Bitmap.Config.ARGB_4444);
}
if(mCanvas==null){
mCanvas=new Canvas();
}
if(mPaint==null){
mPaint=new Paint();
}
mCanvas.setBitmap(bgBitmap);
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
LinearGradient gradient=new LinearGradient(0, 0, 0, bgBitmap.getHeight(),bgColors[0],bgColors[1], Shader.TileMode.CLAMP);
mPaint.setShader(gradient);
RectF rectF=new RectF(0,0,bgBitmap.getWidth(),bgBitmap.getHeight());
// mCanvas.drawRoundRect(rectF,16,16,mPaint); 這個用來繪制圓角的哈
mCanvas.drawRect(rectF,mPaint);
ivBg.setImageBitmap(bgBitmap);
}
先給大家看看目前效果,免得枯燥
image.png
|
image.png
|
---|
ok,目前背景色就實現到這了
2. 接著是最蛋疼的讓他漸變融入到背景色中了
我目前有兩種思路(兩種我都用過了,推薦第二種)
思路 | 優點 | 缺點 |
---|---|---|
在圖片上面疊加一層顏色漸變的圖片 | 方便簡單,只需多加一個控件 | 需要獲取旁邊背景色對應的顏色值,這個比較難,而且我目前才用的算法獲得有時候不準確 |
通過修改圖片的透明度來達到漸變效果 | 無需計算旁邊顏色,最終效果較佳 | 圖片較大時,計算量比較大,速度較慢 |
ok,由于我最后還是采用了第二種,這里就只介紹第二種方法了,思路很簡單,就是獲取圖片的bitmap數組,通過遍歷來判斷修改相應的透明度,具體代碼如下:
//修改透明度
public static Bitmap getImageToChange(Bitmap mBitmap) {
Log.d(TAG,"with="+mBitmap.getWidth()+"--height="+mBitmap.getHeight());
Bitmap createBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_4444);
int mWidth = mBitmap.getWidth();
int mHeight = mBitmap.getHeight();
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int color = mBitmap.getPixel(j, i);
int g = Color.green(color);
int r = Color.red(color);
int b = Color.blue(color);
int a = Color.alpha(color);
float index=i*1.0f/mHeight;
if(index>0.5f ){
float temp=i-mHeight/2.0f;
a= 255-(int) (temp/375*255);
}
color = Color.argb(a, r, g, b);
createBitmap.setPixel(j, i, color);
}
}
return createBitmap;
}
(ps:代碼中采用的一些寬高和數值,要看具體效果來設置,這里僅做參考!)
2.1 增加一種修改透明度的方法
該算法使用位移和模運算來單獨修改透明值,不用把ARGB的四個顏色都取出來,會比之前的速度快很多
//透明漸變
int[] argb=new int[ALBUM_SIZE*ALBUM_SIZE];
localBitmap.getPixels(argb, 0, localBitmap.getWidth(), 0, 0, localBitmap.getWidth(), localBitmap.getHeight());
//循環開始的下標,設置從什么時候開始改變
int start = argb.length / 2;
int mid = argb.length * 83 / 100;
int lines = ((mid - start) / localBitmap.getHeight()) + 2;
int width = localBitmap.getWidth();
for (int i = 0; i < lines; i++) {
for (int j = 0; j < width; j++) {
int index = start - width + i * width + j;
//由于默認圖片透明色為0,所以要增加判斷,不然后續處理的顏色會變為黑色
if(argb[index]!=0){
argb[index] = ((int) ((1 - ((float) i / lines)) * 255) << 24) | (argb[index] & 0x00FFFFFF);
}
}
}
for (int i = mid; i < argb.length; i++) {
argb[i] = (argb[i] & 0x00FFFFFF);
}
localBitmap = Bitmap.createBitmap(argb, localBitmap.getWidth(), localBitmap.getHeight(), Bitmap.Config.ARGB_8888);
(ps:算法中的數值也是僅供參考,具體還要看自己想要實現的效果,比如 <<24 和 0x00FFFFFF 是由于bitmap采用Config.ARGB_8888,大家根據自身需求修改就好,這里只提供思路)
2.2 適配圖片透明處理
對于原圖中帶有透明的情況,獲取像素點的時候透明的位置顏色值為0,所以在做透明漸變的時候要判斷一下,避免后續顏色變成黑色
if(argb[index]!=0){
argb[index] = ((int) ((1 - ((float) i / lines)) * 255) << 24) | (argb[index] & 0x00FFFFFF);
}
最終效果如下:
image.png
|
image.png
|
---|
總結
本次內容不難,重要是實現思路,我一開始采用第一種疊加圖片的方法,尋找計算線性漸變某一位置的值,后來找到了但最終效果不如上述的第二種方法,但是我發現第二種方法在計算比較大的Bitmap的時候速度是真很慢的(遍歷一個Bitmap數組,腦殼痛),所以具體還是看大家的需求吧
(ps:好久沒寫過文章了啊,自今年畢業來就一直忙東忙西,終于有點時間寫東西了 TAT)