balu
balu

Reputation: 73

Xamrin Forms : Swipe to delete(gesture) in ListView

I want to implement the swipe to delete functionality in Xamrin Forms, for which i have tried the following.

  1. Wrote a custom renderer for the list view and in the "OnElementChanged" of the renderer am able to access the binded command to the "CustomListView" and am able to add this command to the Swipe Gesture as added below.

       swipeGestureRecognizer = new UISwipeGestureRecognizer (() => {
            if (command == null) {
                Console.WriteLine ("No command set");
                return;}
    
            command.Execute (null);
        });
    

However i am having trouble in accessing the specific row(swiped row), so that i could make a button visible/hidden on the swiped row in the list view. Please could you recommend a way to implement the same?

Upvotes: 7

Views: 12056

Answers (3)

Ryano
Ryano

Reputation: 495

I was able to accomplish this with the new Xamarin.Forms SwipeView

Pass the current row into the CommandParameter, and use it in the event handler.

FYI: For some reason the SwipeView has a default BackgroundColor of white, which you can override with something else to match your theme.

Xaml:

            <ListView Margin="-20,0,0,0" x:Name="photosListView" ItemSelected="OnItemSelected" VerticalOptions="FillAndExpand" SeparatorColor="Gray" VerticalScrollBarVisibility="Default" HasUnevenRows="true"  SeparatorVisibility="Default" Background="{StaticResource PrimaryDark}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <SwipeView BackgroundColor="{StaticResource PrimaryDark}" >
                                <SwipeView.RightItems>
                                    <SwipeItems>
                                        <SwipeItem Text="Delete" BackgroundColor="LightPink" Clicked="OnDeleteRow" CommandParameter="{Binding .}" />
                                    </SwipeItems>
                                </SwipeView.RightItems>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>

                                    <StackLayout Orientation="Horizontal">
                                        <CheckBox IsVisible="{Binding SelectEnabled}" Color="{StaticResource White}" IsChecked="{Binding Selected}" Margin="20,0,-15,0"  CheckedChanged="OnItemCheckedChanged" />
                                        <Grid WidthRequest="70" HeightRequest="50">
                                            <Grid.Margin>
                                                <OnPlatform x:TypeArguments="Thickness" Android="15,0,0,0" iOS="10,0,0,0" />
                                            </Grid.Margin>
                                            <Image Aspect="AspectFill"  Source="{Binding ThumbImageSource}" HorizontalOptions="Fill" />
                                        </Grid>
                                    </StackLayout>

                                    <StackLayout Grid.Column="1" Spacing="0" Padding="0" Margin="0,5,0,0">
                                        <Label Text="{Binding Photo.Description}" TextColor="{StaticResource TextColour}" FontSize="16" FontAttributes="Bold"  />
                                        <Label Text="{Binding DateTakenString}" TextColor="{StaticResource TextColour}" FontSize="14" />
                                    </StackLayout>
                                </Grid>
                            </SwipeView>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>

cs:

    public async void OnDeleteRow(object sender, EventArgs e)
    {
        if (await GetDeleteRowConfirmationFromUser())
        {
            SwipeItem si = sender as SwipeItem;
            PhotoListItem itemToDelete = si.CommandParameter as PhotoListItem;
            LocalDatabaseService db = new LocalDatabaseService();
            db.DeletePhoto(itemToDelete.Photo);
            _listItems.Remove(itemToDelete);
        }
    }

Upvotes: 0

Caitlin Taggart
Caitlin Taggart

Reputation: 71

Swipe to delete is now built into Xamarin Froms ListViews using a ContextAction. Here is the most basic tutorial of how to do it. It is very easy to implement.

http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/listview/

Upvotes: 7

madaboutcode
madaboutcode

Reputation: 2137

You could do something like this:

    protected override void OnElementChanged (ElementChangedEventArgs<ListView> e)
    {
        base.OnElementChanged (e);
        var swipeDelegate = new SwipeRecogniserDelegate ();
        swipeGestureRecognizer = new UISwipeGestureRecognizer {
            Direction = UISwipeGestureRecognizerDirection.Left,
            Delegate = swipeDelegate
        };
        swipeGestureRecognizer.AddTarget (o => {
            var startPoint = swipeDelegate.GetStartPoint ();
            Console.WriteLine (startPoint);
            var indexPath = this.Control.IndexPathForRowAtPoint(startPoint);
            if(listView.SwipeCommand != null) {
                listView.SwipeCommand.Execute(indexPath.Row);
            }
        });
        this.Control.AddGestureRecognizer (swipeGestureRecognizer);
        this.listView = (SwipableListView)this.Element;
    }

The key is SwipeRecogniserDelegate. its implemented like so:

public class SwipeRecogniserDelegate : UIGestureRecognizerDelegate
{
    PointF startPoint;

    public override bool ShouldReceiveTouch (UIGestureRecognizer recognizer, UITouch touch)
    {
        return true;
    }

    public override bool ShouldBegin (UIGestureRecognizer recognizer)
    {
        var swipeGesture = ((UISwipeGestureRecognizer)recognizer);
        this.startPoint = swipeGesture.LocationOfTouch (0, swipeGesture.View);
        return true;
    }

    public PointF GetStartPoint ()
    {
        return startPoint;
    }
}

Upvotes: 4

Related Questions