您的位置:首页 > 移动开发 > Android开发

Android自定义控件实例,圆形头像(图库 + 裁剪+设置),上传头像显示为圆形,附源码

2016-12-05 22:30 471 查看
Android项目开发中经常会遇见需要实现圆角或者圆形的图片功能,如果仅仅使用系统自带的ImageView控件显然无法实现此功能,所以通过系列文章的形式由简到繁全方位的介绍一下此功能的实现,巩固一下自身的学习,同时,和广大网友交流分享

本项目源码下载地址:链接:http://pan.baidu.com/s/1sljdvtF密码:xj85

首先看效果图









首先看一下CircleImageView的主要流程

1.首先通过setImageXxx()方法设置图片Bitmap;
2.进入构造函数CircleImageView()获取自定义参数,以及调用setup()函数;
3.

进入setup()函数(非常关键),进行图片画笔边界画笔(Paint)一些重绘参数初始化:构建渲染器BitmapShader用Bitmap来填充绘制区域,设置样式和内外圆半径计算等,以及调用updateShaderMatrix()函数和
invalidate()函数;
4.进入updateShaderMatrix()函数,计算缩放比例和平移,设置BitmapShader的Matrix参数等;
5.触发ondraw()函数完成最终的绘制。使用配置好的Paint先画出绘制内圆形来以后再画边界圆形。

下面看具体的代码实现:

attr.xml

<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<declare-styleablename="roundedimageview">
<attrname="border_thickness"format="dimension"/>
<attrname="border_inside_color"format="color"/>
<attrname="border_outside_color"format="color"></attr>
</declare-styleable>
</resources>


然后是自定义ImageView的实现类:

RoundImageView.class
  


**
*圆形ImageView,可设置最多两个宽度不同且颜色不同的圆形边框。
*设置颜色在xml布局文件中由自定义属性配置参数指定
*/
publicclassRoundImageViewextendsImageView{
privateintmBorderThickness=0;
privateContextmContext;
privateintdefaultColor=0xFFFFFFFF;
//如果只有其中一个有值,则只画一个圆形边框
privateintmBorderOutsideColor=0;
privateintmBorderInsideColor=0;
//控件默认长、宽
privateintdefaultWidth=0;
privateintdefaultHeight=0;
//构造方法,参数上下文
publicRoundImageView(Contextcontext){
super(context);
mContext=context;
}

publicRoundImageView(Contextcontext,AttributeSetattrs){
super(context,attrs);
mContext=context;
setCustomAttributes(attrs);
}

publicRoundImageView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
mContext=context;
setCustomAttributes(attrs);
}

privatevoidsetCustomAttributes(AttributeSetattrs){
TypedArraya=mContext.obtainStyledAttributes(attrs,R.styleable.roundedimageview);
mBorderThickness=a.getDimensionPixelSize(R.styleable.roundedimageview_border_thickness,0);
mBorderOutsideColor=a.getColor(R.styleable.roundedimageview_border_outside_color,defaultColor);
mBorderInsideColor=a.getColor(R.styleable.roundedimageview_border_inside_color,defaultColor);
}

@Override
protectedvoidonDraw(Canvascanvas){
Drawabledrawable=getDrawable();
if(drawable==null){
return;
}
if(getWidth()==0||getHeight()==0){
return;
}
this.measure(0,0);
if(drawable.getClass()==NinePatchDrawable.class)
return;
Bitmapb=((BitmapDrawable)drawable).getBitmap();
Bitmapbitmap=b.copy(Bitmap.Config.ARGB_8888,true);
if(defaultWidth==0){
defaultWidth=getWidth();
}
if(defaultHeight==0){
defaultHeight=getHeight();
}
intradius=0;
if(mBorderInsideColor!=defaultColor&&mBorderOutsideColor!=defaultColor){//定义画两个边框,分别为外圆边框和内圆边框
radius=(defaultWidth<defaultHeight?defaultWidth:defaultHeight)/2-2*mBorderThickness;
//画内圆
drawCircleBorder(canvas,radius+mBorderThickness/2,mBorderInsideColor);
//画外圆
drawCircleBorder(canvas,radius+mBorderThickness+mBorderThickness/2,mBorderOutsideColor);
}elseif(mBorderInsideColor!=defaultColor&&mBorderOutsideColor==defaultColor){//定义画一个边框
radius=(defaultWidth<defaultHeight?defaultWidth:defaultHeight)/2-mBorderThickness;
drawCircleBorder(canvas,radius+mBorderThickness/2,mBorderInsideColor);
}elseif(mBorderInsideColor==defaultColor&&mBorderOutsideColor!=defaultColor){//定义画一个边框
radius=(defaultWidth<defaultHeight?defaultWidth:defaultHeight)/2-mBorderThickness;
drawCircleBorder(canvas,radius+mBorderThickness/2,mBorderOutsideColor);
}else{//没有边框
radius=(defaultWidth<defaultHeight?defaultWidth:defaultHeight)/2;
}
BitmaproundBitmap=getCroppedRoundBitmap(bitmap,radius);
canvas.drawBitmap(roundBitmap,defaultWidth/2-radius,defaultHeight/2-radius,null);
}

/**
*获取裁剪后的圆形图片
*
*@param
*/
//radius半径
publicBitmapgetCroppedRoundBitmap(Bitmapbmp,intradius){
BitmapscaledSrcBmp;
intdiameter=radius*2;
//为了防止宽高不相等,造成圆形图片变形,因此截取长方形中处于中间位置最大的正方形图片
intbmpWidth=bmp.getWidth();
intbmpHeight=bmp.getHeight();
intsquareWidth=0,squareHeight=0;
intx=0,y=0;
BitmapsquareBitmap;
if(bmpHeight>bmpWidth){//高大于宽
squareWidth=squareHeight=bmpWidth;
x=0;
y=(bmpHeight-bmpWidth)/2;
//截取正方形图片
squareBitmap=Bitmap.createBitmap(bmp,x,y,squareWidth,squareHeight);
}elseif(bmpHeight<bmpWidth){//宽大于高
squareWidth=squareHeight=bmpHeight;
x=(bmpWidth-bmpHeight)/2;
y=0;
squareBitmap=Bitmap.createBitmap(bmp,x,y,squareWidth,squareHeight);
}else{
squareBitmap=bmp;
}
if(squareBitmap.getWidth()!=diameter||squareBitmap.getHeight()!=diameter){
scaledSrcBmp=Bitmap.createScaledBitmap(squareBitmap,diameter,diameter,true);
}else{
scaledSrcBmp=squareBitmap;
}
Bitmapoutput=Bitmap.createBitmap(scaledSrcBmp.getWidth(),
scaledSrcBmp.getHeight(),
Bitmap.Config.ARGB_8888);
Canvascanvas=newCanvas(output);

Paintpaint=newPaint();
Rectrect=newRect(0,0,scaledSrcBmp.getWidth(),scaledSrcBmp.getHeight());

paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0,0,0,0);
canvas.drawCircle(scaledSrcBmp.getWidth()/2,
scaledSrcBmp.getHeight()/2,
scaledSrcBmp.getWidth()/2,
paint);
paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(scaledSrcBmp,rect,rect,paint);
bmp=null;
squareBitmap=null;
scaledSrcBmp=null;
returnoutput;
}

/**
*边缘画圆
*/
privatevoiddrawCircleBorder(Canvascanvas,intradius,intcolor){
Paintpaint=newPaint();
/*去锯齿*/
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(color);
/*设置paint的 style 为STROKE:空心*/
paint.setStyle(Paint.Style.STROKE);
/*设置paint的外框宽度*/
paint.setStrokeWidth(mBorderThickness);
canvas.drawCircle(defaultWidth/2,defaultHeight/2,radius,paint);
}
}


使用时非常简单,直接在布局中调用自定义的类

activity_main.xml,这里要注意的是,第二个是带有边框的,效果图如上

<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:imagecontrol="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.ceshi.MainActivity">

<Button
android:id="@+id/aaa"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击设置头像"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<com.example.ceshi.RoundImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<!--border_outside_color外部圆圈的颜色-->
<!--border_inside_color内部部圆圈的颜色-->
<!--border_thickness外圆和内圆的宽度-->
<com.example.ceshi.RoundImageView
android:id="@+id/img2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
imagecontrol:border_inside_color="#bc0978"
imagecontrol:border_outside_color="#ba3456"
imagecontrol:border_thickness="1dp"/>
</LinearLayout>


打开图库选取图片,截取图片和设置图片在MainActivity.class中实现

MainActivity.class

publicclassMainActivityextendsAppCompatActivity{
privateButtonbt;
privatestaticfinalintPHOTO_REQUEST_GALLERY=2;//从相册中选择
privatestaticfinalintPHOTO_REQUEST_CUT=3;//结果
privateImageViewphoto,photo2;
privateFiletempFile;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
photo=(ImageView)findViewById(R.id.image);
photo2=(ImageView)findViewById(R.id.img2);

bt=(Button)findViewById(R.id.aaa);
bt.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
//Intentintent=newIntent(Intent.ACTION_PICK);
//intent.setType("image/*");
//startActivityForResult(intent,PHOTO_REQUEST_GALLERY);
//激活系统图库,选择一张图片
Intentintent=newIntent(Intent.ACTION_PICK);
intent.setType("image/*");
//开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
startActivityForResult(intent,PHOTO_REQUEST_GALLERY);
}
});
}

/*
*剪切图片
*/
privatevoidcrop(Uriuri){
     //看到有人问裁剪的路径

    //获取系统时间然后将裁剪后的图片保存至指定的文件夹

   //SimpleDateFormatsDateFormat=newSimpleDateFormat("yyyyMMddhhmmss");
    //Stringaddress=sDateFormat.format(newjava.util.Date());

    //imagePath=address+".JPEG";
   // UriimageUri=Uri.parse("保存的文件夹的名称/"+address
//+".JPEG");

//裁剪图片意图
Intentintent=newIntent("com.android.camera.action.CROP");
intent.setDataAndType(uri,"image/*");
intent.putExtra("crop","true");
//裁剪框的比例,1:1
intent.putExtra("aspectX",1);
intent.putExtra("aspectY",1);
//裁剪后输出图片的尺寸大小
intent.putExtra("outputX",250);
intent.putExtra("outputY",250);
    intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);//输出路径
intent.putExtra("outputFormat","JPEG");//图片格式
intent.putExtra("noFaceDetection",true);//取消人脸识别
intent.putExtra("return-data",true);

  //Cursorcursor=LocationApplication.getContext().getContentResolver().query(uri,null,null,null,null);
  //if(cursor!=null&&cursor.moveToFirst()){
//photopath=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
//Log.e("photopath","photopath:------------"+photopath);
  //}

//filePath=photopath;
//定义一个全局变量,接受photopath

//开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUT
startActivityForResult(intent,PHOTO_REQUEST_CUT);
}

@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
super.onActivityResult(requestCode,resultCode,data);
if(requestCode==PHOTO_REQUEST_GALLERY){
//从相册返回的数据
if(data!=null){
//得到图片的全路径
Uriuri=data.getData();
crop(uri);
}
}elseif(requestCode==PHOTO_REQUEST_CUT){
//从剪切图片返回的数据
if(data!=null){
Bitmapbitmap=data.getParcelableExtra("data");
photo.setImageBitmap(bitmap);
photo2.setImageBitmap(bitmap);
}
try{
//将临时文件删除
tempFile.delete();
}catch(Exceptione){
e.printStackTrace();
}

}
super.onActivityResult(requestCode,resultCode,data);

}
}


以上就可以实现自定义控件,设置圆形头像


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: