Xamarin Forms Custom GridView Tap和Long Tap无法一起使用

时间:2019-06-17 10:50:15

标签: xamarin.forms long-press

我想将Tap和Long Tap与Custom Gridview一起使用。

点击正在工作,但长按不起作用。

一键关闭长按也可以使用。

请帮助我。

谢谢。

///////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ////////////////////

  public class GridView : Grid
            {
                public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(GridView), default(IList), BindingMode.TwoWay);
                public static readonly BindableProperty ItemTappedCommandProperty = BindableProperty.Create(nameof(ItemTappedCommand), typeof(ICommand), typeof(GridView), null);

                public static readonly BindableProperty ItemLongTappedCommandProperty = BindableProperty.Create(nameof(ItemLongTappedCommand), typeof(ICommand), typeof(GridView), null);

                public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(GridView), default(DataTemplate));
                public static readonly BindableProperty MaxColumnsProperty = BindableProperty.Create(nameof(MaxColumns), typeof(int), typeof(GridView), 2);
                public static readonly BindableProperty TileHeightProperty = BindableProperty.Create(nameof(TileHeight), typeof(float), typeof(GridView), 220f);//adjusted here reuired height

                public GridView()
                {
                    PropertyChanged += GridView_PropertyChanged;
                    PropertyChanging += GridView_PropertyChanging;
                }



                public IList ItemsSource
                {
                    get { return (IList)GetValue(ItemsSourceProperty); }
                    set { SetValue(ItemsSourceProperty, value); }
                }

                public ICommand ItemTappedCommand
                {
                    get { return (ICommand)GetValue(ItemTappedCommandProperty); }
                    set { SetValue(ItemTappedCommandProperty, value); }
                }

                public ICommand ItemLongTappedCommand
                {
                    get { return (ICommand)GetValue(ItemLongTappedCommandProperty);}
                    set { SetValue(ItemLongTappedCommandProperty, value); }
                }

                public DataTemplate ItemTemplate
                {
                    get { return (DataTemplate)GetValue(ItemTemplateProperty); }
                    set { SetValue(ItemTemplateProperty, value); }
                }

                public int MaxColumns
                {
                    get { return (int)GetValue(MaxColumnsProperty); }
                    set { SetValue(MaxColumnsProperty, value); }
                }

                public float TileHeight
                {
                    get { return (float)GetValue(TileHeightProperty); }
                    set { SetValue(TileHeightProperty, value); }
                }

                private void BuildColumns()
                {
                    ColumnDefinitions.Clear();
                    for (var i = 0; i < MaxColumns; i++)
                    {
                        ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
                    }
                }

                private View BuildTile(object item1)
                {
                    var template = ItemTemplate.CreateContent() as View;
                    template.BindingContext = item1;

                    if (ItemTappedCommand != null)
                    {
                        var tapGestureRecognizer = new TapGestureRecognizer
                        {


                            Command = ItemTappedCommand,
                            CommandParameter = item1,                
                        };               

                        template.GestureRecognizers.Add(tapGestureRecognizer);
                    }

                    // Tap komutu eziyor.
                    if (ItemLongTappedCommand != null)
                    {
                        template.Effects.Add(new LongPressedEffect());
                        LongPressedEffect.SetCommand(template, ItemLongTappedCommand);
                        //LongPressedEffect.SetCommandParameter(template, item1);
                    }


                    return template;
                }

                private void BuildTiles()
                {
                    // Wipe out the previous row & Column definitions if they're there.
                    if (RowDefinitions.Any())
                    {
                        RowDefinitions.Clear();
                    }

                    BuildColumns();
                    Children.Clear();
                    var tiles = ItemsSource;
                    if (tiles != null)
                    {
                        var numberOfRows = Math.Ceiling(tiles.Count / (float)MaxColumns);
                        for (var i = 0; i < numberOfRows; i++)
                        {
                            RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) });
                        }

                        for (var index = 0; index < tiles.Count; index++)
                        {
                            var column = index % MaxColumns;
                            var row = (int)Math.Floor(index / (float)MaxColumns);
                            var tile = BuildTile(tiles[index]);
                            Children.Add(tile, column, row);
                        }
                    }
                }

                private void GridView_PropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                    if (e.PropertyName == ItemsSourceProperty.PropertyName)
                    {
                        var items = ItemsSource as INotifyCollectionChanged;
                        if (items != null)
                            items.CollectionChanged += ItemsCollectionChanged;
                        BuildTiles();
                    }

                    if (e.PropertyName == MaxColumnsProperty.PropertyName || e.PropertyName == TileHeightProperty.PropertyName)
                    {
                        BuildTiles();
                    }
                }

                private void GridView_PropertyChanging(object sender, Xamarin.Forms.PropertyChangingEventArgs e)
                {

                    if (e.PropertyName == ItemsSourceProperty.PropertyName)
                    {
                        var items = ItemsSource as INotifyCollectionChanged;
                        if (items != null)
                            items.CollectionChanged -= ItemsCollectionChanged;
                    }
                }

                private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                {
                    BuildTiles();
                }
            }


          public class LongPressedEffect : RoutingEffect
        {
            public LongPressedEffect() : base("MyApp.LongPressedEffect")
            {

            }

            public static readonly BindableProperty CommandProperty = BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(LongPressedEffect), (object)null);
            public static ICommand GetCommand(BindableObject view)
            {

                //do something you want 
                Console.WriteLine("long press Gesture recognizer has been striked");


                return (ICommand)view.GetValue(CommandProperty);
            }

            public static void SetCommand(BindableObject view, ICommand value)
            {
                view.SetValue(CommandProperty, value);

            }


            public static readonly BindableProperty CommandParameterProperty = BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(LongPressedEffect), (object)null);
            public static object GetCommandParameter(BindableObject view)
            {

                return view.GetValue(CommandParameterProperty);
            }

            public static void SetCommandParameter(BindableObject view, object value)
            {
                view.SetValue(CommandParameterProperty, value);
            }
        }

1 个答案:

答案 0 :(得分:0)

我注意到您使用Effect来创建自己的长按命令。但是,如果您同时消耗TapGestureRecognizer,它将截获效果。这样您长按的命令就不会被触发。

您可以定义效果中的单击事件,以实现二者。这是我的效果:

public class PressedEffect : RoutingEffect
{
    public PressedEffect() : base("MyApp.PressedEffect")
    {
    }

    public static readonly BindableProperty LongTapCommandProperty = BindableProperty.CreateAttached("LongTapCommand", typeof(ICommand), typeof(PressedEffect), (object)null);
    public static ICommand GetLongTapCommand(BindableObject view)
    {
        return (ICommand)view.GetValue(LongTapCommandProperty);
    }

    public static void SetLongTapCommand(BindableObject view, ICommand value)
    {
        view.SetValue(LongTapCommandProperty, value);
    }


    public static readonly BindableProperty LongParameterProperty = BindableProperty.CreateAttached("LongParameter", typeof(object), typeof(PressedEffect), (object)null);
    public static object GetLongParameter(BindableObject view)
    {
        return view.GetValue(LongParameterProperty);
    }

    public static void SetLongParameter(BindableObject view, object value)
    {
        view.SetValue(LongParameterProperty, value);
    }

    public static readonly BindableProperty TapCommandProperty = BindableProperty.CreateAttached("TapCommand", typeof(ICommand), typeof(PressedEffect), (object)null);
    public static ICommand GetTapCommand(BindableObject view)
    {
        return (ICommand)view.GetValue(TapCommandProperty);
    }

    public static void SetTapCommand(BindableObject view, ICommand value)
    {
        view.SetValue(TapCommandProperty, value);
    }

    public static readonly BindableProperty TapParameterProperty = BindableProperty.CreateAttached("TapParameter", typeof(object), typeof(PressedEffect), (object)null);
    public static object GetTapParameter(BindableObject view)
    {
        return view.GetValue(TapParameterProperty);
    }

    public static void SetTapParameter(BindableObject view, object value)
    {
        view.SetValue(TapParameterProperty, value);
    }
}

Android实现:

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(AndroidPressedEffect), "PressedEffect")]
namespace PressedEffectDemo.Droid
{
    public class AndroidPressedEffect : PlatformEffect
    {
        private bool _attached;

        public static void Initialize() { }

        public AndroidPressedEffect()
        {
        }

        protected override void OnAttached()
        {
            if (!_attached)
            {
                if (Control != null)
                {
                    Control.LongClickable = true;
                    Control.LongClick += Control_LongClick;
                    Control.Click += Control_Click;
                }
                else
                {
                    Container.LongClickable = true;
                    Container.LongClick += Control_LongClick;
                    Container.Click += Control_Click;
                }
                _attached = true;
            }
        }

        private void Control_Click(object sender, EventArgs e)
        {
            var command = PressedEffect.GetTapCommand(Element);
            command?.Execute(PressedEffect.GetTapParameter(Element));
        }

        private void Control_LongClick(object sender, Android.Views.View.LongClickEventArgs e)
        {
            var command = PressedEffect.GetLongTapCommand(Element);
            command?.Execute(PressedEffect.GetLongParameter(Element));
        }

        protected override void OnDetached()
        {
            if (_attached)
            {
                if (Control != null)
                {
                    Control.LongClickable = true;
                    Control.LongClick -= Control_LongClick;
                    Control.Click -= Control_Click;
                }
                else
                {
                    Container.LongClickable = true;
                    Container.LongClick -= Control_LongClick;
                    Control.Click -= Control_Click;
                }
                _attached = false;
            }
        }
    }
}

iOS实现:

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(iOSPressedEffect), "PressedEffect")]
namespace PressedEffectDemo.iOS
{
    public class iOSPressedEffect : PlatformEffect
    {
        private bool _attached;
        private readonly UILongPressGestureRecognizer _longPressRecognizer;
        private readonly UITapGestureRecognizer _tapRecognizer;
        public iOSPressedEffect()
        {
            _longPressRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
            _tapRecognizer = new UITapGestureRecognizer(HandleClick);
        }

        protected override void OnAttached()
        {
            if (!_attached)
            {
                Container.AddGestureRecognizer(_longPressRecognizer);
                Container.AddGestureRecognizer(_tapRecognizer);
                _attached = true;
            }
        }

        private void HandleClick()
        {
            var command = PressedEffect.GetTapCommand(Element);
            command?.Execute(PressedEffect.GetTapParameter(Element));
        }
        private void HandleLongClick(UILongPressGestureRecognizer recognizer)
        {
            if (recognizer.State == UIGestureRecognizerState.Ended)
            {
                var command = PressedEffect.GetLongTapCommand(Element);
                command?.Execute(PressedEffect.GetLongParameter(Element));
            }           
        }

        protected override void OnDetached()
        {
            if (_attached)
            {
                Container.RemoveGestureRecognizer(_longPressRecognizer);
                Container.RemoveGestureRecognizer(_tapRecognizer);
                _attached = false;
            }
        }
    }
}

最后,您可以像这样在XAML上使用它们:

<StackLayout>        
    <Grid HeightRequest="200" 
            BackgroundColor="Green" 
            local:PressedEffect.TapCommand="{Binding TapCommand}" 
            local:PressedEffect.LongTapCommand="{Binding LongTapCommand}">
        <Grid.Effects>
            <local:PressedEffect />
        </Grid.Effects>
    </Grid>
</StackLayout>

您可以参考我的示例here