Android glide-transformations 使用demo 實現Blur等效果
README
本文對Glide - transformations進行簡單的使用說明
Glide - transformations是Android平臺一款優秀的圖片處理工具
新增Glide依賴
首先在你的Android Studio裡新建一個Android專案
然後開啟這個檔案
開啟以後,加上這句話
implementation 'jp.wasabeef:glide-transformations:3.3.0'
就像這樣
然後,在你的當前包下面,新建一個java 類,叫Utils
這個類的程式碼可以這樣寫
package cn.edu.zju.glidetest; import android.content.Context; public class Utils { public static int dip2px(Context context, float dp) { float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } }
什麼意思呢?其實看函式的名字就知道了,相當於一個量綱的轉化
具體為什麼要有這樣一個轉化,以及轉化的程式碼為什麼要這樣寫
新增RecycleView依賴
接下來,還是回到app目錄下的gradle檔案裡
就是這裡
新增如下程式碼
implementation 'com.android.support:recyclerview-v7:28.0.0'
新增完成後,就是這樣的
新增RecycleView控制元件
接下來,開啟MainActivity的佈局檔案(XML檔案)
先把不用的刪掉
然後新增RecycleView的控制元件,程式碼如下
<android.support.v7.widget.RecyclerView android:id="@+id/list" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
就像這樣
這裡,RecycleView控制元件的id,你可以命名為list,也可以命名為recycler_view
因為你的RecycleView控制元件並不是內建在系統的SDK中,所以用的時候,需要把完整的包的路徑都寫出來,而不是像LinearLayout那種,前面沒有完整的包名
新增item佈局檔案
接下來,新建一個Layout檔案,這個用於存放你的每一個條目的佈局,就叫layout_list_item
這個我們就這樣寫
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/image" android:layout_width="250dp" android:layout_height="250dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:cropToPadding="false" android:scaleType="fitCenter" app:layout_constraintBottom_toTopOf="@+id/title" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </android.support.constraint.ConstraintLayout>
做好之後就是這樣的
介面卡
接下來,你需要為你的RecycleView準備介面卡
那麼什麼是介面卡呢,這個我們看了後面的程式碼,相信你就會有自己的理解了
新建介面卡類的方法很簡單,和上面說過的是一樣的,這個類的名字就叫做MainAdapter
因為你的這個介面卡(Adapter)是針對RecycleView的,所以你需要讓這個介面卡繼承自RecycleView.Adapter這個類,寫好之後就像上面這樣
此外,我們還需要將泛型指定為MainAdapter.ViewHolder,其中的ViewHolder就是我們在MainAdapter中定義的一個內部類
這個類的建構函式就這樣寫
第一個引數是你的上下文,這個是常規套路,一般都會有這樣的一個context引數
第二個引數是一個List,List中的每一個數據的型別都是Type(這個我們後面再定義,你可以先理解成這就是一個我們自己定義的資料型別),這個陣列的名字就叫做dataSet
剛剛我們提到了,需要在這裡加一個內部類,如圖所示
首先ViewHolder肯定是需要繼承自RecyclerView.ViewHolder的
ViewHolder內部的程式碼其實很簡單,寫法也是很固定的
首先定義一下,你在每個item佈局中用到的東西,比如我們之前用到的是一個ImageView和一個TextView,因此這裡就這樣定義即可
他的建構函式也很簡單,就是把那些layout裡的控制元件找一下就好,這些程式碼都是常規套路
然後你在你的MainAdpter中定義私有的資料型別,這個也是常規套路了
接下來看一下onCreateViewHolder函式
這個函式的寫法還是比較固定的,但是有一點需要注意的是,如果你用上面的這種寫法,你必須在MainAdapter裡定義私有成員變數context,然後在MainAdapter的建構函式裡面賦值一下,就像這樣
如果你上面這兩句話沒有寫,那麼你的onCreateViewHolder函式應該這樣寫
@Override public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item, parent, false);
return new ViewHolder(v);
}
你不這樣寫,IDE是會報錯的
onBindViewHolder
接下來是一個非常重要的函式onBindViewHolder
在做這個函式之前,我們先把一些圖片資源載入進來,載入的方式很簡單,只要把圖片放到你的mipmap資料夾裡就好(圖片的資源我會放在附件裡)
接下來分析這個onBindViewHolder函式,先看程式碼
@Override public void onBindViewHolder(MainAdapter.ViewHolder holder, int position) {
switch (dataSet.get(position)) {
case Mask: {
int width = Utils.dip2px(context, 266.66f);
int height = Utils.dip2px(context, 252.66f);
Glide.with(context)
.load(R.mipmap.check)
.apply(overrideOf(width, height))
.apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(),
new MaskTransformation(R.mipmap.mask_starfish))))
.into(holder.image);
break;
}
case NinePatchMask: {
int width = Utils.dip2px(context, 300.0f);
int height = Utils.dip2px(context, 200.0f);
Glide.with(context)
.load(R.mipmap.check)
.apply(overrideOf(width, height))
.apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(),
new MaskTransformation(R.mipmap.mask_chat_right))))
.into(holder.image);
break;
}
case CropTop:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100),
CropType.TOP)))
.into(holder.image);
break;
case CropCenter:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100), CropType.CENTER)))
.into(holder.image);
break;
case CropBottom:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100),
CropType.BOTTOM)))
.into(holder.image);
break;
case CropSquare:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new CropSquareTransformation()))
.into(holder.image);
break;
case CropCircle:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new CropCircleTransformation()))
.into(holder.image);
break;
case ColorFilter:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new ColorFilterTransformation(Color.argb(80, 255, 0, 0))))
.into(holder.image);
break;
case Grayscale:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new GrayscaleTransformation()))
.into(holder.image);
break;
case RoundedCorners:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new RoundedCornersTransformation(45, 0,
RoundedCornersTransformation.CornerType.BOTTOM)))
.into(holder.image);
break;
case Blur:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new BlurTransformation(250)))
.into(holder.image);
break;
case SupportRSBlur:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SupportRSBlurTransformation(25, 10)))
.into(holder.image);
break;
case Toon:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new ToonFilterTransformation()))
.into(holder.image);
break;
case Sepia:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SepiaFilterTransformation()))
.into(holder.image);
break;
case Contrast:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new ContrastFilterTransformation(2.0f)))
.into(holder.image);
break;
case Invert:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new InvertFilterTransformation()))
.into(holder.image);
break;
case Pixel:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new PixelationFilterTransformation(20)))
.into(holder.image);
break;
case Sketch:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SketchFilterTransformation()))
.into(holder.image);
break;
case Swirl:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(
new SwirlFilterTransformation(0.5f, 1.0f, new PointF(0.5f, 0.5f))).dontAnimate())
.into(holder.image);
break;
case Brightness:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new BrightnessFilterTransformation(0.5f)).dontAnimate())
.into(holder.image);
break;
case Kuawahara:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new KuwaharaFilterTransformation(25)).dontAnimate())
.into(holder.image);
break;
case Vignette:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new VignetteFilterTransformation(new PointF(0.5f, 0.5f),
new float[] { 0.0f, 0.0f, 0.0f }, 0f, 0.75f)).dontAnimate())
.into(holder.image);
break;
}
holder.title.setText(dataSet.get(position).name());
}
要分析這個函式,其實很簡單
首先看開頭
可以看到,這個函式的兩個引數分別是ViewHolder的物件和position值
不難猜到,這個函式的作用就是把一個ViewHolder和一個position一一對應起來
那麼我們想一下,如果要我們自己寫,那麼應該怎麼寫呢
當然是首先拿到position,然後把這個position和對應的viewholder聯絡起來即可,實際上我們也是這麼做的
MASK
對位掩模操作(MASK),你的底層圖片(簡稱底片)大小肯定是確定的,這個我們是不能進行更改的(確切的說,應該是不會去更改,想改還是可以得),因為你的底片大小定義在這裡
顯然,你的底片大小是:寬250dp 高250dp
那麼你的掩模板大小的寬和高都應該接近於250dp,這樣掩模的效果是最好的
比如說,我們把掩模板寬設為266dp,高設為252dp
這樣做是什麼意思呢?就是說,你的掩模板裡的東西是多少畫素
如果說你按照上面的設定,顯示出來的效果是這樣的:
如果你把數字改小一些,比如寬慰2dp,高為2dp,那麼效果就是這樣的:
想明白了這個,接下來就很簡單了
Blur
Blur的操作,同樣很簡單
大部分的引數含義都是和上面一樣的,因為少了掩模板的操作,因此Blur的操作其實更加簡單
這裡需要注意一下的是,radius引數的大小可以決定你的模糊程度,這個數值越大,就越模糊