Android自定义组件(四)

本文深入探讨了在Android中如何使用阴影、渐变、图层以及位图运算技巧进行高级图形绘制。详细介绍了Paint类的setShadowLayer方法用于设置阴影效果,Shader类及其子类如LinearGradient、RadialGradient等实现复杂渐变效果,以及如何利用Matrix实现渐变的变形效果。此外,还讲解了Canvas的图层管理机制和位图运算的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.阴影

阴影即可以为文字和图形指定阴影,默认情况下,我们的文字和图形都是绘制在主层(main layer)上,我们也可以将内容绘制到新的layer上,实际上阴影就是在main layer的下面添加了一个阴影层。

Paint类为此定义了一个名为setShadowLayer的方法:

public void setShadowLayer(float radius, float dx, float dy, int shadowColor),其中:
radius:阴影半径
dx: x 方向阴影的偏移量
dy: y 方向阴影的偏移量
shadowColor: 阴影的颜色

2.渐变

渐变就是绘图的过程中颜色或者位图以特定的规律进行变化。Graphics2D提供的渐变种类有:

 线性渐变: LinearGradient
 径向渐变: RadialGradient
 扫描渐变: SweepGradient
 位图渐变: BitmapShader
 混合渐变: ComposeShader

其中前三种渐变模式属于颜色渐变,可以指定两种或者两种以上的颜色,根据颜色过渡算法自动计算中间的过渡颜色。

而位图渐变则不再是简单的颜色渐变,而是以图片作为贴片的有规律的变化。

混合渐变则是能将多种渐变进行组合,从而实现复杂的渐变效果。 

3.渐变类与Matrix

渐变类都继承自同一个父类Shader,该类定义了一个public void setLocalMatrix(Matrix localM)的方法,该方法能与渐变结合,从而在填充渐变颜色的时候实现移位、旋转、缩放和拉斜的效果。

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setFocusable(true);
        setFocusableInTouchMode(true);
        float x = 160;
        float y = 100;
        mShader = new SweepGradient(x, y, new int[]{Color.GREEN,
                Color.BLACK,
                Color.GRAY,
                Color.GREEN}, null);
        mPaint.setShader(mShader);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = mPaint;
        float x = 160;
        float y = 100;
        canvas.translate(300, 300);
        canvas.drawColor(Color.WHITE);
        mMatrix.setRotate(mRotate, x, y);
        mShader.setLocalMatrix(mMatrix);
        mRotate += 3;
        if (mRotate >= 360) {
            mRotate = 0;
        }
        invalidate();
        canvas.drawCircle(x, y, 380, paint);

    }

}

4.图层
Canvas一般情况都会看做一个画布,所有的绘图操作都在这个画布上绘制,但是对于复杂的绘图操作,比如多层动画、地图等,需要Canvas提供的图层的支持。这是,Canvas就需要创建一些中间层,按照“栈结构”来对其进行管理。

在我们进行绘制的时候,通常会创建新的图层进行入栈,创建图层的方法有:

public int saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags)
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(RectF bounds, Paint paint)
public int saveLayer(float left, float top, float right, float bottom, Paint paint)

除了这些方法,还可以为图层指定透明度:

public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
public int saveLayerAlpha(RectF bounds, int alpha)
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags)
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha)

 其中saveFlags用于指定保存的标识位,上面的方法均会返回一个int类型的id作为layer出栈的标记。

出栈调用的方法为:public void restoreToCount(int saveCount)

5.位图的运算技巧

 关于位图的运算,一般可以简化为以下几个步骤:

1) 准备好分别代表 DST 和 SRC 的位图, 同时准备第三个位图, 该位图用于绘制 DST 和
SRC 运算后的结果;
2) 创建大小合适的图层(layer) 并入栈;
3) 先将 DST 位图绘制在第三个位图上;
4) 调用 Paint 的 setXfermode()方法定义位图运算模式;
5) 再将 SRC 位图绘制在第三个位图上;
6) 清除位图运算模式;
7) 图层(layer) 出栈
8) 将第三个位图绘制在 View 的 Canvas 上以便显示。

 

public class MyView extends View {


    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Bitmap dst = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
        Bitmap src = dst.copy(Bitmap.Config.ARGB_8888, true);
        Bitmap b3 = Bitmap.createBitmap(450, 450, Bitmap.Config.ARGB_8888);
        Canvas c1 = new Canvas(dst);
        Canvas c2 = new Canvas(src);
        Canvas c3 = new Canvas(b3);

        Paint p1 = new Paint();
        p1.setColor(Color.GRAY);
        c1.drawCircle(150, 150, 150, p1);
        Paint p2 = new Paint();
        p2.setColor(Color.GREEN);
        c2.drawRect(0, 0, 300, 300, p2);

//      定义画笔
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//      创建图层
        int layer = c3.saveLayer(0, 0, 450, 450, null, Canvas.ALL_SAVE_FLAG);
//      画圆
        c3.drawBitmap(dst, 0, 0, null);
//      定义位图的运算模式
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
//      画正方形
        c3.drawBitmap(src, 150, 150, paint);
//      清除运算效果
        paint.setXfermode(null);
//      恢复
        c3.restoreToCount(layer);
//      绘制到 Canvas 上
        canvas.drawBitmap(b3, 0, 0, null);

下面的实例是我们根据位图的运算绘制一个圆形头像的实例:

public class CirclePhotoView extends View {
    private Bitmap bmpCircleMask;
    private Canvas cvsCircle;
    private Paint paint;
    private Bitmap bitmap;

    public CirclePhotoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //将图片转换为bitmap
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.cat);
        int minWidth = Math.min(bitmap.getWidth(), bitmap.getHeight());

        //绘制一个圆形
        bmpCircleMask = Bitmap.createBitmap(minWidth, minWidth,
                Bitmap.Config.ARGB_8888);
        cvsCircle = new Canvas(bmpCircleMask);
        int r = minWidth / 2;
        cvsCircle.drawCircle(r, r, r, paint);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w = bmpCircleMask.getWidth();
        int layer = canvas.saveLayer(0, 0, w, w, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(bitmap, 0, 0, null);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.drawBitmap(bmpCircleMask, 0, 0, paint);
        canvas.restoreToCount(layer);
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值