滚动时如何捕获ScrollView的一部分? [英] How to capture part of a ScrollView as its content is scrolling?

查看:64
本文介绍了滚动时如何捕获ScrollView的一部分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

扩展ScrollView类之后,我可以轻松地实时获得滚动通知.

After extending the ScrollView class I was able to easily be notified of the scrolling in realtime.

现在,我需要在非常特定的部分中捕获此滚动视图的内容. 假设我要捕获屏幕的顶部(匹配的父级宽度和已定义的高度,例如100dp).但是,如果顶部有其他内容,而不是ScrollView的一部分,则只有ScrollView的内容,而不是其余部分.

Now I need to capture the content of this scrollview in a very specific part. Let's say I want to capture the top of the screen (matching parent width and a defined height, like 100dp). But only the content of the ScrollView and not the rest, if there is anything else on the top but not as part of the ScrollView.

我尝试在scrollview上使用:

I tried using on the scrollview :

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

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

Then I tried to crop so that I get the part I want :

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

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

Results are very far from what I want to achieve and performance are very very poor and at some point I would get either a SIGENV or getDrawingCache(true) tries to use a recycled bitmap...

那么如何在不影响性能的前提下轻松捕获所需区域中的内容?

So how can I easily capture the content in the desired area without too much performance hit ?

注意:此过程必须在滚动内容时完成,因此请在ScrollView的onScrollChanged(final int x, final int y)中.

Note: this process must be done as I am scrolling the content, so inside ScrollView's onScrollChanged(final int x, final int y).

谢谢!

推荐答案

由于这个问题很有趣,所以我实现了它,看来一切正常.我猜您每次都在重新创建位图,这就是为什么变慢的原因.
想法是这样的,您在ScrollView中创建要复制的区域(请参见Rect cropRectBitmap screenshotBitmap),该区域为全宽度,您只需要设置高度即可.该视图会自动在其自身上设置一个滚动侦听器,并且在每次滚动时都会复制该区域.请注意,实例化视图时,仅一次调用setDrawingCacheEanbled(true),它基本上告诉视图您将调用getDrawingCache(),这将返回视图在其上绘制自身的位图.然后将其复制到screenshotBitmap上感兴趣的区域,这就是您可能要使用的Bitmap.

Since the problem was fun I implemented it, it seems to work fine. I guess that you are recreating a Bitmap each time that's why goes slow.

The idea is like this, you create an area in the ScrollView that you want to copy (see Rect cropRect and Bitmap screenshotBitmap), it's full width and you just need to set the height. The view automatically set a scroll listener on itself and on every scroll it will copy that area. Note that setDrawingCacheEanbled(true) is called just once when the view is instantiated, it basically tells the view that you will call getDrawingCache(), which will return the Bitmap on which the view is drawing itself. It then copy the area of interest on screenshotBitmap and that's the Bitmap that you might want to use.

ScreenshottableScrollView.java

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

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

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

这篇关于滚动时如何捕获ScrollView的一部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆