編輯:關於Android編程
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) {
}
}
下面是下面就分析一下相關原理:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+MaGivdjNvMjnus7P1Mq+PC9wPgo8cD692M28uvO3tbvYttTTprXEYml0bWFwo6zTw1dpbmRvd01hbmFnZXLWsb3T1NrGwcS7yc+9q2JpdG1hcM/Uyr6z9sC0o6zSsr7Nyse9q2JpdG1hcLfFtb3Su7j2aW1hZ2VWaWV31tCjrFdpbmRvd01hbmFnZXIgYWRkdmlld77Nv8nS1M/Uyr7By6GjPC9wPgo8cD7OqsHL09DS9dOwtcTQp7n7o6zV4sDvtu7N4rao0uXBy9K7uPZsYXlvdXSjumdsb2JhbF9zY3JlZW5zaG90LnhtbKOsyOfPwjwvcD4KPHA+PHByZSBjbGFzcz0="brush:java;"><frameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
上面的布局一共有三層,最下面的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); ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
statusBarVisible, navBarVisible);
在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);
}
});
}
Android中的Intent和Intent-filter總結
一.相關概念(一)基本概念Intent中文意思指”意圖”,按照Android的設計理念,Android使用Intent來封裝程序的”調
RecycleView進階三(實現不一樣的拖動排序以及側滑刪除)
前言:上次呢為大家介紹了如何給RecycleView添加頭部、尾部達到裝飾的效果,那麼本章節將為大家介紹RecycleView實現不一樣的拖動排序以及側滑刪除。首先呢我們
Android應用層View繪制流程與源碼分析
1 背景還記得前面《Android應用setContentView與LayoutInflater加載解析機制源碼分析》這篇文章嗎?我們有分析到Activity
魅族mx6跑分多少 魅族mx6性能跑分評測
相信一些有關注魅族的用戶都知道魅族即將要發布一款新機為魅族mx6,那麼魅族mx6這款新機怎麼樣?魅族mx6跑分多少呢?下文帶來魅族mx6性能跑分評測,一起和