自定义View

简介: 自定义View画一个实心圆效果图创建attrs.xml文件初始化样式属性支持Padding属性支持wrap_content属性布局文件中的应用画一个带外圆环的圆效果图创建attrs.xml文件初始化样式属性内圆与外圆环的绘制布局文件中的应用画一个外圆环可根据数值变动的圆效果图创建attrs.xml文件初始化样式属性绘制View提供方法修改样式布局文件中的应用


画一个实心圆



效果图

image.png


创建attrs.xml


在value文件夹下创建一个名为attrs.xml文件,为圆设置一个背景颜色的属性,代码如下:

<declare-styleable name="CircleView_Solid">
        <attr name="CircleColor_Solid" format="color"/>
</declare-styleable>


初始化样式属性


为圆设置颜色属性,并设置抗锯齿

private void InitAttrs(Context context , AttributeSet attrs){
        TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Solid,0,0 );
        mCircleBGColor = array.getColor( R.styleable.CircleView_Solid_CircleColor_Solid,0xFFFFFFFF );
    }
    private void InitVar(){
        mCirclePaint = new Paint(  );
        mCirclePaint.setAntiAlias( true );
        mCirclePaint.setColor( mCircleBGColor );
    }


支持Padding属性


由于直接继承view,不再onDraw()中进行处理,是无法直接使用Padding属性,代码如下:

protected void onDraw(Canvas canvas) {
        super.onDraw( canvas );
        int PaddingLeft = getPaddingLeft();
        int PaddingRight = getPaddingRight();
        int PaddingTop = getPaddingTop();
        int PaddingBottom = getPaddingBottom();
        int Width = (getWidth() - (PaddingLeft+PaddingRight)) / 2 +PaddingLeft;
        int Height = (getHeight() -(PaddingTop+PaddingBottom))/2+PaddingTop;
        int Radius = Math.min( Width,Height )/2;
        canvas.drawCircle( Width,Height,Radius,mCirclePaint );
    }


支持wrap_content属性


若不在onMeasure()对wrap_content进行处理,效果很可能达不到预期效果,如果控件使用wrap_content属性,那么他的Measure specification mode就为At_Most,而它的宽高就等于specSize,这种情况下specSize是就相当于父容器当前剩余的大小,代码如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure( widthMeasureSpec, heightMeasureSpec );
        int Width = 500;
        int Height = 500;
        int WidthMode = MeasureSpec.getMode( widthMeasureSpec );
        int WidthSize = MeasureSpec.getSize( widthMeasureSpec );
        int HeightMode = MeasureSpec.getMode( heightMeasureSpec );
        int HeightSize = MeasureSpec.getSize( heightMeasureSpec );
        if (WidthMode == MeasureSpec.AT_MOST && HeightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension( Math.min( Width,HeightSize ),Math.min( Height ,HeightSize) );
        } else if (WidthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension( Math.min( Width,HeightSize ),HeightSize );
        }else if (HeightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension( WidthSize,Math.min( Height ,HeightSize) );
        }
    }


布局文件中的应用

<com.franzliszt.customcircleview.CircleView_Solid
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:CircleColor_Solid="@color/colorRed"
    android:padding="10dp"/>


画一个带外圆环的圆



效果图

image.png


创建attrs.xml文件

<declare-styleable name="CircleView_Text">
<!--        内圆颜色-->
        <attr name="CircleColor" format="color"/>
<!--        外圆环颜色-->
        <attr name="RingColor" format="color"/>
<!--        圆的半径-->
        <attr name="Radius" format="dimension"/>
<!--        外圆环的宽度-->
        <attr name="StrokeWidth" format="dimension"/>
    </declare-styleable>


初始化样式属性

 private void InitAttrs(Context context , AttributeSet attrs){
        TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Text,0,0 );
        CircleColor = array.getColor( R.styleable.CircleView_Text_CircleColor,0xFFFFFFFF );
        RingColor = array.getColor( R.styleable.CircleView_Text_RingColor,0xFFFFFFFF );
        mRadius = array.getDimension( R.styleable.CircleView_Text_Radius,80 );
        mStrokeWidth = array.getDimension( R.styleable.CircleView_Text_StrokeWidth,10 );
        mRingRadius = mRadius + mStrokeWidth / 2;
    }
    private void InitVar(){
        //内圆
        //设置颜色
        CirclePaint.setColor( CircleColor );
        //设置填充方式
        CirclePaint.setStyle( Paint.Style.FILL );
        //设置抗锯齿
        CirclePaint.setAntiAlias( true );
        //外圆环
        RingPaint.setColor( RingColor );
        RingPaint.setStyle( Paint.Style.STROKE );
        RingPaint.setAntiAlias( true );
        RingPaint.setStrokeWidth( mStrokeWidth );
    }


内圆与外圆环的绘制

protected void onDraw(Canvas canvas) {
        super.onDraw( canvas );
        mCenterX = getWidth()/2;
        mCenterY = getHeight()/2;
        canvas.drawCircle( mCenterX,mCenterY,mRadius,CirclePaint );
        RectF rect = new RectF(  );
        rect.left = mCenterX - mRingRadius;
        rect.right = 2 * mRingRadius + (mCenterX - mRingRadius);
        rect.top = mCenterY - mRingRadius;
        rect.bottom = 2 * mRingRadius + (mCenterY - mRingRadius);
       canvas.drawArc( rect,0,360,false,RingPaint );
    }


布局文件中的应用

 <com.franzliszt.customcircleview.CircleView
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:Radius="40dp"
        app:StrokeWidth="10dp"
        app:CircleColor="@color/colorBlack"
        app:RingColor="@color/colorRed"/>


画一个外圆环可根据数值变动的圆



效果图

image.png


创建attrs.xml文件

<declare-styleable name="CircleView_Progress">
        <!--        内圆颜色-->
        <attr name="CircleProgressColor" format="color"/>
        <!--        外圆环颜色-->
        <attr name="RingProgressColor" format="color"/>
        <!--        外圆环覆盖部分颜色-->
        <attr name="RingBgProgressColor" format="color"/>
        <!--        文字颜色-->
        <attr name="TextProgressColor" format="color"/>
        <!--        圆的半径-->
        <attr name="RadiusProgress" format="dimension"/>
        <!--        外圆环的宽度-->
        <attr name="StrokeWidthProgress" format="dimension"/>
        <attr name="CurrentProgress" format="float"/>
    </declare-styleable>


初始化样式属性

private void InitAttrs(Context context , AttributeSet attrs){
        TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Progress,0,0 );
        CircleColor = array.getColor( R.styleable.CircleView_Progress_CircleProgressColor,0xFFFFFFFF );
        RingColor = array.getColor( R.styleable.CircleView_Progress_RingProgressColor,0xFFFFFFFF );
        RingBgColor = array.getColor( R.styleable.CircleView_Progress_RingBgProgressColor,0xFFFFFFFF );
        TextColor = array.getColor( R.styleable.CircleView_Progress_TextProgressColor, 0xFFFFFFFF);
        mRadius = array.getDimension( R.styleable.CircleView_Progress_RadiusProgress,80 );
        mStrokeWidth = array.getDimension( R.styleable.CircleView_Progress_StrokeWidthProgress,10 );
        mCurrentProgress = array.getFloat( R.styleable.CircleView_Progress_CurrentProgress,10 );
        mRingRadius = mRadius + mStrokeWidth / 2;
    }
    private void InitVar(){
        //内圆
        //设置颜色
        CirclePaint.setColor( CircleColor );
        //设置填充方式
        CirclePaint.setStyle( Paint.Style.FILL );
        //设置抗锯齿
        CirclePaint.setAntiAlias( true );
        //外圆环
        RingPaint.setColor( RingColor );
        RingPaint.setStyle( Paint.Style.STROKE );
        RingPaint.setAntiAlias( true );
        RingPaint.setStrokeWidth( mStrokeWidth );
        //外圆环覆盖部分
        RingBgPaint.setColor( RingBgColor );
        RingBgPaint.setStyle( Paint.Style.STROKE );
        RingBgPaint.setAntiAlias( true );
        RingBgPaint.setStrokeWidth( mStrokeWidth );
        //中间文字
        TextPaint.setStyle( Paint.Style.FILL );
        TextPaint.setAntiAlias( true );
        TextPaint.setColor( TextColor );
        TextPaint.setTextSize( mRadius/2 );
        //文字的高度
        Paint.FontMetrics fontMetrics = TextPaint.getFontMetrics();
        mTextHeight = (int)Math.ceil( fontMetrics.descent - fontMetrics.ascent );
    }


绘制View

protected void onDraw(Canvas canvas) {
        super.onDraw( canvas );
        mCenterX = getWidth()/2;
        mCenterY = getHeight()/2;
        canvas.drawCircle( mCenterX,mCenterY,mRadius,CirclePaint );
        RectF rect = new RectF(  );
        rect.left = mCenterX - mRingRadius;
        rect.right = 2 * mRingRadius + (mCenterX - mRingRadius);
        rect.top = mCenterY - mRingRadius;
        rect.bottom = 2 * mRingRadius + (mCenterY - mRingRadius);
        canvas.drawArc( rect,0,360,false,RingPaint );
        //当mCurrentProgress大于0时,外圆环覆盖部分显示
        if (mCurrentProgress > 0){
            RectF rect_progress = new RectF(  );
            rect_progress.left = mCenterX - mRingRadius;
            rect_progress.right = 2 * mRingRadius + (mCenterX - mRingRadius);
            rect_progress.top = mCenterY - mRingRadius;
            rect_progress.bottom = 2 * mRingRadius + (mCenterY - mRingRadius);
            //例如外圆环数值为35,即35/100*360,获得外圆环覆盖部分
            canvas.drawArc( rect,-90,(float) (mCurrentProgress / mTotalProgress)*360,false,RingBgPaint );
        }
        //文字部分
        String text = mCurrentProgress+"%";
        //文字部分的宽度
        mTextWidth = TextPaint.measureText( text,0,text.length() );
        canvas.drawText( text,mCenterX - mTextWidth / 2, mCenterY + mTextHeight / 4,TextPaint );
    }


提供方法修改样式

 public void setProgress(double progress){
        mCurrentProgress = progress;
        postInvalidate();
    }
    public void setRingBgColor(int Color){
        RingBgColor = Color;
        postInvalidate();
    }
    public void setTextColor(int Color){
        TextColor = Color;
        postInvalidate();
    }


布局文件中的应用

 <com.franzliszt.customcircleview.CircleView_ProgressBar
        android:id="@+id/Progress"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="50dp"
        app:Radius="100dp"
        app:StrokeWidth="10dp"
        app:CircleColor="@color/colorWhite"
        app:RingColor="@color/colorGrey"
        app:RingProgressColor="@color/colorRed"
        app:TextProgressColor="@color/colorPrimary"
        app:CurrentProgress="59"
        />


相关文章
|
XML Android开发 数据格式
自定义View入门
自定义View入门
|
XML 前端开发 Android开发
Android自定义View-入门(明白自定义View和自定义ViewGroup)
为什么要自定义View? 主要是Andorid系统内置的View 无法实现我们的 需求,我们需要针对我们的业务需求定制我们想要的 View.
130 0
Android自定义View-入门(明白自定义View和自定义ViewGroup)
|
前端开发 Android开发
Android进阶之绘制-自定义View完全掌握(四)
Android进阶之绘制-自定义View完全掌握(四)
107 0
Android进阶之绘制-自定义View完全掌握(四)
|
前端开发
自定义View -简单的 SwitchView
前言 实现一个简单的滑动开发,效果图如下: switchView完整版本 分析 平分整个View为两份 平分VIew 测量字体的高度和宽度,确定左右View的文字的位置并进行绘制 确定字体的位置和绘制 绘制...
1029 0
|
XML Android开发 数据格式
3.6 自定义View (3.6.2)
本文对应项目的码云地址:https://gitee.com/wanchuanxy/AndroidHeroesTest/tree/master/3/SystemWidget 3.6.2 创建复合控件 创建复合控件可以很好地创建出具有重用功能的控件集合。
658 0
|
前端开发 Android开发
3.6 自定义View (3.6.1)
本文对应项目的码云地址:https://gitee.com/wanchuanxy/AndroidHeroesTest/tree/master/3/SystemWidget Android给我们提供了丰富的组件库来创建丰富的UI效果,同时也提供了非常方便的拓展方法。
735 0
|
Android开发
自定义View解决滑动冲突
最近在读Android开发艺术探索,本文作为自己对view的滑动冲突的理解和实践记录 而滑动冲突,需要了解Android的事件分发机制,如果这个还有些疑惑的地方,请参考这篇文章,以及其中的参考文章 还需要View的Measure和Layout的相关知识View的Measure流程总结 自定义view注意 1.
1083 0
|
XML 数据格式
自定义View(一)
一、初探 大家都知道自定义view需要重写onMeasure和onDraw两个方法,这里我们在讲这两个方法前首先看看什么时候走这两个方法,这里只是大致讲讲方便理解,详细的之后会说。
750 0
|
XML 数据格式 容器
自定义View(二)简单的viewgroup
上篇讲了自定义View的简单实现,这章就趁热打铁,讲讲自定义ViewGroup的简单实现。 一、初探 和上篇一样,看看ViewGroup的绘制是什么走的。
782 0