20:View自定义详解

注意点:

this.outCircleWidth = (int) array.getDimensionPixelSize(attr, 50);

getDimension:、getDimensionPixelSize:、getDimensionPixelOffset

这三个函数返回的都是dip值乘以屏幕密度,如果你在资源文件中定义的长度单位不是dip,而是px的话,程序会直接抛出异常

1:res->values->attrs定义:

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    
    <declare-styleable name="CustomTitleView">  
        <attr name="titleText" format="string"/>  
        <attr name="titleTextColor" format="color"/>  
        <attr name="titleTextSize" format="dimension"/>  
    </declare-styleable>
    
    <declare-styleable name="CircleImageView">
        <attr name="outCircleColor" format="color"/>
        <attr name="outCircleWidth" format="dimension"/>
    </declare-styleable>
</resources>

2:activity_main

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    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=".MainActivity" 
    xmlns:app="http://schemas.android.com/apk/res/com.example.circleimageview">

    <com.example.circleimageview.CircleImageView 
        xmlns:app="http://schemas.android.com/apk/res-auto" 
        android:layout_width="200dp"  
        android:layout_height="200dp"   
        android:src="@drawable/ic_launcher"
        app:outCircleWidth="30dp"
        app:outCircleColor="#ff0000"
        >  
    </com.example.circleimageview.CircleImageView>  

</RelativeLayout>

3:CircleImageView:

package com.example.circleimageview;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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.util.Log;
import android.widget.ImageView;

public class CircleImageView extends ImageView {
    //外圆的宽度
    private int outCircleWidth;

    //外圆的颜色
    private int outCircleColor = Color.BLUE;

    //画笔
    private Paint paint;

    //view的宽度和高度
    private int viewWidth;
    private int viewHeigth;

    private Bitmap image;

    public CircleImageView(Context context) {
        super(context);
        Log.d("yjm", "aaaaaaaaa");
        // TODO Auto-generated constructor stub
    }
    
    public CircleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.d("yjm", "bbbbbbbbb");
        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) {
            //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签
            //即属性集合的标签,在R文件中名称为R.styleable+name
            array = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);

            int len = array.length();
            
            //第一个参数为属性集合里面的属性,R文件名称:R.styleable+属性集合名称+下划线+属性名称
            //第二个参数为,如果没有设置这个属性,则设置的默认的值
            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:
                        //getDimensionPixelSize返回的值是XML里面设置的值乘以屏幕密度
                        this.outCircleWidth = (int) array.getDimensionPixelSize(attr, 50);
                        Log.d("yjm", "outCircleWidth--->"+outCircleWidth);
                        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);

        //viewWith=616,  width=656   
        //viewHegth=1030   heigth=1070
        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);

            //画圆,参数:圆心X, 圆心y,半径,画笔
            canvas.drawCircle(circleCenter + outCircleWidth, circleCenter + outCircleWidth, circleCenter + outCircleWidth, 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() {
        //通过XML里面的android:src获取
        BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();

        if (bitmapDrawable != null) {
            image = bitmapDrawable.getBitmap();
        }
        //image = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    }

    /**
     * 对外提供的可以设置外圆的颜色的方法
     * @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();
    }

}

猜你喜欢

转载自www.cnblogs.com/wnpp/p/9216276.html