Android 截屏带动画,缩小移动至屏幕右上角消失
传示例小视频没成功,就直接代码解释吧
最关键的几个操作,(思路:一般情况下,绝大多数View在绘制都可以设置缓存,我获取缓存,会返回给我们一个Bitmap对象,这个Bitmap对象是就是我们需要的)下面看下几个关键操作
//设置缓存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//从缓存中获取当前屏幕的图片
view.getDrawingCache();
//清楚缓存
destroyDrawingCache();
这里我单独写了一个类来处理截屏,这是构造方法
public ScreenGraspUtils(Activity activity, View view) {
this.activity = activity;
this.LayoutTop = view;
}
下面是截屏方法
public void grasp() {
File appDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "xxPic");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = "推广二维码.jpg";
File file = new File(appDir, fileName);
if (file.exists()) {
if (file.length() < 10) {
file.delete();
} else {
ToastUtil.showToast(activity, "二维码已经存在了,请在相册中查看");
return;
}
}
//先隐藏顶部的导航栏
LayoutTop.setVisibility(View.INVISIBLE);
//获取当前屏幕的大小
int width = activity.getWindow().getDecorView().getRootView().getWidth();
int height = activity.getWindow().getDecorView().getRootView().getHeight();
//生成相同大小的图片
temBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
temBitmap.setDensity(activity.getResources().getDisplayMetrics().densityDpi);
//找到当前页面的跟布局
View view = activity.getWindow().getDecorView().getRootView();
//先清缓存
//view.destroyDrawingCache();
//设置缓存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//从缓存中获取当前屏幕的图片
temBitmap = view.getDrawingCache();
// 获取状态栏高度
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
// 获取屏幕长和高
screenwidth = activity.getResources().getDisplayMetrics().widthPixels;
screenheight = activity.getResources().getDisplayMetrics().heightPixels;
// 去掉标题栏
bitmap = Bitmap.createBitmap(temBitmap, 0, statusBarHeight, screenwidth, screenheight - statusBarHeight);
//清缓存
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
//将截屏的bitmap保存至本地
saveImage(bitmap);
//构造一个ImageView对象,用于显示一个截屏的动画
imageView = new ImageView(activity);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
imageView.setImageBitmap(bitmap);
//将ImageView对象添加到当前Activity所在界面
activity.addContentView(imageView, params);
//构造一个图片的像素矩阵,通过操作矩阵变化,来实现图片缩小移动的动画
mScaleMatrix = new Matrix();
//设置图片的变换方式为矩阵变换
imageView.setScaleType(ImageView.ScaleType.MATRIX);
//这是一个自定义的定时器,具体实现待会看下面
TimeUtils.getTaskTimer(1000, 25, new TimeUtils.ITimerTask() {//矩阵变化时间为1s,没25ms发送一次,一共会发送40次,也就是变化40次,手机性能差的,可能1s没有执行完成,在下面的onFished移除任务,没到40次几页就不会执行了,
@Override
public void onTask(long leftTime) {
sX = screenwidth;//图片变化中心点的X
sY = 0;//图片变化中心的Y坐标
mScaleMatrix.postScale(0.9f, 0.9f, sX, sY);//改变图片的像素矩阵,结果是0.9倍缩放,当然就是变小了
imageView.setImageMatrix(mScaleMatrix);//缩小图片
}
@Override
public void onFished() {
TimeUtils.setTimer(null);//移除任务
//移除跟布局锁添加的imageview,
((ViewGroup) activity.getWindow().getDecorView().getRootView()).removeView(imageView);
//销毁ImageView所占用的bitmap资源,不然imageview不会移除,下次再次截屏会覆盖在上面
imageView.setImageBitmap(null);
//下面两个都是回收,不回收会增加内存消耗,(建议不用就收回)
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();//回收bitmap
bitmap = null;
}
if (temBitmap != null && !temBitmap.isRecycled()) {
temBitmap.recycle();//回收bitmap
temBitmap = null;
}
//这是一个顶部带返回按钮和保存二维码的导航栏,截屏前为了截取的图片没有这些,开始隐藏了,现在还原,保证用户可以正常操作界面
LayoutTop.setVisibility(View.VISIBLE);
}
}).start();//start()一定不能忘记,这是开启定时器
}
下面是保存图片,写入文件的权限,我这里就没有申请了,需要的自己申请下也很简单
private void saveImage(Bitmap bmp) {
if (bmp == null) return;
File appDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "xxPic");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = "推广二维码.jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
//系统广播,刷新相册,在相册中才能看到截屏
activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File("/sdcard/xxPic/推广二维码.jpg"))));
ToastUtil.showToast(activity, "已保存至 xxPic/推广二维码.jpg");
} catch (FileNotFoundException e) {
ToastUtil.showToast(activity, "保存失败");
e.printStackTrace();
} catch (IOException e) {
ToastUtil.showToast(activity, "保存失败");
e.printStackTrace();
}
}
下面是定时器类
public class TimeUtils{
private static MyTimer mTimer;
public static void setTimer(MyTimer myTimer){
mTimer=myTimer;
}
public static MyTimer getTaskTimer(long millisInFuture, long countDownInterval, ITimerTask iTimerTask) {
if (mTimer == null) {
mTimer = new MyTimer(millisInFuture, countDownInterval, iTimerTask);
} else {
if (mTimer.isRunning()) {
mTimer.cancel();
mTimer = null;
return new MyTimer(millisInFuture, countDownInterval, iTimerTask);
}
}
return mTimer;
}
/**
* 倒计时工具
*/
public static class MyTimer extends CountDownTimer {
private ITimerTask iTimerTask;
private boolean isRunning;
/**
* @param millisInFuture 倒计时
* @param countDownInterval 以多少毫秒的方式倒计时
*/
public MyTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
/**
* @param millisInFuture 倒计时
* @param countDownInterval 以多少毫秒的方式倒计时
* @param timerTask 倒计时开启后的任务接口
*/
public MyTimer(long millisInFuture, long countDownInterval, ITimerTask timerTask) {
super(millisInFuture, countDownInterval);
this.iTimerTask = timerTask;
}
@Override
public void onTick(long millisUntilFinished) {
isRunning = true;
iTimerTask.onTask(millisUntilFinished);
}
@Override
public void onFinish() {
if (iTimerTask != null)
iTimerTask.onFished();
isRunning = false;
}
public boolean isRunning() {
return isRunning;
}
}
/**
* 倒计时任务接口
*/
public interface ITimerTask {
/**
* @param leftTime 倒计时剩余时间
* 倒计时开启后执行的任务
*/
void onTask(long leftTime);
/**
* 倒计时结束
*/
void onFished();
}
}
到这里就搞定了