Android:如何在不显示webview的情况下在webview中渲染html

Android: How to render html in webview without displaying webview

我想使用 Webview 呈现 html,但我不想显示内容。为此,我以编程方式创建一个 Webview 并加载 HTML。它几乎正在工作。问题是我似乎无法设置 Webview 的尺寸,因此 HTML 以我想要的尺寸呈现。我正在使用 WebviewClient 拍摄 WebviewContent 的快照并将其转换为位图。

以下代码仅供测试,并非我的最终意图。我根本不想显示内容,但这会测试功能,当用户点击打印按钮时会填充图像。我希望图像的宽度为 380(高度可以根据需要设置)。图片非常小 ( 87 x 144 )。

我对以下代码有 2 个问题:

  1. 第一次运行时,快照总是抛出异常,指示位图尺寸必须> 0

  2. 在第二次尝试(以及后续尝试)中,生成的位图不是所需的尺寸。当然,缩放只会让情况变得更糟。

    包 com.b2ps.htmlrender;

    进口androidx.appcompat.app.AppCompatActivity;

    进口android.graphics.Bitmap; 导入 android.graphics.Canvas; 导入 android.graphics.Paint; 导入 android.os.Bundle; 导入 android.view.View; 导入 android.webkit.WebView; 导入 android.webkit.WebView 客户端; 导入 android.widget.Button; 导入 android.widget.ImageView; 导入 android.util.Log;

    进口java.io.BufferedReader; 导入 java.io.IOException; 导入 java.io.InputStreamReader;

    /**

    • 主要活动

    */ public class MainActivity 扩展 AppCompatActivity {

     private static final String TAG = "USDK";
    
     private ImageView ImagePreview = null;
     private WebView mReceiptView = null;
     private WebViewClient mWebviewClient = null;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         WebView.enableSlowWholeDocumentDraw();
    
         Button printBtn = ( Button )findViewById( R.id.btnPrint );
         printBtn.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                 onPrintClicked();
             }
         });
    
         ImagePreview = ( ImageView )findViewById( R.id.imgPreview );
     }
    
    
     private void onPrintClicked() {
         print();
     }
    
     private void print() {
         mReceiptView = new WebView( this );
         mWebviewClient = new SnapshotWebviewClient( this );
         mReceiptView.setWebViewClient( mWebviewClient );
         mReceiptView.setMinimumWidth( 380 );
         mReceiptView.setMinimumHeight( 720 );
    
         String receiptHtml = getHtml();
         mReceiptView.loadData( receiptHtml, "text/html; charset=utf-8", "UTF-8" );
    
     }
    
     protected String getHtml() {
         StringBuilder htmlStr = new StringBuilder();
         BufferedReader reader = null;
         try {
             reader = new BufferedReader( new InputStreamReader( this.getAssets().open("Receipt2.html" ) ) );
    
             // do reading, usually loop until end of file reading
             String mLine;
             while ((mLine = reader.readLine()) != null) {
                 //process line
                 htmlStr.append( mLine );
                 htmlStr.append( "\n" );
             }
         }
         catch (IOException e) {
             //log the exception
             Log.e( TAG, "IO exception", e);
         }
         finally {
             if (reader != null) {
                 try {
                     reader.close();
                 }
                 catch (IOException e) {
                     //log the exception
                     Log.e( TAG, "error closing stream", e );
                 }
             }
         }
         return htmlStr.toString();
     }
    
    
    
     //---------------------------------------------------------------------------------------------
     // #region SnapshotWebviewClient
    
     /**
      * SnapshotWeviewClient
      */
     private static class SnapshotWebviewClient extends WebViewClient {
    
         private static final String TAG = "USDK";
    
         private MainActivity mMainActivity;
    
         public SnapshotWebviewClient( MainActivity activity ) {
             mMainActivity = activity;
         }
    
         @Override
         public void onPageFinished(WebView view, String url) {
             // FYI anyone wanting to do this right, use webView.ScrollView.ContentSize.Height then
             // set the Frame of the webview. Works perfect!
    
             Log.i( TAG, "SnapshotWebviewClient.onPageFinished" );
             super.onPageFinished( view, url );
    
             try
             {
                 // Thread.sleep( 25 );
    
                 // Bitmap bitmap = Bitmap.CreateBitmap( view.MeasuredWidth, view.ContentHeight, Bitmap.Config.Argb8888 );
                 // Canvas canvas = new Canvas( bitmap );
                 // Paint paint = new Paint();
                 // int iHeight = bitmap.Height;
                 // canvas.DrawBitmap( bitmap, 0, iHeight, paint );
                 // view.Draw( canvas );
    
                 Bitmap bitmap = screenshot( view );
                 // bitmap = scaleToReceipt( bitmap, 380 );
                 Log.i( TAG, String.format( "Bitmap size: w(%d), h(%d)", bitmap.getWidth(), bitmap.getHeight() ) );
                 mMainActivity.ImagePreview.setImageBitmap( bitmap );
    
                 // save bitmap to file
                 java.io.File externalPath = view.getContext().getExternalFilesDir( null );
                 java.io.File filePath = new java.io.File( externalPath, "Receipt.png" );
                 java.io.FileOutputStream stream = new java.io.FileOutputStream( filePath );
                 bitmap.compress( Bitmap.CompressFormat.PNG, 100, stream );
                 stream.close();
                 Log.i( TAG, "WebViewClient.PrintToBitmap" );
             }
             catch ( Exception printErr )
             {
                 Log.e( TAG, "PrintWebView: "+printErr.toString(), printErr );
             }
         }
    
    
         private Bitmap screenshot(android.webkit.WebView webView )
         {
             webView.measure( View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED ),
                     android.view.View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED ) );
             Log.i( TAG, String.format( "webView dimensions1: w(%d), h(%d)", webView.getMeasuredWidth(), webView.getMeasuredHeight() ) );
             webView.layout( 0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight() );
             Log.i( TAG, String.format( "webView dimensions2: w(%d), h(%d)", webView.getMeasuredWidth(), webView.getMeasuredHeight() ) );
             webView.setDrawingCacheEnabled( true );
             webView.buildDrawingCache();
             Bitmap bitmap = Bitmap.createBitmap( webView.getMeasuredWidth(), webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888 );
             Log.i( TAG, String.format( "HtmlBmp: w(%d), h(%d)", bitmap.getWidth(), bitmap.getHeight() ) );
    
             Canvas canvas = new Canvas( bitmap );
             Paint paint = new Paint();
             int iHeight = bitmap.getHeight();
             canvas.drawBitmap( bitmap, 0, iHeight, paint );
             webView.draw( canvas );
             return bitmap;
         }
    
         private Bitmap scaleToReceipt( Bitmap bmp, int printWidth )
         {
             double scale = (( double )(printWidth - 1) / ( double )bmp.getWidth());
             int w = ( int )(bmp.getWidth() * scale);
             int h = ( int )(bmp.getHeight() * scale);
             Log.i( TAG, String.format( "Scale Bmp: W(%d), H(%d)", w, h ) );
             return Bitmap.createScaledBitmap( bmp, w, h, true );
         }
    
     }
    
     // #endregion SnapshowWebviewClient
     //---------------------------------------------------------------------------------------------
    

    }

这是布局XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

        <Button
            android:id="@+id/btnPrint"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Print" />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <ImageView
                android:id="@+id/imgPreview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </ScrollView>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

要解决问题 (1),请调用 WebView.Layout(...) 而不是设置宽度和高度。

要解决问题 (2),必须在活动 onCreate(...) 方法中创建 WebView。

见下文:

/**
 * MainActivity
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "USDK";

    private ImageView ImagePreview = null;
    private WebView mReceiptView = null;
    private WebViewClient mWebviewClient = null;

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

        Button printBtn = (Button) findViewById(R.id.btnPrint);
        printBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onPrintClicked();
            }
        });

        ImagePreview = (ImageView) findViewById(R.id.imgPreview);

        mReceiptView = new WebView( this.getApplicationContext() );
        mWebViewClientClient = new ReceiptWebViewClient();

        mReceiptView.layout( 0, 0, 380, 720 );
        mReceiptView.setWebViewClient( mWebViewClientClient );
        mReceiptView.loadData("<html></html>", "text/html; charset=utf-8", "UTF-8" );

    }


    private void onPrintClicked() {
        print();
    }

    private void print() {
        String receiptHtml = getHtml();
        mReceiptView.loadData(receiptHtml, "text/html; charset=utf-8", "UTF-8");

    }

    protected String getHtml() {
        StringBuilder htmlStr = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(this.getAssets().open("Receipt2.html")));

            // do reading, usually loop until end of file reading
            String mLine;
            while ((mLine = reader.readLine()) != null) {
                //process line
                htmlStr.append(mLine);
                htmlStr.append("\n");
            }
        } catch (IOException e) {
            //log the exception
            Log.e(TAG, "IO exception", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    //log the exception
                    Log.e(TAG, "error closing stream", e);
                }
            }
        }
        return htmlStr.toString();
    }


    //---------------------------------------------------------------------------------------------
    // #region SnapshotWebviewClient

    /**
     * SnapshotWeviewClient
     */
    private static class SnapshotWebviewClient extends WebViewClient {

        private static final String TAG = "USDK";

        private MainActivity mMainActivity;

        public SnapshotWebviewClient(MainActivity activity) {
            mMainActivity = activity;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            // FYI anyone wanting to do this right, use webView.ScrollView.ContentSize.Height then
            // set the Frame of the webview. Works perfect!

            Log.i(TAG, "SnapshotWebviewClient.onPageFinished");
            super.onPageFinished(view, url);

            if ( url.compareTo( "data:text/html; charset=utf-8,<html></html>" ) == 0 )
                return;

            try {
                Bitmap bitmap = screenshot(view);
                // bitmap = scaleToReceipt( bitmap, 380 );
                Log.i(TAG, String.format("Bitmap size: w(%d), h(%d)", bitmap.getWidth(), bitmap.getHeight()));
                mMainActivity.ImagePreview.setImageBitmap(bitmap);

                // save bitmap to file
                java.io.File externalPath = view.getContext().getExternalFilesDir(null);
                java.io.File filePath = new java.io.File(externalPath, "Receipt.png");
                java.io.FileOutputStream stream = new java.io.FileOutputStream(filePath);
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                stream.close();
                Log.i(TAG, "WebViewClient.PrintToBitmap");
            } catch (Exception printErr) {
                Log.e(TAG, "PrintWebView: " + printErr.toString(), printErr);
            }
        }


        private Bitmap screenshot(android.webkit.WebView webView) {
            webView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    android.view.View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            Log.i(TAG, String.format("webView dimensions1: w(%d), h(%d)", webView.getMeasuredWidth(), webView.getMeasuredHeight()));
            webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight());
            Log.i(TAG, String.format("webView dimensions2: w(%d), h(%d)", webView.getMeasuredWidth(), webView.getMeasuredHeight()));
            webView.setDrawingCacheEnabled(true);
            webView.buildDrawingCache();
            Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(), webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
            Log.i(TAG, String.format("HtmlBmp: w(%d), h(%d)", bitmap.getWidth(), bitmap.getHeight()));

            Canvas canvas = new Canvas(bitmap);
            Paint paint = new Paint();
            int iHeight = bitmap.getHeight();
            canvas.drawBitmap(bitmap, 0, iHeight, paint);
            webView.draw(canvas);
            return bitmap;
        }

        private Bitmap scaleToReceipt(Bitmap bmp, int printWidth) {
            double scale = ((double) (printWidth - 1) / (double) bmp.getWidth());
            int w = (int) (bmp.getWidth() * scale);
            int h = (int) (bmp.getHeight() * scale);
            Log.i(TAG, String.format("Scale Bmp: W(%d), H(%d)", w, h));
            return Bitmap.createScaledBitmap(bmp, w, h, true);
        }

    }

    // #endregion SnapshowWebviewClient
    //-----------------------------

}