涉及技术

自定义控件、自定义控件动画

第一步:继承自定义控件

虽然已经实现了需要的控件,但是这个控件的功能还是不够强大,使用起来也不够方便。举个例子:让控件的颜色随着能力值的大小而不同或者是点击之后有动画效果等。此时一个简简单单的控件就不行了,接下来先让控件变得更方便使用。
继承上篇文章创建的自定义控件Ring,首先让这个控件更容易控制其颜色,使用如下形式创建的时候是很容易控制颜色的:
也就是只需要传入 名称、技能值、技能颜色 就可以创建这个控件,根据这个思路,我们很容易写出下面的代码(其中颜色来自此网站,感兴趣的朋友可以看看):
    public Skill(Context context, String name, int percent, int styleType) {
        super(context);
        this.context = context;
        switch (styleType) {
            case BLUE:
                init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#004884"), percent);
                break;
            case GREEN:
                init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#36B77D"), percent);
                break;
            case RED:
                init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#ED1654"), percent);
                break;
            case PINK:
                init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#EB9F9F"), percent);
                break;
            case YELLOW:
                init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#E2A937"), percent);
                break;
        }

这个init函数是父类Ring的函数。

接下来还可以实现一个根据能力值来自动指明颜色的构造方法,并且可以使用这个方法批量的来生成不同颜色的控件,想到了这点,我们自然又定义了一个xml来存储数据,xml的格式在这里。xml解析不赘述,我使用的pull方式,解析到了数据就能使用循环和我们定义的构造器来自动生产控件了,构造器代码如下:
    public Skill(Context context, int id, String name, int percent) {
        super(context);
        this.id = id;
        this.context = context;

        if(percent >= 90) {
            init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#ED1654"), percent);
        } else if (percent >= 80) {
            init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#EB9F9F"), percent);
        } else if (percent >= 75) {
            init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#E2A937"), percent);
        } else if (percent >= 65) {
            init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#36B77D"), percent);
        } else {
            init(name, Color.WHITE, RING_WIDTH, Color.parseColor("#004884"), percent);
        }
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(UI_WIDTH,UI_WIDTH);
        this.setLayoutParams(lp);
    }

在PagerActivity中,解析到xml后可以如下的创建控件:

        if (skills != null) {
            LinearLayout ll = (LinearLayout) skills.findViewById(R.id.skills_layout);
            List> skillList = SkillsParser.getSkillsList(context);
            for (Map skill : skillList) {
                Skill o = new Skill(context, Integer.parseInt((String) skill.get("id")), (String) skill.get("name"),
                        Integer.parseInt((String) skill.get("point")));
                ll.addView(o);
            }
        }

其中构造器有一个id,是为了跳转Activity来服务的,下一步就会知道。

第二步:添加动画

我不是交互设计师,脑子只有这点想象力,所以就只能想出个发光的效果,呵呵,献丑了。大家如果有什么好的想法也可以自己实现试试,相信看了下面的代码大家应该会启发大家,以后什么样的特效都能做的出来。
我想做的是点击了控件之后,控件发出光波,然后页面变大淡出,后面的页面变小淡入,具体效果如下:
有了思路,接下来就分析代码应该怎么实现:
1.首先控件还是得画出来。
2.控件上发出光。
3.光闪完了之后进入下一个Activity。
其实分析一下还是挺简单的,第一步调用父类的onDraw就能实现,第二步借助触摸事件和变量来计数实现,第三步只需要稍微进行判断就可以。首先定义这样的一些变量来记录动画的一些信息:
我们还需要复写onTouchEvent函数,用于处理触摸事件:
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.i("Ring", "Action Up Speed: " + ANIMATE_SPEED);
            touched = true;
            ringAlpha = START_ALPHA;
            translateRadius = START_RADIUS;
            invalidate();
        }
        return true;
    }

将触摸标志设为true之后,调用invalidate来强制重绘,会调用onDraw,此时onDraw函数应该这样写:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(touched) {
            Paint p = new Paint();
            p.setStyle(Paint.Style.FILL);
            p.setColor(skillColor);
            p.setStrokeWidth(1);
            p.setAlpha(ringAlpha);
            int w = canvas.getClipBounds().width();//获取高度
            int c = w / 2;//计算中心点
            int inner = Math.round(c - this.ringWidth - translateRadius); //设置内圆半径
            canvas.drawCircle(c,c, inner, p);

            translateRadius -= ANIMATE_SPEED;
            ringAlpha -= ANIMATE_SPEED * 5;

            if(inner >= UI_WIDTH/2 || ringAlpha <= 0) {
                touched = false;
                Intent toSkill = new Intent(context, SkillActivity.class);
                toSkill.putExtra("id", id);
                context.startActivity(toSkill);
            }

            postInvalidateDelayed(20);
        }
    }

我们不停的绘制这个光圈(或者说光圆),直到光圈的透明度变为透明了或者光圈扩散到了看不见的地方。postInvalidateDelayed是为了控制动画播放的速度,降低帧率的。做完了这些,我们自定义控件的动画就完成了。动画虽然是小儿科,但是可以学习到做动画的方法,其实还有很多的方法可以产生自定义控件动画,有兴趣可以查一查,我见过的做的最漂亮的自定义控件和自定义控件动画是Timely,它的数字动画和背景颜色过渡简直看醉了,我就不给链接了,有兴趣的同学可以去百度一下安装看看,不过好像需要Android
4.2+还是4.0+,安装不了的可以看看宣传视频(Google的Android Design居然两次提到了这款应用)。

真·结尾 + 扯淡

四篇博文,写完了我的这个安卓简历,其实这个安卓简历我已经使用了,但是效果只能说:呵呵。我想去的那家公司还是连笔试都没有给我,我展示的安卓简历,hr也只是敷衍的看了一眼,点了下头。说实话心情有些低落,但是低落归低落,还是很感谢这个安卓简历。我真没想到第一篇博文能够被推荐到首页,也没想到有那么多人给我鼓励,很感动。进不进那个公司无所谓了,它要挑学校筛简历我也没什么办法,只能再默默的提高自己实力。
我的兴趣肯定不会因为这点小事而被打压,做更多的实践,J2EE的项目做的够多了,接下来就是Android和Hadoop,我从来不害怕学习新技术,学习新技术会让我很兴奋,自从大一开始,我就很享受这种解决问题的感觉,也许就是这种成就感,让我有动力来不断的学习。呵呵,扯多了,就到这吧,希望我后面能写出更好的文章吧~
分类: 前端

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注