Android高级UI学习记录(图形绘制Paint)

在自定义控件中Paint和Canvas的重要性就不用了多说了,本篇文章将记录学习内容。

Paint的基础使用就不记录了,这里记录下渲染、滤镜和Xfermode。

先来看看渲染,渲染的主要形式是以Shader 着色器来实现。看下例子:

/**

* TileMode.CLAMP 拉伸最后一个像素去铺满剩下的地方

* TileMode.MIRROR 通过镜像翻转铺满剩下的地方。

* TileMode.REPEAT 重复图片平铺整个画面(电脑设置壁纸)

* 在图片和显示区域大小不符的情况进行扩充渲染

*/

/**

* 位图渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)

* Bitmap:构造shader使用的bitmap

* tileX:X轴方向的TileMode

* tileY:Y轴方向的TileMode

*/

BitmapShader bitmapShader =new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

mPaint.setShader(bitmapShader);

例子中使用位图渲染,接下来记录下其他的几种渲染方式:

/**线性渲染

* x0, y0, 起始点

*  x1, y1, 结束点

* int[]  mColors, 中间依次要出现的几个颜色

* float[] positions 位置数组,position的取值范围[0,1],作用是指定几个颜色分别放置在那个位置上,

* 如果传null,渐变就线性变化。

*    tile 用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法

*/

LinearGradient linearGradient =new LinearGradient(0, 0, 500, 600, mColors,mFloats , Shader.TileMode.REPEAT);

/**

* 扫描渲染

* cx,cy 渐变中心坐标

* color0,color1:渐变开始结束颜色

* colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变

*/

SweepGradient sweepGradient =new SweepGradient(400, 400, mColors, null);

/**

* 组合渲染,

* ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)

* ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)

* shaderA,shaderB:要混合的两种shader

* Xfermode mode: 组合两种shader颜色的模式  

* PorterDuff.Mode mode: 组合两种shader颜色的模式

*/

ComposeShader composeShader =new ComposeShader(sweepGradient, linearGradient, PorterDuff.Mode.SRC);

渲染中最常用的是组合渲染,其中用到PorterDuff.Mode这里就不记录了附上官网链接方便点击查看。渲染就到这里接下来看看滤镜:

滤镜其实是对图像颜色进行调整。

颜色模式分为:RBG模式、CMYK模式、HSB模式、Lab模式、位图模式、灰度模式、索引模式、颜色模式、双色调模式、多通道模式。

颜色模式的不同颜色的通道也不同。

这里介绍常用的ARGB模式 A为透明通道R红色G为绿色B为蓝色 这些通道的值越大像素点所占比颜色就越多。比如A通道值越大就越透明。

颜色矩阵:android中可以通过颜色矩阵 ColorMatrix 方便的操作颜色,可以用来方面的修改图片中RGBA各分量的值,一般以是一个5x4 的矩阵。


颜色矩阵

计算方式为: 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

这里记录下一些例子:

//平移运算---加法

ColorMatrix colorMartrix1 =new ColorMatrix(new float[]{

1, 0,0,0,0,

        0,1,0,0,100,

        0,0,1,0,0,

        0,0,0,1,0,

});

  //反相效果 -- 底片效果

ColorMatrix colorMartrix2 =new ColorMatrix(new float[]{

-1, 0,0,0,255,

        0,-1,0,0,255,

        0,0,-1,0,255,

        0,0,0,1,0,

});

// 缩放运算---乘法 -- 颜色增强

ColorMatrix colorMartrix3 =new ColorMatrix(new float[]{

1.2f, 0,0,0,0,

        0,1.2f,0,0,0,

        0,0,1.2f,0,0,

        0,0,0,1.2f,0,

});

/** 黑白照片

*是将我们的三通道变为单通道的灰度模式

*去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,

*同时为了保证图像亮度不变,同一个通道里的R+G+B =1

*/

ColorMatrix colorMartrix4 =new ColorMatrix(new float[]{

0.213f, 0.715f,0.072f,0,0,

        0.213f, 0.715f,0.072f,0,0,

        0.213f, 0.715f,0.072f,0,0,

        0,0,0,1,0,

});

// 发色效果---(比如红色和绿色交换)

ColorMatrix colorMartrix5 =new ColorMatrix(new float[]{

1,0,0,0,0,

        0, 0,1,0,0,

        0,1,0,0,0,

        0,0,0,0.5F,0,

});

// 复古效果

ColorMatrix colorMartrix6 =new ColorMatrix(new float[]{

1/2f,1/2f,1/2f,0,0,

        1/3f, 1/3f,1/3f,0,0,

        1/4f,1/4f,1/4f,0,0,

        0,0,0,1,0,

});

// 颜色通道过滤

//两个矩阵

//本身颜色矩阵 A

//过滤矩阵  c

//a*c=out color

ColorMatrix colorMartrix7 =new ColorMatrix(new float[]{

1.3F,0,0,0,0,

        0,1.3F,0,0,0,

        0,0,1.3F,0,0,

        0,0,0,1,0,

});

setMaskFilter方法为设置滤镜这里记录几个例子:

/**

* 模糊遮罩效果

* @param radius 阴影的半径

* @param style  NORMOL -- 整个图像都被模糊掉

*              SOLID -- 图像边界外产生一层与Paint颜色一致阴影效果,不影响图像的本身

*              OUTER -- 图像边界外产生一层阴影,并且将图像变成透明效果

*              INNER -- 在图像内部边沿产生模糊效果

* @return

*/

mPaint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER));

/**

* 浮雕遮罩效果(绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样(在设计软件中类似的效果称之为斜面浮雕))

* @param direction  指定光源的位置,长度为xxx的数组标量[x,y,z]

* @param ambient    环境光的因子 (0~1),越接近0,环境光越暗

* @param specular  镜面反射系数 越接近0,镜面反射越强

* @param blurRadius 模糊半径 值越大,模糊效果越明显

*/

mPaint.setMaskFilter(new EmbossMaskFilter(new float[]{1,1,1},0.2f,60,80));

需要注意的是这些特效是需要关闭硬件加速的:setLayerType(View.LAYER_TYPE_SOFTWARE,null);//关闭硬件加速

如果不关闭则看不到这些效果。

接下来记录下Xfermode:该Api可以完成图像组合的效果(通过两张图片组合,生成新的图片)

组合模式使用PorterDuff.Mode详细点击查看。

其子类有3个PixelXorXfermode、AvoidXfermode、PorterDuffXfermode其中前两个已经过时不推荐使用就不做记录了,看看PorterDuffXfermode的例子:

public class Xfermodeextends View {

private PaintmPaint;

    float mTextSize =25;

    float mItemSize =0;

    float mItemHorizontalOffset =0;

    float mItemVerticalOffset =0;

    float mCircleRadius =0;

    float mRectSize =0;

    int mCircleColor =0xffffcc44;//黄色

    int mRectColor =0xff66aaff;//蓝色

    private static final android.graphics.Xfermode[]sModes = {

new PorterDuffXfermode(PorterDuff.Mode.CLEAR),

            new PorterDuffXfermode(PorterDuff.Mode.SRC),

            new PorterDuffXfermode(PorterDuff.Mode.DST),

            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),

            new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),

            new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),

            new PorterDuffXfermode(PorterDuff.Mode.DST_IN),

            new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),

            new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),

            new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),

            new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),

            new PorterDuffXfermode(PorterDuff.Mode.XOR),

            new PorterDuffXfermode(PorterDuff.Mode.DARKEN),

            new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),

            new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),

            new PorterDuffXfermode(PorterDuff.Mode.SCREEN)

};

    private static final String[]sLabels = {

"Clear", "Src", "Dst", "SrcOver",

            "DstOver", "SrcIn", "DstIn", "SrcOut",

            "DstOut", "SrcATop", "DstATop", "Xor",

            "Darken", "Lighten", "Multiply", "Screen"

    };

    public Xfermode(Context context) {

super(context);

        init(null, 0);

    }

public Xfermode(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

        init(attrs, 0);

    }

public Xfermode(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

        init(attrs, defStyleAttr);

    }

private void init(AttributeSet attrs, int defStyle) {

if(Build.VERSION.SDK_INT >=11){

setLayerType(LAYER_TYPE_SOFTWARE, null);

        }

mPaint =new Paint(Paint.ANTI_ALIAS_FLAG);

        mPaint.setTextSize(mTextSize);

        mPaint.setTextAlign(Paint.Align.CENTER);

        mPaint.setStrokeWidth(2);

    }

@Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

        mItemSize = w /4.5f;

        mItemHorizontalOffset =mItemSize /6;

        mItemVerticalOffset =mItemSize *0.426f;

        mCircleRadius =mItemSize /3;

        mRectSize =mItemSize *0.6f;

    }

@Override

    protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

        canvas.drawColor(Color.WHITE);

        int canvasWidth = canvas.getWidth();

        int canvasHeight = canvas.getHeight();

        for (int row =0; row <4; row++) {

for (int column =0; column <4; column++) {

canvas.save();

                int layer = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);

                mPaint.setXfermode(null);

                int index = row *4 + column;

                float translateX = (mItemSize +mItemHorizontalOffset) * column;

                float translateY = (mItemSize +mItemVerticalOffset) * row;

                canvas.translate(translateX, translateY);

                //画文字

                String text =sLabels[index];

                mPaint.setColor(Color.BLACK);

                float textXOffset =mItemSize /2;

                float textYOffset =mTextSize + (mItemVerticalOffset -mTextSize) /2;

                canvas.drawText(text, textXOffset, textYOffset, mPaint);

                canvas.translate(0, mItemVerticalOffset);

                //画边框

                mPaint.setStyle(Paint.Style.STROKE);

                mPaint.setColor(0xff000000);

                canvas.drawRect(2, 2, mItemSize -2, mItemSize -2, mPaint);

                mPaint.setStyle(Paint.Style.FILL);

                //画圆

                mPaint.setColor(mCircleColor);

                float left =mCircleRadius +3;

                float top =mCircleRadius +3;

                canvas.drawCircle(left, top, mCircleRadius, mPaint);

                mPaint.setXfermode(sModes[index]);

                //画矩形

                mPaint.setColor(mRectColor);

                float rectRight =mCircleRadius +mRectSize;

                float rectBottom =mCircleRadius +mRectSize;

                canvas.drawRect(left, top, rectRight, rectBottom, mPaint);

                mPaint.setXfermode(null);

                //canvas.restore();

                canvas.restoreToCount(layer);

            }

}

}

}

这个例子包含了所有例子。到这里paint就结束了。

作者:Dean_Xu

原创博客,请注明转载处....

你可能感兴趣的:(Android高级UI学习记录(图形绘制Paint))