http://blog.csdn.net/xu_fu/article/details/39268771
Android在4.0版本之后同时按电源键和音量键可以截取当前屏幕,截图后会有一个过渡动画效果,这里提取了将效果这部分提取出来,可以用于应用截图分享功能。
截图功能在源码中的位置是com.android.systemui.screenshot,下面有四个类
其中主要工作都在GlobalScreenshot中,包括截图后的动画效果、保存到本地和显示到通知栏。为了简单,下面的代码只保留了过渡动画部分
- class GlobalScreenshot {
- private static final String TAG = "GlobalScreenshot";
- private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
- private static final int SCREENSHOT_DROP_IN_DURATION = 430;
- private static final int SCREENSHOT_DROP_OUT_DELAY = 500;
- private static final int SCREENSHOT_DROP_OUT_DURATION = 430;
- private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;
- private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;
- private static final float BACKGROUND_ALPHA = 0.5f;
- private static final float SCREENSHOT_SCALE = 1f;
- private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;
- private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
- private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
- private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
- private Context mContext;
- private WindowManager mWindowManager;
- private WindowManager.LayoutParams mWindowLayoutParams;
- private Display mDisplay;
- private DisplayMetrics mDisplayMetrics;
- private Bitmap mScreenBitmap;
- private View mScreenshotLayout;
- private ImageView mBackgroundView;
- private ImageView mScreenshotView;
- private ImageView mScreenshotFlash;
- private AnimatorSet mScreenshotAnimation;
- private float mBgPadding;
- private float mBgPaddingScale;
- private MediaActionSound mCameraSound;
- /**
- * @param context everything needs a context :(
- */
- public GlobalScreenshot(Context context) {
- Resources r = context.getResources();
- mContext = context;
- LayoutInflater layoutInflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- // Inflate the screenshot layout
- mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
- mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
- mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
- mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
- mScreenshotLayout.setFocusable(true);
- mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // Intercept and ignore all touch events
- return true;
- }
- });
- // Setup the window that we are going to use
- mWindowLayoutParams = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
- WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
- WindowManager.LayoutParams.FLAG_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
- PixelFormat.TRANSLUCENT);
- mWindowLayoutParams.setTitle("ScreenshotAnimation");
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mDisplay = mWindowManager.getDefaultDisplay();
- mDisplayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(mDisplayMetrics);
- // Scale has to account for both sides of the bg
- mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
- mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
- // Setup the Camera shutter sound
- mCameraSound = new MediaActionSound();
- mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
- }
- /**
- * Takes a screenshot of the current display and shows an animation.
- */
- void takeScreenshot(View view, Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
- // Take the screenshot
- mScreenBitmap = SurfaceControl.screenshot(view);
- if (mScreenBitmap == null) {
- notifyScreenshotError(mContext);
- finisher.run();
- return;
- }
- // Optimizations
- mScreenBitmap.setHasAlpha(false);
- mScreenBitmap.prepareToDraw();
- // Start the post-screenshot animation
- startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
- statusBarVisible, navBarVisible);
- }
- /**
- * Starts the animation after taking the screenshot
- */
- private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,
- boolean navBarVisible) {
- // Add the view for the animation
- mScreenshotView.setImageBitmap(mScreenBitmap);
- mScreenshotLayout.requestFocus();
- // Setup the animation with the screenshot just taken
- if (mScreenshotAnimation != null) {
- mScreenshotAnimation.end();
- mScreenshotAnimation.removeAllListeners();
- }
- mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
- ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
- ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
- statusBarVisible, navBarVisible);
- mScreenshotAnimation = new AnimatorSet();
- mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
- mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Save the screenshot once we have a bit of time now
- saveScreenshotInWorkerThread(finisher);
- mWindowManager.removeView(mScreenshotLayout);
- // Clear any references to the bitmap
- mScreenBitmap = null;
- mScreenshotView.setImageBitmap(null);
- }
- });
- mScreenshotLayout.post(new Runnable() {
- @Override
- public void run() {
- // Play the shutter sound to notify that we've taken a screenshot
- mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
- mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mScreenshotView.buildLayer();
- mScreenshotAnimation.start();
- }
- });
- }
- private ValueAnimator createScreenshotDropInAnimation() {
- final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
- / SCREENSHOT_DROP_IN_DURATION);
- final float flashDurationPct = 2f * flashPeakDurationPct;
- final Interpolator flashAlphaInterpolator = new Interpolator() {
- @Override
- public float getInterpolation(float x) {
- // Flash the flash view in and out quickly
- if (x <= flashDurationPct) {
- return (float) Math.sin(Math.PI * (x / flashDurationPct));
- }
- return 0;
- }
- };
- final Interpolator scaleInterpolator = new Interpolator() {
- @Override
- public float getInterpolation(float x) {
- // We start scaling when the flash is at it's peak
- if (x < flashPeakDurationPct) {
- return 0;
- }
- return (x - flashDurationPct) / (1f - flashDurationPct);
- }
- };
- ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
- anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mBackgroundView.setAlpha(0f);
- mBackgroundView.setVisibility(View.VISIBLE);
- mScreenshotView.setAlpha(0f);
- mScreenshotView.setTranslationX(0f);
- mScreenshotView.setTranslationY(0f);
- mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
- mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
- mScreenshotView.setVisibility(View.VISIBLE);
- mScreenshotFlash.setAlpha(0f);
- mScreenshotFlash.setVisibility(View.VISIBLE);
- }
- @Override
- public void onAnimationEnd(android.animation.Animator animation) {
- mScreenshotFlash.setVisibility(View.GONE);
- }
- });
- anim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
- - scaleInterpolator.getInterpolation(t)
- * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
- mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
- mScreenshotView.setAlpha(t);
- mScreenshotView.setScaleX(scaleT);
- mScreenshotView.setScaleY(scaleT);
- mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));
- }
- });
- return anim;
- }
- private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
- boolean navBarVisible) {
- ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
- anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBackgroundView.setVisibility(View.GONE);
- mScreenshotView.setVisibility(View.GONE);
- mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- });
- if (!statusBarVisible || !navBarVisible) {
- // There is no status bar/nav bar, so just fade the screenshot away in place
- anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);
- anim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
- - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
- mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
- mScreenshotView.setAlpha(1f - t);
- mScreenshotView.setScaleX(scaleT);
- mScreenshotView.setScaleY(scaleT);
- }
- });
- } else {
- // In the case where there is a status bar, animate to the origin of the bar (top-left)
- final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION
- / SCREENSHOT_DROP_OUT_DURATION;
- final Interpolator scaleInterpolator = new Interpolator() {
- @Override
- public float getInterpolation(float x) {
- if (x < scaleDurationPct) {
- // Decelerate, and scale the input accordingly
- return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
- }
- return 1f;
- }
- };
- // Determine the bounds of how to scale
- float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
- float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
- final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
- final PointF finalPos = new PointF(
- -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
- -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
- // Animate the screenshot to the status bar
- anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
- anim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
- - scaleInterpolator.getInterpolation(t)
- * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
- mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
- mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
- mScreenshotView.setScaleX(scaleT);
- mScreenshotView.setScaleY(scaleT);
- mScreenshotView.setTranslationX(t * finalPos.x);
- mScreenshotView.setTranslationY(t * finalPos.y);
- }
- });
- }
- return anim;
- }
- private void notifyScreenshotError(Context context) {
- }
- private void saveScreenshotInWorkerThread(Runnable runnable) {
- }
- }
class GlobalScreenshot { private static final String TAG = "GlobalScreenshot"; private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130; private static final int SCREENSHOT_DROP_IN_DURATION = 430; private static final int SCREENSHOT_DROP_OUT_DELAY = 500; private static final int SCREENSHOT_DROP_OUT_DURATION = 430; private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370; private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320; private static final float BACKGROUND_ALPHA = 0.5f; private static final float SCREENSHOT_SCALE = 1f; private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f; private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f; private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f; private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f; private Context mContext; private WindowManager mWindowManager; private WindowManager.LayoutParams mWindowLayoutParams; private Display mDisplay; private DisplayMetrics mDisplayMetrics; private Bitmap mScreenBitmap; private View mScreenshotLayout; private ImageView mBackgroundView; private ImageView mScreenshotView; private ImageView mScreenshotFlash; private AnimatorSet mScreenshotAnimation; private float mBgPadding; private float mBgPaddingScale; private MediaActionSound mCameraSound; /** * @param context everything needs a context :( */ public GlobalScreenshot(Context context) { Resources r = context.getResources(); mContext = context; LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Inflate the screenshot layout mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background); mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot); mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash); mScreenshotLayout.setFocusable(true); mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // Intercept and ignore all touch events return true; } }); // Setup the window that we are going to use mWindowLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, PixelFormat.TRANSLUCENT); mWindowLayoutParams.setTitle("ScreenshotAnimation"); mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mDisplay = mWindowManager.getDefaultDisplay(); mDisplayMetrics = new DisplayMetrics(); mDisplay.getRealMetrics(mDisplayMetrics); // Scale has to account for both sides of the bg mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding); mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels; // Setup the Camera shutter sound mCameraSound = new MediaActionSound(); mCameraSound.load(MediaActionSound.SHUTTER_CLICK); } /** * Takes a screenshot of the current display and shows an animation. */ void takeScreenshot(View view, Runnable finisher, boolean statusBarVisible, boolean navBarVisible) { // Take the screenshot mScreenBitmap = SurfaceControl.screenshot(view); if (mScreenBitmap == null) { notifyScreenshotError(mContext); finisher.run(); return; } // Optimizations mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); // Start the post-screenshot animation startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels, statusBarVisible, navBarVisible); } /** * Starts the animation after taking the screenshot */ private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible, boolean navBarVisible) { // Add the view for the animation mScreenshotView.setImageBitmap(mScreenBitmap); mScreenshotLayout.requestFocus(); // Setup the animation with the screenshot just taken if (mScreenshotAnimation != null) { mScreenshotAnimation.end(); mScreenshotAnimation.removeAllListeners(); } mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation(); ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible); mScreenshotAnimation = new AnimatorSet(); mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim); mScreenshotAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // Save the screenshot once we have a bit of time now saveScreenshotInWorkerThread(finisher); mWindowManager.removeView(mScreenshotLayout); // Clear any references to the bitmap mScreenBitmap = null; mScreenshotView.setImageBitmap(null); } }); mScreenshotLayout.post(new Runnable() { @Override public void run() { // Play the shutter sound to notify that we've taken a screenshot mCameraSound.play(MediaActionSound.SHUTTER_CLICK); mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null); mScreenshotView.buildLayer(); mScreenshotAnimation.start(); } }); } private ValueAnimator createScreenshotDropInAnimation() { final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION) / SCREENSHOT_DROP_IN_DURATION); final float flashDurationPct = 2f * flashPeakDurationPct; final Interpolator flashAlphaInterpolator = new Interpolator() { @Override public float getInterpolation(float x) { // Flash the flash view in and out quickly if (x <= flashDurationPct) { return (float) Math.sin(Math.PI * (x / flashDurationPct)); } return 0; } }; final Interpolator scaleInterpolator = new Interpolator() { @Override public float getInterpolation(float x) { // We start scaling when the flash is at it's peak if (x < flashPeakDurationPct) { return 0; } return (x - flashDurationPct) / (1f - flashDurationPct); } }; ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(SCREENSHOT_DROP_IN_DURATION); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mBackgroundView.setAlpha(0f); mBackgroundView.setVisibility(View.VISIBLE); mScreenshotView.setAlpha(0f); mScreenshotView.setTranslationX(0f); mScreenshotView.setTranslationY(0f); mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale); mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale); mScreenshotView.setVisibility(View.VISIBLE); mScreenshotFlash.setAlpha(0f); mScreenshotFlash.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(android.animation.Animator animation) { mScreenshotFlash.setVisibility(View.GONE); } }); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale) - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE); mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(t); mScreenshotView.setScaleX(scaleT); mScreenshotView.setScaleY(scaleT); mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t)); } }); return anim; } private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible, boolean navBarVisible) { ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mBackgroundView.setVisibility(View.GONE); mScreenshotView.setVisibility(View.GONE); mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null); } }); if (!statusBarVisible || !navBarVisible) { // There is no status bar/nav bar, so just fade the screenshot away in place anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE); mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(1f - t); mScreenshotView.setScaleX(scaleT); mScreenshotView.setScaleY(scaleT); } }); } else { // In the case where there is a status bar, animate to the origin of the bar (top-left) final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION / SCREENSHOT_DROP_OUT_DURATION; final Interpolator scaleInterpolator = new Interpolator() { @Override public float getInterpolation(float x) { if (x < scaleDurationPct) { // Decelerate, and scale the input accordingly return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f)); } return 1f; } }; // Determine the bounds of how to scale float halfScreenWidth = (w - 2f * mBgPadding) / 2f; float halfScreenHeight = (h - 2f * mBgPadding) / 2f; final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET; final PointF finalPos = new PointF( -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth, -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight); // Animate the screenshot to the status bar anim.setDuration(SCREENSHOT_DROP_OUT_DURATION); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE); mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t)); mScreenshotView.setScaleX(scaleT); mScreenshotView.setScaleY(scaleT); mScreenshotView.setTranslationX(t * finalPos.x); mScreenshotView.setTranslationY(t * finalPos.y); } }); } return anim; } private void notifyScreenshotError(Context context) { } private void saveScreenshotInWorkerThread(Runnable runnable) { } }
看一下效果
下面是下面就分析一下相关原理:
1、截图如何显示
截图后返回对应的bitmap,用WindowManager直接在屏幕上将bitmap显示出来,也就是将bitmap放到一个imageView中,WindowManager addview就可以显示了。
为了有阴影的效果,这里额外定义了一个layout:global_screenshot.xml,如下
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView android:id="@+id/global_screenshot_background"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="@android:color/black"
- android:visibility="gone" />
- <ImageView android:id="@+id/global_screenshot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@drawable/screenshot_panel"
- android:visibility="gone"
- android:adjustViewBounds="true" />
- <ImageView android:id="@+id/global_screenshot_flash"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="@android:color/white"
- android:visibility="gone" />
- </FrameLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/global_screenshot_background" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@android:color/black" android:visibility="gone" /> <ImageView android:id="@+id/global_screenshot" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/screenshot_panel" android:visibility="gone" android:adjustViewBounds="true" /> <ImageView android:id="@+id/global_screenshot_flash" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@android:color/white" android:visibility="gone" /> </FrameLayout>
上面的布局一共有三层,最下面的background用于遮盖,中间的screenshot用于放截图,最上边还有一层flash,主要是用于做一个反光的效果。
截图的bitmap就放在global_screenshot这个imageview中。对应的代码
- mScreenshotView.setImageBitmap(mScreenBitmap);
- mScreenshotLayout.requestFocus();
- // Setup the animation with the screenshot just taken
- if (mScreenshotAnimation != null) {
- mScreenshotAnimation.end();
- mScreenshotAnimation.removeAllListeners();
- }
- mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
mScreenshotView.setImageBitmap(mScreenBitmap); mScreenshotLayout.requestFocus(); // Setup the animation with the screenshot just taken if (mScreenshotAnimation != null) { mScreenshotAnimation.end(); mScreenshotAnimation.removeAllListeners(); } mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
这样就可以在屏幕上看到截图了,之后还有一个过渡动画效果,分别是
- ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
- ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
- statusBarVisible, navBarVisible);
ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation(); ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible);
这两个属性动画完成了显示-缩放-消失这个过程,具体就是对上面三层view进行变换了。
在Activity中调用
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final GlobalScreenshot screenshot = new GlobalScreenshot(this);
- findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- screenshot.takeScreenshot(getWindow().getDecorView(), new Runnable() {
- @Override
- public void run() {
- }
- }, true, true);
- }
- });
- }
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final GlobalScreenshot screenshot = new GlobalScreenshot(this); findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { screenshot.takeScreenshot(getWindow().getDecorView(), new Runnable() { @Override public void run() { } }, true, true); } }); }
后面的两个boolean参数是表示是否有状态栏,用于显示不同的淡出动画,如果有一个为false,就会直接淡出,而不会向上偏移到状态栏上。