美文网首页Android开发者俱乐部Android开发程序员
自定义ImageView完成圆形头像自定义

自定义ImageView完成圆形头像自定义

作者: 菜鸟_一枚 | 来源:发表于2016-05-01 20:53 被阅读589次

    自定义ImageView完成圆形头像自定义

    前言

    我们可以看到现在的好多app的头像都是圆形的,记得应该是一年之前吧,具体的时间也不记得了,那个时候更新飞信,那次改版挺大,头像是圆形的,感觉挺不错的。那么今天也来实现以下吧。

    我们来分析一下,怎么去实现

    • 第一步:我们应该知道显示的头像是一个imageview,那么我们就继承ImageView
    • 第二步:它有自己的自定义属性(外部有一个大小可以变的圆,颜色也可以变化)

    接下来我们来实现吧

    • 首先要来看看他有的自定义属性
      attrs.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="CircleImageView">
            <attr name="outCircleColor" format="color"/>
            <attr name="outCircleWidth" format="dimension"/>
        </declare-styleable>
    </resources>
    
    • 来实现自定义的ImageView:
      这里面也没有多少的代码,在这里用到的测量宽高,绘制圆,代码里面都有了注释。
    package com.example.headimage;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.drawable.BitmapDrawable;
    import android.util.AttributeSet;
    import android.widget.ImageView;
    
    /**
     * Created by 若兰 on 2016/2/13.
     * 一个懂得了编程乐趣的小白,希望自己
     * 能够在这个道路上走的很远,也希望自己学习到的
     * 知识可以帮助更多的人,分享就是学习的一种乐趣
     * QQ:1069584784
     * csdn:http://blog.csdn.net/wuyinlei
     */
    public class CircleImageView extends ImageView {
    
        //外圆的宽度
        private int outCircleWidth;
    
        //外圆的颜色
        private int outCircleColor = Color.WHITE;
    
        //画笔
        private Paint paint;
    
        //view的宽度和高度
        private int viewWidth;
        private int viewHeigth;
    
        private Bitmap image;
    
        public CircleImageView(Context context) {
            this(context, null);
        }
    
        public CircleImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            initAttrs(context, attrs, defStyleAttr);
        }
    
        /**
         * 初始化资源文件
         *
         * @param context
         * @param attrs
         * @param defStyleAttr
         */
        private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
            TypedArray array = null;
            if (attrs != null) {
                array = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
    
                int len = array.length();
    
                for (int i = 0; i < len; i++) {
                    int attr = array.getIndex(i);
                    switch (attr) {
                        //获取到外圆的颜色
                        case R.styleable.CircleImageView_outCircleColor:
                            this.outCircleColor = array.getColor(attr, Color.WHITE);
                            break;
                        //获取到外圆的半径
                        case R.styleable.CircleImageView_outCircleWidth:
                            this.outCircleWidth = (int) array.getDimension(attr, 5);
                            break;
                    }
                }
            }
            paint = new Paint();
            paint.setColor(outCircleColor);//颜色
            paint.setAntiAlias(true);//设置抗锯齿
            array.recycle();  //回收
    
        }
    
        /**
         * view的测量
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
            int width = measureWith(widthMeasureSpec);
            int height = measureWith(heightMeasureSpec);
    
            viewWidth = width - outCircleWidth * 2;
            viewHeigth = height - outCircleWidth * 2;
    
            //调用该方法将测量后的宽和高设置进去,完成测量工作,
            setMeasuredDimension(width, height);
        }
    
        /**
         * 测量宽和高,这一块可以是一个模板代码(Android群英传)
         * @param widthMeasureSpec
         * @return
         */
        private int measureWith(int widthMeasureSpec) {
            int result = 0;
            //从MeasureSpec对象中提取出来具体的测量模式和大小
            int mode = MeasureSpec.getMode(widthMeasureSpec);
            int size = MeasureSpec.getSize(widthMeasureSpec);
            if (mode == MeasureSpec.EXACTLY) {
                //测量的模式,精确
                result = size;
            } else {
                result = viewWidth;
            }
            return result;
        }
    
        /**
         * 绘制
         * @param canvas
         */
        @Override
        protected void onDraw(Canvas canvas) {
            //加载图片
            loadImage();
    
            if (image != null) {
                //拿到最小的值(这里我们要去到最小的)
                int min = Math.min(viewWidth, viewHeigth);
    
                int circleCenter = min / 2;
    
                image = Bitmap.createScaledBitmap(image, min, min, false);
    
                //画圆
                canvas.drawCircle(circleCenter + outCircleWidth, circleCenter + outCircleWidth, circleCenter + outCircleColor, paint);
    
                //画图像
                canvas.drawBitmap(createCircleBitmap(image, min), outCircleWidth, outCircleWidth, null);
            }
    
    
        }
    
        /**
         * 创建一个圆形的bitmap
         *
         * @param image  传入的image
         * @param min
         * @return
         */
        private Bitmap createCircleBitmap(Bitmap image, int min) {
    
            Bitmap bitmap = null;
    
    
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            bitmap = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
    
            Canvas canvas = new Canvas(bitmap);
    
            //画一个和图片大小相等的画布
            canvas.drawCircle(min / 2, min / 2, min / 2, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    
            canvas.drawBitmap(image, 0, 0, paint);
    
    
            return bitmap;
        }
    
        /**
         * 加载Image
         */
        private void loadImage() {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
    
            if (bitmapDrawable != null) {
                image = bitmapDrawable.getBitmap();
            }
        }
    
        /**
         * 对外提供的可以设置外圆的颜色的方法
         * @param outCircleColor
         */
        public void setOutCircleColor(int outCircleColor) {
            if (null != paint) {
                paint.setColor(outCircleColor);
            }
            this.invalidate();
        }
    
        /**
         * 对外提供给的设置外圆的宽度大小的方法
         * @param outCircleWidth
         */
        public void setOutCircleWidth(int outCircleWidth) {
            this.outCircleWidth = outCircleWidth;
            this.invalidate();
        }
    }
    
    

    我们来看下效果图:



    好了,这里我在添加一些功能吧,就是可以选择相册图片,可以调用系统相机,在使用图片的时候可以裁剪。我们点击的时候用到了PopupWindow。这些代码都很简单(我以为还有点知识点,结果被鄙视了。。。)

    package com.example.headimage;
    
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.drawable.BitmapDrawable;
    import android.net.Uri;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.provider.Settings;
    import android.support.v7.app.AlertDialog;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.PopupWindow;
    import android.widget.RelativeLayout;
    import android.widget.Toast;
    
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private CircleImageView ivHead;
        private RelativeLayout layout_choose;
        private RelativeLayout layout_photo;
        private RelativeLayout layout_close;
    
        private LinearLayout layout_all;
        protected int mScreenWidth;
    
        /**
         * 定义三种状态
         */
        private static final int REQUESTCODE_PIC = 1;//相册
        private static final int REQUESTCODE_CAM = 2;//相机
        private static final int REQUESTCODE_CUT = 3;//图片裁剪
    
        private Bitmap mBitmap;
        private File mFile;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ivHead = (CircleImageView) findViewById(R.id.iv_head);
            layout_all = (LinearLayout) findViewById(R.id.layout_all);
    
            ivHead.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.iv_head:
                    showMyDialog();
                    break;
            }
        }
    
        PopupWindow avatorPop;
    
    
        private void showMyDialog() {
            View view = LayoutInflater.from(this).inflate(R.layout.pop_show_dialog,
                    null);
            layout_choose = (RelativeLayout) view.findViewById(R.id.layout_choose);
            layout_photo = (RelativeLayout) view.findViewById(R.id.layout_photo);
            layout_close = (RelativeLayout) view.findViewById(R.id.layout_close);
    
            layout_choose.setBackgroundColor(getResources().getColor(
                    R.color.base_color_text_white));
            layout_photo.setBackgroundDrawable(getResources().getDrawable(
                    R.drawable.pop_bg_press));
            layout_close.setBackgroundColor(getResources().getColor(
                    R.color.base_color_text_white));
    
    
            layout_photo.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View arg0) {
                    // TODO Auto-generated method stub
                    layout_choose.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
                    layout_photo.setBackgroundDrawable(getResources().getDrawable(
                            R.drawable.pop_bg_press));
                    layout_close.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
    
    
                    openCamera();
    
                   // Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    //intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                    //startActivityForResult(intent,);
                }
            });
    
            layout_choose.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View arg0) {
                    // TODO Auto-generated method stub
                    layout_photo.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
                    layout_choose.setBackgroundDrawable(getResources().getDrawable(
                            R.drawable.pop_bg_press));
                    layout_close.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
                    openPic();
    
                }
            });
    
            layout_close.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    layout_photo.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
                    layout_close.setBackgroundDrawable(getResources().getDrawable(
                            R.drawable.pop_bg_press));
                    layout_choose.setBackgroundColor(getResources().getColor(
                            R.color.base_color_text_white));
                    avatorPop.dismiss();
                }
            });
    
    
    
            DisplayMetrics metric = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metric);
            mScreenWidth = metric.widthPixels;
            avatorPop = new PopupWindow(view, mScreenWidth, 200);
            avatorPop.setTouchInterceptor(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                        avatorPop.dismiss();
                        return true;
                    }
                    return false;
                }
            });
    
            //设置宽度
            avatorPop.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
            //设置高度
            avatorPop.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
            //可以点击
            avatorPop.setTouchable(true);
            avatorPop.setFocusable(true);
            avatorPop.setOutsideTouchable(true);
            avatorPop.setBackgroundDrawable(new BitmapDrawable());
            // 动画效果 从底部弹起
            avatorPop.setAnimationStyle(R.style.Animations_GrowFromBottom);
            avatorPop.showAtLocation(layout_all, Gravity.BOTTOM, 0, 0);
        }
    
        /**
         * 打开相册
         */
        private void openPic() {
            Intent picIntent = new Intent(Intent.ACTION_PICK,null);
            picIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
            startActivityForResult(picIntent,REQUESTCODE_PIC);
        }
    
        /**
         * 调用相机
         */
        private void openCamera() {
            String state = Environment.getExternalStorageState();
            if (state.equals(Environment.MEDIA_MOUNTED)){
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
                if (!file.exists()){
                    file.mkdirs();
                }
                mFile = new File(file, System.currentTimeMillis() + ".jpg");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mFile));
                intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);
                startActivityForResult(intent,REQUESTCODE_CAM);
            } else {
                Toast.makeText(this, "请确认已经插入SD卡", Toast.LENGTH_SHORT).show();
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
                    case REQUESTCODE_CAM:
                        startPhotoZoom(Uri.fromFile(mFile));
                        break;
                    case REQUESTCODE_PIC:
    
                        if (data == null || data.getData() == null){
                            return;
                        }
                        startPhotoZoom(data.getData());
    
                        break;
                    case REQUESTCODE_CUT:
    
                        if (data!= null){
                            setPicToView(data);
                        }
                        break;
                }
            }
    
    
            super.onActivityResult(requestCode, resultCode, data);
        }
    
        private void setPicToView(Intent data) {
           Bundle bundle =  data.getExtras();
            if (bundle != null){
                //这里也可以做文件上传
                mBitmap = bundle.getParcelable("data");
                ivHead.setImageBitmap(mBitmap);
            }
        }
    
        /**
         * 打开系统图片裁剪功能
         * @param uri
         */
        private void startPhotoZoom(Uri uri) {
            Intent intent = new Intent("com.android.camera.action.CROP");
            intent.setDataAndType(uri,"image/*");
            intent.putExtra("crop",true);
            intent.putExtra("aspectX",1);
            intent.putExtra("aspectY",1);
            intent.putExtra("outputX",300);
            intent.putExtra("outputY",300);
            intent.putExtra("scale",true); //黑边
            intent.putExtra("scaleUpIfNeeded",true); //黑边
            intent.putExtra("return-data",true);
            intent.putExtra("noFaceDetection",true);
            startActivityForResult(intent,REQUESTCODE_CUT);
    
        }
    }
    
    

    我们来看下效果


    裁剪功能:

    裁剪后确定:

    这里我们对于动画,还有资源属性用到了一些style样式,还有一些动画资源文件,这里我就不上传了,直接给git地址,方便下载,查看更多资源
    https://github.com/wuyinlei/CircleImgae

    相关文章

      网友评论

      • 紫禁之云:测量宽和高,这一块可以是一个模板代码(Android群英传)这段代码中的result = viewWidth;有错误,如果设置成match_parent 就会报错
        菜鸟_一枚:@紫禁之云 你好,这个match_parent我还没用过,有空试下
      • 盖小同学:学习啦
      • moshimoshi:可以可以可以

      本文标题: 自定义ImageView完成圆形头像自定义

      本文链接:https://www.haomeiwen.com/subject/yexlrttx.html