android点击一个View进入一个应用,通常会有好几种动画,可以通过xml控制,也可以通过其内部提供的ActivityOptions类来控制。那么最近我们的载体(一个桌面)需要使用ActivityOptions.makeScaleUpAnimation的动画方式来进入一个应用,如果我们点击的是一个View v,那么正常的程序可以是酱紫:
Intent intent = 。。。
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight()));
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(),
v.getMeasuredHeight());
startActivity(intent, opts.toBundle());
上述效果就是点击一个图标(一个View)然后就进入到一个应用,中间的这个过程的动画效果就是伤处的opts控制滴,所以这种方法还是蛮简单的。那么问题来了,我点击的不是View怎么办?其实在桌面上的东西都是View,只不过我们的东西有点特别,opengl实现的,整体的内容是一个View,但是内部的空间没有一个是View的子类,那怎么办咯?例如amigo随变桌面里的创意时钟就是酱紫的,这整张图是一个View,内部的却不是View,又要求以点击的部位弹出应用,而不是以整个View弹出:
首先可以看到startActivity的第一个参数intent需要的内容,它就是需要4个int类型的值,而且分别是左上角的x坐标,左上角的y坐标,长度,宽度,好吧,这4个值都可以自己给值了。
再看到startActivity的第二个参数,一个Bundle对象,然后我们就进入到了ActivityOptions的源码看到toBundle方法,其实就是要传一些键值对:
public Bundle toBundle() {
if (mAnimationType == ANIM_DEFAULT) {
return null;
}
Bundle b = new Bundle();
if (mPackageName != null) {
b.putString(KEY_PACKAGE_NAME, mPackageName);
}
b.putInt(KEY_ANIM_TYPE, mAnimationType);
switch (mAnimationType) {
case ANIM_CUSTOM:
case ...
...
}
return b;
}
再看makeScaleUpAnimation方法:
public static ActivityOptions makeScaleUpAnimation(View source,
int startX, int startY, int width, int height) {
ActivityOptions opts = new ActivityOptions();
opts.mPackageName = source.getContext().getPackageName();
opts.mAnimationType = ANIM_SCALE_UP;
int[] pts = new int[2];
source.getLocationOnScreen(pts);
opts.mStartX = pts[0] + startX;
opts.mStartY = pts[1] + startY;
opts.mWidth = width;
opts.mHeight = height;
return opts;
}
可以看到这个View v的作用:1.获取当前应用的包名;2.获取这个view在屏幕上的左上角的坐标
结合上述两个源码,我们再次进入到toBundle,找到mAnimationType = ANIM_SCALE_UP需要的简直对:
b.putString(KEY_PACKAGE_NAME, mPackageName);//这个自己可以获取
b.putInt(KEY_ANIM_TYPE, mAnimationType);//ANIM_SCALE_UP常量
case ANIM_SCALE_UP:
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
b.putInt(KEY_ANIM_WIDTH, mWidth);
b.putInt(KEY_ANIM_HEIGHT, mHeight);
break;
好吧,由此可见需要的键值对一共有6个,另外需要的就是动画起始的坐标和初始框框的长度与宽度,其中长度和宽度我们可以自己给个固定的值,那么接下来就是mStartX和mStartY怎么获取?
其实它的源码写的很清楚了
int[] pts = new int[2];
View.getLocationOnScreen(pts);
通过上述方法可以得到一个View控制的左上角的坐标,但是这里的值并非我们想要的,我们需要点击例如上图的右下角那个图标呢? 不可能以整个View来弹出吧,所以还需要详细的点击的坐标。好在onTouchEvent(MotionEvent event)中的event可以得到当前点击的view中的坐标
event.getX()得到该点击在View中的坐标,又View在屏幕上的左上角的坐标是pts[0],那就是说 x=event.getX()+pts[0]就是我所点击的点在屏幕上的x坐标,由此y=event.getY()+pts[1]是我所点击的点在屏幕上的Y坐标,再给个定值长度和宽度=20,那就可以得到想要的Bundle了。
Bundle b = new Bundle();
b.putString(KEY_PACKAGE_NAME, packageName);
b.putInt(KEY_ANIM_TYPE, ANIM_SCALE_UP);
b.putInt(KEY_ANIM_START_X, x);
b.putInt(KEY_ANIM_START_Y, y);
b.putInt(KEY_ANIM_WIDTH, constVlaue);
b.putInt(KEY_ANIM_HEIGHT, constVlaue);
Context.startActivity(intent, b);
好吧,虽然废话了一大把,但还是写出来作为一个记录,让自己以后养成查看源码的习惯,不要害怕,,,