Android中Paint的相关用法

来源:互联网 发布:php多文件上传 编辑:程序博客网 时间:2024/05/29 08:25

一、Paint.setColorFilter(ColorFilter filter)

  ColorFilter是用来改变每个像素的工具类,顾名思义,它是一个filter,只需要定义了它的过滤规则,剩下的工作就由它来完成。

  ColorFilter是一个抽象类,我们从来不会直接使用它,而是使用它的3个子类:

  • LightingColorFilter
  • ColorMatrixColorFilter
  • PorterDuffColorFilter

1.LightingColorFilter

  LightingColorFilter比较简单,文档中的第一句话就说它可以用来实现简单的点亮效果,直接new出来set一下就好,不再赘述了

paint.setColorFilter(new LighingColorFilter(0xFFFFFFFF, 0x00FFFF00)); // 过滤为黄色

2.ColorMatrixColorFilter

  ColorMatrixColorFilter就稍微复杂一点,要想了解ColorMatrixColorFilter就先要了解Android中的ColorMatrix。在Android中图片的像素信息都是以ARGB像素点的形式加载到内存中的,如果想要对像素信息进行修改,那就需要借助ColorMatrix类。

ColorMatrix colorMatrix = new ColorMatrix(new float[]{    1, 0, 0, 0, 0,    0, 1, 0, 0, 0,    0, 0, 1, 0, 0,    0, 0, 0, 1, 0});

  ColorMatrix实际上是对像素信息进行运算的规则,有了ColorMatrixColorFilter,就不用对海量的像素信息一个一个进行setColor()了。说到这里,我想提一个问题,为什么ColorMatrix是4x5的?为什么他不是3x4或者5x6之类的?

  我们刚刚说过,ColorMatrix是用来对像素信息进行修改的.既然如此,RGBA这个4x1的矩阵在经过运算后当然还得是4x1的矩阵,只不过里面的像素信息改变了。

R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;

  其实说到这里,正常人类都会觉得4x4才对啊,为什么ColorMatrix最后是4x5呢?之所以有第5列,是因为有偏移的概念,第5列代表对色彩的偏移,如果希望某个颜色浓一点,可以将它的偏移值设大一点。

3.PorterDuffColorFilter

  PorterDuffColorFilter相对于它的另外两个兄弟来说就相对复杂一些。首先开到它的名字就比较让人费解,PorterDuff这个词在词典上是查不到的,因为它就不是一个词,而是用Tomas Porter和Tom Duff名字混合而成。这两位同学最早提出了图形混合的概念,对图形学做出了重大的贡献,这里用他们的名字来命名这个ColorFillter也算是对这两位同学的致敬吧。

  言归正传,我们之前讲ColorMatrix时说过“ColorFilter是用来改变paint中每个像素的工具类,它是一个filter,只需要定义了它的过滤规则”,这里PorterDuffColorFilter为我们提供了16中规则,这16种规则被封装在PorterDuff.Mode中,为了更直观地理解这16种规则,我们一起来看一看ApiDemos给我们提供的一张图吧~

这里写图片描述

  看了上面这张图如果你还不知明白这16种规则,那么你可以去看看文档对PorterDuff.Mode的描述,相信在你看了之后……应该会更不明白的。

  好的,PorterDuffColorFilter就讲到这里,相信大家对它都有了一个清晰的认识-_-。如果还有点不懂也没关系,后面还会讲到PorterDuffXfermode,在那里也会用到PorterDuff.Mode,将他们结合起来看会更好理解一点。

二、Paint.setMaskFilter (MaskFilter maskfilter)

  MaskFilter和ColorFilter类似,都是绘制内容的工具类,不过ColorFilter偏重于对颜色的操作,而MaskFilter文档的说法是“perform transformations on an alpha-channel mask before drawing it”。MaskFilter是一个抽象类,我们平时使用的是它的两个子类:

  • BlurMaskFilter
  • EmbossMaskFilter

1.BlurMaskFilter

  BlurMaskFilter顾名思义就是给图像添加一个模糊的效果,它使用起来非常简单。它的构造方法只用两个参数BlurMaskFilter (float radius, BlurMaskFilter.Blur style),radius就是模糊的半径,style就是模糊的样式,它是一个枚举,有四种类型:

  • INNER  向内模糊,在原图边界外不绘制任何东西
  • NORMAL  既向内又向外模糊
  • OUTER  向外模糊,在原图边界内不绘制任何东西
  • SOLID  将原图边界内全部模糊,同时也向外模糊

  具体效果可以看看下面的截图

这里写图片描述

  不过BlurMaskFilter虽然简单,但有一点需要注意,那就是:

BlurMaskFilter is not supported with hardware acceleration. (As of July 10, 2012)

  因此需要在AndroidManifest.xml中添加一行android:hardwareAccelerated="false",否则BlurMaskFilter就不会有效果。

2.EmbossMaskFilter

  EmbossMaskFilter通常是用来实现浮雕效果的,它使用起来也非常简单,它的构造方法EmbossMaskFilter (float[] direction, float ambient, float specular, float blurRadius)只有四个参数:

  • direction  光照方向
  • ambient  光照强度
  • specular  光的反射系数
  • blurRadius  模糊半径

  四个参数中可能direction需要解释一下float[] directions = new float[]{x, y, z}其中,x的正方向是屏幕正左方,y的正方向是屏幕正上方,z的正方向是屏幕正对的正方向。所以float[] directions = new float[]{1f, 1f, 1f}就可以理解为在“屏幕的左上方,有光源照射下的浮雕效果”。说到这里,你应该很好奇“如果z<=0,会是什么样的效果?”自己试一下吧~别忘了android:hardwareAccelerated="false"

三、Paint.setShader (Shader shader)

  “Shader is the based class for objects that return horizontal spans of colors during drawing.”Shader是在绘制是对颜色进行渐变的基类。它是一个抽象类,我们平时使用的都是它的5个子类:

  • LinearGradient  线性渐变
  • RadialGradient  环形渐变
  • SweepGradient  扫面渐变(就像雷达扫描的那种效果)
  • BitmapShader  将bitmap进行平铺
  • ComposeShader  将两个shader进行组合

  这5个类的用法很简单,我就不(bo)再(zhu)赘(tai)述(lan-_-)了。唯一值得一提的是Shader还有一个public void setLocalMatrix (Matrix localM)有了这个方法,就可以方便地对shader进行matrix变换的操作了(比如说:旋转一个角度,缩放一下大小等)。

四、Paint.setXfermode(Xfermode xfermode)

  ”Xfermode is the base class for objects that are called to implement custom “transfer-modes” in the drawing pipeline.”Xfermode是在绘制通道中用来实现自定义“过渡模式”的基类。

  Xfermode有三个子类:

  • AvoidXfermode
  • PixelXorXfermode
  • PorterDuffXfermode

  其中AvoidXfermode和PixelXorXfermode从API level 16开始就被废弃了,过时的东西自然我们就不必深究。我们一起来看看PorterDuffXfermode吧~

  PorterDuffXfermode只有一个方法,那就是它的构造方法public PorterDuffXfermode (PorterDuff.Mode mode),这里的PorterDuff.Mode就是我们之前讲PorterDuffColorFilter时所提到的那个PorterDuff.Mode,所以PorterDuffColorFilter和PorterDuffXfermode使用的规则是一样的,只不过PorterDuffColorFilter侧重于滤镜的过滤,而PorterDuffXfermode侧重于图形混合。

  不要小看PorterDuff.Mode的这16种混合规则,这16种股则看似简单,但如果和其他的工具一起配合使用,就会做成很多效果,如:刮刮乐效果、图片加阴影边框、生成渐变倒影等。下面我们就来一起实现“渐变倒影”效果。

  老规矩,我们先来分析一下需求:

  • 倒影
  • 渐变

  这种分析……-_- 好吧,需求就是这么简单。实现方式其实也很简单,首先倒影可以用Bitmap的createBitmap()来实现,说白了就是生成一张新的图片。那么渐变呢?这个实现的方式有很多,可以使用BitmapShader和LinearGradient混合而成一个ComposeShader,也可以使用Xfermode。鉴于ComposeShader的构造方法是ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode),我们可知ComposeShader的底层实现也是使用的PorterDuff这一套,所以我们就用第二种实现方法(Xfermode),这样来的更直接一些。

public class MyRefectionView extends View {    private Bitmap mBitmap;    private Bitmap mReflection;    private Paint mPaint;    public MyRefectionView(Context context) {        this(context, null);    }    public MyRefectionView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyRefectionView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        BitmapFactory.Options options = new BitmapFactory.Options();        options.inSampleSize = 4;        mBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.jurassic_world, options);        Matrix matrix = new Matrix();        matrix.setScale(1f, -1f);        mReflection = Bitmap.createBitmap(mBitmap, 0, mBitmap.getHeight() * 1 /4, mBitmap.getWidth(), mBitmap.getHeight() * 3 /4, matrix, false);        mPaint = new Paint();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawBitmap(mBitmap, 0, 0, mPaint);        int sc = canvas.saveLayer(new RectF(0f, 0f, mBitmap.getWidth(), mBitmap.getHeight() * 7 / 4), mPaint, Canvas.ALL_SAVE_FLAG);        // 绘制DST        canvas.drawBitmap(mReflection, 0f, mBitmap.getHeight(), mPaint);        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));        mPaint.setShader(new LinearGradient(0f, mBitmap.getHeight(), 0f, mBitmap.getHeight() * 7 / 4, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP));        // 绘制SRC        canvas.drawRect(0f, mBitmap.getHeight(), mBitmap.getWidth(), mBitmap.getHeight() * 7 / 4, mPaint);        canvas.restoreToCount(sc);    }}

效果如下图:
这里写图片描述

0 0