android实现截图并动画消失效果的思路详解

来自:网络
时间:2020-10-14
阅读:
免费资源网 - https://freexyz.cn/

android实现截图并动画消失效果的思路详解
android实现截图并动画消失效果的思路详解
android实现截图并动画消失效果的思路详解

整体思路

1、获取要截图的view
2、根据这个view创建Bitmap
3、保存图片,拿到图片路径
4、把图片路径传入自定义view(自定义view实现的功能:画圆角边框,动画缩小至消失)
主要用到的是ObjectAnimator属性动画的缩小和平移

核心代码

得到图片的路径

private String getFilePath() {
 Bitmap bitmap = createViewBitmap(picImg);
 if (bitmap != null) {
  try {
  // 首先保存图片
  String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "HIS";
  File appDir = new File(storePath);
  if (!appDir.exists()) {
   appDir.mkdir();
  }
  String fileName = System.currentTimeMillis() + ".jpg";
  File file = new File(appDir, fileName);

  BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
  bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
  bos.flush();
  bos.close();
  Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  Uri uri = Uri.fromFile(file);
  intent.setData(uri);
  sendBroadcast(intent);
  return file.getAbsolutePath();
  } catch (Exception e) {
  return null;
  }
 } else {
  return null;
 }

 }
public Bitmap createViewBitmap(View v) {
 Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas canvas = new Canvas(bitmap);
 v.draw(canvas);
 return bitmap;
 }

把图片路径传入自定义view

String filePath = getFilePath();
 mDisplayScreenshotSnv.setVisibility(View.GONE);
 mDisplayScreenshotSnv.setPath(filePath, picImg.getMeasuredWidth(), picImg.getMeasuredHeight(), true);
 mDisplayScreenshotSnv.setVisibility(View.VISIBLE);

截图实现圆角边框和动画消失

//实现截图动画(添加圆角边框)
  Glide.with(getContext())
   .load(new File(path))
   .transform(new CenterCrop(getContext()), new GlideRoundTransform(getContext(), radius))
   .crossFade()
   .listener(new RequestListener<File, GlideDrawable>() {
    @Override
    public boolean onException(Exception e, File model, Target<GlideDrawable> target, boolean isFirstResource) {
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, File model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
    if (thumb.getDrawable() == null) {
     // 避免截图成功时出现短暂的全屏白色背景
     thumb.setImageDrawable(resource);
    }
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }
   }).into(thumb);

  //启动延时关闭截图(显示5秒消失截图)
  startTick(true);

动画设置

/**
 * 动画设置
 * @param view
 * @param start
 */
 private void anim(final ImageView view, boolean start) {
 if (!start) {
  if (getChildCount() > 0) {
  // 快速点击截图时,上一次添加的子视图尚未移除,需重置视图
  resetView();
  }
  setScaleX(1f);
  setScaleY(1f);
  setTranslationX(0f);
  setTranslationY(0f);
  clearAnimation();
  if (mScaleXAnim != null) {
  mScaleXAnim.cancel();
  mScaleXAnim = null;
  }
  if (mScaleYAnim != null) {
  mScaleYAnim.cancel();
  mScaleYAnim = null;
  }
  if (mTranslationXAnim != null) {
  mTranslationXAnim.cancel();
  mTranslationXAnim = null;
  }
  if (mTranslationYAnim != null) {
  mTranslationYAnim.cancel();
  mTranslationYAnim = null;
  }
  return;
 }

 view.post(new Runnable() {
  @Override
  public void run() {
  if (!view.isAttachedToWindow()) {
   // 子视图已被移除
   return;
  }
  setCardBackgroundColor(Color.WHITE);

  //等待cross fade动画
  float margins = DisplayUtil.dip2px(getContext(), 10);
  float scaleToX = (float) mFinalW / getMeasuredWidth();
  float scaleToY = (float) mFinalH / getMeasuredHeight();
  float translateToX = -(getMeasuredWidth() / 2f - (mFinalW / 2 + margins));
  float translateToY = getMeasuredHeight() / 2f - (mFinalH / 2f + margins);

  //以当前view为中心,x轴右为正,左为负;y轴下为正,上为负

  mScaleXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleX", 1.0f, scaleToX);
  mScaleYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleY", 1.0f, scaleToY);

  mTranslationXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationX", 1.0f, translateToX);
  mTranslationYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationY", 1.0f, translateToY);

  //设置速度
  mScaleXAnim.setDuration(500);
  mScaleYAnim.setDuration(500);
  mTranslationXAnim.setDuration(500);
  mTranslationYAnim.setDuration(500);

  //缩放
  mScaleXAnim.start();
  mScaleYAnim.start();
  //平移
  mTranslationXAnim.start();
  mTranslationYAnim.start();
  setEnabled(false);
  mScaleXAnim.addListener(new AnimatorListenerAdapter() {
   @Override
   public void onAnimationCancel(Animator animation) {
   super.onAnimationCancel(animation);
   setEnabled(true);
   }

   @Override
   public void onAnimationEnd(Animator animation) {
   super.onAnimationEnd(animation);
   setEnabled(true);
   setClickable(true);
   }

   @Override
   public void onAnimationStart(Animator animation) {
   super.onAnimationStart(animation);
   }
  });

  }
 });
 }

完整代码

ScreenshotNotifyView.java

package com.lyw.myproject.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.lyw.myproject.screenshot.GlideRoundTransform;
import com.lyw.myproject.utils.DisplayUtil;
import java.io.File;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;

public class ScreenshotNotifyView extends CardView {
 private int mFinalW;
 private int mFinalH;

 private Handler mHandler;

 private ObjectAnimator mScaleXAnim = null;
 private ObjectAnimator mScaleYAnim = null;

 private ObjectAnimator mTranslationXAnim = null;
 private ObjectAnimator mTranslationYAnim = null;

 public ScreenshotNotifyView(@NonNull Context context) {
 super(context);
 init(context);
 }

 public ScreenshotNotifyView(@NonNull Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }

 public ScreenshotNotifyView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }

 @Override
 public void setVisibility(int visibility) {
 super.setVisibility(visibility);
 if (visibility == GONE) {
  resetView();
 }
 }

 @Override
 protected void onDetachedFromWindow() {
 super.onDetachedFromWindow();
 anim(null, false);
 startTick(false);
 }

 private void init(Context context) {
 mHandler = new Handler(Looper.getMainLooper());
 setCardElevation(0);
 }

 public void setPath(final String path, int w, int h, final boolean anim) {
 setClickable(false);
 anim(null, false);
 final ImageView thumb = new ImageView(getContext());
 FrameLayout.LayoutParams thumbParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
 FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
 int padding = (int) DisplayUtil.dip2px(getContext(), 2);
 int margins = (int) DisplayUtil.dip2px(getContext(), 8);

 //设置截图之后的宽度,高度按照比例设置
 mFinalW = (int) DisplayUtil.dip2px(getContext(), 90);
 mFinalH = (int) ((float) mFinalW * h) / w;
 if (!anim) {
  //设置边框
  params.setMargins(margins, margins, margins, margins);
  margins = (int) DisplayUtil.dip2px(getContext(), 2);
  params.width = mFinalW + margins * 2;
  params.height = mFinalH + margins * 2;
  params.gravity = Gravity.START | Gravity.BOTTOM;

  thumbParams.width = mFinalW;
  thumbParams.height = mFinalH;
  thumbParams.gravity = Gravity.CENTER;
  setLayoutParams(params);
  requestLayout();
 } else {
  //设置边框
  thumbParams.setMargins(margins, margins, margins, margins);
  params.setMargins(0, 0, 0, 0);
  params.width = FrameLayout.LayoutParams.MATCH_PARENT;
  params.height = FrameLayout.LayoutParams.MATCH_PARENT;
  setLayoutParams(params);
  requestLayout();
 }
 thumb.setScaleType(ImageView.ScaleType.FIT_XY);
 thumb.setLayoutParams(thumbParams);
 addView(thumb);
 post(new Runnable() {
  @Override
  public void run() {
  float scale = (float) mFinalW / getMeasuredWidth();
  int radius = 5;
  if (anim) {
   radius = (int) (5f / scale);
  }
  setRadius((int) DisplayUtil.dip2px(getContext(), radius));

  //显示截图(添加圆角)
  Glide.with(getContext())
   .load(new File(path))
   .transform(new CenterCrop(getContext()), new GlideRoundTransform(getContext(), radius))
   .crossFade()
   .listener(new RequestListener<File, GlideDrawable>() {
    @Override
    public boolean onException(Exception e, File model, Target<GlideDrawable> target, boolean isFirstResource) {
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, File model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
    if (thumb.getDrawable() == null) {
     // 避免截图成功时出现短暂的全屏白色背景
     thumb.setImageDrawable(resource);
    }
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }
   }).into(thumb);

  //启动延时关闭截图(显示5秒消失截图)
  startTick(true);
  }
 });
 }

 /**
 * 动画设置
 * @param view
 * @param start
 */
 private void anim(final ImageView view, boolean start) {
 if (!start) {
  if (getChildCount() > 0) {
  // 快速点击截图时,上一次添加的子视图尚未移除,需重置视图
  resetView();
  }
  setScaleX(1f);
  setScaleY(1f);
  setTranslationX(0f);
  setTranslationY(0f);
  clearAnimation();
  if (mScaleXAnim != null) {
  mScaleXAnim.cancel();
  mScaleXAnim = null;
  }
  if (mScaleYAnim != null) {
  mScaleYAnim.cancel();
  mScaleYAnim = null;
  }
  if (mTranslationXAnim != null) {
  mTranslationXAnim.cancel();
  mTranslationXAnim = null;
  }
  if (mTranslationYAnim != null) {
  mTranslationYAnim.cancel();
  mTranslationYAnim = null;
  }
  return;
 }

 view.post(new Runnable() {
  @Override
  public void run() {
  if (!view.isAttachedToWindow()) {
   // 子视图已被移除
   return;
  }
  setCardBackgroundColor(Color.WHITE);

  //等待cross fade动画
  float margins = DisplayUtil.dip2px(getContext(), 10);
  float scaleToX = (float) mFinalW / getMeasuredWidth();
  float scaleToY = (float) mFinalH / getMeasuredHeight();
  float translateToX = -(getMeasuredWidth() / 2f - (mFinalW / 2 + margins));
  float translateToY = getMeasuredHeight() / 2f - (mFinalH / 2f + margins);

  //以当前view为中心,x轴右为正,左为负;y轴下为正,上为负

  mScaleXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleX", 1.0f, scaleToX);
  mScaleYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleY", 1.0f, scaleToY);

  mTranslationXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationX", 1.0f, translateToX);
  mTranslationYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationY", 1.0f, translateToY);

  //设置速度
  mScaleXAnim.setDuration(500);
  mScaleYAnim.setDuration(500);
  mTranslationXAnim.setDuration(500);
  mTranslationYAnim.setDuration(500);

  //缩放
  mScaleXAnim.start();
  mScaleYAnim.start();
  //平移
  mTranslationXAnim.start();
  mTranslationYAnim.start();
  setEnabled(false);
  mScaleXAnim.addListener(new AnimatorListenerAdapter() {
   @Override
   public void onAnimationCancel(Animator animation) {
   super.onAnimationCancel(animation);
   setEnabled(true);
   }

   @Override
   public void onAnimationEnd(Animator animation) {
   super.onAnimationEnd(animation);
   setEnabled(true);
   setClickable(true);
   }

   @Override
   public void onAnimationStart(Animator animation) {
   super.onAnimationStart(animation);
   }
  });

  }
 });
 }

 private void resetView() {
 setCardBackgroundColor(Color.TRANSPARENT);
 removeAllViews();
 startTick(false);
 }

 private void startTick(boolean start) {
 if (!start) {
  mHandler.removeCallbacksAndMessages(null);
  return;
 }
 mHandler.postDelayed(new Runnable() {
  @Override
  public void run() {
  setVisibility(GONE);
  }
 }, 5 * 1000);
 }
}

GlideRoundTransform.java

package com.lyw.myproject.screenshot;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;

/**
 * Created on 2018/12/26.
 *
 * @author lyw
 **/
public class GlideRoundTransform extends BitmapTransformation {

 private static float radius = 0f;

 /**
 * 构造函数 默认圆角半径 4dp
 *
 * @param context Context
 */
 public GlideRoundTransform(Context context) {
 this(context, 4);
 }

 /**
 * 构造函数
 *
 * @param context Context
 * @param dp 圆角半径
 */
 public GlideRoundTransform(Context context, int dp) {
 super(context);
 radius = Resources.getSystem().getDisplayMetrics().density * dp;
 }

 @Override
 protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
 return roundCrop(pool, toTransform);
 }

 private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {
 if (source == null) {
  return null;
 }

 Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
 if (result == null) {
  result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
 }

 Canvas canvas = new Canvas(result);
 Paint paint = new Paint();
 paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
 paint.setAntiAlias(true);
 RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
 canvas.drawRoundRect(rectF, radius, radius, paint);
 return result;
 }

 @Override
 public String getId() {
 return getClass().getName() + Math.round(radius);
 }
}

activity_screen_shot1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">

 <FrameLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content">
 <ImageView
  android:id="@+id/pic_iv"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:scaleType="fitXY"
  android:src="@mipmap/picture" />

 <com.lyw.myproject.widget.ScreenshotNotifyView
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/display_screenshot_snv"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:visibility="gone"
  app:cardBackgroundColor="@color/src_trans" />

 </FrameLayout>

 <Button
 android:id="@+id/screen_btn"
 android:text="截图"
 android:layout_gravity="center"
 android:layout_marginTop="20dp"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
</LinearLayout>

ScreenShotActivity1.java

package com.lyw.myproject.screenshot;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.lyw.myproject.BaseActivity;
import com.lyw.myproject.R;
import com.lyw.myproject.utils.LoadingLayout;
import com.lyw.myproject.utils.MemoryUtils;
import com.lyw.myproject.utils.PermissionUtil;
import com.lyw.myproject.widget.ScreenshotNotifyView;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;

import androidx.annotation.Nullable;

/**
 * 功能描述:截图
 */
public class ScreenShotActivity1 extends BaseActivity {
 private ImageView picImg;
 private Button screenBtn;
 private ScreenshotNotifyView mDisplayScreenshotSnv;
 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_screen_shot1);
 initView();
 initEvent();
 }
 private void initView() {
 picImg = (ImageView) findViewById(R.id.pic_iv);
 mDisplayScreenshotSnv = (ScreenshotNotifyView) findViewById(R.id.display_screenshot_snv);
 screenBtn = (Button) findViewById(R.id.screen_btn);
 }

 private void initEvent() {
 screenBtn.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
  handleScreenShot();
  }
 });
 }

 /**
 * 处理截屏的业务
 */
 private void handleScreenShot() {
 if (!PermissionUtil.isHasSDCardWritePermission(this)) {
  Toast.makeText(ScreenShotActivity1.this, "没有权限", Toast.LENGTH_SHORT).show();
  PermissionUtil.requestSDCardWrite(this);
  return;
 }
 if (!MemoryUtils.hasEnoughMemory(MemoryUtils.MIN_MEMORY)) {
  Toast.makeText(ScreenShotActivity1.this, "内存不足,截图失败", Toast.LENGTH_SHORT).show();
  return;
 }
 String filePath = getFilePath();
 mDisplayScreenshotSnv.setVisibility(View.GONE);
 mDisplayScreenshotSnv.setPath(filePath, picImg.getMeasuredWidth(), picImg.getMeasuredHeight(), true);
 mDisplayScreenshotSnv.setVisibility(View.VISIBLE);
 }

 private String getFilePath() {
 Bitmap bitmap = createViewBitmap(picImg);
 if (bitmap != null) {
  try {
  // 首先保存图片
  String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "HIS";
  File appDir = new File(storePath);
  if (!appDir.exists()) {
   appDir.mkdir();
  }
  String fileName = System.currentTimeMillis() + ".jpg";
  File file = new File(appDir, fileName);

  BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
  bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
  bos.flush();
  bos.close();

  Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  Uri uri = Uri.fromFile(file);
  intent.setData(uri);
  sendBroadcast(intent);
  return file.getAbsolutePath();
  } catch (Exception e) {
  return null;
  }
 } else {
  return null;
 }
 }

 public Bitmap createViewBitmap(View v) {
 Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas canvas = new Canvas(bitmap);
 v.draw(canvas);
 return bitmap;
 }
}

PermissionUtil.java

package com.lyw.myproject.utils;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;

public class PermissionUtil {
 /**
 * 请求地理位置
 *
 * @param context
 */
 public static void requestLocationPermission(Context context) {
 if (Build.VERSION.SDK_INT >= 23) {
  if (!isHasLocationPermission(context)) {
  ActivityCompat.requestPermissions((Activity) context, PermissionManager.PERMISSION_LOCATION, PermissionManager.REQUEST_LOCATION);
  }
 }
 }

 /**
 * 判断是否有地理位置
 *
 * @param context
 * @return
 */
 public static boolean isHasLocationPermission(Context context) {
 return ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
 }

 /**
 * 判断是否有文件读写的权限
 *
 * @param context
 * @return
 */
 public static boolean isHasSDCardWritePermission(Context context) {
 return ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
 }

 /**
 * 文件权限读写
 *
 * @param context
 */

 public static void requestSDCardWrite(Context context) {
 if (Build.VERSION.SDK_INT >= 23) {
  if (!isHasSDCardWritePermission(context)) {
  ActivityCompat.requestPermissions((Activity) context, PermissionManager.PERMISSION_SD_WRITE, PermissionManager.REQUEST_SD_WRITE);
  }
 }
 }
}

MemoryUtils.java

package com.lyw.myproject.utils;
import android.util.Log;
public class MemoryUtils {
 public static final int MIN_MEMORY = 50 * 1024 * 1024;
 /**
 * 判断有没足够内存截图
 *
 * @param size
 * @return
 */
 public static boolean hasEnoughMemory(int size) {
 //最大内存
 long maxMemory = Runtime.getRuntime().maxMemory();
 //分配的可用内存
 long freeMemory = Runtime.getRuntime().freeMemory();
 //已用内存
 long usedMemory = Runtime.getRuntime().totalMemory() - freeMemory;
 //剩下可使用的内存
 long canUseMemory = maxMemory - usedMemory;
 Log.d("Memory", "hasEnoughMemory: " +
  "maxMemory = " + maxMemory +
  ", freeMemory = " + freeMemory +
  ", usedMemory = " + usedMemory +
  ", canUseMemory = " + canUseMemory);
 if (canUseMemory >= size) {
  return true;
 }
 return false;
 }
}
免费资源网 - https://freexyz.cn/
返回顶部
顶部