今年一下已经过了一半了,时间其实过得很快,但是感觉自己总体上并没有什么大改变,年初的时候开始看一些书,东野圭吾的几本——《白夜行》《解忧杂货铺》《假面前夜》《假面饭店》《嫌疑人X的献身》,还看了大冰的几本书,为了装X看的《时间简史》,又看了《了不起的盖茨比》,最近又看了夏目漱石的《心》,自我安慰自己也是个读书人。其实呢,在看完盖茨比的时候,自己感觉好像没有看懂作者描述的盖茨比有多了不起,再看完《心》,发现自己太注重结果了,对于书中作者描述的人和事总想有一个定性答案,好像最后作者如果不在结尾的时候做一个中心思想陈述,这本书就是不完成的。联想到现实生活,对于感情对于人和事,自己总是这样,活的不够明白。正如一句话所说的:“天地生人,除大仁大恶两种,余者皆无大异。若大仁者,则应运而生,大恶者,则应劫而生。”,大家都是普通人罢了,喜怒哀乐,皆为常态。
一、前言
这个效果已经做出来很久了,但是之前因为工作的原因而没有整理出文章,初始目的是想写个炫酷的个人APP的,结果现在只写好了登录界面。先看下效果图:
这个效果其实是我在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);
}
画一个示意图: 上面部分为按钮的普通状态
如上所示,我们使用一个全局变量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开发工作。