刚刚发现一个开源项目ShrinkButton 感觉挺漂亮的(作者的代码地址:https://github.com/wusp/IndicatorBox#shrinkbutton),
可以用在很多地方,登录的时候或者图片上传的时候,
代码不是很难就拿出来研究一下,并且稍微改动了一下更加符合自己的需求。简单介绍一下代码的思路.
ShrinkButton,设置圆角背景,radius 25dp, 高度45dp 当你点击按钮时候,button将会动态缩小自己的宽度。
利用属性动画里valueAnimator 将宽度缩小到与高度相等,圆角矩形按钮就变成了圆形按钮。此时再利用属性动画
画进度条。
就完成了,点击登录按钮,按钮变成了进度条的动作。很巧妙。
代码分析如下:
bt = (ShrinkButton)findViewById(R.id.login);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("gac", "login");
Toast.makeText(MainActivity.this, "login", Toast.LENGTH_SHORT).show();
}
});
调用如此简单,跟普通的button 调用一样。
那么它是在什么时候让button改变宽度的呢?因为调用了onClickListener.它应该在点击事件上做了文章。
在ShrinkButton 找到事件处理的函数如下:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (MotionEventCompat.getActionMasked(event)){
case MotionEvent.ACTION_DOWN:
if (!isWindowFocused){//如果界面还未完全显示 则此时不进行事件处理
return true;
}
if (animationState == STATE_EXPANDED){//当按钮的动作状态处于 扩展状态时候,(正常状态时候),此时点击事件发生,开始执行动画效果,
startWholeAnimation(); //并且应该onTouch返回fasle,不拦截onClickListener事件 ,按钮动作状态处于其它状态,
//this.callOnClick(); //此时onTouch返回true 拦截onClickListener 不让点击事件发生。
return false;
}else{
return true;
}
case MotionEvent.ACTION_UP:
return false;
}
return true;
}
在这里你可以找到按钮状态变化的入口点startWholeAnimatoin
此时你需要搞明白一个变量animationState
public static final int STATE_EXPANDED = ;//按钮属于正常状态
public static final int STATE_SHRINKING = ;//按钮属于 正在收缩动作的状态
public static final int STATE_SHRINKED = ;//按钮完成收缩动作的状态
public static final int STATE_PROGRESSING = ;//按钮处于进度条执行状态
public static final int STATE_EXPANDING = ;//按钮处于 由进度条变为正常状态的动作时候
作者代码命名挺规范的,基本看变量名就知道按钮的状态了。
public void startWholeAnimation(){
//animationState > 0 说明按钮此时不是正常状态,那么不管他处于什么状态,我们基本这个方法不需要执行了
//这个方法是让按钮从正常状态变为进度条状态 isWindowFocused 是界面是否显示的变量 界面没有显示直接return
if (animationState > || !isWindowFocused){
return;
}
//Initial those animation fraction firstly.
initAnimationParameters();
//初始化两个animation 收缩的animation和 进度条的animation
if (mShrinkingController == null || mProgressingController == null){
initShrinkingAnimationController();
initProgressingAnimationController();
}
if (mShrinkingController.isRunning() || mProgressingController.isRunning()){
mShrinkingController.end();
mShrinkingController.cancel();
mProgressingController.end();
mProgressingController.cancel();
}
//执行收缩animation动作
mShrinkingController.start();
}
我们先来分析initShrinkingAnimationController这个方法:
大概思路就是,动作开始时候讲button的文本内容去掉,然后,改变animastate这个变量状态,
在动作变化的时候,lp.width = (int) (mButtonInitialWidth - (mButtonInitialWidth - lp.height) * (float) animation.getAnimatedValue());
lp.width不断变化,根据这个值animation.getAnimatedValue(0,1)最后lp.width = lp.height;
这样button就会变成一个园。
此时动作结束按钮 startProgressAnimation开始执行进度条animation
//button 开始收缩的的动作
private void initShrinkingAnimationController(){
mShrinkingController = ValueAnimator.ofFloat(, );
mShrinkingController.setDuration(mShrinkingDuration);
mShrinkingController.setInterpolator(new DecelerateInterpolator());
mShrinkingController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//不断更新按钮的宽度
ViewGroup.LayoutParams lp = getLayoutParams();
//最后放缩到button 宽高值一样 ,高的设置为45dp
lp.width = (int) (mButtonInitialWidth - (mButtonInitialWidth - lp.height) * (float) animation.getAnimatedValue());
setLayoutParams(lp);
}
});
mShrinkingController.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//Make text disappeared.
buttonText = getText().toString();
setText(null);
// setEnabled(false);
animationState = STATE_SHRINKING;
}
@Override
public void onAnimationEnd(Animator animation) {
animationState = STATE_SHRINKED;
//放缩完成后 开始执行 进度条动作
//setBackground(generateCircleDrawable(Color.RED));
startProgressingAnimation();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
进度条的变化,作者将代码分离出来,利用一个接口。为什么别人代码写的总是那么好。
哎!
我改动的地方仅仅是,onTouch方法,我任务按钮处于正常状态,可以有点击事件。处于其它状态时候
点击事件应该不可以用的。