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…

【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 …

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

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

一文谈谈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;总模型只…

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

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

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

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

Mybatis 新增/批量新增, 拿到返回的自增主键ID

单个新增 &#xff1a; /** * 插入菜单 * param menuInfo * return */ int insertMenuInfo(MenuInfo menuInfo); xml&#xff1a; <insert id"insertMenuInfo" parameterType"com.XXXX..MenuInfo" keyProperty"id&quo…

GoogleLeNet V2 V3 —— Batch Normalization

文章目录 Batch Normalizationinternal covariate shift激活层的作用BN执行的位置数据白化网络中的BN层训练过程 BN的实验效果MNIST与GoogleLeNet V1比较 GoogleLeNet出来之后&#xff0c;Google在这个基础上又演进了几个版本&#xff0c;一般来说是说有4个版本&#xff0c;之前…

Redis 数据库的高可用

文章目录 一.Redis 数据库的持久化1.Redis 高可用概念2.Redis 实现高可用的技术2.1 持久化2.2 主从复制2.3 哨兵2.4 Cluster集群 3.Redis 持久化3.1 持久化的功能3.2 Redis 提供持久化的方式3.2.1 RDB 持久化3.2.2 AOF 持久化&#xff08;append only file&#xff09; 3.3 RDB…

web前端tips:js继承——原型链继承

原型链继承 原型链继承是 JavaScript 中实现继承的一种方式&#xff0c;它通过使用原型来实现对象之间的继承关系。 在 JavaScript 中&#xff0c;每个对象都有一个原型&#xff08;prototype&#xff09;&#xff0c;它是一个指向另一个对象的引用。当我们访问一个对象的属性…

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…

ES6:Object.assign方法详解

ES6&#xff1a;Object.assign方法详解 1、前言2、语法3、基本用法3.1 目标对象和源对象无重名属性3.2 目标对象和源对象有重名属性3.3 有多个源对象3.4 其他情况3.4.1 只有一个参数时&#xff0c;Object.assign会直接返回该参数3.4.2 如果该参数不是对象&#xff0c;则会先转成…

SOC FPGA之HPS模型设计(二)

根据SOC FPGA之HPS模型设计(一)&#xff0c; Quartus工程经过全编译后会产生Handoff文件夹、SOPCINFO文件、SVD文件 二、生成Preloader镜像文件 通过信息交换文件Handoff文件生成Preloader&#xff0c;需要用到SOC EDS Preloader也被称为spl(Second Program Loader)或u-boot…

【云原生 • Kubernetes】认识 k8s、k8s 架构、核心概念点介绍

目录 一、Kubernetes 简介 二、Kubernetes 架构 三、Kunbernetes 有哪些核心概念&#xff1f; 1. 集群 Cluster 2. 容器 Container 3. POD 4. 副本集 ReplicaSet 5. 服务 service 6. 发布 Deployment 7. ConfigMap/Secret 8. DaemonSet 9. 核心概念总结 一、Kubern…