您的位置:首页 > 移动开发 > Android开发

模仿实现360桌面水晶球式的一键清理特效

2013-08-14 20:20 357 查看
半年前,鄙人想搞一下 android一键清理的特效,于是乎研究了一下市面上各个产品的界面效果,发现360桌面的水晶球效果很细腻,所以就试着模仿了一下。今天翻阅以前写的代码,刚好看到了它,所以就想把它分享出来,供大家拍砖。


先上一副截图,看看原版的效果:



其实360的这个界面效果,最细腻的地方在于它在水面的最上层,覆盖了一张具有立体效果的水面图片,这样用户看起来,这个水晶球的浮动效果就很有立体的感觉了。

要想实现这个动画特效,以我的思路看来,只需要解决两个关键点就可以了:

1.利用clipdrawable对背景带有颜色的图片进行切割

2.对最上层的那张立体图片,进行缩放和上下平移,这样就可以达到跟背景图片融合为一体的效果了。

稍候我会把这个demo工程继续上传到csdn上来,所以项目中用到的素材图片,是如何分配的,大家可以把demo下载下来后,自己研究一下,还是有几个细节是需要向360学习的。

下面我们开始讲解代码:

首先,我先把项目中用到的xml文件贴出来,供大家参考:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<ImageView
android:id="@+id/image_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/taskmanager_background"
android:src="@drawable/task_killer_full_clip"/>

<ImageView
android:id="@+id/image_waterlevel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/taskmanager_circle_full_waterlevel"/>

<ImageView
android:id="@+id/image_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/taskmanager_water_top"/>
</RelativeLayout>
id号为image_waterlevel的控件,就是用来承载那张立体水面的空间。

id号为image_backd的空间,就是带有背景颜色的空间,android:src 所引用的drawable就是一个自定义的clipdrawable的xml,下面我把它的xml贴出来:

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/taskmanager_circle_full"
android:clipOrientation="vertical"
android:gravity="bottom">
</clip>
这里的几个参数需要注意一下,drawable引用的资源文件就是res下面真实的图片资源。clipOrientation属性指的是图片的切割是按什么方向切割的,这里我们选择的是垂直方向切割。gravity属性指的是图片从哪个位置开始切割,我们这里选择从底部开始切割。

用到的几个xml主要就这些,另外还有两个clipdrawable的xml,不过属性设置都一样,只是引用的背景颜色图片不一样。大家可以从demo工程中看到。

下面我们开始讲解代码:

package com.example.taskkillerdemo;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.graphics.drawable.ClipDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class MainActivity extends Activity implements OnClickListener{

final int CLEANTASK = 1;
final int CLEANNUMBER = 10;//水面每次变化是时,clipdrawable变化的程度,大家可以自己随意修改这个数值,用来控制水面变化的速度。

ImageView imageSrc;//用来显示液体颜色的控件
ImageView waterLevel;//用来显示睡眠的那张图片,有了这张图片的修饰,整个水晶球的水面才有了立体的效果。这个设计真的好巧妙
final int TOTALLEVEL = 10000;//clipdrawable的切割范围,clipdrawable的切割范围是从0到10000
int actualLevel;//表示clipdrawable实时的切割数值,在初始化方法中,我们会将它赋值为8000
float radius;//液体颜色那张图片的半径

private Timer timer;
private TimerTask task;

private Handler hand;

boolean isDown = true;//这个变量用来判断水面现在是出于下降的状态还是上升的状态
boolean isOver;//timer每次循环都会根据它来判断handler是否已经把上次的动画效果处理完,如果还没有处理完,那就不向handler发送新的消息

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

/**
* 这个handler用来跟timer交互,实时更改水晶球水面的变化和背景颜色
*/
hand = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what == CLEANTASK){
//每次开始处理动画时,把isover设置成false,这样timer就不会再发新的消息过来了。
isOver = false;

//下面的代码用来判断水面是否已经下降到了底部或者回升到了最大值
if(isDown){
actualLevel = (actualLevel-CLEANNUMBER)>=0?(actualLevel-CLEANNUMBER):0;
if(actualLevel==0){
//当下降到最底部时,isDown设为false,后面handler在接受到消息时,就开始处理上升的动画
isDown = false;
}
}else{
actualLevel = (actualLevel+CLEANNUMBER)<=8000?(actualLevel+CLEANNUMBER):8000;
if(actualLevel==8000){
//当回升到最上层时,isDown设为true,本次动画过程彻底结束,timer控制器注销。
isDown = true;
task.cancel();
task = null;
timer.cancel();
timer = null;
}
}

//根据clipdrawable切割的范围,来更换背景颜色和立体水面的颜色。
if(actualLevel>=6000){
imageSrc.setImageResource(R.drawable.task_killer_full_clip);
waterLevel.setImageResource(R.drawable.taskmanager_circle_full_waterlevel);
}else if(actualLevel<6000&&actualLevel>4000){
imageSrc.setImageResource(R.drawable.task_killer_mid_clip);
waterLevel.setImageResource(R.drawable.taskmanager_circle_mid_waterlevel);
}else{
imageSrc.setImageResource(R.drawable.task_killer_low_clip);
waterLevel.setImageResource(R.drawable.taskmanager_circle_min_waterlevel);
}

ClipDrawable clip = (ClipDrawable) imageSrc.getDrawable();
clip.setLevel(actualLevel);
waterLevelChange();

//每次动画处理结束后,把isover设置成true,这样timer又会发新的消息过来
isOver = true;
}
}
};

initData();
initView();
}

/**
* 初始化数据
*/
void initData(){
actualLevel = 8000;
isOver = true;
}

/**
* 初始化视图
*/
void initView(){
imageSrc = (ImageView)findViewById(R.id.image_back);
waterLevel = (ImageView)findViewById(R.id.image_waterlevel);

imageSrc.setOnClickListener(this);

//这里获取clipdrawable的实例,获取背景图片的半径值,然后对clipdrawable进行切割,对水面进行平移缩放
ClipDrawable clip = (ClipDrawable) imageSrc.getDrawable();
radius = clip.getIntrinsicHeight()/2;
clip.setLevel(actualLevel);
waterLevelChange();
}

/**
* 计算水面的那张图片,缩放的大小和上下平移的大小,运用勾股定理来计算
*/
void waterLevelChange(){
//默认水面那张图片处在中间位置,那么她随着水面上下移动的距离应该为:
float transY = ((5000-actualLevel)/5000.0f)*radius;
//根据上面的计算值,然后根据勾股定理,可以计算出水面在水平方向的缩放比例:
float scaleX= 0.0f;
if(actualLevel!=5000){
scaleX = (float) (Math.sqrt(radius*radius - transY*transY)/radius);
}else{
scaleX = 1f;
}
//这里设置水面图片的上下平移值和水平缩放值
waterLevel.setTranslationY(transY);
waterLevel.setScaleX(scaleX);
}

@Override
public void onClick(View v) {
//每次点击时,看看现在水晶球是否处于动画状态,如果不处于,才进行新的动画处理。这里的判断规则可以随意规定,我就用最简单粗暴的方式来实现了。
if(actualLevel==8000){
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
//timer每次循环都会根据它来判断handler是否已经把上次的动画效果处理完,如果还没有处理完,那就不向handler发送新的消息
if(isOver){
Message msg = new Message();
msg.what = CLEANTASK;
hand.sendMessage(msg);
}
}
};
timer.schedule(task, 0, 1);
}
}
}

用到的代码就这么一点点,因为写的比较仓促,代码结构不是很好,没有进行封装拆分,还望大家谅解。分享出来,就是希望能够在动画效果方面,给大家提供一种思路,如果文章里有误人子弟的地方,请及时告诉我,鄙人定会面壁思过,阿弥陀佛!!!


本来想上传一张GIF的demo图片,可是每次上传之后,都是显示为静态图片。好费解。。。。

下面是demo的下载地址:

http://download.csdn.net/detail/pringlee2011/5946421
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息