使用自定义渲染器时,Xamarin Forms Switch的Toggled事件未被触发

时间:2018-03-23 11:01:28

标签: xamarin xamarin.forms

我有Xamarin.Forms个应用,我创建了一个自定义Switch,如下所示:

public class ExtSwitch : Switch
{
   public static readonly BindableProperty SwitchOnColorProperty =
          BindableProperty.Create(nameof(SwitchOnColor),
                                  typeof(Color), typeof(ExtSwitch), Color.Default);

   public Color SwitchOnColor
   {
      get { return (Color)GetValue(SwitchOnColorProperty); }
      set { SetValue(SwitchOnColorProperty, value); }
   }

   // More codes here //
}

在我的XAML我用过它:

<local:ExtSwitch Grid.Column = "2"
       IsToggled="{Binding IsToggled}" 
       Toggled="Handle_Toggled"
       SwitchThumbColor="White" 
       SwitchOnColor="Red" 
       SwitchOffColor="Gray"
       HorizontalOptions="End" 
       VerticalOptions="Center" />

在我的C#代码中,我有一个Handle_Toggled方法来处理Swich切换时发生的事情。但不知何故,Toggled事件在我的自定义开关中使用时没有被触发,但在普通开关中使用时效果很好。

有人能指出我在这里错过了什么,或者我做错了什么?

修改

iOS中的自定义渲染器:

class ExtSwitchRenderer : SwitchRenderer
{
   protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
   {
       base.OnElementChanged(e);

       if (e.OldElement != null || e.NewElement == null) return;

       ExtSwitch s = Element as ExtSwitch;

       UISwitch sw = new UISwitch();
       sw.ThumbTintColor = s.SwitchThumbColor.ToUIColor();
       sw.OnTintColor = s.SwitchOnColor.ToUIColor();

       SetNativeControl(sw);
    }
}

使用上面的代码:

enter image description here

使用下面建议的代码:

enter image description here

Android中的自定义渲染器:

public class ExtSwitchRenderer : SwitchRenderer
    {
        public ExtSwitchRenderer(Context context) : base(context) { }
        ExtSwitch s;

       protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
      {
        base.OnElementChanged(e);
        if (e.OldElement != null || e.NewElement == null)
            return;

        s = Element as ExtSwitch;
        if (this.Control != null)
        {
            if (this.Control.Checked)
            {
                this.Control.TrackDrawable.SetColorFilter(s.SwitchOnColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
            }
            else
            {
                this.Control.TrackDrawable.SetColorFilter(s.SwitchOffColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
            }
            this.Control.CheckedChange += this.OnCheckedChange;
        }
        Control.Toggle();
    }

    void OnCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
    {
        if (this.Control.Checked)
        {
            this.Control.ThumbDrawable.SetColorFilter(s.SwitchOnColor.ToAndroid(), PorterDuff.Mode.Multiply);
            this.Control.TrackDrawable.SetColorFilter(s.SwitchOnColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
        }
        else
        {
            this.Control.ThumbDrawable.SetColorFilter(s.SwitchOffColor.ToAndroid(), PorterDuff.Mode.Multiply);
            this.Control.TrackDrawable.SetColorFilter(s.SwitchOffColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
        }
    }
}

3 个答案:

答案 0 :(得分:1)

在IO渲染器上

protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
    {
        base.OnElementChanged(e);



        if (e.OldElement != null || e.NewElement == null) return;

        CustomSwitch s = Element as CustomSwitch;



        //this.Control.ThumbTintColor = s.SwitchThumbColor.ToUIColor();
        this.Control.OnTintColor = s.SwitchOnColor.ToUIColor();

    }

和OnCheckedChange中的Android渲染器

private void OnCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
   {
        if (this.Control.Checked)
        {
            this.Control.TrackDrawable.SetColorFilter(view.SwitchOnColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
        }
        else
        {
            this.Control.TrackDrawable.SetColorFilter(view.SwitchOffColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
        }

        Element.IsToggled = Control.Checked;


    }

答案 1 :(得分:0)

不要设置本机控件,而只是更新当前的Control,如下所示:

this.Control.ThumbTintColor = s.SwitchThumbColor.ToUIColor();
this.Control.OnTintColor = s.SwitchOnColor.ToUIColor();

并且无需致电SetNativeControl

答案 2 :(得分:0)

SetColorFilter 同时被弃用。使用 Xamarin.AndroidX.Core 包,您可以像这样使用渲染器:

public class ColoredSwitchRenderer : SwitchRenderer
{
    private readonly Android.Graphics.Color _defaultColor = ((Color)Application.Current.Resources["Default"]).ToAndroid();
    private readonly Android.Graphics.Color _activeColor = ((Color)Application.Current.Resources["Active"]).ToAndroid();
    private readonly Android.Graphics.Color _inactiveColor = ((Color)Application.Current.Resources["Inactive"]).ToAndroid();

    public ColoredSwitchRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
    {
        base.OnElementChanged(e);

        if (Control == null)
        {
            return;
        }

        SetThumbColor();
        UpdateTrackColors();
        Control.CheckedChange += OnCheckedChange;
    }

    private void SetThumbColor()
    {
        var filter = BlendModeColorFilterCompat.CreateBlendModeColorFilterCompat(_defaultColor, BlendModeCompat.SrcAtop);
        Control.ThumbDrawable.SetColorFilter(filter);
    }

    private void OnCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
    {
        UpdateTrackColors();
        Element.IsToggled = Control.Checked;
    }

    private void UpdateTrackColors()
    {
        if (Control.Checked)
        {
            var filter = BlendModeColorFilterCompat.CreateBlendModeColorFilterCompat(_activeColor, BlendModeCompat.Src);
            Control.TrackDrawable?.SetColorFilter(filter);
        }
        else
        {
            var filter = BlendModeColorFilterCompat.CreateBlendModeColorFilterCompat(_inactiveColor, BlendModeCompat.Src);
            Control.TrackDrawable?.SetColorFilter(filter);
        }
    }

    protected override void Dispose(bool disposing)
    {
        Control.CheckedChange -= OnCheckedChange;
        base.Dispose(disposing);
    }
}

为了完整起见,iOS 渲染器:

public class ColoredSwitchRenderer : SwitchRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
    {
        base.OnElementChanged(e);

        if (Control != null)
        {
            Application.Current.Resources.TryGetValue("Active", out var activeColor);
            Control.OnTintColor = ((Color)activeColor).ToUIColor();

            Application.Current.Resources.TryGetValue("Default", out var defaultColor);
            Control.ThumbTintColor = ((Color)defaultColor).ToUIColor();

            Application.Current.Resources.TryGetValue("Inactive", out var inactiveColor);
            Control.Subviews[0].Subviews[0].BackgroundColor = ((Color)inactiveColor).ToUIColor();
        }
    }
}