如何在内容滚动时捕获 ScrollView 的一部分?

How to capture part of a ScrollView as its content is scrolling?

在扩展 ScrollView class 之后,我能够轻松地实时收到滚动通知。

现在我需要在一个非常具体的部分捕获这个滚动视图的内容。 假设我想捕获屏幕的顶部( 匹配父级宽度 和定义的高度,例如 100dp)。但只有 ScrollView 的内容而不是其余内容,如果顶部有任何其他内容但不作为 ScrollView 的一部分。

我尝试在滚动视图上使用 :

  1. setDrawingCacheEnabled(true);
  2. getDrawingCache(true);
  3. setDrawingCacheEnabled(false);

然后我尝试裁剪以获得我想要的部分:

Bitmap.createBitmap(complete, 0, 0, width, height);

结果与我想要达到的目标相去甚远,性能非常非常差,有时我会得到 SIGENVgetDrawingCache(true) 尝试使用回收位图...

那么,如何才能在不影响性能的情况下轻松捕获所需区域的内容?

注意:这个过程必须在我滚动内容时完成,所以在 ScrollView 的 onScrollChanged(final int x, final int y).

里面

谢谢!

由于这个问题很有趣,所以我实施了它,它似乎工作正常。我猜你每次都在重新创建位图,这就是速度变慢的原因。

思路是这样的,你在ScrollView中创建一个你想要复制的区域(参见Rect cropRectBitmap screenshotBitmap),它是全宽的,你只需要设置高度。该视图会自动在其自身上设置一个滚动侦听器,并且在每次滚动时它都会复制该区域。请注意 setDrawingCacheEanbled(true) 在实例化视图时仅调用一次,它基本上告诉视图您将调用 getDrawingCache(),这将 return 视图在其上绘制自身的位图。然后它会复制 screenshotBitmap 上感兴趣的区域,这就是您可能想要使用的位图。

ScreenshottableScrollView.java

package com.example.lelloman.screenshottablescrollview;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.widget.ScrollView;

/**
 * Created by lelloman on 16-2-16.
 */
public class ScreenshottableScrollView extends ScrollView implements ViewTreeObserver.OnScrollChangedListener {

    public interface OnNewScreenshotListener {
        void onNewScreenshot(Bitmap bitmap);
    }

    private Bitmap screenshotBitmap = null;
    private Canvas screenshotCanvas = null;
    private int screenshotHeightPx = 0;
    private OnNewScreenshotListener listener = null;
    private Rect cropRect;
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);


    public ScreenshottableScrollView(Context context) {
        super(context);
        init();
    }

    public ScreenshottableScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ScreenshottableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ScreenshottableScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init(){
        setDrawingCacheEnabled(true);
        getViewTreeObserver().addOnScrollChangedListener(this);
    }

    public void setOnNewScreenshotListener(OnNewScreenshotListener listener){
        this.listener = listener;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if(screenshotHeightPx != 0)
            makeScrenshotBitmap(w,h);
    }

    public void setScreenshotHeightPx(int q){
        screenshotHeightPx = q;
        makeScrenshotBitmap(getWidth(), getHeight());
    }

    private void makeScrenshotBitmap(int width, int height){

        if(screenshotBitmap != null) screenshotBitmap.recycle();

        if(width == 0 || height == 0) return;

        screenshotBitmap = Bitmap.createBitmap(width, screenshotHeightPx, Bitmap.Config.ARGB_8888);
        screenshotCanvas = new Canvas(screenshotBitmap);

        cropRect = new Rect(0,0,width,screenshotHeightPx);


    }

    @Override
    public void onScrollChanged() {
        if(listener == null) return;

        Bitmap bitmap = getDrawingCache();

        screenshotCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        screenshotCanvas.drawBitmap(bitmap,cropRect, cropRect,paint);
        listener.onNewScreenshot(screenshotBitmap);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.lelloman.screenshottablescrollview.MainActivity">

    <com.example.lelloman.screenshottablescrollview.ScreenshottableScrollView
        android:id="@+id/scrollView"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="0dp">

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </com.example.lelloman.screenshottablescrollview.ScreenshottableScrollView>
    <View
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="#ff000000"/>
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="100dp" />

</LinearLayout>

MainActivity.java

package com.example.lelloman.screenshottablescrollview;

import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Random;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        StringBuilder builder = new StringBuilder();

        Random random = new Random();
        String AB = "abcdefghijklmnopqrstuvwxyz ";

        for(int i=0;i<100;i++){
            builder.append("\n\n"+Integer.toString(i)+"\n\n");
            for(int j =0;j<1000;j++){
                builder.append(AB.charAt(random.nextInt(AB.length())));
            }
        }

        ((TextView) findViewById(R.id.textView)).setText(builder.toString());
        final ImageView imageView = (ImageView) findViewById(R.id.imageView);

        ScreenshottableScrollView scrollView = (ScreenshottableScrollView) findViewById(R.id.scrollView);
        scrollView.setScreenshotHeightPx((int) (getResources().getDisplayMetrics().density * 100));

        scrollView.setOnNewScreenshotListener(new ScreenshottableScrollView.OnNewScreenshotListener() {
            @Override
            public void onNewScreenshot(Bitmap bitmap) {
                Log.d("MainActivity","onNewScreenshot");
                imageView.setImageBitmap(bitmap);
            }
        });
    }
}