如何使用 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 iOS 中出现 ListView 之前,如何将 ListView 滚动位置设置为底部?