自定义View:自定义CircleImageView实现及图形渲染

在很多应用中头像是以圆形图片展示的,默认图片的话可以让UI切一套圆形的,但是用户设置头像的话不可能也让UI切。其实已经有很多前辈牛人已经写了成熟完善的工具类供程序猿使用。当然实现方式也多种多样。这里道长使用图形渲染实现CircleImageView,然后说一下图形渲染的一些知识。

一、CircleImageView实现

  • 构造方法初始化变量
    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mMatrix = new Matrix();
        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);

    }

    public CircleImageView(Context context) {
        this(context, null);
    }
  • 测量并设置控件宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRadius = mWidth / 2;
        setMeasuredDimension(mWidth, mWidth);

    }
  • 给Paint设置渲染规则
    private void setPaintShader() {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }

        Bitmap bitmap = drawable2Bitmap(drawable);
        // 创建Bitmap渲染对象
        mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale = 1.0f;
        // 比较bitmap宽和高,获得较小值
        int bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
        scale = mWidth * 1.0f / bSize;

        // shader的变换矩阵,用于放大或者缩小
        mMatrix.setScale(scale, scale);
        // 设置变换矩阵
        mBitmapShader.setLocalMatrix(mMatrix);
        // 设置shader
        mBitmapPaint.setShader(mBitmapShader);
    }

    /**
     * drawable转bitmap
     *
     * @param drawable
     * @return
     */
    private Bitmap drawable2Bitmap(Drawable drawable) {

        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }

        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }
  • 在画布上绘制图片
    @Override
    protected void onDraw(Canvas canvas) {

        if (getDrawable() == null) {
            return;
        }

        try {
            setPaintShader();
            canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
  • 在布局中添加如下代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">


    <ImageView
        android:id="@+id/iv_default"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:src="@drawable/head" />

    <com.yushan.picturerenderdemo.CircleImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_below="@id/iv_default"
        android:layout_margin="5dp"
        android:src="@drawable/head" />

</RelativeLayout>
  • 上面的为原图,下面的为CircleImageView,效果图如下

这里写图片描述

就这么简单,是不是so easy~当然这个代码中有一个弊端道长没有处理,就是在测量设置控件宽高时道长只是简单的取了一个宽高最小值,然后除以2就设置了。这就导致了CircleImageView最大只能展示原图大小。这个大家可以自行处理。然后我们说一下图形渲染……

二、图形渲染

在实现自定义CircleImageView中道长使用了图形渲染中的图像渲染,而前面道长说过的画布实现自定义View(折线图实现),在绘制限制区域时道长使用的就是图形渲染中的线性渲染。这里道长就不贴代码了,前面有链接童鞋们可以去看一下。图形渲染大概分为五种:

  • BitmapShader(图像渲染)
    /**
     * @param bitmap 用来作为纹理填充的位图
     * @param tileX 在位图X方向上位图衔接形式
     * @param tileY 在位图Y方向上位图衔接形式
     */
    public BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY);

  Shader.TileMode有3种参数可供选择,分别为CLAMP、REPEAT和MIRROR。

  CLAMP - 如果渲染器超出原始边界范围,则会复制边缘颜色对超出范围的区域进行着色。
  REPEAT - 在横向和纵向上以平铺的形式重复渲染位图。
  MIRROR - 在横向和纵向上以镜像的方式重复渲染位图。

简单使用:

    /**
     * 图像渲染
     *
     * @param canvas
     * @param paint
     */
    private void drawBitmapShader(Canvas canvas, Paint paint) {

        // 加载图像资源
        Bitmap mBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.head)).getBitmap();

        // 创建Bitmap渲染对象
        Shader mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        // 绘制Bitmap渲染的圆
        paint.setShader(mBitmapShader);
        canvas.drawCircle(100, 100, 100, paint);
    }
  • LinearGradient(线性渲染)
    /**
     * @param x0 渐变的起始点x坐标
     * @param y0 渐变的起始点y坐标
     * @param x1 渐变的终点x坐标
     * @param y1 渐变的终点y坐标
     * @param colors 渐变的颜色数组
     * @param positions 指定颜色数组的相对位置
     * @param tile 平铺方式
     */
    public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile);

注意:参数positions设为null,表示颜色数组以斜坡线的形式均匀分布。

简单使用:

    /**
     * 线性渲染
     *
     * @param canvas
     * @param paint
     */
    private void drawLinearGradient(Canvas canvas, Paint paint) {

        // 创建线性渲染对象
        int mColorLinear[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
        Shader mLinearGradient = new LinearGradient(150, 150, 100, 100, mColorLinear, null, Shader.TileMode.REPEAT);

        // 绘制线性渐变的矩形
        paint.setShader(mLinearGradient);
        canvas.drawRect(100, 300, 400, 500, paint);
    }
  • ComposeShader(混合渲染)
    /**
     * @param shaderA 一种渲染效果
     * @param shaderB 一种渲染效果
     * @param mode 两种渲染效果的叠加模式
     */
    public ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode);

  PorterDuff.Mode有16种参数可供选择,分别为:CLEAR、SRC、DST、SRC_OVER、DST_OVER、SRC_IN、DST_IN、SRC_OUT、DST_OUT、SRC_ATOP、DST_ATOP、XOR、DARKEN、LIGHTEN、MULTIPLY、SCREEN。

  叠加模式的具体叠加效果如下图所示:
这里写图片描述

简单使用:

   /**
     * 混合渲染
     *
     * @param canvas
     * @param paint
     */
    private void drawComposeShader(Canvas canvas, Paint paint) {
        // 创建线性渲染对象
        int mColorLinear[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
        Shader mLinearGradient = new LinearGradient(150, 150, 100, 100, mColorLinear, null, Shader.TileMode.REPEAT);

        // 创建环形渲染对象
        int mColorRadial[] = {Color.GREEN, Color.RED, Color.BLUE, Color.WHITE};
        Shader mRadialGradient = new RadialGradient(300, 300, 75, mColorRadial, null, Shader.TileMode.REPEAT);

        //创建混合渲染对象
        Shader mComposeShader = new ComposeShader(mLinearGradient, mRadialGradient, PorterDuff.Mode.DARKEN);
        //绘制混合渐变(线性与环形混合)的矩形
        paint.setShader(mComposeShader);
        canvas.drawRect(10, 420, 250, 570, paint);
    }
  • RadialGradient(环形渲染)
    /**
     * @param x 圆心x坐标
     * @param y 圆心y坐标
     * @param radius 半径
     * @param colors 渐变的颜色数组
     * @param positions 颜色数组的相对位置
     * @param tile 平铺的方式
     */
    public RadialGradient (float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile);

简单使用:

    /**
     * 环形渲染
     *
     * @param canvas
     * @param paint
     */
    private void drawRadialGradient(Canvas canvas, Paint paint) {
        // 创建环形渲染对象
        int mColorRadial[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
        Shader mRadialGradient = new RadialGradient(500, 500, 100, mColorRadial, null, Shader.TileMode.REPEAT);
        // 绘制环形渐变的圆
        paint.setShader(mRadialGradient);
        canvas.drawCircle(500, 500, 100, paint);
    }
  • SweepGradient(梯度渲染)
    /**
     * @param cx 扫描的中心x坐标
     * @param cy 扫描的中心y坐标
     * @param colors 渐变的颜色数组
     * @param positions 颜色数组的相对位置
     */
    public SweepGradient (float cx, float cy, int[] colors, float[] positions);

简单使用:

    /**
     * 梯度渲染
     *
     * @param canvas
     * @param paint
     */
    private void drawSweepGradient(Canvas canvas, Paint paint) {
        // 创建梯形渲染对象
        int mColorSweep[] = {Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN};
        Shader mSweepGradient = new SweepGradient(650, 700, mColorSweep, null);
        // 绘制梯形渐变的矩形
        paint.setShader(mSweepGradient);
        canvas.drawRect(600, 600, 700, 800, paint);
    }

到了这里关于自定义CircleImageView的实现以及图形渲染已经说完了,其实道长说自定义CircleImageView是一个引子,重点是说一下图形渲染,这个图形渲染在自定义View中还是比较常用的。好了,希望这篇博客能够为你提供一些帮助。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值