1. 程式人生 > >Android glide-transformations 使用demo 實現Blur等效果

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引數的大小可以決定你的模糊程度,這個數值越大,就越模糊