Android glide-transformations 使用demo 实现Blur等效果

README

本文对Glide - transformations进行简单的使用说明

Glide - transformations是Android平台一款优秀的图片处理工具

Github地址为:https://github.com/wasabeef/glide-transformations

本文所用到的代码地址:https://github.com/nikolajohn/GlideTransformationDemo


添加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);
  }
}

什么意思呢?其实看函数的名字就知道了,相当于一个量纲的转化

具体为什么要有这样一个转化,以及转化的代码为什么要这样写

可以查看这篇文章: https://blog.csdn.net/arui319/article/details/6777133?utm_source=blogxgwz0 


添加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参数的大小可以决定你的模糊程度,这个数值越大,就越模糊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值