Android实现dialog的3D翻转

本文实现了Android中dialog的3D翻转效果。这里通过一个简单的应用场景记录下。

效果图

起初自己的思路是Activity进行界面跳转实现旋转效果,网上看了很多,写下来发现效果不对。之后又看到Google上面的Card Flid Animation效果是这样的。

看着确实不错,然而拿下来demo放慢翻转速度后发现,不是我想要的。但是跟我看到的一个app里面的效果一样
然后想改成dialog试试效果,发现更是不行了。

Card Flid Animation效果如下:
这个是通过Activity来切换Fragment实现的,可以看到区别是翻转时候貌似会变大,其实没用,只是翻转后的视觉问题。

听说openGl比较麻烦,并且没有用过。然后就搜了下Rotate3DAnimaitons。
搜到了这篇文章
http://blog.csdn.net/growing_tree/article/details/50428148
所以这篇文章里的实现方法不是我的原创,是参考人家的。在这里感谢这位大神。
不过他这个是activity里的,我就想要一个dialog效果,因为电脑上TIM的打开红包这个3D效果看着不错,其实大同小异,就拿过来改成Dialog。
对于Rotate3DAnimaitons这篇文章已经很详细了,有需要的可以参考下。

这里也贴下Rotate3dAnimation 的代码

简单加了两行注释

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
/**
* An animation that rotates the view on the Y axis between two specified angles.
* This animation also adds a translation on the Z axis (depth) to improve the effect.
*/
public class Rotate3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;

/**
* Creates a new 3D rotation on the Y axis. The rotation is defined by its
* start angle and its end angle. Both angles are in degrees. The rotation
* is performed around a center point on the 2D space, definied by a pair
* of X and Y coordinates, called centerX and centerY. When the animation
* starts, a translation on the Z axis (depth) is performed. The length
* of the translation can be specified, as well as whether the translation
* should be reversed in time.
*
* @param fromDegrees the start angle of the 3D rotation //起始角度
* @param toDegrees the end angle of the 3D rotation //结束角度
* @param centerX the X center of the 3D rotation //x中轴线
* @param centerY the Y center of the 3D rotation //y中轴线
* @param reverse true if the translation should be reversed, false otherwise//是否反转
*/
public Rotate3dAnimation(float fromDegrees, float toDegrees,
float centerX, float centerY, float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;//Z轴移动的距离,这个来影响视觉效果,可以解决flip animation那个给人看似放大的效果
mReverse = reverse;
}

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;

final Matrix matrix = t.getMatrix();

Log.i("interpolatedTime", interpolatedTime+"");
camera.save();
if (mReverse) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();

matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}

dialog实现3D翻转代码,

说明:动画部分的代码是拿的搜的的那篇文章的

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
207
208
209
210
public class MyDialog extends Dialog {

@BindView(R.id.et_user_name)
EditText etUserName;
@BindView(R.id.et_password)
EditText etPassword;
@BindView(R.id.cb_auto_login)
CheckBox cbAutoLogin;
@BindView(R.id.tv_forget_pwd)
TextView tvForgetPwd;
@BindView(R.id.ll_content)
LinearLayout llContent;
@BindView(R.id.et_email)
EditText etEmail;
@BindView(R.id.btn_back)
Button btnBack;
@BindView(R.id.container)
RelativeLayout container;
private Context context;

@BindView(R.id.ll_register)
LinearLayout llRegister;


//接口回调传递参数
private OnClickListenerInterface mListener;
private View view;
//
private String strContent;


private int centerX;
private int centerY;
private int depthZ = 700;//修改此处可以改变距离来达到你满意的效果
private int duration = 300;//动画时间
private Rotate3dAnimation openAnimation;
private Rotate3dAnimation closeAnimation;

private boolean isOpen = false;

public interface OnClickListenerInterface {

/**
* 确认,
*/
void doConfirm();

/**
* 取消
*/
// public void doCancel();
}

public MyDialog(Context context) {
super(context);
this.context = context;
}

public MyDialog(Context context, String content) {
super(context);
this.context = context;
this.strContent = content;

}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//去掉系统的黑色矩形边框
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
requestWindowFeature(Window.FEATURE_NO_TITLE);

init();
}

public void init() {
LayoutInflater inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.dialog_my, null);
setContentView(view);
ButterKnife.bind(this);
etPassword.setTypeface(Typeface.DEFAULT);
etPassword.setTransformationMethod(new PasswordTransformationMethod());
tvForgetPwd.setOnClickListener(new OnWidgetClickListener());
btnBack.setOnClickListener(new OnWidgetClickListener());
Window dialogWindow = getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
DisplayMetrics d = context.getResources().getDisplayMetrics(); // 获取屏幕宽、高用
lp.width = (int) (d.widthPixels * 0.8); // 宽度设置为屏幕的0.8
lp.height = (int) (d.heightPixels * 0.6); // 高度设置为屏幕的0.6
dialogWindow.setAttributes(lp);
setCanceledOnTouchOutside(false);
setCancelable(true);
}

public void setClicklistener(OnClickListenerInterface clickListenerInterface) {
this.mListener = clickListenerInterface;
}

private class OnWidgetClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {

int id = v.getId();
switch (id) {
case R.id.tv_forget_pwd:
startAnimation();
break;
case R.id.btn_back:
startAnimation();
break;
}
}
}

private void startAnimation() {
//接口回调传递参数
centerX = container.getWidth() / 2;
centerY = container.getHeight() / 2;
if (openAnimation == null) {
initOpenAnim();
initCloseAnim();
}

//用作判断当前点击事件发生时动画是否正在执行
if (openAnimation.hasStarted() && !openAnimation.hasEnded()) {
return;
}
if (closeAnimation.hasStarted() && !closeAnimation.hasEnded()) {
return;
}

//判断动画执行
if (isOpen) {

container.startAnimation(openAnimation);

} else {

container.startAnimation(closeAnimation);

}
isOpen = !isOpen;
}

/**
*注意旋转角度
*/
private void initOpenAnim() {
//从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见,
openAnimation = new Rotate3dAnimation(0, 90, centerX, centerY, depthZ, true);
openAnimation.setDuration(duration);
openAnimation.setFillAfter(true);
openAnimation.setInterpolator(new AccelerateInterpolator());
openAnimation.setAnimationListener(new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
llRegister.setVisibility(View.GONE);
llContent.setVisibility(View.VISIBLE);
//从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见
Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(270, 360, centerX, centerY, depthZ, false);
rotateAnimation.setDuration(duration);
rotateAnimation.setFillAfter(true);
rotateAnimation.setInterpolator(new DecelerateInterpolator());
container.startAnimation(rotateAnimation);
}
});
}


private void initCloseAnim() {
closeAnimation = new Rotate3dAnimation(360, 270, centerX, centerY, depthZ, true);
closeAnimation.setDuration(duration);
closeAnimation.setFillAfter(true);
closeAnimation.setInterpolator(new AccelerateInterpolator());
closeAnimation.setAnimationListener(new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
llRegister.setVisibility(View.VISIBLE);
llContent.setVisibility(View.GONE);
Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 0, centerX, centerY, depthZ, false);
rotateAnimation.setDuration(duration);
rotateAnimation.setFillAfter(true);
rotateAnimation.setInterpolator(new DecelerateInterpolator());
container.startAnimation(rotateAnimation);
}
});
}
}

关于Flip效果的实现可以参考文章Card Flip Animations的实现

源码中也有Flip效果的实现

Demo下载

说明:上传的Demo全部为免积分,现在CSDN设置最低收了一积分,没办法了。没有积分的可以在github上下载

githHub下载