如何使用 Xamarin Forms 为 iOS 项目制作可点击的滑块?

Posted

技术标签:

【中文标题】如何使用 Xamarin Forms 为 iOS 项目制作可点击的滑块?【英文标题】:How to make clickable slider for iOS project with Xamarin Forms? 【发布时间】:2018-07-26 15:12:54 【问题描述】:

我使用滑块来制作评分星功能。为此,我将滑块放在背景中以接收手指的位置。这在 android 上工作得很好,因为每当你触摸滑块时,它都会改变它的值。 ios 上的 UISlider 仅在您触摸它的拇指时触发事件。

我认为,可以这样做。

1.为整个滑块控件添加点击手势

        UILongPressGestureRecognizer uiTap = new UILongPressGestureRecognizer(Tapped);
        uiTap.MinimumPressDuration = 0;
        AddGestureRecognizer(uiTap);

2。从触摸读取坐标并将它们传递给控制。 但我不知道该怎么做。

我的 xaml 看起来像这样。

<Grid>
    <Slider/>
    <Grid>
    <!-- here is my stars -->
    </Grid>
</Grid>

这里有很好的答案,objective-c 上有代码:https://***.com/a/22982080/10139785

【问题讨论】:

你创建了iOS控件吗? 我使用自定义渲染器。在覆盖的 OnElementChanged 内部,我放置了上面编写的代码。当在任何地方触摸滑块时它会触发事件。但不知道如何获取坐标并将滑块移动到该位置。 【参考方案1】:

如果您使用的是最近稳定的 Xamarin.Forms,Microsoft Documentation 可以为您提供更简单的方法。基本上在 iOS 特定命名空间上为滑块设置一个属性。惊喜!

这是它在 Xaml 中的要点:

<ContentPage ...
         xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
    <Slider ... ios:Slider.UpdateOnTap="true" />
    ...
</StackLayout>

或在后面的代码中:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

//(in constructor or OnAppearing say)
var slider = new Xamarin.Forms.Slider();
slider.On<iOS>().SetUpdateOnTap(true);

希望这会有所帮助。

【讨论】:

【参考方案2】:

好的,我能够将 swift 上的代码从 this answer 改编为 C# 代码,所以现在一切正常。

这是我的代码:

using MyProject.iOS.Renderers;
using CoreGraphics;
using Foundation;
using System;
using System.Linq;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(Slider), typeof(ClickableSliderRenderer))]
namespace MyProject.iOS.Renderers

public class ClickableSliderRenderer : SliderRenderer

    UILongPressGestureRecognizer uiTap;
    protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
    
        base.OnElementChanged(e);

        uiTap = new UILongPressGestureRecognizer(Tapped);
        uiTap.MinimumPressDuration = 0;
        AddGestureRecognizer(uiTap);

    

    private void Tapped(object sender)
    
        CGPoint point = uiTap.LocationInView(this);
        nfloat thumbWidth = Control.Subviews.LastOrDefault().Bounds.Size.Width;
        nfloat value;

        if (point.X <= thumbWidth / 2.0)
            value = Control.MinValue;
        else if (point.X >= Control.Bounds.Size.Width - thumbWidth / 2)
            value = Control.MaxValue;
        else
        
            var percentage = ((point.X - thumbWidth / 2) / (Control.Bounds.Size.Width - thumbWidth));
            var delta = percentage * (Control.MaxValue - Control.MinValue);

            value = Control.MinValue + delta;
        

        if (uiTap.State == UIGestureRecognizerState.Began)
        
            UIView.Animate(0.35, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animation:
                () =>
                
                    Control.SetValue((float)value, true);
                    Control.SendActionForControlEvents(UIControlEvent.ValueChanged);
                , completion: null);
        
        else if (uiTap.State == UIGestureRecognizerState.Changed)
        
            Control.SetValue((float)value, false);
            Control.SendActionForControlEvents(UIControlEvent.ValueChanged);
        
        else
        
            Control.SetValue((float)value, false);
        

        Control.ThumbRectForBounds(Bounds, Bounds, (float)value);
    


【讨论】:

【参考方案3】:

我在 Xamarin iOS C# 中创建了一个类似的解决方案

(改编自answer)

[Register(nameof(UISliderCustom))]
[DesignTimeVisible(true)]
public class UISliderCustom : UISlider


    public UISliderCustom(IntPtr handle) : base(handle)  

    public UISliderCustom()
    
        // Called when created from code.
        Initialize();
    

    public override void AwakeFromNib()
    
        // Called when loaded from xib or storyboard.
        Initialize();
    

    void Initialize()
    
        // Common initialization code here.

        var longPress = new UILongPressGestureRecognizer(tapAndSlide);
        longPress.MinimumPressDuration = 0;
        //longPress.CancelsTouchesInView = false;
        this.AddGestureRecognizer(longPress);
        this.UserInteractionEnabled = true;

    

    private void tapAndSlide(UILongPressGestureRecognizer gesture)
    
        System.Diagnostics.Debug.WriteLine($"nameof(UISliderCustom) RecognizerState gesture.State");

        // need to propagate events down the chain
        // I imagine iOS does something similar
        // for whatever recogniser on the thumb control
        // It's not enough to set CancelsTouchesInView because
        // if clicking on the track away from the thumb control
        // the thumb gesture recogniser won't pick it up anyway
        switch (gesture.State)
        
            case UIGestureRecognizerState.Cancelled:
                this.SendActionForControlEvents(UIControlEvent.TouchCancel);
                break;

            case UIGestureRecognizerState.Began:
                this.SendActionForControlEvents(UIControlEvent.TouchDown);
                break;

            case UIGestureRecognizerState.Changed:
                this.SendActionForControlEvents(UIControlEvent.ValueChanged);                    
                break;

            case UIGestureRecognizerState.Ended:
                this.SendActionForControlEvents(UIControlEvent.TouchUpInside);
                break;

            case UIGestureRecognizerState.Failed:
                //?
                break;

            case UIGestureRecognizerState.Possible:
                //?
                break;

        

        var pt = gesture.LocationInView(this);
        var thumbWidth = CurrentThumbImage.Size.Width;
        var value = 0f;

        if (pt.X <= thumbWidth / 2)
        
            value = this.MinValue;
        
        else if (pt.X >= this.Bounds.Size.Width - thumbWidth / 2)
        
            value = this.MaxValue;
        
        else
        
            var percentage = ((pt.X - thumbWidth / 2) / (this.Bounds.Size.Width - thumbWidth));
            var delta = percentage * (this.MaxValue - this.MinValue);
            value = this.MinValue + (float)delta;
        

        if (gesture.State == UIGestureRecognizerState.Began)
                       
            UIView.Animate(0.35, 0, UIViewAnimationOptions.CurveEaseInOut,
                () =>
                
                    this.SetValue(value, true);
                ,
                null);
        
        else
        
            this.SetValue(value, animated: false);
        

    


【讨论】:

以上是关于如何使用 Xamarin Forms 为 iOS 项目制作可点击的滑块?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用依赖注入在 Xamarin.Forms 中实现 Flyoutnavigation

如何将现有 iOS 应用升级到 Xamarin Forms 应用

Xamarin.Forms + 本机库 OpenCV

在 Xamarin Forms iOS 中出现 ListView 之前,如何将 ListView 滚动位置设置为底部?

如何在 iOS 的 xamarin.forms 应用程序中设置应用程序的应用程序图标

如何在 Xamarin.Forms 中获取/检测屏幕大小?