自定义View之会动的闪电

前两天在csdn手机端上看到貌似是有个app具有这个闪电的loading标志,非常感兴趣,正好目前正在学习自定义view,所以就想自己来实现一下,还好自己完成了,不是很难~

效果图:

由于是手机上截的图,所以没有弄成动态的,大家体谅一下哈。

下面是代码:

首先自定义view的属性,我先以属性的形式实现了,大家如果想做成loading的效果的话,可以自己去实现。。

```
<resources>
    <declare-styleable name="LightView">

        <attr name="light_color" format="color"></attr>
        <attr name="bg_color" format="color"></attr>
        <attr name="speed" format="integer"></attr>
        <attr name="lightSize" format="dimension"></attr>

    </declare-styleable>

</resources>

这里面我定义了light_color 首次闪电的绘制颜色,bg_color 第二次绘制闪电的颜色,后面如果绘制的话,其实就不分首次和下一次了,因为需要来回的转换,speed 绘制的速度,lightSize 闪电的高度

下面看具体实现代码:

public class LightView extends View {

    private int mLightColor, mBgColor, mspeed, addSpeed = 1, mLightSize;

    private Paint paint;

    private int mWidth, mHeight, measureHeight;

    private Path path;

    private boolean flag = false;

    private RectF rect;

    public LightView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LightView(Context context) {
        this(context, null);
    }

    public LightView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightView, defStyleAttr, 0);

        mLightColor = a.getColor(R.styleable.LightView_light_color, Color.YELLOW);

        mBgColor = a.getColor(R.styleable.LightView_bg_color, Color.RED);

        mspeed = a.getInt(R.styleable.LightView_speed, 1);

        mLightSize = a.getDimensionPixelSize(R.styleable.LightView_lightSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 17,
                getResources().getDisplayMetrics()));

        a.recycle();

        paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(1);
        paint.setColor(mLightColor);

        rect = new RectF();

        new Thread(new Runnable() {
            @Override
            public void run() {

                while (true) {

                    //高度的增量
                    addSpeed += 10;

                    postInvalidate();
                    try {

                        Thread.sleep(mspeed);//绘制的速度

                    } catch (Exception e) {

                        e.printStackTrace();
                    }

                }

            }
        }).start();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        measureHeight = MeasureSpec.getSize(heightMeasureSpec);

        if (heightMode == MeasureSpec.EXACTLY) {

            mHeight = Math.min(measureHeight, mLightSize);

        } else {

            mHeight = mLightSize;

        }

        mWidth = 2 * mHeight / 3;//以高度来决定view的宽度,设置宽度永远为高度的三分之二。。我是觉得这样好看。。=。=

        //使用path绘制闪电形状
        path = new Path();
        path.moveTo(mWidth * 2 / 3, 0);

        path.lineTo(mWidth / 2, 4 * mHeight / 9);
        path.lineTo(mWidth * 2 / 3, 4 * mHeight / 9);
        path.lineTo(mWidth / 3, mHeight);
        path.lineTo(mWidth / 2, 5 * mHeight / 9);
        path.lineTo(mWidth / 3, 5 * mHeight / 9);
        path.close();

        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        rect.top = 0;
        rect.left = 0;
        rect.right = mWidth;
        rect.bottom = mHeight;
        paint.setColor(Color.GREEN);
        canvas.drawRoundRect(rect, mWidth / 2, mHeight / 2, paint);

        //通过对切割画布的高度的判断,判断是否第二次的绘制已经完成,然后改变初次绘制的闪电的颜色
        if (addSpeed >= mHeight) {
            addSpeed = 0;

            if (!flag) {

                flag = true;

            } else {

                flag = false;

            }

        }

        if (!flag) {

            paint.setColor(mLightColor);

            canvas.drawPath(path, paint);//绘制完全的闪电

            paint.setColor(mBgColor);

            canvas.clipRect(0, 0, mWidth, addSpeed);//通过切割画布,在重新绘制闪电,并不会对已经绘制过的图形产生影响

            canvas.drawPath(path, paint);

        } else {

            paint.setColor(mBgColor);

            canvas.drawPath(path, paint);

            paint.setColor(mLightColor);

            canvas.clipRect(0, 0, mWidth, addSpeed);

            canvas.drawPath(path, paint);

        }

    }

}

其实这里面主要是对基础的path和clipRect的理解

找到一个介绍clipRect的不错的文章,摘过来

android的clip有以下两点疑问:

Clip(剪切)的时机

Clip中的Op的参数的意思。

通常咱们理解的clip(剪切),是对已经存在的图形进行clip的。但是,在android上是对canvas(画布)上进行clip的,要在画图之前对canvas进行clip,如果画图之后再对canvas进行clip不会影响到已经画好的图形。一定要记住clip是针对canvas而非图形。

接下来通过android自带的APIdemo Clipping例子详细讲述Clip中的Op的参数的意思。Android提供clipRect、clipPath和clipRegion剪切区域的API。

Op一共有 DIFFERENCE,INTERSECT,UNION,XOR, REVERSE_DIFFERENCE, REPLACE六种选择。

例子:

在canvas上剪切从(0,0)到(60,60)的方块。下图蓝色区域加紫色区域。

在canvas上剪切从(40,40)到(100,100)的方块。下图橄榄色区域加紫色区域。

在canvas上剪切从(0,0)到(100,100)的方块。

先在第二方块上加上Op参数例如:canvas.clipRect(40, 40, 100, 100, Region.Op. DIFFERENCE);

首先,需要搞清楚Op参数针对的对象。接着了解其含义。

Op参数针对的对象是之前剪切的区域以及当前要剪切的区域。

在本例中涉及到区域是从(0,0)到(60,60)的方块和从(40,40)到(100,100)的方块。

那有哪些含义呢?就是表示当前要剪切的区域与之前剪切过的之间的关系。

DIFFERENCE:之前剪切过除去当前要剪切的区域(蓝色区域)。

INTERSECT:当前要剪切的区域在之前剪切过内部的部分(紫色区域)。

UNION:当前要剪切的区域加上之前剪切过内部的部分(蓝色区域+紫色区域+橄榄色区域)。

XOR:异或,当前要剪切的区域与之前剪切过的进行异或。(蓝色区域+橄榄色区域)。

REVERSE_DIFFERENCE:与DIFFERENCE相反,以当前要剪切的区域为参照物,当前要剪切的区域除去之前剪切过的区域(橄榄色区域);

REPLACE:用当前要剪切的区域代替之前剪切过的区域。(橄榄色区域+紫色区域);

没带Op参数效果与INTERSECT的效果一样,两个区域的交集。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-10 17:20:13

自定义View之会动的闪电的相关文章

自定义View之实现日出日落太阳动效

以前也很羡慕网上大神随手写写就是一个很漂亮的自定义控件,所以我下决心也要学着去写,刚好最近复习了Android View的绘制流程知识,看来看去就是那些个知识点,没点产出总感觉很迷.现在个人呢用的是华为荣耀8手机,碰巧在看自带的天气APP时,滑到最下面看到那个动效图:日出时间和日落时间上边是一个半圆,白天任意的时刻(在日出和日落时间之间)都有对应一个太阳从日出时刻沿着半圆弧做动画特效,个人第一感觉就是:就拿这个来练练手啦!于是拿着笔和纸,画了模型图,甚至求什么sin.cos函数,有点过分了哈,还

自定义View之圆形水波扩散动效

这个效果做出来以后,真的美极了!放在你的应用中,无疑增添了光彩! 效果图    其实,第一种效果,才是产品的需求要的效果.第三种效果,是不是很熟悉?支付宝的咻一咻!哈哈,无意中,我就写出来了. 实现步骤 1.attrs.xml定义属性 <declare-styleable name="WaveView"> <!--圆颜色--> <attr name="wave_color" format="color"/> &

自定义View 篇三 《手动打造ViewPage》

有了之前自定义View的理论基础,有了ViewPage.事件分发机制.滑动冲突.Scroller使用等相关知识的铺垫,今天纯手动打造一款ViewPage. 1.完成基本的显示: 在MainActivity中: public class MainActivity extends AppCompatActivity { private MyViewPage mViewPage; int[] imageIds = new int[]{ R.drawable.pic_0, R.drawable.pic_

iOS开发——笔记篇&amp;关于字典plist读取/字典转模型/自定义View/MVC/Xib的使用/MJExtension使用总结

关于字典plist读取/字典转模型/自定义View/MVC/Xib的使用/MJExtension使用总结 一:Plist读取 1 /******************************************************************************/ 2 一:简单plist读取 3 4 1:定义一个数组用来保存读取出来的plist数据 5 @property (nonatomic, strong) NSArray *shops; 6 7 2:使用懒加载的方

自定义View实现钟摆效果进度条PendulumView

在网上看到了一个IOS组件PendulumView,实现了钟摆的动画效果.由于原生的进度条确实是不好看,所以想可以自定义View实现这样的效果,以后也可以用于加载页面的进度条. 废话不多说,先上效果图 底部黑边是录制时不小心录上的,可以忽略. 既然是自定义View我们就按标准的流程来,第一步,自定义属性自定义属性 建立属性文件 在Android项目的res->values目录下新建一个attrs.xml文件,文件内容如下: [html] view plain copy <?xml versio

Android自定义View(二)

前言 魅族手机的闹钟应用中有个倒计时,这个控件还是蛮有趣的.左边是魅族闹钟,右边是我们最终实现的效果,虽然有些细节还需优化,不过基本上已经达到了想要的效果,我们先来就来看看如何实现吧. 分析 确定宽高 对一个Android自定义控件来说,一般都经过三个步骤 onLayout() onMeasure() onDraw() onLayout明确子控件在父控件中的位置(本控件不需要重写),onMeasure是确定控件的大小(宽.高),而onDraw是我们重点关注的方法,我们需要在这个方法中写入显示Vi

Android_自定义view动画按钮

昨天偶偶然看见UI 给的一个交互的效果,原图如下 就是下面的loginbutton,于是大概模仿了一下, 并没有做这个UI的全部效果,有兴趣的可以完善后面展开的效果 下面是demo的button效果 这个View用到的知识点比较简单: view的坐标系知识,(大家没有不熟悉的吧) view的canvas基本API(画矩形,画扇形,) view的自定义属性(attr提供选项) 属性动画的知识(老生常谈的知识,ObjectAnimation和ValueAniamtion) 下面我们就一步步实现这个b

Android自定义View——仿vivo i管家病毒扫描动画效果

技术是永无止境的,如果真的爱技术,那就勇敢的坚持下去.我很喜欢这句话,当我在遇到问题的时候.当我觉得代码枯燥的时候,我就会问自己,到底是不是真的热爱技术,这个时候,我心里总是起着波澜,我的答案是肯定的,我深深的爱着这门技术. 今天我们继续聊聊Android的自定义View系列.先看看效果吧: 这个是我手机杀毒软件的一个动画效果,类似于雷达搜索,所以用途还是很广泛的,特别是先了解一下这里的具体逻辑和写法,对技术的进步一定很有用. 先简单的分析一下这里的元素,主要有四个圆.一个扇形.还有八条虚线.当

Android UI 绘制过程浅析(五)自定义View

前言 这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇.再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章<带你一步步深入了解View>后进行的实践. 前面依次了解了inflate的过程,以及绘制View的三个步骤:measure, layout, draw.这一次来亲身实践一下,通过自定义View来加深对这几个过程的理解. 自定义View的分类 根据实现方式,自定义View可以分为以下3种类型. 自绘控件.View的绘制代码(onDraw