c# - 通过 Xamarin.Forms 在 Android 上打印本地文件

标签 c# android xamarin xamarin.android xamarin.forms

我需要通过表单使用打印对话框。我在 iOS 上找到了解决方案,但 android 实现给我带来了问题。

据我所知,调用 Android 打印管理器并向其解析文件是不可能的。 它只能是一个 Android.Views.View,是这样吗? 这样做是我理想的解决方案。

我试图将我的内容(一个显示本地 pdf 的 WebView )转换为这个 android View ,但这似乎也没有真正起作用,但我在这里超出了我的深度。

在下面的代码中,我尝试将 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);
        }
    }
}

最佳答案

我现在有了一个“有效”的解决方案。

这会获取当前的 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

关于c# - 通过 Xamarin.Forms 在 Android 上打印本地文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43520769/

相关文章:

Xamarin Cam2 IOnImageAvailableListener 的 OnImageAvailable 被调用两次导致

ios - 为什么 Xamarin.Auth 使用 OAuth1Authenticator 和 Twitter 引发身份验证错误

c# - 如何在 .net-core System.Composition (Mef) 中设置 CreationPolicy 单例

java - 在标签(Actor)上设置文本会停止绘制

android - 更改 Android 应用程序中的区域设置不会更改 Activity 标签

android - 动态创建drawable资源路径

xamarin - 制作一个 2 单元格的水平堆栈布局,占设备屏幕宽度的 50%

来自 XML 的 C# 类定义

c# - 您如何向 C#/Java 开发人员解释 C++ 指针?

c# - C# 中的内部与公共(public)