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
然后是自定义ImageView的实现类:
使用时非常简单,直接在布局中调用自定义的类
activity_main.xml,这里要注意的是,第二个是带有边框的,效果图如上
打开图库选取图片,截取图片和设置图片在MainActivity.class中实现
MainActivity.class
以上就可以实现自定义控件,设置圆形头像
本项目源码下载地址:链接: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); } }
以上就可以实现自定义控件,设置圆形头像
相关文章推荐
- Android裁剪圆形头像源码
- Android 从本地图库或拍照后裁剪图片并设置头像
- Android 从本地图库或拍照后裁剪图片并设置头像
- Android 头像上传 相机+图库 绘制圆形头像
- Android实现本地上传图片并设置为圆形头像
- Android实现从本地图库/相机拍照后裁剪图片并设置头像
- Android实现本地上传图片并设置为圆形头像
- 超实用的Andoird圆形头像设置 —— 实现相机、相册选择并裁剪尽在一行代码之间(兼容Android6.0/7.0)
- Android圆形头像设置(实现相机、相册选择并裁剪)兼容6.0/7.0
- android 相机拍照或从图库获取图片并裁剪设置头像
- Android实现本地上传图片并设置为圆形头像
- android 设置头像以及裁剪功能
- 开源中国 OsChina Android 客户端源码分析(6)拍照、图库、裁剪
- Android:调用系统相机 图库 裁剪-图片上传-客服端-服务器
- android 用户头像,图片裁剪,上传并附带用户数据base64code 方式
- 《Android开发卷——设置圆形头像,Android截取圆形图片》
- android从摄像头或者图库选择图片,并进行裁剪,可以用来用户头像处理
- Android实战简易教程-第二十七枪(Android设置头像上传功能实现)
- Android从服务器获取图片并设置圆形头像
- Android 上传头像,解决小米3等手机无法直接得到裁剪照片问题