这里有新鲜出炉的精品教程,程序狗速度看过来!
Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。
本篇文章主要介绍了android长截屏原理及实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
小米系统自带的长截屏应该很多人都用过,效果不错。当长截屏时listview就会自动滚动,当按下停止截屏时,就会得到一张完整的截屏。
该篇就介绍一下长截屏的原理
上篇中介绍了android屏幕共享实现方式,该篇的原理和上一篇基本一致。
获取view影像
当我们想得到一个view的影像时,我们可以调用系统api,得到view的bitmap,但有时可能得不到。我们可以通过另一种方式得到。
首先创建一个和view一样大小的bitmap
- Bitmap bmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
然后把view绘制到bmp上
- Canvas canvas = new Canvas();
- canvas.setBitmap(bmp);
- view.draw(canvas);
执行完上面代码后bmp上就是view的影像了。
制造滚动事件,促使view滚动
我们可以创建一个MotionEvent,然后定时修改MotionEvent的y值,并分发给view,从而促使view上下滚动。当然我们也可以定时修改x值促使view左右滚动。
代码大致如下
- final MotionEvent motionEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, view.getWidth() / 2, view.getHeight() / 2, 0);
- view.postDelayed(new Runnable() {@Override public void run() {
- motionEvent.setAction(MotionEvent.ACTION_MOVE);
- motionEvent.setLocation((int) motionEvent.getX(), (int) motionEvent.getY() - 1);
- //把事件分发给view
- view.dispatchTouchEvent(motionEvent);
- view.postDelayed(this, DELAY);
- }
- },
- DELAY);
注意:从分发DOWN事件到结束都要使用同一个MotionEvent对象,只需要不断改变x或y值。
每次x或y的值相对于上次改动不能过大,若过大,view实际滚动距离可能达不到为MotionEvent设置的值(因view滚动时卡顿导致)。
截屏
当为MotionEvent设置的x或y值正好时当前view的大小时,创建新的bitmap,通过上述方法把view绘制到bitmap上,想要停止截屏时拼接所有bitmap即可。
备注
当我们想要把Listview长截屏时,需要为ListView外面嵌套一层和ListView一样大小的View,以上的所有操作都在嵌套的这层view上操作。当我们调用嵌套的这层view的draw(new Canvas(bmp))时会把当前看到的这块ListView绘制到bmp上,不管ListView嵌套了多少层子view都可以绘制到当前bmp上。
由于ListView中根据滑动的距离是否大于ViewConfiguration.get(view.getContext()).getScaledTouchSlop() )来确定要不要滚动,所以一开始我们要特殊处理下,为什么是ViewConfiguration.get(view.getContext()).getScaledTouchSlop() )可以查看ListView的事件分发相关函数得到(dispatchTouchEvent),让Listview认为是开始滚动,这样才能保证以后分发的滑动距离和实际滚动距离一致。
Listview也要通知是否滚动到了最后,不然如果没有手动停止的话,虽然还是在一直分发滚动事件,但ListView不再滚动,导致最终截图后后面全是重复的最后一屏幕。
附 实现大致方式代码,有待优化
- package com.example.wanjian.test;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.os.Environment;
- import android.os.SystemClock;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewConfiguration;
- import android.widget.LinearLayout;
- import android.widget.Toast;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.lang.ref.WeakReference;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by wanjian on 16/8/18.
- */
- public class ScrollableViewRECUtil {
- public static final int VERTICAL = 0;
- private static final int DELAY = 2;
- private List < Bitmap > bitmaps = new ArrayList < >();
- private int orientation = VERTICAL;
- private View view;
- private boolean isEnd;
- private OnRecFinishedListener listener;
- public ScrollableViewRECUtil(View view, int orientation) {
- this.view = view;
- this.orientation = orientation;
- }
- public void start(final OnRecFinishedListener listener) {
- this.listener = listener;
- final MotionEvent motionEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, view.getWidth() / 2, view.getHeight() / 2, 0);
- view.dispatchTouchEvent(motionEvent);
- motionEvent.setAction(MotionEvent.ACTION_MOVE);
- //滑动距离大于ViewConfiguration.get(view.getContext()).getScaledTouchSlop()时listview才开始滚动
- motionEvent.setLocation(motionEvent.getX(), motionEvent.getY() - (ViewConfiguration.get(view.getContext()).getScaledTouchSlop() + 1));
- view.dispatchTouchEvent(motionEvent);
- motionEvent.setLocation(motionEvent.getX(), view.getHeight() / 2);
- view.postDelayed(new Runnable() {@Override public void run() {
- if (isEnd) {
- //停止时正好一屏则全部绘制,否则绘制部分
- if ((view.getHeight() / 2 - (int) motionEvent.getY()) % view.getHeight() == 0) {
- Bitmap bitmap = rec();
- bitmaps.add(bitmap);
- } else {
- Bitmap origBitmap = rec();
- int y = view.getHeight() / 2 - (int) motionEvent.getY();
- Bitmap bitmap = Bitmap.createBitmap(origBitmap, 0, view.getHeight() - y % view.getHeight(), view.getWidth(), y % view.getHeight());
- bitmaps.add(bitmap);
- origBitmap.recycle();
- }
- //最后一张可能高度不足view的高度
- int h = view.getHeight() * (bitmaps.size() - 1);
- Bitmap bitmap = bitmaps.get(bitmaps.size() - 1);
- h = h + bitmap.getHeight();
- Bitmap result = Bitmap.createBitmap(view.getWidth(), h, Bitmap.Config.RGB_565);
- Canvas canvas = new Canvas();
- canvas.setBitmap(result);
- for (int i = 0; i < bitmaps.size(); i++) {
- Bitmap b = bitmaps.get(i);
- canvas.drawBitmap(b, 0, i * view.getHeight(), null);
- b.recycle();
- }
- listener.onRecFinish(result);
- return;
- }
- if ((view.getHeight() / 2 - (int) motionEvent.getY()) % view.getHeight() == 0) {
- Bitmap bitmap = rec();
- bitmaps.add(bitmap);
- }
- motionEvent.setAction(MotionEvent.ACTION_MOVE);
- //模拟每次向上滑动一个像素,这样可能导致滚动特别慢,实际使用时可以修改该值,但判断是否正好滚动了
- //一屏幕就不能简单的根据 (view.getHeight() / 2 - (int) motionEvent.getY()) % view.getHeight() == 0 来确定了。
- //可以每次滚动n个像素,当发现下次再滚动n像素时就超出一屏幕时可以改变n的值,保证下次滚动后正好是一屏幕,
- //这样就可以根据(view.getHeight() / 2 - (int) motionEvent.getY()) % view.getHeight() == 0来判断要不要截屏了。
- motionEvent.setLocation((int) motionEvent.getX(), (int) motionEvent.getY() - 1);
- view.dispatchTouchEvent(motionEvent);
- view.postDelayed(this, DELAY);
- }
- },
- DELAY);
- }
- public void stop() {
- isEnd = true;
- }
- private Bitmap rec() {
- Bitmap film = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
- Canvas canvas = new Canvas();
- canvas.setBitmap(film);
- view.draw(canvas);
- return film;
- }
- public interface OnRecFinishedListener {
- void onRecFinish(Bitmap bitmap);
- }
- }
activity代码
- setContentView(R.layout.activity_main4);
- //
- listview= (ListView) findViewById(R.id.listview);
- listview.setAdapter(new BaseAdapter() {
- @Override
- public int getCount() {
- return 100;
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView==null){
- Button button= (Button) LayoutInflater.from(getApplication()).inflate(R.layout.item,listview,false);
- button.setText(""+position);
- return button;
- }
- ((Button)convertView).setText(""+position);
- return convertView;
- }
- });
- //
- File file=new File(Environment.getExternalStorageDirectory(),"aaa");
- file.mkdirs();
- for (File f:file.listFiles()){
- f.delete();
- }
- listview.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- listview.getViewTreeObserver().removeGlobalOnLayoutListener(this);
- start();
- }
- });
- private void start(){
- final View view=findViewById(R.id.view);
- final ScrollableViewRECUtil scrollableViewRECUtil=new ScrollableViewRECUtil(view,ScrollableViewRECUtil.VERTICAL);
- scrollableViewRECUtil.start(new ScrollableViewRECUtil.OnRecFinishedListener() {
- @Override
- public void onRecFinish(Bitmap bitmap) {
- File f= Environment.getExternalStorageDirectory();
- System.out.print(f.getAbsoluteFile().toString());
- Toast.makeText(getApplicationContext(),f.getAbsolutePath(),Toast.LENGTH_LONG).show();
- try {
- bitmap.compress(Bitmap.CompressFormat.JPEG,60,new FileOutputStream(new File(f,"rec"+System.currentTimeMillis()+".jpg")));
- Toast.makeText(getApplicationContext(),"Success",Toast.LENGTH_LONG).show();
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- });
- // scrollableViewRECUtil
- view.postDelayed(new Runnable() {
- @Override
- public void run() {
- scrollableViewRECUtil.stop();
- }
- },90*1000);
- }
布局
- <?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:id="@+id/view"
- android:orientation="vertical"
- >
- <ListView
- android:id="@+id/listview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:divider="#e1e1e1"
- android:dividerHeight="2dp"
- ></ListView>
- </LinearLayout>
效果图
屏幕
最终截屏
可以看到毫无拼接痕迹。
来源: http://www.phperz.com/article/17/0913/345761.html