父级滚动时隐藏浮动动作按钮

时间:2018-07-29 11:40:46

标签: c# mvvm xamarin.forms xamarin.ios xamarin.android

我正在使用FABandroidiOS平台创建自定义Xamarin.Forms按钮。

一切正常,但现在我希望能够以某种方式从scrolled按钮的最近父级接收FAB事件,因此我将能够隐藏{{1 }}按钮在用户滚动时,然后在滚动2秒后再次显示?。

父级可以是普通的FAB项目,也可以是ScrollView
是否可以通过每个平台使用相同的自定义渲染器来实现?还是完全可以实现?

这是我到目前为止所做的:

  1. ListView类:


FabButton
  1. public partial class FabButton : Button { public static BindableProperty ButtonColorProperty = BindableProperty.Create(nameof(ButtonColor), typeof(Color), typeof(FabButton), Color.Accent); public Color ButtonColor { get => (Color)GetValue(ButtonColorProperty); set => SetValue(ButtonColorProperty, value); } public FabButton() { InitializeComponent(); } } 自定义渲染器:

    iOS
  2. public class FabButtonRenderer:ButtonRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Button> e) { base.OnElementChanged(e); if(e.NewElement == null) return; if (Element.WidthRequest <= 0) Element.WidthRequest = 60; if (Element.HeightRequest <= 0) Element.HeightRequest = 60; if (Element.Margin == new Thickness(0, 0, 0, 0)) Element.Margin = new Thickness(0, 0, 20, 20); Element.CornerRadius = (int) Element.WidthRequest / 2; Element.BorderWidth = 0; Element.Text = null; Control.BackgroundColor = ((FabButton) Element).ButtonColor.ToUIColor(); } public override void Draw(CGRect rect) { base.Draw(rect); Layer.ShadowRadius = 0.2f; Layer.ShadowColor = UIColor.Black.CGColor; Layer.ShadowOffset = new CGSize(1, 1); Layer.ShadowOpacity = 0.80f; Layer.ShadowPath = UIBezierPath.FromOval(Layer.Bounds).CGPath; Layer.MasksToBounds = false; } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == nameof(FabButton.ButtonColor)) Control.BackgroundColor = ((FabButton) Element).ButtonColor.ToUIColor(); } } 自定义渲染器:

    android

2 个答案:

答案 0 :(得分:1)

我认为Scrollview的“ Scrolled”事件可以为您提供帮助,您将获得X和Y轴值,基于此,您必须在滚动时隐藏fab按钮。 并在2秒钟后使用“ Device.StartTimer”。

答案 1 :(得分:1)

很遗憾,没有built-in的方法。
由于我的原因,Floating Action Button可能会受到ScrollView控件滚动或列表视图控件的影响
我想到的唯一方法是明确指定ScrollView控件Floating Action Button的连接位置,因为这将是在将Floating Action Button连接到列表视图ScrollView时,实现起来很麻烦,并且由于最好使用MVVM模式,因此我找到了一种更简单的方法。
首先,我声明了一个接口IFloatingActionButtonHost

public interface IFloatingActionButtonHost
{
    bool ShouldBeHiddenWhenScrolling { get; }
    event Action LinkedScrollViewScrolled;
}

然后,我在BindableProperty控件内声明了FabButton,如下所示:

public static BindableProperty ButtonHostProperty = BindableProperty.Create(nameof(ButtonHost), typeof(IFloatingActionButtonHost), typeof(FabButton));
public IFloatingActionButtonHost ButtonHost
{
    get => (IFloatingActionButtonHost)GetValue(ButtonHostProperty);
    set => SetValue(ButtonHostProperty, value);
}

例如,在Renderer渲染器上的iOS中,我检查了此属性是否不为null,以及是否应隐藏Floating Action Button 当目标ScrollView滚动或不滚动然后在界面中订阅该事件时。

    var fabButton = (FabButton)Element;
    if (fabButton.ButtonHost != null && fabButton.ButtonHost.ShouldBeHiddenWhenScrolling)
    {
        fabButton.ButtonHost.LinkedScrollViewScrolled += OnLinkedScrollView_Scrolled;
    }

然后我在渲染器中处理了事件:

private void OnLinkedScrollView_Scrolled()
{
    Element.IsVisible = false;
    Device.StartTimer(TimeSpan.FromSeconds(3), () =>
    {
        if(Element != null){
            Element.IsVisible = true;
        }
        return false;
    });
}

OnElementPropertyChanged实现也应更改。

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    base.OnElementPropertyChanged(sender, e);
    if (e.PropertyName == nameof(FabButton.ButtonColor))
        Control.BackgroundColor = ((FabButton) Element).ButtonColor.ToUIColor();
    else if(e.PropertyName == nameof(FabButton.ButtonHost)){
        var fabButton = (FabButton)Element;
        if (fabButton.ButtonHost != null && fabButton.ButtonHost.ShouldBeHiddenWhenScrolling)
        {
            fabButton.ButtonHost.LinkedScrollViewScrolled += OnLinkedScrollView_Scrolled;
        }
    }
}

在每个页面code-behind上,我使页面继承自该接口,然后将页面实例传递给目标ViewModel
P.S。。对于ListView,我不得不编写一个自定义渲染器以暴露Scrolled事件。抱歉,我找不到更好的方法。

这是我尝试解决的问题,如果您有更好的解决方案,请为此问题写另一个答案,我会将其标记为最佳答案。