日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android长截屏代码,android长截屏原理及实现代码

發(fā)布時間:2023/12/15 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android长截屏代码,android长截屏原理及实现代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

android長截屏原理及實現(xiàn)代碼

發(fā)布時間:2020-08-31 06:55:16

來源:腳本之家

閱讀:158

作者:Android筆記

小米系統(tǒng)自帶的長截屏應該很多人都用過,效果不錯。當長截屏時listview就會自動滾動,當按下停止截屏時,就會得到一張完整的截屏。

該篇就介紹一下長截屏的原理

上篇中介紹了android屏幕共享實現(xiàn)方式,該篇的原理和上一篇基本一致。

獲取view影像

當我們想得到一個view的影像時,我們可以調用系統(tǒng)api,得到view的bitmap,但有時可能得不到。我們可以通過另一種方式得到。

首先創(chuàng)建一個和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);

執(zhí)行完上面代碼后bmp上就是view的影像了。

制造滾動事件,促使view滾動

我們可以創(chuàng)建一個MotionEvent,然后定時修改MotionEvent的y值,并分發(fā)給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);

//把事件分發(fā)給view

view.dispatchTouchEvent(motionEvent);

view.postDelayed(this, DELAY);

}

}, DELAY);

注意:從分發(fā)DOWN事件到結束都要使用同一個MotionEvent對象,只需要不斷改變x或y值。

每次x或y的值相對于上次改動不能過大,若過大,view實際滾動距離可能達不到為MotionEvent設置的值(因view滾動時卡頓導致)。

截屏

當為MotionEvent設置的x或y值正好時當前view的大小時,創(chuàng)建新的bitmap,通過上述方法把view繪制到bitmap上,想要停止截屏時拼接所有bitmap即可。

備注

當我們想要把Listview長截屏時,需要為ListView外面嵌套一層和ListView一樣大小的View,以上的所有操作都在嵌套的這層view上操作。當我們調用嵌套的這層view的draw(new Canvas(bmp))時會把當前看到的這塊ListView繪制到bmp上,不管ListView嵌套了多少層子view都可以繪制到當前bmp上。

由于ListView中根據(jù)滑動的距離是否大于ViewConfiguration.get(view.getContext()).getScaledTouchSlop() )來確定要不要滾動,所以一開始我們要特殊處理下,為什么是ViewConfiguration.get(view.getContext()).getScaledTouchSlop() )可以查看ListView的事件分發(fā)相關函數(shù)得到(dispatchTouchEvent),讓Listview認為是開始滾動,這樣才能保證以后分發(fā)的滑動距離和實際滾動距離一致。

Listview也要通知是否滾動到了最后,不然如果沒有手動停止的話,雖然還是在一直分發(fā)滾動事件,但ListView不再滾動,導致最終截圖后后面全是重復的最后一屏幕。

附 實現(xiàn)大致方式代碼,有待優(yōu)化

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 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);

//模擬每次向上滑動一個像素,這樣可能導致滾動特別慢,實際使用時可以修改該值,但判斷是否正好滾動了

//一屏幕就不能簡單的根據(jù) (view.getHeight() / 2 - (int) motionEvent.getY()) % view.getHeight() == 0 來確定了。

//可以每次滾動n個像素,當發(fā)現(xiàn)下次再滾動n像素時就超出一屏幕時可以改變n的值,保證下次滾動后正好是一屏幕,

//這樣就可以根據(jù)(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);

}

布局

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/view"

android:orientation="vertical"

>

android:id="@+id/listview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:divider="#e1e1e1"

android:dividerHeight="2dp"

>

效果圖

屏幕

最終截屏

可以看到毫無拼接痕跡。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結

以上是生活随笔為你收集整理的android长截屏代码,android长截屏原理及实现代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。