关于缩放比例

        本例中,我们会为BitmapShader设置了一个matrix,目的是按比例放大或者缩小bitmap,并移动到View控件的中心,我们不会让view的宽高大于我们bitmap的宽高,只会让bitmap的宽高大于的view宽高,当然大出的区域就被裁剪掉了。
  • 圆形时:设为圆形时需要注意下,因为原始图片可能是长方形,有的宽比较大,有的高比较大,那么为显示成圆形,当尺寸大于或者小于设置尺寸时,我们就要对其进行放大或者缩小。取bitmap的宽或者高的小值(因为是分子相同,所以分母的小值对于scale就是大值)作为基准,如果采用大值,缩放后肯定不能填满我们的圆形区域。然后,view的mWidth/bSize ; 得到的就是scale。
  • 圆角时:因为涉及到宽/高比例,我们分别得到宽高的scale;最终取大值(因为分子可能不同同,所以不能像圆形时取分母的小值即可),因为我们要让最终缩放完成的图片一定要大于我们的view的区域;比如:view的宽高为10*20;图片的宽高为5*20;宽高的scale分别为2和1,最终我们应该按照宽的比例放大,而不是按照高的比例缩小;因为我们需要让缩放后的图片,一定大于我们的view宽高,并保证原图比例。

View

public class RoundImageView extends ImageView {
    public static final int TYPE_CIRCLE = 0;
    public static final int TYPE_ROUND = 1;
    /**图片的类型,圆形or圆角,值请参考TYPE_CIRCLE或TYPE_ROUND*/
    private int viewType;
    /**圆角的大小*/
    private int roundRadiu;
    /**圆形的半径*/
    private int circleRadiu;
    /**记录圆角矩形的边界*/
    private RectF mRoundRect;
    private Paint mBitmapPaint;

    public RoundImageView(Context context) {
        this(context, null);
    }
    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        roundRadiu = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius, dp2px(10));//默认为10dp
        viewType = typedArray.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);//默认为圆形
        //circleRadiu的大小需要在onMeasure根据测量到的宽高确定
        typedArray.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为我们是直接继承ImageView(而不是继承自View),所以直接调用super方法就能正确得到实际的宽高(按ImageView默认的规则)
        if (viewType == TYPE_CIRCLE) {
            int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
            circleRadiu = mSize / 2;
            setMeasuredDimension(mSize, mSize);//实际的大小
        }
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) return;
        //1、根据Bitmap要裁剪的类型,以及bitmap和view的宽高,计算Bitmap需要缩放的比例
        Bitmap bitmap = drawableToBitamp(drawable);
        float scale = calculateBitmapScale(bitmap);
        //2、为BitmapShader定义一个变换矩阵Matrix,通过Matrix对Bitmap进行缩放
        Matrix mMatrix = new Matrix();
        mMatrix.setScale(scale, scale);
        //3、通过Matrix将缩放后的Bitmap移动到View的中心位置
        float dx = getMeasuredWidth() - bitmap.getWidth() * scale;
        float dy = getMeasuredHeight() - bitmap.getHeight() * scale;
        mMatrix.postTranslate(dx / 2, dy / 2);//注意只能用一个set方法,其他的要用post或pre方法
        //4、通过BitmapShader对Bitmap进行渲染,
        BitmapShader bitmapShader = new BitmapShader(bitmap, TileMode.MIRROR, TileMode.REPEAT);//后两个参数:填充模式
        bitmapShader.setLocalMatrix(mMatrix);//由于我们已经让Bitmap的宽高一定【大于】view的宽高,所以上面的填充模式是没有任何效果的。
        mBitmapPaint.setShader(bitmapShader);
        //5、最后画出所需要的图形
        if (viewType == TYPE_ROUND) {
            // 【一】可以在这里通过getWidth、getHeight获取View的大小
            mRoundRect = new RectF(0, 0, getWidth(), getHeight());
            canvas.drawRoundRect(mRoundRect, roundRadiu, roundRadiu, mBitmapPaint);//在哪个矩形区域绘制,圆角大小
        } else {
            canvas.drawCircle(circleRadiu, circleRadiu, circleRadiu, mBitmapPaint);//圆心坐标,半径
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 【二】也可以在这里直接使用系统帮我们测量的准确的View的大小
        //    if (viewType == TYPE_ROUND) mRoundRect = new RectF(0, 0, w, h);
        Log.i("bqt", "w=" + w + "--h=" + h);
    }

    /**drawable转bitmap*/
    private Bitmap drawableToBitamp(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            return bitmapDrawable.getBitmap();
        }
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawableWidth, drawableHeight);
        drawable.draw(canvas);
        return bitmap;
    }
    /**计算Bitmap需要缩放的比例*/
    private float calculateBitmapScale(Bitmap bitmap) {
        float scale = 1.0f;
        if (viewType == TYPE_CIRCLE) {
            int bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
            scale = circleRadiu * 2.0f / bSize;
        } else if (viewType == TYPE_ROUND) {
            // 如果Bitmap的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的Bitmap的宽高,一定要【大于】view的宽高
            if (bitmap.getWidth() != getWidth() || bitmap.getHeight() != getHeight()) {
                float scaleWidth = getWidth() * 1.0f / bitmap.getWidth();
                float scaleHeight = getHeight() * 1.0f / bitmap.getHeight();
                scale = Math.max(scaleWidth, scaleHeight);
            }
        }
        Log.i("bqt", "缩放比例" + scale);
        return scale;
    }
    /**根据屏幕规格,将dp值转为px值*/
    public int dp2px(int dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
    }

    //对外公布两个方法,用于动态修改圆角大小和type
    public void setBorderRadius(int borderRadius) {
        int pxVal = dp2px(borderRadius);
        if (roundRadiu != pxVal) {
            roundRadiu = pxVal;
            invalidate();
        }
    }
    public void setType(int type) {
        if (type != TYPE_ROUND && type != TYPE_CIRCLE) {
            type = TYPE_CIRCLE;
        }
        if (viewType != type) {
            viewType = type;
            requestLayout();
        }
    }
}

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundImageView">
        <attr name="borderRadius" format="dimension" />
        <attr name="type">
            <enum name="circle" value="0" />
            <enum name="round" value="1" />
        </attr>
    </declare-styleable>
</resources>

使用


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bqt="http://schemas.android.com/apk/res/com.bqt.myview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#2000"
    android:orientation="vertical"
    android:padding="10dp" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal" >
        <com.bqt.myview.RoundImageView
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@drawable/icon"
            bqt:borderRadius="10dp"
            bqt:type="circle" />
        <com.bqt.myview.RoundImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:src="@drawable/icon" />
        <com.bqt.myview.RoundImageView
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:src="@drawable/icon" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal" >
        <com.bqt.myview.RoundImageView
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@drawable/icon"
            bqt:borderRadius="10dp"
            bqt:type="round" />
        <com.bqt.myview.RoundImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:src="@drawable/icon"
            bqt:borderRadius="10dp"
            bqt:type="round" />
        <com.bqt.myview.RoundImageView
            android:layout_width="100dp"
            android:layout_height="50dp"
            android:layout_marginLeft="5dp"
            android:src="@drawable/icon"
            bqt:borderRadius="15dp"
            bqt:type="round" />
    </LinearLayout>
</LinearLayout>

自定义控件【圆形】圆角 BitmapShader的更多相关文章

  1. Android 圆形/圆角图片的方法

    Android 圆形/圆角图片的方法 眼下网上有非常多圆角图片的实例,Github上也有一些成熟的项目.之前做项目,为了稳定高效都是选用Github上的项目直接用.但这样的结束也是Android开发必 ...

  2. 安卓图片载入之使用universalimageloader载入圆形圆角图片

    前言 话说这universalimageloader载入图片对搞过2年安卓程序都是用烂了再熟悉只是了.就是安卓新手也是百度就会有一大堆东西出来,今天为什么这里还要讲使用universalimagelo ...

  3. [Android] 给图像加入相框、圆形圆角显示图片、图像合成知识

        前一篇文章讲述了Android触屏setOnTouchListener实现突破缩放.移动.绘制和加入水印,继续我的"随手拍"项目完毕给图片加入相框.圆形圆角显示图片和图像合 ...

  4. 自定义控件之 圆形 / 圆角 ImageView

    一.问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的:       二.怎么搞? 机智的我,第一想法就是,切一张中间圆形透明.四周与底色相同.尺寸与头像相同的蒙板图片,盖在 ...

  5. Android实现圆形圆角图片

    本文主要使用两种方法实现图形圆角图片 自定View加上使用Xfermode实现 Shader实现 自定View加上使用Xfermode实现 /** * 根据原图和变长绘制圆形图片 * * @param ...

  6. 用开源项目RoundedImageView来实现 圆形 / 圆角 / 椭圆的图片

    该开源项目的地址:https://github.com/vinc3m1/RoundedImageView 我自己分流下载文件的:http://download.csdn.net/detail/shar ...

  7. CircleImageManager——圆形 / 圆角图片的工具类

    这个类可以实现圆角,或者是圆形图片的操作. CircleImageManager.java package com.kale.utils; import android.content.Context ...

  8. android 自定义控件---圆形方向盘

    在做Android平台开发的时候,经常会遇到安卓原生控件无法满足需求的情况,安卓允许开发者去继承已经存在的控件或者实现你自己的控件. 先来看一下效果图 采用直接集成View类,重写onDrow方法绘制 ...

  9. Flutter 圆形/圆角头像图片

    图片显示 1.本地图片 Image.asset加载项目资源包的图片 //先将图片拷贝到项目 images 目录中,然后在 pubspec.yaml文件配置文件相对路径到 assets Image.as ...

随机推荐

  1. js 日期修改

    很早之前在CSDN上发的博客,现在CSDN上得少了,就把这个转到园子里来 //重写toString方法,将时间转换为Y-m-d H:i:s格式 Date.prototype.toString = fu ...

  2. jQuery MVC 科室异步联动

    //科室改变,级联医生 js $("#DepartmentId").change(function () { if (isNaN($(this).val())) { $(" ...

  3. sql server2008附加数据库5120错误

    解决方法: 附加数据库时,显示错误,错误信息为 一种解决方法为,设置mdf文件所在文件夹的权限(有些资料说只设置mdf文件的权限就好,但我试了不管用),在文件夹上右击——属性——安全,如图所示: 选择 ...

  4. 探究ListView 的缓存机制

    概述 ListView 是继承AbListView,AbListView是所有列表类控件的基类. ListView的数据加载 在ListView数据加载中最关键的一个函数就是makeAndAddVie ...

  5. testservice小项目总结

    关于自做小项目testservice的总结: 1.Activity与Service的绑定及之间的通信: 1)关于Activity和Service的生命周期的理解: 2)bindService方法中Se ...

  6. spring mvc velocity多视图

    1.ViewResolverUrlBasedViewResolver 这个东西是根据url 进行路由的.网上搜了 1.order 排序,同名出现各种问题 2.XmlViewResolver,BeanN ...

  7. Skynet:特性收集

    基于云风的 blog,收集 skynet 的特性以便将来在代码中一一验证. “ ... ” 部分节选自云风的 BLOG. 1. 基于 Erlang-Actor 模式的 C 实现 “把一个符合规范的 C ...

  8. 洛谷 P1331 海战

    传送门 题解:由于船是方形的,所以比较简单.但是考试的时候跪了,orz.忘了考虑类似一圈井号中间有一摊水.          可以只考虑这个点上方和左边点的情况,这样分为四种情况.一种是左边是一滩水, ...

  9. Asp.net中request.QueryString与request.Params的区别 【转】

    Request.Form:获取以POST方式提交的数据(接收Form提交来的数据): Request.QueryString:获取地址栏参数(以GET方式提交的数据) Request:包含以上两种方式 ...

  10. ViewPage和ActionBar打造滑动视图

    滑动效果非常流畅,可以将页签放置到ActionBar上,点击页签可以切换ViewPage,滑动ViewPage会同步更显Tabs. main.xml <?xml version="1. ...