web-dev-qa-db-ja.com

ビューをAndroidに表示せずにビットマップに変換しますか?

私が何をする必要があるかを正確に説明しようとします。

A、B、Cと言う3つの画面があります。 say HomeScreenと呼ばれる別の画面があります。この画面では、3つのビットマップすべてをギャラリービューに表示し、ユーザーはどのビューに行きたいかを選択できます。

HomeScreenアクティビティのみにすべてのコードを配置することにより、3つの画面すべてのビットマップを取得し、ギャラリービューに表示することができました。さて、これはコードをかなり複雑にしているので、単純化したいと思います。

したがって、HomeScreenから別のアクティビティを呼び出して表示せずに、その画面のビットマップを取得できますか。たとえば、HomeScreenを呼び出すだけで、アクティビティA、B、Cを呼び出し、A、B、Cのアクティビティが表示されないとします。 getDrawingCache()によってその画面のビットマップを提供するだけです。そして、それらのビットマップをHomeScreenのギャラリービューに表示できます。

問題を非常に明確に説明したと思います。

これが実際に可能かどうかを教えてください。

120
sunil

これを行う方法があります。ビットマップとキャンバスを作成し、view.draw(canvas)を呼び出す必要があります。

コードは次のとおりです。

public static Bitmap loadBitmapFromView(View v) {
    Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);                
    Canvas c = new Canvas(b);
    v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
    v.draw(c);
    return b;
}

ビューのサイズがゼロになる前にビューが表示されなかった場合。次のように測定することが可能です。

if (v.getMeasuredHeight() <= 0) {
    v.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    v.draw(c);
    return b;
}

編集: この投稿によると、WRAP_CONTENTmakeMeasureSpec()に値として渡すことは何の役にも立ちません(ただし、一部のビュークラスでは機能します)、推奨される方法は次のとおりです。

// Either this
int specWidth = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.AT_MOST);
// Or this
int specWidth = MeasureSpec.makeMeasureSpec(0 /* any */, MeasureSpec.UNSPECIFIED);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();
192
Simon Heinen

ここに私の解決策があります:

public static Bitmap getBitmapFromView(View view) {
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null) 
        bgDrawable.draw(canvas);
    else 
        canvas.drawColor(Color.WHITE);
    view.draw(canvas);
    return returnedBitmap;
}

楽しい :)

24
Gil SH

これを試して、

        /**
         * Draw the view into a bitmap.
         */
        public static Bitmap getViewBitmap(View v) {
            v.clearFocus();
            v.setPressed(false);

            boolean willNotCache = v.willNotCacheDrawing();
            v.setWillNotCacheDrawing(false);

            // Reset the drawing cache background color to fully transparent
            // for the duration of this operation
            int color = v.getDrawingCacheBackgroundColor();
            v.setDrawingCacheBackgroundColor(0);

            if (color != 0) {
                v.destroyDrawingCache();
            }
            v.buildDrawingCache();
            Bitmap cacheBitmap = v.getDrawingCache();
            if (cacheBitmap == null) {
                Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
                return null;
            }

            Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);

            // Restore the view
            v.destroyDrawingCache();
            v.setWillNotCacheDrawing(willNotCache);
            v.setDrawingCacheBackgroundColor(color);

            return bitmap;
        }
20
Dwivedi Ji

これは古い問題かもしれないことは知っていますが、これらのソリューションのいずれかがうまく機能しないという問題がありました。具体的には、膨張後にビューに変更が加えられた場合、それらの変更がレンダリングされたビットマップに組み込まれないことがわかりました。

これが私のケースで機能する方法です。ただし、1つ注意点があります。 getViewBitmap(View)を呼び出す前に、ビューを拡大し、既知の寸法でレイアウトするように要求しました。これは、コンテンツが内部に配置されるまでビューレイアウトの高さ/幅がゼロになるために必要でした。

View view = LayoutInflater.from(context).inflate(layoutID, null);
//Do some stuff to the view, like add an ImageView, etc.
view.layout(0, 0, width, height);

Bitmap getViewBitmap(View view)
{
    //Get the dimensions of the view so we can re-layout the view at its current size
    //and create a bitmap of the same size 
    int width = view.getWidth();
    int height = view.getHeight();

    int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
    int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);

    //Cause the view to re-layout
    view.measure(measuredWidth, measuredHeight);
    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());

    //Create a bitmap backed Canvas to draw the view into
    Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);

    //Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
    view.draw(c);

    return b;
}

私の「魔法のソース」はここにありました: https://groups.google.com/forum/#!topic/Android-developers/BxIBAOeTA1Q

乾杯、

レヴィ

15
levigroker

お役に立てれば

View view="some view instance";        
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
view.setDrawingCacheEnabled(false);

更新
getDrawingCache()メソッドはAPIレベル28で非推奨になりました。したがって、APIレベル> 28の他の代替手段を探してください。

2
Akhilesh Kumar

私はこれが少し良いと思います:

/**
 * draws the view's content to a bitmap. code initially based on :
 * http://nadavfima.com/Android-snippet-inflate-a-layout-draw-to-a-bitmap/
 */
@Nullable
public static Bitmap drawToBitmap(final View viewToDrawFrom, int width, int height) {
    boolean wasDrawingCacheEnabled = viewToDrawFrom.isDrawingCacheEnabled();
    if (!wasDrawingCacheEnabled)
        viewToDrawFrom.setDrawingCacheEnabled(true);
    if (width <= 0 || height <= 0) {
        if (viewToDrawFrom.getWidth() <= 0 || viewToDrawFrom.getHeight() <= 0) {
            viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            width = viewToDrawFrom.getMeasuredWidth();
            height = viewToDrawFrom.getMeasuredHeight();
        }
        if (width <= 0 || height <= 0) {
            final Bitmap bmp = viewToDrawFrom.getDrawingCache();
            final Bitmap result = bmp == null ? null : Bitmap.createBitmap(bmp);
            if (!wasDrawingCacheEnabled)
                viewToDrawFrom.setDrawingCacheEnabled(false);
            return result;
        }
        viewToDrawFrom.layout(0, 0, width, height);
    } else {
        viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
        viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
    }
    final Bitmap drawingCache = viewToDrawFrom.getDrawingCache();
    final Bitmap bmp = ThumbnailUtils.extractThumbnail(drawingCache, width, height);
    final Bitmap result = bmp == null || bmp != drawingCache ? bmp : Bitmap.createBitmap(bmp);
    if (!wasDrawingCacheEnabled)
        viewToDrawFrom.setDrawingCacheEnabled(false);
    return result;
}

上記のコードを使用すると、ビュー自体のいずれかを使用する場合、ビットマップのサイズを指定する必要はありません(幅と高さに0を使用)。

また、特別なビュー(SurfaceView、Surface、Windowなど)をビットマップに変換する場合は、 PixelCopyの使用を検討する必要があります。 代わりにクラス。ただし、API 24以降が必要です。以前はどうすればいいのかわかりません。

0

ビットマップへのレイアウトまたはビュー:

 private Bitmap createBitmapFromLayout(View tv) {      
    int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    tv.measure(spec, spec);
    tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
    Bitmap b = Bitmap.createBitmap(tv.getMeasuredWidth(), tv.getMeasuredWidth(),
            Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    c.translate((-tv.getScrollX()), (-tv.getScrollY()));
    tv.draw(c);
    return b;
}

呼び出し方法:

Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);
0
Shyam Kumar

Android KTXには素晴らしいKotlin拡張機能があります: View.drawToBitmap(Bitmap.Config)

0
a.ch.