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

来源:互联网 发布:python获取当前日期 编辑:程序博客网 时间:2024/06/11 07:54

在很多应用中头像是以圆形图片展示的,默认图片的话可以让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
原创粉丝点击