在Android应用中开发截图功能涉及到以下几个步骤:获取屏幕内容、处理截图、保存截图等。
/**
* 截取当前可见范围屏幕
*/
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);
}
/**
* 截取当前可见范围屏幕(不包含状态栏)
*/
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);
}
/**
* 截取某个控件
* @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 Runnable scrollRunnable = new Runnable() {
@SuppressLint("NewApi")
@Override
public 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);
}
}
}
}
};
截屏时有一个缩放的动画效果,缩放到右上角。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="500"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="90%"
android:pivotY="15%"
android:toXScale="0.35"
android:toYScale="0.35"/>
<alpha
android:duration="200"
android:fromAlpha="0.5"
android:toAlpha="1.0"/>
set>
mCardView.startAnimation(animation);
截屏完成,会将截取的图片显示在界面中,显示截屏3s后会自动消失。
/**
* 显示截图3s后自动消失
*/
private Runnable captureViewRunnable = new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
mCardView.clearAnimation();
mCardView.setVisibility(View.INVISIBLE);
}
};
activity_screenshot.xml
。
<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">
<Button
android: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"/>
<Button
android: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"/>
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_screenshot">
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
ScrollView>
<androidx.cardview.widget.CardView
android: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">
<ImageView
android: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>
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;
@Override
protected 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);
// 动态添加textview
for (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() {
@Override
public void onClick(View v) {
// screenCapture();
// screenCapture(scrollView);
screenCapture(scrollView);
// screenCaptureNoStatusBar();
}
});
btnLong.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(scrollRunnable);
}
});
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mHandler.postDelayed(captureViewRunnable, CAPTURE_SHOW_TIMEOUT);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
@Override
protected void onPause() {
super.onPause();
mHandler.removeCallbacks(scrollRunnable);
mHandler.removeCallbacks(captureViewRunnable);
}
/**
* 滚屏的线程
*/
private Runnable scrollRunnable = new Runnable() {
@SuppressLint("NewApi")
@Override
public 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")
@Override
public 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() {
@Override
public 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 的子View
View 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;
}
}
}
scale_animation.xml
。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="500"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="90%"
android:pivotY="15%"
android:toXScale="0.35"
android:toYScale="0.35"/>
<alpha
android:duration="200"
android:fromAlpha="0.5"
android:toAlpha="1.0"/>
set>