Android 截图功能实现

Android 截图功能实现

  • 简介
  • 效果图
  • 功能实现
    • 1. 截取当前可见范围屏幕
    • 2. 截取当前可见范围屏幕(不包含状态栏)
    • 3. 截取某个控件
    • 4. 截取ScrollView
    • 5. 长截图
    • 6. 截屏动画效果
    • 7. 显示截屏结果,自动消失
    • 6. 完整代码

简介

在Android应用中开发截图功能涉及到以下几个步骤:获取屏幕内容、处理截图、保存截图等。

效果图

在这里插入图片描述
在这里插入图片描述

功能实现

1. 截取当前可见范围屏幕

/*** 截取当前可见范围屏幕*/
private void screenCapture() {
//        View decorView = getWindow().getDecorView();
//        decorView.setDrawingCacheEnabled(true);// 清空缓存,可用于实时截图
//        decorView.buildDrawingCache();
//        Bitmap screenBitmap = Bitmap.createBitmap(decorView.getDrawingCache());
//        decorView.setDrawingCacheEnabled(false); // 清空缓存,可用于实时截图View decorView = getWindow().getDecorView();Bitmap screenBitmap = Bitmap.createBitmap(decorView.getWidth(), decorView.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);decorView.draw(canvas);updateImageCapture(screenBitmap);
}

2. 截取当前可见范围屏幕(不包含状态栏)

/*** 截取当前可见范围屏幕(不包含状态栏)*/
private void screenCaptureNoStatusBar() {View view = getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();// 获取状态栏高度Rect rect = new Rect();view.getWindowVisibleDisplayFrame(rect);int statusBarH = rect.top;// 获取屏幕宽高int w = view.getWidth();int h = view.getHeight();// 去掉状态栏Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarH, w, h - statusBarH);// 销毁缓存信息view.destroyDrawingCache();updateImageCapture(bitmap);
}

3. 截取某个控件

/*** 截取某个控件* @param view*/
private void screenCapture(View view) {Bitmap screenBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);view.draw(canvas);updateImageCapture(screenBitmap);
}

4. 截取ScrollView

/*** 截取ScrollView* @param view*/
private void screenCapture(ScrollView view) {int h = 0;for (int i = 0; i < view.getChildCount(); i++) {h += view.getChildAt(i).getHeight();view.getChildAt(i).setBackgroundColor(Color.parseColor("#FFFFFF"));}Bitmap screenBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), h, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);view.draw(canvas);updateImageCapture(screenBitmap);
}

5. 长截图

/*** 滚屏截长图*/
private Runnable scrollRunnable = new Runnable() {@SuppressLint("NewApi")@Overridepublic void run() {boolean isToBottom = isScrollToEnd();if (isToBottom) {Log.i(TAG, "run: to bottom");Thread.currentThread().interrupt();mHandler.removeCallbacks(scrollRunnable);screenCapture(scrollView);} else {// 未滑动到底部int off = linearLayout.getMeasuredHeight() - scrollView.getHeight(); // 判断高度if (off > 0) {scrollView.scrollBy(0, 6);if (scrollView.getScaleY() >= off) {Thread.currentThread().interrupt();mHandler.removeCallbacks(scrollRunnable);} else {mHandler.postDelayed(this, 10);}}}}
};

6. 截屏动画效果

截屏时有一个缩放的动画效果,缩放到右上角。

  1. 动画效果文件,/res/anim/scale_animation.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="500"android:fromXScale="1.0"android:fromYScale="1.0"android:pivotX="90%"android:pivotY="15%"android:toXScale="0.35"android:toYScale="0.35"/><alphaandroid:duration="200"android:fromAlpha="0.5"android:toAlpha="1.0"/></set>
  1. 代码中使用动画效果
mCardView.startAnimation(animation);

7. 显示截屏结果,自动消失

截屏完成,会将截取的图片显示在界面中,显示截屏3s后会自动消失。

/*** 显示截图3s后自动消失*/
private Runnable captureViewRunnable = new Runnable() {@SuppressLint("NewApi")@Overridepublic void run() {mCardView.clearAnimation();mCardView.setVisibility(View.INVISIBLE);}
};

6. 完整代码

  1. 布局文件:activity_screenshot.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ScreenshotActivity"><Buttonandroid:id="@+id/btn_screenshot"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="60dp"android:text="截图"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"/><Buttonandroid:id="@+id/bnt_long"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="长截图"android:layout_marginStart="20dp"app:layout_constraintStart_toEndOf="@id/btn_screenshot"app:layout_constraintTop_toTopOf="@id/btn_screenshot"app:layout_constraintBottom_toBottomOf="@id/btn_screenshot"/><ScrollViewandroid:id="@+id/scroll_view"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/btn_screenshot"><LinearLayoutandroid:id="@+id/linear_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"/></ScrollView><androidx.cardview.widget.CardViewandroid:id="@+id/cardView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@android:color/transparent"app:contentPadding="3dp"app:cardCornerRadius="15dp"app:cardElevation="20dp"app:cardPreventCornerOverlap="true"app:cardUseCompatPadding="true"android:visibility="invisible"app:layout_constraintTop_toTopOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"><ImageViewandroid:id="@+id/iv_capture"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"/></androidx.cardview.widget.CardView></androidx.constraintlayout.widget.ConstraintLayout>
  1. Activity文件:ScreenshotActivity.java
public class ScreenshotActivity extends AppCompatActivity {private static final String TAG = "ScreenshotActivity";private ScrollView scrollView;private LinearLayout linearLayout;private ImageView ivScreenshots;private CardView mCardView;private Handler mHandler = new Handler();// 截图动画private Animation animation;// 截图显示的时间,超时后消失private static final int CAPTURE_SHOW_TIMEOUT = 3000;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_screenshot);scrollView = findViewById(R.id.scroll_view);linearLayout = findViewById(R.id.linear_layout);ivScreenshots = findViewById(R.id.iv_capture);mCardView = findViewById(R.id.cardView);Button btnScreenshots = findViewById(R.id.btn_screenshot);Button btnLong = findViewById(R.id.bnt_long);animation = AnimationUtils.loadAnimation(this, R.anim.scale_animation);animation.setFillAfter(true);// 动态添加textviewfor (int i = 0; i < 50; i++) {TextView textView = new TextView(this);textView.setText("item-" + (i + 1));textView.setGravity(Gravity.CENTER);textView.setTextSize(16);linearLayout.addView(textView);}btnScreenshots.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {
//                screenCapture();
//                screenCapture(scrollView);screenCapture(scrollView);
//                screenCaptureNoStatusBar();}});btnLong.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mHandler.post(scrollRunnable);}});animation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {mHandler.postDelayed(captureViewRunnable, CAPTURE_SHOW_TIMEOUT);}@Overridepublic void onAnimationRepeat(Animation animation) {}});}@Overrideprotected void onPause() {super.onPause();mHandler.removeCallbacks(scrollRunnable);mHandler.removeCallbacks(captureViewRunnable);}/*** 滚屏的线程*/private Runnable scrollRunnable = new Runnable() {@SuppressLint("NewApi")@Overridepublic void run() {boolean isToBottom = isScrollToEnd();if (isToBottom) {Log.i(TAG, "run: to bottom");Thread.currentThread().interrupt();mHandler.removeCallbacks(scrollRunnable);screenCapture(scrollView);} else {// 未滑动到底部int off = linearLayout.getMeasuredHeight() - scrollView.getHeight(); // 判断高度if (off > 0) {scrollView.scrollBy(0, 6);if (scrollView.getScaleY() >= off) {Thread.currentThread().interrupt();mHandler.removeCallbacks(scrollRunnable);} else {mHandler.postDelayed(this, 10);}}}}};/*** 显示截图3s后自动消失*/private Runnable captureViewRunnable = new Runnable() {@SuppressLint("NewApi")@Overridepublic void run() {mCardView.clearAnimation();mCardView.setVisibility(View.INVISIBLE);}};/*** 截取当前可见范围屏幕*/private void screenCapture() {
//        View decorView = getWindow().getDecorView();
//        decorView.setDrawingCacheEnabled(true);// 清空缓存,可用于实时截图
//        decorView.buildDrawingCache();
//        Bitmap screenBitmap = Bitmap.createBitmap(decorView.getDrawingCache());
//        decorView.setDrawingCacheEnabled(false); // 清空缓存,可用于实时截图View decorView = getWindow().getDecorView();Bitmap screenBitmap = Bitmap.createBitmap(decorView.getWidth(), decorView.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);decorView.draw(canvas);updateImageCapture(screenBitmap);}/*** 截取某个控件* @param view*/private void screenCapture(View view) {Bitmap screenBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);view.draw(canvas);updateImageCapture(screenBitmap);}/*** 截取ScrollView* @param view*/private void screenCapture(ScrollView view) {int h = 0;for (int i = 0; i < view.getChildCount(); i++) {h += view.getChildAt(i).getHeight();view.getChildAt(i).setBackgroundColor(Color.parseColor("#FFFFFF"));}Bitmap screenBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), h, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(screenBitmap);view.draw(canvas);updateImageCapture(screenBitmap);}/*** 截取当前可见范围屏幕(不包含状态栏)*/private void screenCaptureNoStatusBar() {View view = getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();// 获取状态栏高度Rect rect = new Rect();view.getWindowVisibleDisplayFrame(rect);int statusBarH = rect.top;// 获取屏幕宽高int w = view.getWidth();int h = view.getHeight();// 去掉状态栏Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarH, w, h - statusBarH);// 销毁缓存信息view.destroyDrawingCache();updateImageCapture(bitmap);}private void updateImageCapture(final Bitmap screenBitmap) {runOnUiThread(new Runnable() {@Overridepublic void run() {mCardView.setVisibility(View.VISIBLE);ivScreenshots.setImageBitmap(screenBitmap);}});mCardView.startAnimation(animation);}/*** scrollview是否已经滑到底部* @return*/private boolean isScrollToEnd() {// 获取 ScrollView 的可视高度int visibleHeight = scrollView.getHeight() - scrollView.getPaddingTop() - scrollView.getPaddingBottom();// 获取 ScrollView 的子ViewView lastChild = scrollView.getChildAt(scrollView.getChildCount() - 1);// 获取 ScrollView 可以滑动的范围int scrollRange = scrollView.getChildAt(0).getHeight() - scrollView.getHeight();// 获取 ScrollView 的滚动位置int scrollY = scrollView.getScrollY();// 计算ScrollView底部位置int scrollViewBottom = scrollY + visibleHeight;// 获取ScrollView的子View的底部位置int lastChildBottom = lastChild.getBottom();// 判断 ScrollView 是否滚动到底部if (scrollY == scrollRange) {// 已滑动到底部return true;} else if (scrollViewBottom >= lastChildBottom) {// scrollTo 和 scrollTo 不是同时回调,所以添加两个逻辑都可(可根据需要决定是否需要使用两个逻辑组合)// 已滑动到底部return true;} else {return false;}}}
  1. 截图动画文件:scale_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="500"android:fromXScale="1.0"android:fromYScale="1.0"android:pivotX="90%"android:pivotY="15%"android:toXScale="0.35"android:toYScale="0.35"/><alphaandroid:duration="200"android:fromAlpha="0.5"android:toAlpha="1.0"/></set>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/11382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

顺序表的实现

文章目录 1.概念及结构 2.接口实现 3.数组相关oj题 4.顺序表的问题及思考 文章内容 1.概念及结构 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序…

【物理】模拟粒子在电场和磁场中的轨迹研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 模拟粒子在电场和磁场中的轨迹研究是物理学中的一个重要研究领域&#xff0c;涉及到电磁场、粒子运动、轨迹分析等多个方面。在这个研究中&…

Python爬虫实例之淘宝商品页面爬取(api接口)

可以使用Python中的requests和BeautifulSoup库来进行网页爬取和数据提取。以下是一个简单的示例&#xff1a; import requests from bs4 import BeautifulSoupdef get_product_data(url):# 发送GET请求&#xff0c;获取网页内容headers {User-Agent: Mozilla/5.0 (Windows NT…

前端CryptoJS-AES加解密 对应php的AES-128-CBC加解密踩坑(java也相同加解密)

前端部分注意看填充是pkcs7 有个前提&#xff0c;要看前端有没有转成hex格式&#xff0c;如果没转&#xff0c;php那边就不需要调用特定函数转hex格式的 const keyStr 5hOwdHxpW0GOciqZ;const iv 0102030405060708;//加密function Encrypt(word) {let key CryptoJS.enc.Ut…

今天你做代码检查了吗?

当下&#xff0c;各行各业都在寻找可以降本增效的效率途径&#xff0c;AI人工智能、机器学习等概念也被广泛应用至业务中&#xff1b;而广州云标局推出了一款智能ide代码工具——codigger&#xff0c;不仅项目体检能为开发项目提供快速代码检测&#xff0c;主要检测维度包括bug…

【Spring框架】Spring读取与存储综合练习

练习 在 Spring 项⽬中&#xff0c;通过 main ⽅法获取到 Controller 类&#xff0c;调⽤ Controller ⾥⾯通过注⼊的⽅式调⽤ Service 类&#xff0c;Service 再通过注⼊的⽅式获取到 Repository 类&#xff0c;Repository 类⾥⾯有⼀个⽅法构建⼀个 User 对象&#xff0c;返…

抖音账号矩阵系统开发源码

一、技术自研框架开发背景&#xff1a; 抖音账号矩阵系统是一种基于数据分析和管理的全新平台&#xff0c;能够帮助用户更好地管理、扩展和营销抖音账号。 部分源码分享&#xff1a; ic function indexAction() { //面包屑 $breadcrumbs [ [tit…

虚拟机 RHEL8 安装 MySQL 8.0.34

目录 安装步骤一、清除所有残留的旧MySQL二、安装MySQL 报错问题1. 提示未找到匹配的参数&#xff1a; mysql-community-server2. 公钥问题 安装步骤 一、清除所有残留的旧MySQL 1. 关闭MySQL [rootlocalhost /]# service mysqld stop Redirecting to /bin/systemctl stop …

线程池与ThreadLocal同时使用读取到脏数据

问题&#xff1a;当线程池与ThreadLocal共用时&#xff0c;ThreadLocal读取数据出现错乱。 问题验证&#xff1a; public static void main(String[] args) {ExecutorService executorService Executors.newFixedThreadPool(2);final ThreadLocal<String> threadLocal…

【导入外部jar包到maven项目中--亲测可行】

若项目为springweb项目&#xff0c;则先将jar放到WEB-INF/lib 目录下选中对应的jar包&#xff0c;右键选项 add-lirrary &#xff1b;成功加入之后的jar包是一个项目的目录结构&#xff1a; 至此&#xff0c;项目能够正常运行&#xff0c;在代码周也能够进行导包 转折点&…

windows下若依vue项目部署

下载若依项目&#xff0c;前端后端项目本地启动前端打包&#xff0c;后端打包配置nginx.conf 需要注意的是&#xff1a;路径别用中文&#xff0c;要不然报错 #前台访问地址及端口80&#xff0c;在vue.config.js中可查看server {listen 80;server_name localhost; #后台…

一文谈谈Git

"And if forever lasts till now Alright" 为什么要有git&#xff1f; 想象一下&#xff0c;现如今你的老师同时叫你和张三&#xff0c;各自写一份下半年的学习计划交给他。 可是你的老师是一个极其"较真"的人&#xff0c;发现你俩写的学习计划太"水&…

QT:当登录成功时,关闭登录界面,跳转到新的界面中

1> 继续完善登录框&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;跳转到新的界面中 widget.h #include "widget.h" //#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent)//, ui(new Ui::Widget) {//ui->setu…

使用python部署chineseocr_lite

使用python部署chineseocr_lite 简介安装报错解决python调用结果 简介 项目地址&#xff1a;https://github.com/DayBreak-u/chineseocr_lite chineseocr_lite 是一个开源项目&#xff0c;用来实现中文的文字识别&#xff0c;支持竖排文字识别、繁体识别&#xff0c;总模型只…

机器学习分布式框架ray运行TensorFlow实例

使用Ray来实现TensorFlow的训练是一种并行化和分布式的方法&#xff0c;它可以有效地加速大规模数据集上的深度学习模型的训练过程。Ray是一个高性能、分布式计算框架&#xff0c;可以在集群上进行任务并行化和数据并行化&#xff0c;从而提高训练速度和可扩展性。 以下是实现…

java调用Groovy动态代码

感谢作者&#xff1a;https://www.ab62.cn/article/36028.html 我的使用 场景&#xff1a;参数转换&#xff08;适配上下游&#xff09; public static void main(String[] args) {String scriptText script();GroovyClassLoader classLoader new GroovyClassLoader();Clas…

某制造企业基于 KubeSphere 的云原生实践

背景介绍 随着业务升级改造与软件产品专案的增多&#xff0c;常规的物理机和虚拟机方式逐渐暴露出一些问题&#xff1a; 大量服务部署在虚拟机上&#xff0c;资源预估和硬件浪费较大&#xff1b;大量服务部署在虚拟机上&#xff0c;部署时间和难度较大&#xff0c;自动化程度…

Linux chmod

chmod 首先chmod 用于修改文件权限&#xff0c;使用命令 ll 查看文件列表&#xff0c;或者使用stat文件名 可以查看其相应的权限 显示的形式为例如 rwx r- - r-- &#xff0c;即所有者拥有读写执行的权限 &#xff0c;同组人员和其他人都只拥有读的权限 一般修改权限为三部分…

加利福尼亚大学|3D-LLM:将3D世界于大规模语言模型结合

来自加利福尼亚大学的3D-LLM项目团队提到&#xff1a;大型语言模型 (LLM) 和视觉语言模型 (VLM) 已被证明在多项任务上表现出色&#xff0c;例如常识推理。尽管这些模型非常强大&#xff0c;但它们并不以 3D 物理世界为基础&#xff0c;而 3D 物理世界涉及更丰富的概念&#xf…

SQL关于having用法及与where的区别

having后面只能接聚合函数 因为having的存在本来就是为了解决&#xff1a;where后面不能接聚合函数&#xff0c;这个问题。 与where的异同&#xff1a; 相同之处&#xff1a; 1.作用都是筛选 2.都可以使用比较运算符&#xff1a;in&#xff0c;between and&#xff0c;lik…