ToggleButton canvas 上绘制的文本和线条出现在屏幕上但不出现在屏幕截图上

Text and line drawn on ToggleButton canvas appear on screen but not on screenshot

我创建了一个扩展 ToogleButton 的视图 MyToggleButton。我覆盖了 Togglebutton 的 onDraw 方法以在按钮上画一条线并旋转它的文本。

这里是MyToggleButton:

package com.example.gl.myapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.widget.ToggleButton;

public class MyToggleButton extends ToggleButton {

    public float textRotation=0;

    public MyToggleButton(Context context, float rotationValue) {
        super(context);

        textRotation=rotationValue;
    }

    @Override
    protected void onDraw(Canvas canvas){

        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        textPaint.drawableState = getDrawableState();

        canvas.save();

        //paint
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(7);
        paint.setStrokeCap(Paint.Cap.ROUND);

        canvas.drawLine(canvas.getWidth() / 2, canvas.getHeight() / 2, (float) (canvas.getHeight() / 2 + 400), (canvas.getHeight() / 2), paint);

        canvas.rotate(textRotation, canvas.getWidth() / 2, canvas.getHeight() / 2);

        getLayout().draw(canvas);

        canvas.restore();

    }


}

之后我想截屏并查看它,为此我使用了 takeScreenshot() 方法,该方法通过按屏幕上的第三个按钮调用。截图代码基于How to programmatically take a screenshot in Android?。 Whosebug 上的其他帖子以及我在周围找到的各种站点和教程中都采用了相同的方法。

这是我使用的MainActivity

package com.example.gl.myapplication;

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.PorterDuffXfermode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

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

        //add 3 buttons
        addButtons();

    }


    private void addButtons(){

        LinearLayout linear1= (LinearLayout) findViewById(R.id.vert1);

        //MyToggleButton with rotated text
        MyToggleButton btn1 = new MyToggleButton(this,0);
        btn1.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        btn1.setTextOff("Button 1 not rotated");
        btn1.setTextOn("Button 1 not rotated");
        btn1.setText("Button 1 not rotated");
        linear1.addView(btn1);

        //MyToggleButton with normal text
        MyToggleButton btn2 = new MyToggleButton(this,50);
        btn2.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        btn2.setTextOff("Button 2 rotated");
        btn2.setTextOn("Button 2 rotated");
        btn2.setText("Button 2 rotated");
        linear1.addView(btn2);

        //button to create screenshot
        Button btn3 = new Button(this);
        btn3.setText("Create bitmap");
        btn3.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                takeScreenshot();

            }
        });
        linear1.addView(btn3);



    }

    //Screenshotcreator
        private void takeScreenshot() {
            try {
                View v1 = getWindow().getDecorView().getRootView();

                // create bitmap screen capture
                v1.setDrawingCacheEnabled(true);
                Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());

                v1.setDrawingCacheEnabled(false);

                ImageView imageView1 =(ImageView) findViewById(R.id.imageView1);
                imageView1.setImageBitmap(bitmap);


            } catch (Throwable e) {
                e.printStackTrace();
            }
        }


    }

这里是MainActivity的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.gl.myapplication.MainActivity"
    android:id="@+id/relative1">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/vert1">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="250dp"
            android:id="@+id/imageView1" />
    </LinearLayout>
</RelativeLayout>

问题是虽然屏幕上一切正常,但屏幕截图的位图缺少绘制的线条和旋转的文本。

位图中出现奇怪结果的原因可能是什么?

请注意,屏幕截图中缺少设备返回主页最近按钮,还有状态栏信息(时间等)。我怀疑这与我的问题有关。这些元素不属于我的应用程序,因此预计它们不会出现在我使用 v1 = getWindow().getDecorView().getRootView(); 获得的视图中但是我在其上绘制旋转文本和线条的 canvas 确实属于那个观点。

我的问题是:为什么画线和旋转的文字没有出现在屏幕截图上,我如何修改我的代码以获取包含它们的屏幕截图?

我不想做一些需要 root 设备的事情,而且我不能使用 MediaProjection API 因为这是在 API 21 中添加的,但我希望我的应用程序 运行 也在 android 4.4 (API 19) 上。最后,我知道存在外部库,例如 Android Screenshot Library 或这个:https://android-arsenal.com/details/1/2793,但我宁愿不使用任何外部库。

P.S。也许这是相关的:Surfaceview screenshot with line/ellipse drawn over it

问题是 btn1.isDrawingChaceEnabled()btn2.isDrawingChaceEnabled() return false

即使你在 RootView 上调用 setDrawingCacheEnabled(true),它也不会在他的所有子视图上递归设置为 true(我用 Log.d 测试过)。
这意味着您的 ToggleButton 的绘图缓存将为空,如 android.view.View.getDrawingCache() javadoc.

中所述
/**
 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
 *
 * @return A non-scaled bitmap representing this view or null if cache is disabled.
 *
 * @see #getDrawingCache(boolean)
 */

因此请务必为您感兴趣的每个视图设置 setDrawingCacheEnabled(true)
例如,我在您的代码中添加了以下几行:
在 MainActivity

    btn1.setDrawingCacheEnabled(true);
    btn2.setDrawingCacheEnabled(true);

And it looks like this