自定义View学习之12/1

感谢AigeStudio提供的自定义view讲解(地址http://blog.csdn.net/aigestudio)下面是我看了Aige的讲解之后自己的理解以及demo,有说错的地方欢迎大家指出。

在这里自定义一个圆形等级条的view来加强自己对自定义的理解。

思路:

1、需要画一个背景圆,再需要一个覆盖在背景圆上面的进度圆。

2、使用线程让进度圆产生动画。

3、在进度圆达到圆满的时候回到原点,给个回调。

现在我们先画出一个空心圆。

代码块

    /** 背景圆的画笔 */
    private Paint paint;
    /** 进度条圆的画笔 */
    private Paint paint1;
    /** 设置矩阵的坐标点 */
    private RectF rectF;

    /** 屏幕的高度 */
    private int width = 0;
    /** 园的半径 */
    private int circleRadius = 0;
    /** 园的y轴起始坐标 */
    private int circleStartY = 20;
    /** 园的y轴终点坐标 起始坐标加上园的半径*2 */
    private int circleEndy = 0;

    /**我一般喜欢直接写3个构造方法,方便引用*/
    public CircleView(Context context) {
        super(context);
        init(context);
    }
    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**初始化画笔*/
    private void init(Context context){
        paint = new Paint();// 布局xml里面引用
        paint1 = new Paint();// 布局xml里面引用

        paint.setAntiAlias(true);// 设置抗锯齿
            paint.setColor(getResources().getColor(R.color.char_circlebackground));
        paint.setStyle(Style.STROKE);// 设置圆心掏空
        paint.setStrokeWidth(dip2px(context, 10));
        // 设置画笔形状 圆形,需要先设置画笔样式 SYROKE 或者 FILL_AND_STROKE
        paint.setStrokeCap(Paint.Cap.ROUND);

        paint1.setAntiAlias(true);// 设置抗锯齿
        paint1.setColor(getResources().getColor(R.color.char_circleplan));
        paint1.setStyle(Style.STROKE);
        paint1.setStrokeWidth(dip2px(context, 10));
        paint1.setStrokeCap(Paint.Cap.ROUND);

        width = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
        circleRadius = width / 4;
        circleEndy = circleStartY + circleRadius * 2;

        rectF = new RectF(width / 2 - circleRadius, circleStartY, width / 2 + circleRadius, circleEndy);// 弧形
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 第一个参数是圆的大小,根据矩阵来控制。第二个参数是在哪个点起始,已顺时针方向走,所以说90为正下方。0为最右边。第三个参数是圆的度数360为一圈
        canvas.drawArc(rectF, 90, 360, false, paint);
        //这里等级为4/1等级,所以是90
        canvas.drawArc(rectF, 90, 90, false, paint1);

    }
        /**传入dp,返回px*/
    public float dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (float) (dpValue * scale + 0.5f);
    }

效果如下:

效果已经画出来了。但是缺少点东西,现在view里面东西全是死的,得让他活起来,并且具有动画,满级之后自动反0操作。所以我加了以下代码


    /** 背景圆的画笔 */
    private Paint paint;
    /** 进度条圆的画笔 */
    private Paint paint1;
    /** 设置矩阵的坐标点 */
    private RectF rectF;

    /** 屏幕的高度 */
    private int width = 0;
    /** 园的半径 */
    private int circleRadius = 0;
    /** 园的y轴起始坐标 */
    private int circleStartY = 20;
    /** 园的y轴终点坐标 起始坐标加上园的半径*2 */
    private int circleEndy = 0;

    /** 初始进度 */
    private float currentPorcent = 0;
    /** 进度是多少 */
    private float maxPorcent = 0;

    /**满级回调*/
    public RestoreCirclr rc;
    /** 是否还原 */
    public boolean isRestore = false;

    /**我一般喜欢直接写3个构造方法,方便引用*/
    public CircleView(Context context) {
        super(context);
        init(context);
    }
    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**初始化画笔*/
    private void init(Context context){
        paint = new Paint();// 布局xml里面引用
        paint1 = new Paint();// 布局xml里面引用

        paint.setAntiAlias(true);// 设置抗锯齿
        paint.setColor(getResources().getColor(R.color.char_circlebackground));
        paint.setStyle(Style.STROKE);// 设置圆心掏空
        paint.setStrokeWidth(dip2px(context, 10));
        // 设置画笔形状 圆形,需要先设置画笔样式 SYROKE 或者 FILL_AND_STROKE
        paint.setStrokeCap(Paint.Cap.ROUND);

        paint1.setAntiAlias(true);// 设置抗锯齿
        paint1.setColor(getResources().getColor(R.color.char_circleplan));
        paint1.setStyle(Style.STROKE);
        paint1.setStrokeWidth(dip2px(context, 10));
        paint1.setStrokeCap(Paint.Cap.ROUND);

        width = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
        circleRadius = width / 4;
        circleEndy = circleStartY + circleRadius * 2;

        rectF = new RectF(width / 2 - circleRadius, circleStartY, width / 2 + circleRadius, circleEndy);// 弧形
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 第一个参数是圆的大小,根据矩阵来控制。第二个参数是在哪个点起始,已顺时针方向走,所以说90为正下方。0为最右边。第三个参数是圆的度数360为一圈
        canvas.drawArc(rectF, 90, 360, false, paint);
        //这里等级为4/1等级,所以是90
        canvas.drawArc(rectF, 90, currentPorcent, false, paint1);

        if (currentPorcent == 0) {
            handler.postDelayed(drawRunnable, 0);
        }
    }
    /**启动动画刷新界面*/
    public void invalidateView(){
        handler.postDelayed(drawRunnable, 0);
    }

    private Handler handler = new Handler();

    Runnable drawRunnable = new Runnable() {

        @Override
        public void run() {
            if (!isRestore) {//有经验时动画
                if (currentPorcent >= maxPorcent) {
                    currentPorcent = maxPorcent;
                    invalidate();
                    //移除当前Runnable
                    handler.removeCallbacks(drawRunnable);
                } else {
                    currentPorcent += 5;//这里是动画速度,当前为5。可自己去调试经验值增长速度
                    handler.postDelayed(drawRunnable, (long) (1300 / maxPorcent));
                    invalidate();
                }
                if (currentPorcent == 360) {
                    if (rc != null) {
                        isRestore = rc.OnRestoreCirclr();
                        handler.postDelayed(drawRunnable, 0);
                    }
                }
            } else {//满级之后经验条动画返回0进度
                if (currentPorcent <= 0) {
                    currentPorcent = 0;
                    invalidate();

                    handler.removeCallbacks(drawRunnable);
                } else {
                    currentPorcent -= 3;//这里是动画速度,当前为3。可自己去调试经验值反0速度
                    handler.postDelayed(drawRunnable, (long) (1300 / maxPorcent));
                    invalidate();
                }
            }
        }
    };

    public boolean isRestore() {
        return isRestore;
    }
    public void setRestore(boolean isRestore) {
        this.isRestore = isRestore;
    }
    /** 设置等级进度,传入升级经验,以及当前经验  maxPorcent就是当前经验在升级经验占的百分比*/
    public void setCirclePlan(int max, int current) {
        maxPorcent = (int) (((float)360 / (float)max) * current);
    }

    /**传入dp,返回px*/
    public float dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (float) (dpValue * scale + 0.5f);
    }   

    /** 设置园线的颜色 */
    public void setCircleColor(int color) {
        paint.setColor(color);
    }

    /** 设置进度线的颜色 */
    public void setCirclePlanColor(int color) {
        paint1.setColor(color);
    }

    public void setRc(RestoreCirclr rc) {
        this.rc = rc;
    }

    public interface RestoreCirclr {
        public boolean OnRestoreCirclr();
    }

在mainActivity里面调用代码如下:

    private CircleView circleView;
    /** 升级经验为100 */
    private int max ;
    /** 目前经验值为10 */
    private int current ;
    /** 经验加10 */
    private Button button_1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        circleView = (CircleView) findViewById(R.id.circleView);
        button_1 = (Button) findViewById(R.id.button_1);
        button_1.setOnClickListener(this);

        max = 100;
        current = 10;

        circleView.setCirclePlan(max, current);// 进度条已满 升级数是100,当前经验数是10

        circleView.setRc(new RestoreCirclr() {// 满级之后的回调

            @Override
            public boolean OnRestoreCirclr() {
                //满级之后的操作   返回true就回到原点
                current=0;
                return true;
            }
        });

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button_1:
            current += 10;
            circleView.setRestore(false); //false经验值增加
            circleView.setCirclePlan(max, current);
            circleView.invalidateView();//刷新view
            break;
        }
    }

效果图:

由于本人第一次写博客,不会制作那种可动的gif图片,所以导致动画效果看不见。如果各位有兴趣的看看动画效果可去(http://download.csdn.net/detail/u013895206/8431395)这个地址下载源码。

本篇自定义view学习就到这里,欢迎大家指正错误。互相学习。第一次专注的写博客,希望各位大大多多支持。提前祝福兄弟姐妹们新年快乐。。

未完待续、、、

时间: 2024-10-26 23:06:04

自定义View学习之12/1的相关文章

自定义View学习之12/7(进度条之混合模式)

今天重点内容是我们学习自定义view里面的混合模式,其实我们的画布就跟photoshop一样,是个图层关系,一层盖着一层,这样就导致有很多种覆盖模式,这就是我们今天的主题,"混合模式". 好,现在我们来看下这个模式的说明图: canvas原有的图片 可以理解为背景 就是dst 新画上去的图片 可以理解为前景 就是src 从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值: 1.PorterDuff.Mode.CLEAR 所绘制不会提交到画布上. 2.Porte

Android自定义View学习笔记04

Android自定义View学习笔记04 好长时间没有写相关的博客了,前几周在帮学姐做毕设,所以博客方面有些耽误.过程中写了一个类似wp的磁贴的view,想再写个配套的layout,所以昨天看了一下自定义viewGroup的相关知识-晚上睡觉想了一下可行性不是很高-代码量还不如直接自己在xml上写来得快,速度上也是个问题.今天看了一下张鸿洋老师的Android 自定义View (三) 圆环交替 等待效果这篇博文,再加上前一段时间看到的一幅图,结合之前写的一个圆形imageView的实现博文And

Android自定义View学习笔记03

Android自定义View学习笔记03 预备知识 BitMap类 BitMap位图类,其中有一个嵌套类叫Bitmap.Config,内部有四个枚举值.这个类的作用是定义位图存储质量,即存储一个像素的位数,以及是否能显示透明.半透明颜色(Possible bitmap configurations. A bitmap configuration describes how pixels are stored. This affects the quality (color depth) as w

Android自定义view学习笔记02

Android自定义view学习笔记02 本文代码来自于张鸿洋老师的博客之Android 自定义View (二) 进阶 学习笔记,对代码进行些许修改,并补充一些在coding过程中遇到的问题.学习的新东西. 相关代码 //CustomImageView.java package mmrx.com.myuserdefinedview.textview; import android.content.Context; import android.content.res.TypedArray; im

Android 自定义View学习(2)

上一篇学习了基本用法,今天学一下稍微复杂一点的,先看一下效果图 为了完成上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="speed" format="integer" /> <attr name="circleColor"

20170831工作日记--自定义View学习

学习了LayoutInflater的原理分析.视图的绘制流程.视图的状态及重绘等知识,按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.那么下面我们就来依次学习一下,每种方式分别是如何自定义View的. (一)自绘控件 自绘控件的意思就是,这个View上所展现的内容全部都是我们自己绘制出来的.绘制的代码是写在onDraw()方法中的.参考相关博客 http://blog.csdn.net/guolin_blog/article/details/1735

自定义View学习

我一直在学习Android,但是一直对自定义View不是太熟悉,这几天看了下,分享下: 自定义View从他的实现方式可以分成三类 (1) 自己绘制控件:就是通过继承View来进行绘制,只要继承 了View  复写他的onDraw()方法就可以进行简单的绘制: 例如这样的代码: @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); mCanv

【转载】自定义View学习笔记之详解onMeasure

网上对自定义View总结的文章都很多,但是自己还是写一篇,好记性不如多敲字! 其实自定义View就是三大流程,onMeasure.onLayout.onDraw.看名字就知道,onMeasure是用来测量,onLayout布局,onDraw进行绘制. 那么何时开始进行View的绘制流程,这就要从ViewRoot和DecorView的概念说起. ViewRoot对应于ViewRootImpl类,是连接WindowManager和DecorView的纽带,View的三大绘制流程都是通过ViewRoo

Android——自定义View(学习Android开发与艺术探索)

ViewRoot和DecorView ViewRoot对应于ViewRootImpl类,是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的.在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联. View的绘制流程从ViewRoot的performTraversals开始,经过