来自:http://www.2cto.com/kf/201404/292480.html
昨晚没事手机下载了一些APP,发现现在仿win8的主界面越来越多,在大家见惯了类GridView或者类Tab后,给人一种耳目一新的感觉。今天在eoe上偶然发现已经有人实现了这个功能的源码(地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=327557),马上下载跑了一下,效果很炫,但是有些bug,比如点击速度特别快时图像会被放大,以及点击时会触发两次点击事件。
本例子基于eoe中这位大神的实现,做了一些简化,和bug的修复。
效果:
首先普及一个小知识点:
我们在项目中有时候需要一个缓慢的梯度数据,例如:控件的宽度以一定的比例增加,然后以相同的比例还原到原来的长度。
1
2
3
4
5
6
7
8
9
10
|
package
com.zhy._01;
public
class
Test2
{
public
static
void
main(String[] args)
{
float
val =
1
;
float
s =
0
.85f;
int
i =
0
;
s = (
float
) Math.sqrt(
1
/ s);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
System.out.println(val);
while
(i <
5
)
{
val = val *s ;
System.out.println(val);
i++;
}
s =
0
.85f;
i =
0
;
s = (
float
) Math.sqrt(s);
while
(i <
5
)
{
val = val *s ;
System.out.println(val);
i++;
}
}
}
|
输出结果:
1
2
3
4
5
6
7
8
9
10
11
|
1.0
1.0846523
1.1764706
1.2760615
1.384083
1.5012488
1.384083
1.2760615
1.1764706
1.0846523
1.0
|
很完美吧,基本是个对称的梯度数据,梯度的幅度由代码中的s觉得,越接近1幅度越小,反之则反之。
好了下面开始代码:
1、布局文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<!--?xml version=
1.0
encoding=utf-
8
?-->
<linearlayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
android:gravity=
"center"
android:background=
"@drawable/bkg_img_default"
>
<linearlayout android:orientation=
"vertical"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
>
<linearlayout android:orientation=
"horizontal"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
>
<linearlayout android:orientation=
"vertical"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
>
<com.ljp.ani01.myimageview android:id=
"@+id/c_joke"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/left_top"
android:scaletype=
"matrix"
android:layout_margin=
"2dp"
>
<com.ljp.ani01.myimageview android:id=
"@+id/c_idea"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/left_bottom"
android:scaletype=
"matrix"
android:layout_margin=
"2dp"
>
</com.ljp.ani01.myimageview></com.ljp.ani01.myimageview></linearlayout>
<com.ljp.ani01.myimageview android:id=
"@+id/c_constellation"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/right"
android:scaletype=
"matrix"
android:layout_margin=
"2dp"
>
</com.ljp.ani01.myimageview></linearlayout>
<com.ljp.ani01.myimageview android:id=
"@+id/c_recommend"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/bottom"
android:scaletype=
"matrix"
android:layout_margin=
"2dp"
>
</com.ljp.ani01.myimageview></linearlayout>
</linearlayout>
|
布局文件,完成了上面效果图的静态效果,如果你不需要添加点击动画,或者只需要很简单的点击效果,那么就已经完成这样的菜单的编写,再添加个backgroud自定义下点击效果就好了。当然,我们这里有个比较柔和的点击动画,有自定义的ImageView完成。
2、MyImageView.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
package
com.ljp.ani01;
import
android.content.Context;
import
android.graphics.Matrix;
import
android.graphics.drawable.BitmapDrawable;
import
android.graphics.drawable.Drawable;
import
android.os.Handler;
import
android.util.AttributeSet;
import
android.util.Log;
import
android.view.MotionEvent;
import
android.widget.ImageView;
public
class
MyImageView
extends
ImageView
{
private
static
final
String TAG = MyImageView;
private
static
final
int
SCALE_REDUCE_INIT =
0
;
private
static
final
int
SCALING =
1
;
private
static
final
int
SCALE_ADD_INIT =
6
;
/**
* 控件的宽
*/
private
int
mWidth;
/**
* 控件的高
*/
private
int
mHeight;
/**
* 控件的宽1/2
*/
private
int
mCenterWidth;
/**
* 控件的高 1/2
*/
private
int
mCenterHeight;
/**
* 设置一个缩放的常量
*/
private
float
mMinScale =
0
.85f;
/**
* 缩放是否结束
*/
private
boolean
isFinish =
true
;
public
MyImageView(Context context)
{
this
(context,
null
);
}
public
MyImageView(Context context, AttributeSet attrs)
{
this
(context, attrs,
0
);
}
public
MyImageView(Context context, AttributeSet attrs,
int
defStyle)
{
super
(context, attrs, defStyle);
}
/**
* 必要的初始化
*/
@Override
protected
void
onLayout(
boolean
changed,
int
left,
int
top,
int
right,
int
bottom)
{
super
.onLayout(changed, left, top, right, bottom);
if
(changed)
{
mWidth = getWidth() - getPaddingLeft() - getPaddingRight();
mHeight = getHeight() - getPaddingTop() - getPaddingBottom();
mCenterWidth = mWidth /
2
;
mCenterHeight = mHeight /
2
;
Drawable drawable = getDrawable();
BitmapDrawable bd = (BitmapDrawable) drawable;
bd.setAntiAlias(
true
);
}
}
@Override
public
boolean
onTouchEvent(MotionEvent event)
{
switch
(event.getAction())
{
case
MotionEvent.ACTION_DOWN:
float
X = event.getX();
float
Y = event.getY();
mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);
break
;
case
MotionEvent.ACTION_UP:
mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);
break
;
}
return
true
;
}
/**
* 控制缩放的Handler
*/
private
Handler mScaleHandler =
new
Handler()
{
private
Matrix matrix =
new
Matrix();
private
int
count =
0
;
private
float
s;
/**
* 是否已经调用了点击事件
*/
private
boolean
isClicked;
public
void
handleMessage(android.os.Message msg)
{
matrix.set(getImageMatrix());
switch
(msg.what)
{
case
SCALE_REDUCE_INIT:
if
(!isFinish)
{
mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);
}
else
{
isFinish =
false
;
count =
0
;
s = (
float
) Math.sqrt(Math.sqrt(mMinScale));
beginScale(matrix, s);
mScaleHandler.sendEmptyMessage(SCALING);
}
break
;
case
SCALING:
beginScale(matrix, s);
if
(count <
4
)
{
mScaleHandler.sendEmptyMessage(SCALING);
}
else
{
isFinish =
true
;
if
(MyImageView.
this
.mOnViewClickListener !=
null
&& !isClicked)
{
isClicked =
true
;
MyImageView.
this
.mOnViewClickListener.onViewClick(MyImageView.
this
);
}
else
{
isClicked =
false
;
}
}
count++;
break
;
case
6
:
if
(!isFinish)
{
mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);
}
else
{
isFinish =
false
;
count =
0
;
s = (
float
) Math.sqrt(Math.sqrt(
1
.0f / mMinScale));
beginScale(matrix, s);
mScaleHandler.sendEmptyMessage(SCALING);
}
break
;
}
}
};
protected
void
sleep(
int
i)
{
try
{
Thread.sleep(i);
}
catch
(InterruptedException e)
{
e.printStackTrace();
}
}
/**
* 缩放
*
* @param matrix
* @param scale
*/
private
synchronized
void
beginScale(Matrix matrix,
float
scale)
{
matrix.postScale(scale, scale, mCenterWidth, mCenterHeight);
setImageMatrix(matrix);
}
/**
* 回调接口
*/
private
OnViewClickListener mOnViewClickListener;
public
void
setOnClickIntent(OnViewClickListener onViewClickListener)
{
this
.mOnViewClickListener = onViewClickListener;
}
public
interface
OnViewClickListener
{
void
onViewClick(MyImageView view);
}
}
|
有人会觉得使用Handler比较麻烦,这里一直使用Handler.sendMsg的原因是,利用了这个消息队列,队列先进先出,保证动画效果的流畅。因为ACTION_DOWN_与ACTION_UP一瞬点完成的,其实动画还在进行。如果你在onTouchEvent中用while集合sleep完成动画,会出现卡死,监听不到Up事件等问题。
3、主Activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package
com.ljp.ani01;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Toast;
public
class
TestRolateAnimActivity
extends
Activity
{
MyImageView joke;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
joke = (MyImageView) findViewById(R.id.c_joke);
joke.setOnClickIntent(
new
MyImageView.OnViewClickListener()
{
@Override
public
void
onViewClick(MyImageView view)
{
Toast.makeText(TestRolateAnimActivity.
this
, Joke,
1000
).show();
}
});
}
}
|
利用提供的回调接口注册了点击事件。这里说明一下,现在为ImageView设置OnClickLIstener是没有作用的,因为自定义的ImageView的onTouchEvent直接返回了true,不会往下执行click事件,如果你希望通过OnClickLIstener进行注册,你可以把ontouchevent里面返回值改成super.ontouchevent(event),并且需要将ImageView的clickable设置为true。这些都是Ontouch事件的传播机制,不了解的google下,还是很有必要的。