近来无聊,写了一个圆形imageview组件
这组件的优点在于可以自动屏幕适配压缩图片,极大节省占用内存,并且可以在xml中动态设置图片模糊程度,要让图片以多高清晰度显示由你决定
效果如下:
从上到下分别设置了清晰度1, 4, 8,可以看出他们直接清晰度有很大区别
而从内存上来说:
直接显示原图内存是:
而用我的imageview压缩处理之后,内存是:
好啦,吹了这么多,话不多说,下面贴上源代码
首先,现在你的工程的res目录下的values创建一个attrs文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="circleImageView">
<attr name="imageSrc" format="reference"/>
<attr name="inSampleSize" format="integer"/>
</declare-styleable>
</resources>
上面那些是xml的属性,一个是获取图片id,相当于imageview的src,一个是设置图片清晰度,1是不变,越大只是清晰度越小
下面是自定义组件的源码:
package com.example.administrator.testmyidea.myTextView;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.example.administrator.testmyidea.R;
public class circleImageView extends View{
private Paint mPaint;
private Bitmap imageBitmap;
private float circleRadio;
private int imageResourceId;
private int mInSampleSize=1;
private int mWidth;
public circleImageView(Context context,int width) {
super(context);
mPaint=new Paint();
mWidth=width;
}
public circleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("圆的历程"+"circleImageView");
mPaint=new Paint();
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.circleImageView, 0, 0);
System.out.println("imageResourceId="+imageResourceId);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
switch (attr)
{
//获取图片id
case R.styleable.circleImageView_imageSrc:
imageResourceId=a.getResourceId(attr,R.drawable.moren);
break;
//获取图片清晰度设置
case R.styleable.circleImageView_inSampleSize:
mInSampleSize=a.getInteger(attr,1);
break;
}
}
a.recycle();
if(imageResourceId==0)imageResourceId=R.drawable.moren;
}
@Override
protected void onDraw(Canvas canvas) {
System.out.println("圆的历程"+"onDraw");
canvas.drawBitmap(imageBitmap,0,0,mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
mWidth=widthSize;
if(imageBitmap==null||imageBitmap.isRecycled()){
System.out.println("圆的历程"+"imageBitmap");
imageBitmap=getCircle(getSampleBitmap2(imageResourceId,widthSize));
}
setMeasuredDimension(widthSize, heightSize);
System.out.println("圆的历程"+"onMeasure");
}
//动态设置图片
public void setImageid(int imageid){
System.out.println("圆的历程"+"setImageid");
if(mWidth==0)imageResourceId=imageid;
else{
imageResourceId=imageid;
if(!imageBitmap.isRecycled()){
imageBitmap.recycle();
imageBitmap=null;
}
imageBitmap=getCircle(getSampleBitmap2(imageResourceId,mWidth));
postInvalidate();
}
}
//动态设置图片清晰度
public void setSimpleSize(int size){
System.out.println("圆的历程"+"setSimpleSize");
if(mWidth==0)mInSampleSize=size;
else{
mInSampleSize=size;
if(!imageBitmap.isRecycled()){
imageBitmap.recycle();
imageBitmap=null;
}
imageBitmap=getCircle(getSampleBitmap2(imageResourceId,mWidth));
postInvalidate();
}
}
public Bitmap getCircle(Bitmap bitmap){
//circleRadio圆形图片的半径
float circleRadio;
//bitmapSize图片的尺寸,也就是圆的直径,正方形图片的边长
int bitmapSize;
if(bitmap.getHeight()>bitmap.getWidth()){
circleRadio=bitmap.getWidth()/2;
bitmapSize=bitmap.getWidth();
}else{
circleRadio=bitmap.getHeight()/2;
bitmapSize=bitmap.getHeight();
}
//创建一张新的bitmap,跟传入图片一样宽的正方形bitmap,
Bitmap b=Bitmap.createBitmap(bitmapSize,bitmapSize, Bitmap.Config.ARGB_8888);
//将图片密度修改为上面那张的图片密度
b.setDensity(bitmap.getDensity());
//初始化画布,并将刚才创建的bitmap给这画布,让画布画在这bitmap上面
Canvas canvas=new Canvas(b);
//初始化画笔
Paint p=new Paint();
//在画布中画一个等宽的圆
canvas.drawCircle(circleRadio,circleRadio,circleRadio,p);
//设置画笔属性,让画笔只在哪圆圈中画画,关于画笔属性,可以百度一下,很多,但是非常有用
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap,0,0,p);
return b;
}
/**
* 获取特定大小缩略图
* @param imageid 图片资源id
* @param size 你想要获取的图片大小尺寸
* @return
*/
public Bitmap getSampleBitmap2(int imageid,int size){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(getResources(),imageid,options);
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize= calculateInSampleSize(options,size)*mInSampleSize;
//设置图片可以缩小
options.inScaled = true;
int calsize=options.outHeight>options.outWidth?options.outWidth:options.outHeight;
/**
* 计算图片缩小的目标密度,在这里说一下,有一条公式:
* 输出图片的宽高= (原图片的宽高 * (inTargetDensity / inDensity)) / inSampleSize
* 一般来说,图片的options.inDensity默认为160
* 所以inTargetDensity计算公式为:(希望输出的宽高*options.inDensity)/(原来图片的宽高/options.inSampleSize)
*/
options.inTargetDensity =(size*options.inDensity)/(calsize/options.inSampleSize);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),imageid,options);
circleRadio=bitmap.getWidth()/2;
return bitmap;
}
//谷歌源码里面的计算simplesize方法,
public int calculateInSampleSize(BitmapFactory.Options options,
int size) {
int reqWidth,reqHeight;
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
if(options.outHeight>options.outWidth){
reqWidth=size;
reqHeight=size*options.outHeight/options.outWidth;
}else{
reqWidth=size*options.outWidth/options.outHeight;
reqHeight=size;
}
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
然后你用的时候直接这样用就好了:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:luo="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrator.testmyidea.MainActivity">
<com.example.administrator.testmyidea.myTextView.circleImageView
luo:imageSrc="@drawable/timg"
luo:inSampleSize="1"
android:layout_width="150dp"
android:layout_height="150dp"/>
</RelativeLayout>
对了,记得在你的xml里面加上自定义组件的命名空间,如果你用的开发工具是androidStudo,那么要加
xmlns:luo="http://schemas.android.com/apk/res-auto"
如同我上面一样
eclipse的话,那就比较恶心了,得动态加载到包名,格式如同下面
//其中com.xxx是你的包名
xmlns:luo="http://schemas.android.com/apk/res/com.xxx"
好啦,然后就可以使用这个组件啦~~~
public class MainActivity extends Activity {
circleImageView circle;
int size=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.go).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
circle.setSimpleSize(size++);
}
});
circle=(circleImageView)findViewById(ll);
circle.setImageid(R.drawable.touxiang);
}
}