炫酷的Meterial 登录界面实现

今年一下已经过了一半了,时间其实过得很快,但是感觉自己总体上并没有什么大改变,年初的时候开始看一些书,东野圭吾的几本——《白夜行》《解忧杂货铺》《假面前夜》《假面饭店》《嫌疑人X的献身》,还看了大冰的几本书,为了装X看的《时间简史》,又看了《了不起的盖茨比》,最近又看了夏目漱石的《心》,自我安慰自己也是个读书人。其实呢,在看完盖茨比的时候,自己感觉好像没有看懂作者描述的盖茨比有多了不起,再看完《心》,发现自己太注重结果了,对于书中作者描述的人和事总想有一个定性答案,好像最后作者如果不在结尾的时候做一个中心思想陈述,这本书就是不完成的。联想到现实生活,对于感情对于人和事,自己总是这样,活的不够明白。正如一句话所说的:“天地生人,除大仁大恶两种,余者皆无大异。若大仁者,则应运而生,大恶者,则应劫而生。”,大家都是普通人罢了,喜怒哀乐,皆为常态。

一、前言


这个效果已经做出来很久了,但是之前因为工作的原因而没有整理出文章,初始目的是想写个炫酷的个人APP的,结果现在只写好了登录界面。先看下效果图:

QQ20170525-095450-HD.gif

这个效果其实是我在dribbble上看到的设计图,找了些资料最终把它实现出来了,按钮部分自定义View使用的是网上找的一个人写的,我忘记保存作者的地址了,所以找不到链接啦。然后自己修改了部分效果。效果实现分两个部分,自定义按钮和动画跳转。

二、自定义按钮的绘制


自定义的登录按钮继承自TextView,方便绘制’登录‘的文字。按钮有两种形态,普通状态和圆形状态。根据自定义View的套路,我们先处理measure过程,在onMeasure中分别处理高度和宽度。这里没什么好说的,基本都是一个套路。然后是layout过程,不过因为我们继承的是TextView,不是一个ViewGroup类型,所以此步骤省略不用处理。最后就是draw过程,自定义View张啥样就全靠它了。按钮初始时为普通状态,普通状态左右两边各为一个半圆,中间一个矩形,代码如下:

    private RectF leftRectF = new RectF();
    private RectF mid = new RectF();
    private RectF rightRectF = new RectF();
    private void drawPrimaryPart(Canvas canvas) {
        //绘制左边的圆弧
        mPaint.setColor(colorValue);
        leftRectF.set(  commonValue, 0, commonValue + height, height);
        canvas.drawArc(leftRectF, 90, 180, true, mPaint);
        //绘制中间的矩形 这里可以将commonValue当做是0 然后用默认值去看代码 自己拿纸画画就出来了
        mid.set(height / 2 + commonValue, 0, (getMeasuredWidth() - height / 2) - commonValue, height);
        canvas.drawRect(mid, mPaint);
        //绘制右边的圆弧
        rightRectF.set((getMeasuredWidth() - height) - commonValue, 0, (getMeasuredWidth()) - commonValue, height);
        canvas.drawArc(rightRectF, -90, 180, true, mPaint);
    }

画一个示意图: 上面部分为按钮的普通状态


炫酷的Meterial 登录界面实现_第1张图片
hint_img.png

如上所示,我们使用一个全局变量commonValue 以及height,这个高度可以在onMeasure中根据实际设置得到,commonValue初始值默认为0。到此普通状态的登录按钮绘制完成。

接下来,当我们点击登录按钮,按钮会慢慢变成一个圆,代码如下:

  private void initAnimation() {
        //只计算一次
        if (!isFirstMeasure) {
            needScrollValue = (getMeasuredWidth() - height) / 2;
            endValue = needScrollValue;
            isFirstMeasure = !isFirstMeasure;
        }
        v = ValueAnimator.ofInt(startValue, endValue);
        v.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                commonValue = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        v.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                colorValue = DEFAULTCOLOR;
                if(STATE == CIRCLE){
                    STATE = NORMAL;
                    cancelArcAnimation();
                }else{
                    setText("");
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (commonValue == needScrollValue) {
                    startValue = needScrollValue;
                    endValue = 0;
                    STATE = CIRCLE;
                    initArcAnimation();
                } else {
                    setText(text);
                    STATE = NORMAL;
                    startValue = 0;
                    endValue = needScrollValue;
                }
            }
        });
        v.setDuration(DEFAULT_DELAY);
        v.start();
    }

我们来看一下代码,就是对当前的自定义View进行了一个动画操作而已。这里我们定义了一个startValue和一个endValue,通过监听器对动画的过程进行了监听,每当值有改变的时候都会回调onAnimationUpdate()方法。在这个方法当中,我们对commonValue对象进行了重新赋值,并调用了invalidate()方法,这样的话onDraw()方法就会重新调用,并且由于currentPoint对象的坐标已经改变了,那么绘制的位置也会改变,于是一个平移的动画效果也就实现了。

我们还可以通过addListener()方法监听动画的开始和结束,当平移动画开始时,会回调onAnimationStart方法,在这个方法里我们设置按钮的字显示为空,而且当点击按钮时按钮已经是CIRCLE状态,则点击后改变按钮状态变为普通状态,取消旋转动画;当平移动画结束后,commonValue的值等于我们设定的需要平移的距离大小时,开始旋转动画。如果commonValue的值不等于需要平移的距离大小,说明此时我们主动改变了当前按钮的状态,所以重置按钮的状态变为普通状态。

自定义登录按钮就说这么多,剩余的大家可以看我的demo。

三、Activity跳转动画


在这个动画,试验了集中方法都不太理想,现在来说一说。
先在登录界面设定一个颜色和登录按钮一样颜色的View(color_view),铺满全屏,设为gone。然后在点击按钮后,开始一个属性动画。代码如下:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void startAnimate() {
        int[] location = new int[2];
        btn_login.getLocationOnScreen(location);
        int x = location[0];
        int y = location[1];
        Animator mAnimator = ViewAnimationUtils.createCircularReveal(color_view,
                x + btn_login.getMeasuredWidth()/2,
                y + btn_login.getMeasuredHeight()/2,
                btn_login.getWidth()/2, login_content.getHeight());
        mAnimator.setDuration(400);
        mAnimator.setInterpolator(new AccelerateInterpolator());
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);

                Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                startActivity(intent);
                finish();
                overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                color_view.setVisibility(View.VISIBLE);
            }
        });
        mAnimator.start();
    }

在createCircularReveal方法中,将color_view作为动画的控制View传入,得到登录按钮的中心坐标并传入,起始半径为登录按钮变为圆形后的半径,终止半径为手机屏幕的高度。监听动画的状态,当动画开始时,将color_view从不可见设为可见,当动画结束后,跳转到主界面,然后finish掉当前界面即可。

到这里已经把登录效果做完了,因为关键方法ViewAnimationUtils.createCircularReveal的限制,此效果只能应用在Android5.0以上。最后附上源码地址:https://github.com/yinyiliang/MaterialLogin

最后,跪求深圳的Android开发工作。

你可能感兴趣的:(炫酷的Meterial 登录界面实现)