2017-04-20 64 views
1

我需要通過表單使用打印對話框。我在iOS上找到了一個解決方案,但是android實現給我帶來了問題。通過Xamarin.Forms在Android上打印本地文件

據我所見,無法調用Android打印管理器並解析文件。 它只能是一個Android.Views.View,是真的嗎? 要做到這一點將是我理想的解決方案。

我試圖將我的內容(顯示本地pdf的web視圖)轉換爲此android視圖,但這似乎也不是真正的工作,但我在這裏脫離我的深處。

在下面的代碼中,我嘗試將forms.webview轉換爲android.view,然後將其解析爲打印管理器。 這會產生打印對話框,但帶有黑色白色頁面。

var size = new Rectangle(webview.X, webview.Y, webview.Width, webview.Height); 
var vRenderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(webview); 
var viewGroup = vRenderer.ViewGroup; 
vRenderer.Tracker.UpdateLayout(); 
var layoutParams = new Android.Views.ViewGroup.LayoutParams((int)size.Width, (int)size.Height); 
viewGroup.LayoutParameters = layoutParams; 
webview.Layout(size); 
viewGroup.Layout(0, 0, (int)webview.WidthRequest, (int)webview.HeightRequest); 

var printMgr = (Android.Print.PrintManager)Forms.Context.GetSystemService(Android.Content.Context.PrintService); 
var docAdt = new Droid.GenericPrintAdapter(Forms.Context, viewGroup); 

printMgr.Print("test", docAdt, null); 

下一個是 「GenericPrintAdapter」

public class GenericPrintAdapter : PrintDocumentAdapter 
{ 
    View view; 
    Context context; 
    PrintedPdfDocument document; 
    float scale; 

    public GenericPrintAdapter(Context context, View view) 
    { 
     this.view = view; 
     this.context = context; 
    } 

    public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, 
            CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) 
    { 
     document = new PrintedPdfDocument(context, newAttributes); 

     CalculateScale(newAttributes); 

     var printInfo = new PrintDocumentInfo 
      .Builder("MyPrint.pdf") 
      .SetContentType(PrintContentType.Document) 
      .SetPageCount(1) 
      .Build(); 

     callback.OnLayoutFinished(printInfo, true); 
    } 

    void CalculateScale(PrintAttributes newAttributes) 
    { 
     int dpi = Math.Max(newAttributes.GetResolution().HorizontalDpi, newAttributes.GetResolution().VerticalDpi); 

     int leftMargin = (int)(dpi * (float)newAttributes.MinMargins.LeftMils/1000); 
     int rightMargin = (int)(dpi * (float)newAttributes.MinMargins.RightMils/1000); 
     int topMargin = (int)(dpi * (float)newAttributes.MinMargins.TopMils/1000); 
     int bottomMargin = (int)(dpi * (float)newAttributes.MinMargins.BottomMils/1000); 

     int w = (int)(dpi * (float)newAttributes.GetMediaSize().WidthMils/1000) - leftMargin - rightMargin; 
     int h = (int)(dpi * (float)newAttributes.GetMediaSize().HeightMils/1000) - topMargin - bottomMargin; 

     scale = Math.Min((float)document.PageContentRect.Width()/w, (float)document.PageContentRect.Height()/h); 
    } 

    public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, 
            CancellationSignal cancellationSignal, WriteResultCallback callback) 
    { 
     PrintedPdfDocument.Page page = document.StartPage(0); 

     page.Canvas.Scale(scale, scale); 

     view.Draw(page.Canvas); 

     document.FinishPage(page); 

     WritePrintedPdfDoc(destination); 

     document.Close(); 

     document.Dispose(); 

     callback.OnWriteFinished(pages); 
    } 

    void WritePrintedPdfDoc(ParcelFileDescriptor destination) 
    { 
     var javaStream = new Java.IO.FileOutputStream(destination.FileDescriptor); 
     var osi = new OutputStreamInvoker(javaStream); 
     using (var mem = new MemoryStream()) 
     { 
      document.WriteTo(mem); 
      var bytes = mem.ToArray(); 
      osi.Write(bytes, 0, bytes.Length); 
     } 
    } 
} 
+0

'WebView'包含一個名爲'CreatePrintDocumentAdapter'的方法,該方法返回一個'PrintDocumentAdapter',然後傳遞給'PrintManager'實例。 – SushiHangover

+0

@SushiHangover多數民衆贊成在原生的Android WebView :(Xamarin.Forms WebView沒有,因爲它只有一個機器人的東西。你知道一種方式將表單轉換爲本地? – rrr

+1

您將需要訪問本機'WebView'控件有多個選項...你可以通過自定義渲染器公開'native'控件,並將其傳遞給依賴項服務,將本地打印例程嵌入本地渲染器本身,或者讓依賴項服務遍歷所有在當前'Activity'(GetChildCount/GetChildAt/...)中的子視圖找到你的原生android'WebView',然後調用'CreatePrintDocumentAdapter'等等... – SushiHangover

回答

1

我現在有一個 「工作」 的解決方案。

這將獲取當前的Android.Webkir.WebView並從中創建printAdapter。

感謝@SushiHangover指引我在正確的方向。

它的一些破解,但適合我的需求。

如果有其他人需要這個,我已經包含了Android和iOS代碼。

#if __ANDROID__ 
      var vRenderer = Xamarin.Forms.Platform.Android.Platform.GetRenderer(webview); 
      var viewGroup = vRenderer.ViewGroup; 

      for (int i = 0; i < viewGroup.ChildCount; i++) 
      { 
       if (viewGroup.GetChildAt(i).GetType().Name == "WebView") 
       { 
        var AndroidWebView = viewGroup.GetChildAt(i) as Android.Webkit.WebView; 
        var tmp = AndroidWebView.CreatePrintDocumentAdapter("print"); 
        var printMgr = (Android.Print.PrintManager)Forms.Context.GetSystemService(Android.Content.Context.PrintService); 
        printMgr.Print("print", tmp, null); 
        break; 
       } 
      } 
#elif __IOS__ 
      var printInfo = UIKit.UIPrintInfo.PrintInfo; 
      printInfo.Duplex = UIKit.UIPrintInfoDuplex.LongEdge; 
      printInfo.OutputType = UIKit.UIPrintInfoOutputType.General; 
      printInfo.JobName = "AppPrint"; 
      var printer = UIKit.UIPrintInteractionController.SharedPrintController; 
      printer.PrintInfo = printInfo; 
      printer.PrintingItem = Foundation.NSData.FromFile(pdfPath); 
      printer.ShowsPageRange = true; 
      printer.Present(true, (handler, completed, err) => 
      { 
       if (!completed && err != null) 
       { 
        System.Diagnostics.Debug.WriteLine("Printer Error"); 
       } 
      }); 
#endif 
相關問題