如何在内容滚动时捕获 ScrollView 的一部分?
How to capture part of a ScrollView as its content is scrolling?
在扩展 ScrollView
class 之后,我能够轻松地实时收到滚动通知。
现在我需要在一个非常具体的部分捕获这个滚动视图的内容。
假设我想捕获屏幕的顶部( 匹配父级宽度 和定义的高度,例如 100dp)。但只有 ScrollView 的内容而不是其余内容,如果顶部有任何其他内容但不作为 ScrollView 的一部分。
我尝试在滚动视图上使用 :
setDrawingCacheEnabled(true);
getDrawingCache(true);
setDrawingCacheEnabled(false);
然后我尝试裁剪以获得我想要的部分:
Bitmap.createBitmap(complete, 0, 0, width, height);
结果与我想要达到的目标相去甚远,性能非常非常差,有时我会得到 SIGENV
或 getDrawingCache(true)
尝试使用回收位图...
那么,如何才能在不影响性能的情况下轻松捕获所需区域的内容?
注意:这个过程必须在我滚动内容时完成,所以在 ScrollView 的 onScrollChanged(final int x, final int y)
.
里面
谢谢!
由于这个问题很有趣,所以我实施了它,它似乎工作正常。我猜你每次都在重新创建位图,这就是速度变慢的原因。
思路是这样的,你在ScrollView中创建一个你想要复制的区域(参见Rect cropRect
和Bitmap 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);
}
});
}
}
在扩展 ScrollView
class 之后,我能够轻松地实时收到滚动通知。
现在我需要在一个非常具体的部分捕获这个滚动视图的内容。 假设我想捕获屏幕的顶部( 匹配父级宽度 和定义的高度,例如 100dp)。但只有 ScrollView 的内容而不是其余内容,如果顶部有任何其他内容但不作为 ScrollView 的一部分。
我尝试在滚动视图上使用 :
setDrawingCacheEnabled(true);
getDrawingCache(true);
setDrawingCacheEnabled(false);
然后我尝试裁剪以获得我想要的部分:
Bitmap.createBitmap(complete, 0, 0, width, height);
结果与我想要达到的目标相去甚远,性能非常非常差,有时我会得到 SIGENV
或 getDrawingCache(true)
尝试使用回收位图...
那么,如何才能在不影响性能的情况下轻松捕获所需区域的内容?
注意:这个过程必须在我滚动内容时完成,所以在 ScrollView 的 onScrollChanged(final int x, final int y)
.
谢谢!
由于这个问题很有趣,所以我实施了它,它似乎工作正常。我猜你每次都在重新创建位图,这就是速度变慢的原因。
思路是这样的,你在ScrollView中创建一个你想要复制的区域(参见Rect cropRect
和Bitmap 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);
}
});
}
}