自定义View(一)

对于刚开始学自定义渣渣的我,对自定义还是挺恐慌的,不过上手后就好了。

先总结下自定义View的步骤:

1、自定义View的属性

2、在View的构造方法中获得我们自定义的属性

3、绘制机制:重写onMesure (按需求使用)、重写onSizeChange()、重写onLayout(按需求使用)、重写onDraw


一、自定义View的属性

1、首先在res/values/  下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomView">
        <attr name="border_color" format="color"></attr>
        <attr name="border_width" format="dimension"></attr>
    </declare-styleable>
</resources>
我们定义画笔颜色,画笔字体大小2个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。

然后在布局中声明我们的自定义View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation ="vertical"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <com.weather.org.weather.DefindView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:border_color="#f44336"
        app:border_width="2dp"/>
</LinearLayout>
   一定要引入 xmlns:app ="http://schemas.android.com/apk/res-auto"或者具体到哪个包下


二 、在View的构造方法中,获得我们的自定义的样式

public class DefindView extends View{

    private  float mBorderWidth;
    private int mBorderColor;
    private Paint mPaint;
    private RectF mBounds;
    private float width ;
    private float height;
    private float radius;
    private int smallLength ;
    private int largeLength ;
    private int[] FaceColors;



    public DefindView(Context context)
    {
        super(context);
    }

    public DefindView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray =context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomView,0,0);
        try{
            mBorderColor =typedArray.getColor(R.styleable.CustomView_border_color,0xff000000);
            mBorderWidth =typedArray.getDimension(R.styleable.CustomView_border_width,3);
        }catch (Exception e)
        {
            e.printStackTrace();
        }finally {
            typedArray.recycle();
        }
        init();
    }

    public DefindView(Context context, AttributeSet attr, int defStyleAttr)
    {
        super(context,attr,defStyleAttr);

    }

    private  void init(){

        mPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setColor(mBorderColor);

        FaceColors = new int[]{Color.rgb(0, 0, 0), Color.rgb(0, 0, 0), Color.rgb(0, 0, 0),
                Color.rgb(0, 0, 0), Color.rgb(0, 0, 0), Color.rgb(76,175,80)};
 
    }    
  

三、我们重写onSizeChange,onDraw,onMesure调用系统提供的:


 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBounds =new RectF(getLeft(),getTop(),getRight(),getBottom());

        width =mBounds.right - mBounds.left ;
        height=mBounds.bottom -mBounds.top;

        if(width <height)
        {
            radius =width/4;
        }else{
            radius =height/4;
        }
        smallLength =10;
        largeLength =20;
 
    }                                                                                                                           


@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthsize =MeasureSpec.getSize(widthMeasureSpec);
        int widthmode =MeasureSpec.getMode(widthMeasureSpec);
    }


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawColor(0xff000000);
        mPaint.setColor(0x66555555);
        canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*width/2,mBounds.centerY()
                -(float)0.9*height/2,mBounds.centerX()+(float)0.9*width/2,mBounds.centerY()+(float)0.9*height/2),30,30,mPaint);
        mPaint.setColor(mBorderColor);
        canvas.drawCircle(mBounds.centerX(),mBounds.centerY(),radius,mPaint);
        drawGriend(canvas);
        float start_x,start_y;
        float end_x,end_y;
        for (int i=0;i<60;++i)
        {
            start_x =radius*(float)Math.cos(Math.PI/180*i*6);
            start_y =radius*(float)Math.sin(Math.PI/180*i*6);
            if(i%5==0)
            {
                end_x =start_x+largeLength*(float)Math.cos(Math.PI/180*i*6);
                end_y =start_y+largeLength*(float)Math.sin(Math.PI/180*i*6);
            }else
            {
                end_x =start_x+smallLength*(float)Math.cos(Math.PI/180*i*6);
                end_y =start_y+smallLength*(float)Math.sin(Math.PI/180*i*6);
            }
            start_x+=mBounds.centerX();
            end_x += mBounds.centerX();
            start_y +=mBounds.centerY();
            end_y +=mBounds.centerY();
            canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
        }

        canvas.drawCircle(mBounds.centerX(),mBounds.centerY(),20,mPaint);
        //canvas.rotate(60,mBounds.centerX(),mBounds.centerY());
        canvas.drawLine(mBounds.centerX(),mBounds.centerY(),mBounds.centerX(),mBounds.centerY()-radius,mPaint);
    }

    // 渐变色处理

    private void drawGriend(Canvas canvas)
    {
        GradientDrawable gr = new GradientDrawable(
                GradientDrawable.Orientation.TOP_BOTTOM, FaceColors);

        gr.setShape(GradientDrawable.OVAL);
        gr.setBounds((int)mBounds.centerX()-(int)width/4,(int)mBounds.centerY()-(int)width/4,(int)mBounds.centerX()+(int)width/4,(int)mBounds.centerY()+(int)width/4);
        gr.setGradientType(GradientDrawable.RADIAL_GRADIENT);
        gr.setGradientRadius(mBounds.width()/4);
        gr.draw(canvas);

    }
}  

四、关于onMeasure

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:

重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用


效果图:






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值