第二十七章:自定义渲染器(六)

有趣的是,Android SeekBar小部件具有与Steps属性等效的功能,但不等同于Minimum和Maximum属性! 这怎么可能? SeekBar实际上定义了一个名为Max的整数属性,SeekBar的Progress属性始终是一个从0到Max的整数。 因此,Max属性确实指示了SeekBar可以执行的步骤数,并且SeekBar的Progress属性和StepSlider的Value属性之间需要进行转换。
此转换发生在两个地方:SetValue方法从StepSlider的Value属性转换为SeekBar的Progress属性,OnProgressChanged方法从SeekBar的Progress属性转换为StepSlider的Value属性。
另外,事件处理程序有点不同。 SetOnSeekBarChangeListener方法接受类型为IOnSeekBarChangeListener的参数,该参数定义了三个报告Seekbar更改的方法,包括方法OnProgressChanged。 渲染器本身实现了该接口。
这是Xamarin.FormsBook.Platform.Android库中的完整StepSliderRenderer类:

using System.ComponentModel;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Xamarin.FormsBook.Platform.StepSlider),
                          typeof(Xamarin.FormsBook.Platform.Android.StepSliderRenderer))]
namespace Xamarin.FormsBook.Platform.Android
{
    public class StepSliderRenderer : ViewRenderer<StepSlider, SeekBar>,
                                      SeekBar.IOnSeekBarChangeListener
    {
        double minimum, maximum;
        protected override void OnElementChanged(ElementChangedEventArgs<StepSlider> args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                SetNativeControl(new SeekBar(Context));
            }
            if (args.NewElement != null)
            {
                SetMinimum();
                SetMaximum();
                SetSteps();
                SetValue();
                Control.SetOnSeekBarChangeListener(this);
            }
            else
            {
                Control.SetOnSeekBarChangeListener(null);
            }
        }
        protected override void OnElementPropertyChanged(object sender,
                                                         PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(sender, args);
            if (args.PropertyName == StepSlider.MinimumProperty.PropertyName)
            {
                SetMinimum();
            }
            else if (args.PropertyName == StepSlider.MaximumProperty.PropertyName)
            {
                SetMaximum();
            }
            else if (args.PropertyName == StepSlider.StepsProperty.PropertyName)
            {
                SetSteps();
            }
            else if (args.PropertyName == StepSlider.ValueProperty.PropertyName)
            {
                SetValue();
            }
        }
        void SetMinimum()
        {
            minimum = Element.Minimum;
        }
        void SetMaximum()
        {
            maximum = Element.Maximum;
        }
        void SetSteps()
        {
            Control.Max = Element.Steps;
        }
        void SetValue()
        {
            double value = Element.Value;
            Control.Progress = (int)((value - minimum) / (maximum - minimum) * Element.Steps);
        }
        // Implementation of SeekBar.IOnSeekBarChangeListener
        public void OnProgressChanged(SeekBar seekBar, int progress, bool fromUser)
        {
            double value = minimum + (maximum - minimum) * Control.Progress / Control.Max;
            ((IElementController)Element).SetValueFromRenderer(StepSlider.ValueProperty, value);
        }
        public void OnStartTrackingTouch(SeekBar seekBar)
        {
        }
        public void OnStopTrackingTouch(SeekBar seekBar)
        {
        }
    }
}

StepSliderDemo解决方案包含指向Xamarin.FormsBook.Platform库的链接以及对这些库的相应引用。 StepSliderDemo.xaml文件实例化五个StepSlider元素,其中三个是数据绑定,另外两个是显式事件处理程序:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:platform=
                 "clr-namespace:Xamarin.FormsBook.Platform;assembly=Xamarin.FormsBook.Platform"
             x:Class="StepSliderDemo.StepSliderDemoPage">
    <StackLayout Padding="10, 0">
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style TargetType="ContentView">
                    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                </Style>
                <Style TargetType="Label">
                    <Setter Property="FontSize" Value="Large" />
                    <Setter Property="HorizontalOptions" Value="Center" />
                </Style>
            </ResourceDictionary>
        </StackLayout.Resources>
        <ContentView>
            <StackLayout>
                <platform:StepSlider x:Name="stepSlider1" />
                <Label Text="{Binding Source={x:Reference stepSlider1},
                                      Path=Value}" />
            </StackLayout>
        </ContentView>
        <ContentView>
            <StackLayout>
                <platform:StepSlider x:Name="stepSlider2"
                                     Minimum="10"
                                     Maximum="15"
                                     Steps="20"
                                     ValueChanged="OnSliderValueChanged" />
                <Label x:Name="label2" />
            </StackLayout>
        </ContentView>
        <ContentView>
            <StackLayout>
                <platform:StepSlider x:Name="stepSlider3"
                                     Steps="10" />
                <Label Text="{Binding Source={x:Reference stepSlider3},
                                      Path=Value}" />
            </StackLayout>
        </ContentView>
        <ContentView>
            <StackLayout>
                <platform:StepSlider x:Name="stepSlider4"
                                     Minimum="0"
                                     Maximum="1"
                                     Steps="100"
                                     ValueChanged="OnSliderValueChanged" />
                <Label x:Name="label4" />
            </StackLayout>
        </ContentView>
        <ContentView>
            <StackLayout>
                <platform:StepSlider x:Name="stepSlider5"
                                     Minimum="10"
                                     Maximum="20"
                                     Steps="2" />
                <Label Text="{Binding Source={x:Reference stepSlider5},
                                      Path=Value}" />
            </StackLayout>
        </ContentView>
    </StackLayout>
</ContentPage>

代码隐藏文件具有ValueChanged事件处理程序:

public partial class StepSliderDemoPage : ContentPage
{
    public StepSliderDemoPage()
    {
        InitializeComponent();
    }
    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        StepSlider stepSlider = (StepSlider)sender;
        if (stepSlider == stepSlider2)
        {
            label2.Text = stepSlider2.Value.ToString();
        }
        else if (stepSlider == stepSlider4)
        {
            label4.Text = stepSlider4.Value.ToString();
        }
    }
}

您会发现StepSlider的功能类似于普通的Xamarin.Forms Slider,只是StepSlider中的可能值现在处于程序控制之下:
第二十七章:自定义渲染器(六)
第一个StepSlider的增量值为1,第二个增量为0.25,第三个增量为10,第四个增量为0.01,第五个增量为5,只有三个可能的设置。
现在你可以看到Xamarin.Forms如何提供工具,让你超越它最初的样子。 您可以在三个平台中定义的任何内容都可以在一个通用平台中成为可用的东西。 使用C#编程语言,以及Xamarin.Forms和渲染器的强大功能,您不仅可以进入iOS编程,Android编程或Windows编程,而且只需一步即可完成三个步骤,并继续迈向未来 移动开发。

上一篇:推荐Linux管理员不可不知十大PHP安全要点 - SCutePHP


下一篇:IOS版App的控件元素定位