zoukankan      html  css  js  c++  java
  • 从Android4.0源码中提取的截图实现(在当前activity中有效,不能全局截图)

    原文:http://blog.csdn.net/xu_fu/article/details/39268771

    从这个大神的博客看到了这篇文章,感觉写的挺好的。挺实用的功能。虽然是从源码中提取的,但是看得出费了一番心思。而且讲解的很透彻。我这里补充的是这个仅仅能在一个acitvity中使用,不能实现在服务中截图。getWindow().getDecorView()这个方法得到的是当前根视图,这样等于得到了当前屏幕展示的图片,截取即可。这里为了方便没有做图片保存的工作。仅仅作为演示。

    一、使用方式

    这里调用的时候传入了一个getWindow().getDecorView(),就是传入的要截图的视图。也就是说如果你要截图的是button的view传入v即可。我们现在要截图的是整个屏幕,所以就用了getWindow().getDecorView()这个方法得到整个屏幕的图像了。

    package com.kale.viewshot;
    
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    
    
    public class MainActivity extends Activity {
    
        @Override
        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,就会直接淡出,而不会向上偏移到状态栏上。

    二、需要导入的类和布局文件

    GlobalScreenshot.java

    package com.kale.viewshot;
    
    /*
     * Copyright (C) 2011 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    import android.animation.Animator;
    import android.animation.AnimatorListenerAdapter;
    import android.animation.AnimatorSet;
    import android.animation.ValueAnimator;
    import android.animation.ValueAnimator.AnimatorUpdateListener;
    import android.content.Context;
    import android.content.res.Resources;
    import android.graphics.Bitmap;
    import android.graphics.PixelFormat;
    import android.graphics.PointF;
    import android.media.MediaActionSound;
    import android.net.Uri;
    import android.util.DisplayMetrics;
    import android.view.Display;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.WindowManager;
    import android.view.animation.Interpolator;
    import android.widget.ImageView;
    
    /**
     * POD used in the AsyncTask which saves an image in the background.
     */
    class SaveImageInBackgroundData {
        Context context;
        Bitmap image;
        Uri imageUri;
        Runnable finisher;
        int iconSize;
        int result;
    
        void clearImage() {
            image = null;
            imageUri = null;
            iconSize = 0;
        }
    
        void clearContext() {
            context = null;
        }
    }
    
    
    /**
     * TODO:
     * - Performance when over gl surfaces? Ie. Gallery
     * - what do we say in the Toast? Which icon do we get if the user uses another
     * type of gallery?
     */
    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) {
    
        }
    
    
    }

    SurfaceControl.java

    package com.kale.viewshot;
    
    import android.graphics.Bitmap;
    import android.view.View;
    
    /**
     * Created by xf on 2014/9/14.
     */
    public class SurfaceControl {
    
        public static Bitmap screenshot(View view) {
            view.setDrawingCacheEnabled(true);
            view.buildDrawingCache();
            Bitmap bmp = view.getDrawingCache();
            return bmp;
        }
    }

    global_screenshot.xml

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Copyright (C) 2011 The Android Open Source Project
    
         Licensed under the Apache License, Version 2.0 (the "License");
         you may not use this file except in compliance with the License.
         You may obtain a copy of the License at
    
              http://www.apache.org/licenses/LICENSE-2.0
    
         Unless required by applicable law or agreed to in writing, software
         distributed under the License is distributed on an "AS IS" BASIS,
         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         See the License for the specific language governing permissions and
         limitations under the License.
    -->
    <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>

    activity_main.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:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context=".MainActivity">
    
        <TextView
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <Button
            android:id="@+id/main_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Shot"
            android:layout_alignParentBottom="true"/>
    
    </RelativeLayout>

    原来博文的实例代码地址:示例代码->http://download.csdn.net/detail/xu_fu/7921645

  • 相关阅读:
    设计模式学习每日一记(1.简单工厂模式)
    poj1068
    设计模式学习每日一记(2.外观模式)
    qooxdoo一句话备忘录[不断更新]
    设计模式学习每日一记(4.抽象工厂)
    C# 各种数据类型的最大值和最小值常数
    ASP.NET中实现二级或多级域名(修改UrlRewrite)
    网站中定时发送邮件
    重提URL Rewrite(1):IIS与ASP.NET
    Server Application Unavailable 的解决方法
  • 原文地址:https://www.cnblogs.com/tianzhijiexian/p/4057729.html
Copyright © 2011-2022 走看看