xamarin - 如何在 Xamarin Forms 中的不同版本的 Android 上使用不同的自定义渲染器?

标签 xamarin xamarin.android xamarin.forms

我有 Xamarin Forms 解决方案,在 Xamarin Droid 项目中,我有扩展 ContentView 的类 CustomCameraScanView 的自定义渲染器。此 CustomCameraScanView 应在 5.0 (Lollipop) 之前的 Android 上使用 Camera(旧 API),并在 5.0 及更高版本中使用 Camera2(新 API)。如何创建将在不同版本的操作系统上使用的两个渲染器:CustomCameraScanViewRenderer_Droid4 和 CustomCameraScanViewRenderer_Droid5?

我的 CustomCameraScanViewRenderer_Droid4 看起来像这样:

[assembly: ExportRenderer(typeof(CustomCameraScanView), typeof(CustomCameraScanViewRenderer_Droid4))]
namespace Genea.Droid.Renderers
{
    public class CustomCameraScanViewRenderer_Droid4 : ViewRenderer, 
                                                        ISurfaceTextureListener,
                                                        ISurfaceHolderCallback,
                                                        Android.Hardware.Camera.IPreviewCallback,
                                                        Android.Hardware.Camera.IPictureCallback,
                                                        Android.Hardware.Camera.IShutterCallback
    {
    }
}

最佳答案

不幸的是,目前在 Xamarin-Forms 中无法在运行时注册自定义渲染器。更多详情可以查看此forum link 。但您可以做的是使用 OnPlatform 和构建版本号在运行时解析控件。

我当然会首先推荐 @luccas-clezar 建议的条件编译方法;但如果这不是一个选项,那么您可以尝试使用以下步骤在运行时解析您的控件(以及渲染器)。

步骤:

  1. 创建一个简单的合约来解析当前的 API 值 - 在表单项目中

    public interface IBuildVersion { int Number { get; } }
    
  2. 为Android平台实现

    public class AndroidBuildVersion : IBuildVersion
    {
         public int Number { get { return ((int)Android.OS.Build.VERSION.SdkInt); } }
    }
    
  3. 注册 DependencyService

    [assembly: Xamarin.Forms.Dependency (typeof (AndroidBuildVersion))]
    
  4. 子类化您的 CustomCameraScanView分为两种派生类型 - 在表单项目中

    public class CustomCameraScanView_Droid4 : CustomCameraScanView { }
    public class CustomCameraScanView_Droid5 : CustomCameraScanView { }
    
  5. 在 Android 项目中设置渲染器

    [assembly: ExportRenderer(typeof(CustomCameraScanView_Droid4), typeof(CustomCameraScanViewRenderer_Droid4))]
    

    并且,

    [assembly: ExportRenderer(typeof(CustomCameraScanView_Droid5), typeof(CustomCameraScanViewRenderer_Droid5))] 
    
  6. 创建自定义控件以在运行时解析 - 使用 OnPlatform - 在表单项目中

    public class CameraScanContentView : Xamarin.Forms.ContentView
    {
        public CameraScanContentView()
        {
            this.Content = Device.OnPlatform(
                    iOS: new CustomCameraScanView(),
                    Android: DependencyService.Get<IBuildVersion>().Number < 21
                            ? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
                            : ((CustomCameraScanView)new CustomCameraScanView_Droid5()),
                    WinPhone: new CustomCameraScanView()
                );
        }
    }
    
  7. 并且,XAML 用法将如下所示

     <local:CameraScanContentView />
    

更新 05/24

我不相信 Xamarin-Forms 像 WPF 那样支持“属性值”继承 - 因此将值从父控件传播到子控件有点棘手。

一种选择是将这些值级联回 CustomCameraScanView来自CameraScanContentView 通过定义可绑定(bind)属性(推荐):

public class CameraScanContentView : Xamarin.Forms.ContentView
{
    public CameraScanContentView()
    {
        CustomCameraScanView scannerCtrl = null;

        switch (Device.RuntimePlatform)
        {
            case Device.Android:
                scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
                        ? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
                        : ((CustomCameraScanView)new CustomCameraScanView_Droid5());
                break;
            default:
                scannerCtrl = new CustomCameraScanView();
                break;
        }


        scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding(nameof(IsScanning), source: this));
        scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding(nameof(IsTakingImage), source: this));
        scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding(nameof(IsFlashlightOn), source: this));

        Content = scannerCtrl;
    }


    public static readonly BindableProperty IsScanningProperty = BindableProperty.Create("IsScanning", typeof(bool), typeof(CameraScanContentView), false);
    public static readonly BindableProperty IsTakingImageProperty = BindableProperty.Create("IsTakingImage", typeof(bool), typeof(CameraScanContentView), false);
    public static readonly BindableProperty IsFlashlightOnProperty = BindableProperty.Create("IsFlashlightOn", typeof(bool), typeof(CameraScanContentView), false);

    public bool IsScanning
    {
        get { return (bool)GetValue(IsScanningProperty); }
        set { SetValue(IsScanningProperty, value); }
    }

    public bool IsTakingImage
    {
        get { return (bool)GetValue(IsTakingImageProperty); }
        set { SetValue(IsTakingImageProperty, value); }
    }

    public bool IsFlashlightOn
    {
        get { return (bool)GetValue(IsFlashlightOnProperty); }
        set { SetValue(IsFlashlightOnProperty, value); }
    }
}

XAML 用法将如下所示

<local:CameraScanContentView IsScanning="{Binding IsScanning}" IsFlashlightOn="{Binding IsFlashlightOn}" IsTakingImage="{Binding IsTakingImage}" />

或者,您可以手动定义绑定(bind)表达式,如下所示(不推荐,因为它假设 View 模型上的属性名称不会更改):

public class CameraScanContentView : Xamarin.Forms.ContentView
{
    public CameraScanContentView()
    {
        CustomCameraScanView scannerCtrl = null;

        switch (Device.RuntimePlatform)
        {
            case Device.Android:
                scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
                        ? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
                        : ((CustomCameraScanView)new CustomCameraScanView_Droid5());
                break;
            default:
                scannerCtrl = new CustomCameraScanView();
                break;
        }

        scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding("IsScanning", source: this.BindingContext));
        scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding("IsTakingImage", source: this.BindingContext));
        scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding("IsFlashlightOn", source: this.BindingContext));

        Content = scannerCtrl;
    }      
}

注意: 我的第一 react 是使用隐式样式定位 CustomCameraScanView绑定(bind)值 - 但不知何故无法让它工作。

关于xamarin - 如何在 Xamarin Forms 中的不同版本的 Android 上使用不同的自定义渲染器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44139185/

相关文章:

android - 为什么我的 9 补丁 Android 初始屏幕中间有一个黑色矩形?

c# - 颜色按钮 C# Xamarin Android

xamarin.android - 类型 'GroupExpandedEventArgs' 已包含 'P0' Xamarin Android Java Bindings for Thoughtbot ExpandableRecyclerView 的定义

c# - Xamarin.Forms 的分辨率相关的 FontSize

c# - AdMob - iOS 实现 RewardBasedVideoAd

ios - 错误 ITMS-90085 : “No architectures in the binary. Lipo failed to detect any architectures in the bundle executable.”

service - Android 广播监听器中的 MvvmCross DataService

c# - 从 Xamarin 表单中的 Listview 获取选中的值

c# - 从嵌入式资源更改 Gtk.Button 图像

android - 如何在 Xamarin Forms 应用程序 (android) 中仅激活 1 个 ListView 项目并禁用其他项目