AndreiMisiukevich/ContextMenu

SideContextMenuView Not working

AlenToma opened this issue · 5 comments

I just installed this from nuget and im having a problem making it work.
dose the source code differ from nuget?

I have this in listview, the first 5 items work and i could slide it and the button come out but after the 5 items i cant slide anything. and also the items stop beging visible.

Here is my xaml have a look

<controls:YListView x:Name="lstVideos" OnSelected="lstVideos_OnSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <views:SideContextMenuView IsAutoCloseEnabled="true">
                        <views:SideContextMenuView.View>
                            <Frame BorderColor="Transparent" Style="{StaticResource FrameContainer}" 
                                   WidthRequest="{Binding Source={x:Reference lstVideos},
                                   Path=Width, Converter={ StaticResource MenuFitWidth},
                                   ConverterParameter='0'}">
                                <StackLayout Style="{StaticResource FormFloatLeft}">
                                    <Image Aspect="Fill" HeightRequest="40" WidthRequest="50" Source="{ Binding Path=., Converter={StaticResource ImageSource}}" ></Image>
                                    <StackLayout Orientation="Vertical">
                                        <StackLayout Style="{StaticResource FormFloatLeft}">
                                            <Label Text="{Binding Title}" VerticalOptions="Start" HorizontalOptions="Start" Style="{StaticResource Header}" />
                                        </StackLayout>
                                    </StackLayout>
                                </StackLayout>
                            </Frame>
                        </views:SideContextMenuView.View>
                        <views:SideContextMenuView.ContextTemplate>
                            <DataTemplate>
                                <Frame Style="{StaticResource FrameContainer}" BorderColor="Transparent" CornerRadius="10" IsClippedToBounds="true">
                                    <StackLayout Style="{StaticResource FormFloatLeft}">
                                        <controls:CustomButton
                                   IsVisible="{Binding Playable, Converter={StaticResource Invert}}"
                                   CommandParameter="{Binding Video_Id}" 
                                   Image="download.png"
                                   Clicked="CustomButton_Clicked"
                                   HorizontalOptions="EndAndExpand"
                                   VerticalOptions="StartAndExpand"
                                   Style="{StaticResource Icon}" />

                                   <controls:CustomButton 
                                   x:Name="btnDelete"
                                   CommandParameter="{Binding Video_Id}" 
                                   Image="cancel.png"
                                   Clicked="BtnDelete_Clicked"
                                   HorizontalOptions="EndAndExpand"
                                   VerticalOptions="StartAndExpand"
                                   Style="{StaticResource Icon}" />
                                    </StackLayout>
                                </Frame>
                            </DataTemplate>
                        </views:SideContextMenuView.ContextTemplate>
                    </views:SideContextMenuView>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </controls:YListView>```

Ok i have tested your source code and there is many issue with it. SideContextMenuView should be much simpler then what you think. and also its really bad to have it in a scrollview where it will inactive move, click etc

So i build one for my self. and will share the code with you, let me know what you think.

Here you can watch it on youtube
Audi R8

First I have HorizontalSwaper that will detect Swap left and right

    public class HorizontalSwaper : StackLayout
    {

        public event Action<SwipeDirection, float, float> OnSwap;


        public void Swap(SwipeDirection direction, float x, float y)
        {
            OnSwap?.Invoke(direction, x, y);
        }

    }

And then the renderer HorizontalSwaperRenderer

public class HorizontalSwaperRenderer : VisualElementRenderer<StackLayout>
 {
     private float x1, webViewWidth;
     private HorizontalSwaper horizontalSwaper;
     private Context context;


     public HorizontalSwaperRenderer(Context context) : base(context)
     {
         this.context = context;
         webViewWidth = 14;
     }


     protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
     {
         base.OnElementChanged(e);

         horizontalSwaper = e.NewElement as HorizontalSwaper;

         this.Touch += ButtonContextMenuRenderer_Touch;

     }

     private void ButtonContextMenuRenderer_Touch(object sender, TouchEventArgs e)
     {
         e.Handled = false; // false so the user will be able to click on it if it contained within a list view etc
         switch (e.Event.Action)
         {
             case MotionEventActions.Up:
                 break;


             case MotionEventActions.Down:
                 x1 = e.Event.GetX();
                 //webViewWidth = this.Width;
                 break;

             case MotionEventActions.Move:
                 float movement = e.Event.GetX() - x1;
                 float offset = webViewWidth / 2;

                 if (Math.Abs(movement) > offset)
                 {
                     if (movement < 0)
                     {
                         horizontalSwaper.Swap(SwipeDirection.Left, e.Event.GetX(), e.Event.GetY());
                         System.Console.WriteLine("Left swipe");
                         //webView.GoBack();
                     }
                     else
                     {
                         horizontalSwaper.Swap(SwipeDirection.Right, e.Event.GetX(), e.Event.GetY());
                         System.Console.WriteLine("Right swipe");
                         //webView.GoForward();
                     }
                 }

                 break;
         }
     }

     public override bool OnInterceptTouchEvent(MotionEvent ev)
     {
         return true;
     }
 }

And here is the controller ButtonContextMenu that dose not even need a custom renderer.
that corresponds to your SideContextMenuView, it containe View and ContextMenu

 public class ButtonContextMenu : StackLayout
    {
        public static readonly BindableProperty ItemViewProperty = BindableProperty.Create(nameof(ItemView), typeof(DataTemplate), typeof(ButtonContextMenu), default(DataTemplate), BindingMode.TwoWay, null, ItemViewchanged);

        public DataTemplate ItemView
        {
            get { return (DataTemplate)GetValue(ItemViewProperty); }
            set { SetValue(ItemViewProperty, value); }
        }

        public static readonly BindableProperty ItemContextProperty = BindableProperty.Create(nameof(ItemContext), typeof(DataTemplate), typeof(ButtonContextMenu), default(DataTemplate), BindingMode.TwoWay, null, ItemContextchanged);

        public DataTemplate ItemContext
        {
            get { return (DataTemplate)GetValue(ItemContextProperty); }
            set { SetValue(ItemContextProperty, value); }
        }

        protected StackLayout ViewStack { get; }

        protected HorizontalSwaper LeftContent;

        protected StackLayout RightContent;

        protected AbsoluteLayout Container;

        private static void ItemContextchanged(BindableObject bindable, object oldValue, object newValue)
        {
            var itemsLayout = (ButtonContextMenu)bindable;
            itemsLayout.SetItemContextView();
        }

        private static void ItemViewchanged(BindableObject bindable, object oldValue, object newValue)
        {
            var itemsLayout = (ButtonContextMenu)bindable;
            itemsLayout.SetItemView();
        }

        private bool swaptLeft;
        public void Swap(SwipeDirection swipeDirection, float x, float y)
        {

            if (swipeDirection == SwipeDirection.Left)
            {
                if (swaptLeft)
                    return;



                var leftBound = new Rectangle(LeftContent.Bounds.X - RightContent.Width, LeftContent.Bounds.Y, LeftContent.Bounds.Width, LeftContent.Bounds.Height);
                LeftContent.LayoutTo(leftBound, 500, Easing.CubicInOut);

                var rightBounds = new Rectangle(RightContent.Bounds.X - RightContent.Width, RightContent.Bounds.Y, RightContent.Bounds.Width, RightContent.Bounds.Height);
                RightContent.LayoutTo(rightBounds, 500, Easing.CubicInOut);
                swaptLeft = true;

            }
            else
            {
                if (!swaptLeft)
                    return;


                var leftBound = new Rectangle(LeftContent.Bounds.X + RightContent.Width, LeftContent.Bounds.Y, LeftContent.Bounds.Width, LeftContent.Bounds.Height);
                LeftContent.LayoutTo(leftBound, 500, Easing.CubicInOut);


                var rightBounds = new Rectangle(RightContent.Bounds.X + RightContent.Width, RightContent.Bounds.Y, RightContent.Bounds.Width, RightContent.Bounds.Height);
                RightContent.LayoutTo(rightBounds, 500, Easing.CubicInOut);
                swaptLeft = false;
            }
        }

        public ButtonContextMenu()
        {
            Container = new AbsoluteLayout();
            //Orientation = ScrollOrientation.Horizontal;
            VerticalOptions = LayoutOptions.Fill;
            HorizontalOptions = LayoutOptions.Fill;
            //VerticalScrollBarVisibility = ScrollBarVisibility.Never;
            //HorizontalScrollBarVisibility = ScrollBarVisibility.Never;
            Container.Children.Add(ViewStack = new StackLayout
            {
                VerticalOptions = LayoutOptions.Fill,
                HorizontalOptions = LayoutOptions.Fill,
                Spacing = 0,
                Orientation = StackOrientation.Horizontal,
                Children = {

                }
            });

            Children.Add(Container);

        }

        public void SetItemView()
        {
            var leftContent = ItemView.CreateContent();
            var view = leftContent as View;
            if (view == null)
                view = leftContent as ContentView;
            if (view == null)
                throw new Exception("Only a view or Content View is supported");


            LeftContent = new HorizontalSwaper()
            {
                Children = { view },
            };
            LeftContent.OnSwap += Swap;
            ViewStack.Children.Add(LeftContent);
        }


        protected void SetItemContextView()
        {

            var rightContent = ItemContext.CreateContent();
            var rView = rightContent as View;
            if (rView == null)
                rView = rightContent as ContentView;
            if (rView == null)
                throw new Exception("Only a view or Content View is supported");

            ViewStack.Children.Add(rView);
            RightContent = new StackLayout()
            {
                Children = { rView },
            };

            ViewStack.Children.Add(RightContent);


        }

    }

And lastly the xaml

 <controls:ButtonContextMenu HeightRequest="45" >
                    <controls:ButtonContextMenu.ItemView>
                        <DataTemplate>
                            <StackLayout WidthRequest="{Binding Source={x:Reference lstVideos},
                                   Path=Width, Converter={ StaticResource MenuFitWidth},
                                   ConverterParameter='0'}" x:Name="itemContainer" Style="{StaticResource FormFloatLeft}" VerticalOptions="FillAndExpand">
                                <Image Aspect="Fill" HeightRequest="{Binding Source=itemContainer, Path=Height, Converter={ StaticResource MenuFitWidth}, ConverterParameter='-5'}" WidthRequest="50" Source="{ Binding Path=., Converter={StaticResource ImageSource}}" ></Image>
                                <Label Text="{Binding Title}" VerticalOptions="Start" HorizontalOptions="Start" Style="{StaticResource Header}" />
                            </StackLayout>
                        </DataTemplate>
                    </controls:ButtonContextMenu.ItemView>
                    <controls:ButtonContextMenu.ItemContext>
                        <DataTemplate>
                            <Frame Style="{StaticResource FrameContainer}"
                                   BorderColor="Transparent"
                                   Padding="0" Margin="0"
                                   CornerRadius="10" 
                                   IsClippedToBounds="true" HeightRequest="40" VerticalOptions="Center">
                                <StackLayout Style="{StaticResource FormFloatLeft}">
                                    <controls:CustomButton
                                           IsVisible="{Binding Playable, Converter={StaticResource Invert}}"
                                           CommandParameter="{Binding Video_Id}"
                                           Image="download.png"
                                           Clicked="CustomButton_Clicked"
                                           HorizontalOptions="EndAndExpand"
                                           VerticalOptions="StartAndExpand"
                                           Style="{StaticResource Icon}" />

                                    <controls:CustomButton
                                           x:Name="btnDelete"
                                           CommandParameter="{Binding Video_Id}"
                                           Image="cancel.png"
                                           Clicked="BtnDelete_Clicked"
                                           HorizontalOptions="EndAndExpand"
                                           VerticalOptions="StartAndExpand"
                                           Style="{StaticResource Icon}" />
                                </StackLayout>
                            </Frame>
                        </DataTemplate>
                    </controls:ButtonContextMenu.ItemContext>
                </controls:ButtonContextMenu>

Hop this help you make your control much better, as of now i really cant use it.

ListView should have "RecycleElement" strategy

btw, do you see the same error on my samples?

@AlenToma the best approach would be:

  1. fork my repository
  2. apply your changes
  3. make PR to my repo

Well i tried that, but there are many diffrent cases where i get error when working with your library. And i have other controller that inteferes with the structure of you repo. making big changes is time consuming for me and thats why i build my own. I just wanted to show you the code so that you may be willing to remove ScrollView and add Relativelayout instead and with the help of bounds you could have the same effect.

You also need to know that with relativelayout, there wont be interference with any other controller like ListView, Button etc...

When i manage to finish my current project i will be more then willing to improve your library.

So) if you wish to enhance this plugin, feel free to make PR