自定义控件【圆形】圆角 BitmapShader
关于缩放比例
本例中,我们会为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));//默认为10dpviewType = typedArray.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);//默认为圆形//circleRadiu的大小需要在onMeasure根据测量到的宽高确定typedArray.recycle();}@Overrideprotected 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")@Overrideprotected 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);//圆心坐标,半径}}@Overrideprotected 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());}//对外公布两个方法,用于动态修改圆角大小和typepublic 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" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:orientation="horizontal" ><com.bqt.myview.RoundImageViewandroid:layout_width="60dp"android:layout_height="60dp"android:src="@drawable/icon"bqt:borderRadius="10dp"bqt:type="circle" /><com.bqt.myview.RoundImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:src="@drawable/icon" /><com.bqt.myview.RoundImageViewandroid:layout_width="80dp"android:layout_height="80dp"android:layout_marginLeft="10dp"android:src="@drawable/icon" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:orientation="horizontal" ><com.bqt.myview.RoundImageViewandroid:layout_width="60dp"android:layout_height="60dp"android:src="@drawable/icon"bqt:borderRadius="10dp"bqt:type="round" /><com.bqt.myview.RoundImageViewandroid: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.RoundImageViewandroid:layout_width="100dp"android:layout_height="50dp"android:layout_marginLeft="5dp"android:src="@drawable/icon"bqt:borderRadius="15dp"bqt:type="round" /></LinearLayout></LinearLayout>
自定义控件【圆形】圆角 BitmapShader的更多相关文章
- Android 圆形/圆角图片的方法
Android 圆形/圆角图片的方法 眼下网上有非常多圆角图片的实例,Github上也有一些成熟的项目.之前做项目,为了稳定高效都是选用Github上的项目直接用.但这样的结束也是Android开发必 ...
- 安卓图片载入之使用universalimageloader载入圆形圆角图片
前言 话说这universalimageloader载入图片对搞过2年安卓程序都是用烂了再熟悉只是了.就是安卓新手也是百度就会有一大堆东西出来,今天为什么这里还要讲使用universalimagelo ...
- [Android] 给图像加入相框、圆形圆角显示图片、图像合成知识
前一篇文章讲述了Android触屏setOnTouchListener实现突破缩放.移动.绘制和加入水印,继续我的"随手拍"项目完毕给图片加入相框.圆形圆角显示图片和图像合 ...
- 自定义控件之 圆形 / 圆角 ImageView
一.问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的: 二.怎么搞? 机智的我,第一想法就是,切一张中间圆形透明.四周与底色相同.尺寸与头像相同的蒙板图片,盖在 ...
- Android实现圆形圆角图片
本文主要使用两种方法实现图形圆角图片 自定View加上使用Xfermode实现 Shader实现 自定View加上使用Xfermode实现 /** * 根据原图和变长绘制圆形图片 * * @param ...
- 用开源项目RoundedImageView来实现 圆形 / 圆角 / 椭圆的图片
该开源项目的地址:https://github.com/vinc3m1/RoundedImageView 我自己分流下载文件的:http://download.csdn.net/detail/shar ...
- CircleImageManager——圆形 / 圆角图片的工具类
这个类可以实现圆角,或者是圆形图片的操作. CircleImageManager.java package com.kale.utils; import android.content.Context ...
- android 自定义控件---圆形方向盘
在做Android平台开发的时候,经常会遇到安卓原生控件无法满足需求的情况,安卓允许开发者去继承已经存在的控件或者实现你自己的控件. 先来看一下效果图 采用直接集成View类,重写onDrow方法绘制 ...
- Flutter 圆形/圆角头像图片
图片显示 1.本地图片 Image.asset加载项目资源包的图片 //先将图片拷贝到项目 images 目录中,然后在 pubspec.yaml文件配置文件相对路径到 assets Image.as ...
随机推荐
- 浅析Mysql数据回滚错误的解决方法
介绍一下关于Mysql数据回滚错误的解决方法.需要的朋友可以过来参考下 MYSQL的事务处理主要有两种方法. 1.用begin,rollback,commit来实现 begin 开始一个事 ...
- Android源码下载方法详解
转自:http://www.cnblogs.com/anakin/archive/2011/12/20/2295276.html Android源码下载方法详解 相信很多下载过内核的人都对这个很熟悉 ...
- Bootstrap_排版_列表
一.基本列表 <h5>普通列表</h5> <ul> <li>列表项目</li> <li>列表项目</li> < ...
- 浅析a标签的4个伪类 .
关于伪类,大家最熟悉的还是a标签的4个伪类::link 有链接属性时:visited 链接地址已被访问过:active 被用户激活(在鼠标点击与释放之间发生的事件):hov ...
- Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())[4]
数据库版本升级对软件的管理操作. 我们手机经常会收到xxx软件升级什么的提醒,你的软件版本更新,同时你的数据库对应的版本也要相应的更新. 数据库版本更新需要主要的问题: 软件的1.0版本升级到1.1版 ...
- wxpython线程安全的方法
wx中实现了3个线程安全的函数.如果在线程中,直接访问并更新主线程的UI,会遇到问题,有时候阻塞UI或者更新不起作用,有时严重的话会引起python崩溃. 三个安全线程如下: wx.PostEvent ...
- 利用花生壳在自己电脑上建立外网可访问的svn
下载花生壳并注册账号 2.花生壳会送你一个免费的二级域名 3.登陆到路由器界面192.168.0.1或者192.168.0.0进入动态dns选项输入你的花生壳账号密码 4.在路由器设置界面设置转发规则 ...
- 转:MongoDB调查总结
与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度:举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精确值 ...
- jquery-te 轻量级的编辑器
- API风格
Client------------ Request ----------------->多Server端 Server------------------------------------- ...
