Reputation: 41
I need to write code (or XAML) for listview viewcell swipe left and right gestures.
When swiping left, delete the records from listview (or observable collection) list and update the remaining listitems in listview. When swiping right, save the records.
Upvotes: 3
Views: 4957
Reputation: 249
I've reworked James Lin's class to be command based so that it's MVVM friendly.
public class SwipeGestureGrid : Grid
{
public static readonly BindableProperty SwipeLeftCommandProperty =
BindableProperty.Create("SwipeLeftCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeRightCommandProperty =
BindableProperty.Create("SwipeRightCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeUpCommandProperty =
BindableProperty.Create("SwipeUpCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeDownCommandProperty =
BindableProperty.Create("SwipeDownCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty TappedCommandProperty =
BindableProperty.Create("TappedCommand", typeof(ICommand), typeof(ICommand), null);
private double _gestureStartX;
private double _gestureStartY;
private double _gestureDistanceX;
private double _gestureDistanceY;
public double GestureStartX
{
get => _gestureStartX;
private set
{
_gestureStartX = value;
OnPropertyChanged();
}
}
public double GestureStartY
{
get => _gestureStartY;
private set
{
_gestureStartY = value;
OnPropertyChanged();
}
}
private bool IsSwipe { get; set; }
public ICommand TappedCommand
{
get => (ICommand) GetValue(TappedCommandProperty);
set => SetValue(TappedCommandProperty, value);
}
public ICommand SwipeLeftCommand
{
get => (ICommand)GetValue(SwipeLeftCommandProperty);
set => SetValue(SwipeLeftCommandProperty, value);
}
public ICommand SwipeRightCommand
{
get => (ICommand)GetValue(SwipeRightCommandProperty);
set => SetValue(SwipeRightCommandProperty, value);
}
public ICommand SwipeUpCommand
{
get => (ICommand)GetValue(SwipeUpCommandProperty);
set => SetValue(SwipeUpCommandProperty, value);
}
public ICommand SwipeDownCommand
{
get => (ICommand)GetValue(SwipeDownCommandProperty);
set => SetValue(SwipeDownCommandProperty, value);
}
public SwipeGestureGrid()
{
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanGesture_PanUpdated;
var tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += TapGesture_Tapped;
GestureRecognizers.Add(panGesture);
GestureRecognizers.Add(tapGesture);
}
private void TapGesture_Tapped(object sender, EventArgs e)
{
try
{
if (!IsSwipe)
TappedCommand?.Execute(this);
IsSwipe = false;
}
catch (Exception ex)
{
}
}
private void PanGesture_PanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
{
GestureStartX = e.TotalX;
GestureStartY = e.TotalY;
}
break;
case GestureStatus.Running:
{
_gestureDistanceX = e.TotalX;
_gestureDistanceY = e.TotalY;
}
break;
case GestureStatus.Completed:
{
IsSwipe = true;
if (Math.Abs(_gestureDistanceX) > Math.Abs(_gestureDistanceY))
{
if (_gestureDistanceX > 0)
{
SwipeRightCommand?.Execute(this);
}
else
{
SwipeLeftCommand?.Execute(null);
}
}
else
{
if (_gestureDistanceY > 0)
{
SwipeDownCommand?.Execute(null);
}
else
{
SwipeUpCommand?.Execute(null);
}
}
}
break;
}
}
}
We use it in a DataTemplate for a ScrollableListView:
<DataTemplate x:Key="ThreeRowTemplateTemplate" x:DataType="{x:Type tracking:TrackingItem}">
<ViewCell>
<controls:SwipeGestureGrid ColumnSpacing="0" RowSpacing="0" SwipeLeftCommand="{Binding SwipeLeftCommand}">
In this case the bound command has to be on TrackingItem. It seems to work quite well but the detection is sometimes a bit flaky - possibly there's a conflict with the ScrollableListView's gesture handling.
Upvotes: 1
Reputation: 21
I've do it using cs code,You can try it on xaml.
First, you should build swipe compoment using gesture
SwipeGestureGrid.cs
public class SwipeGestureGrid : Grid
{
#region Private Member
private double _gestureX { get; set; }
private double _gestureY { get; set; }
private bool IsSwipe { get; set; }
#endregion
#region Public Member
#region Events
#region Tapped
public event EventHandler Tapped;
protected void OnTapped(EventArgs e)
{
if (Tapped != null)
Tapped(this, e);
}
#endregion
#region SwipeUP
public event EventHandler SwipeUP;
protected void OnSwipeUP(EventArgs e)
{
if (SwipeUP != null)
SwipeUP(this, e);
}
#endregion
#region SwipeDown
public event EventHandler SwipeDown;
protected void OnSwipeDown(EventArgs e)
{
if (SwipeDown != null)
SwipeDown(this, e);
}
#endregion
#region SwipeRight
public event EventHandler SwipeRight;
protected void OnSwipeRight(EventArgs e)
{
if (SwipeRight != null)
SwipeRight(this, e);
}
#endregion
#region SwipeLeft
public event EventHandler SwipeLeft;
protected void OnSwipeLeft(EventArgs e)
{
if (SwipeLeft != null)
SwipeLeft(this, e);
}
#endregion
#endregion
public double Height
{
get
{
return HeightRequest;
}
set
{
HeightRequest = value;
}
}
public double Width
{
get
{
return WidthRequest;
}
set
{
WidthRequest = value;
}
}
#endregion
public SwipeGestureGrid()
{
PanGestureRecognizer panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanGesture_PanUpdated;
TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += TapGesture_Tapped;
GestureRecognizers.Add(panGesture);
GestureRecognizers.Add(tapGesture);
}
private void TapGesture_Tapped(object sender, EventArgs e)
{
try
{
if (!IsSwipe)
OnTapped(null);
IsSwipe = false;
}
catch (Exception ex)
{
}
}
private void PanGesture_PanUpdated(object sender, PanUpdatedEventArgs e)
{
try
{
switch (e.StatusType)
{
case GestureStatus.Running:
{
_gestureX = e.TotalX;
_gestureY = e.TotalY;
}
break;
case GestureStatus.Completed:
{
IsSwipe = true;
//Debug.WriteLine("{0} {1}", _gestureX, _gestureY);
if (Math.Abs(_gestureX) > Math.Abs(_gestureY))
{
if (_gestureX > 0)
{
OnSwipeRight(null);
}
else
{
OnSwipeLeft(null);
}
}
else
{
if (_gestureY > 0)
{
OnSwipeDown(null);
}
else
{
OnSwipeUP(null);
}
}
}
break;
}
}
catch (Exception ex)
{
}
}
}
Next using datatemplate in listview andattach event for Gesturecompoment
Page.cs
ListView lsvData = new ListView()
{
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.Fill,
BackgroundColor = Color.White,
HasUnevenRows = true,
};
List<string> lstData = new List<string>();
public Pages()
{
#region DataTemplate
DataTemplate ListDataTemplate = new DataTemplate(() =>
{
#region DataArea of Template
SwipeGestureGrid gridData = new SwipeGestureGrid()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 60,
RowDefinitions =
{
new RowDefinition { },
},
ColumnDefinitions =
{
new ColumnDefinition { },
}
};
#endregion
#region Base of Template
Grid gridBase = new Grid()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 60,
RowDefinitions =
{
new RowDefinition { },
},
ColumnDefinitions =
{
new ColumnDefinition { }, //Put Cells Data here
new ColumnDefinition { Width = new GridLength(0, GridUnitType.Absolute)}, //Button for Cells here
},
};
#endregion
Label lblText = new Label
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
FontAttributes = FontAttributes.Bold,
VerticalTextAlignment = TextAlignment.End,
TextColor = Color.Black,
BackgroundColor = Color.Silver,
LineBreakMode = LineBreakMode.TailTruncation,
FontSize = 18,
};
lblText.SetBinding(Label.TextProperty, ".");
ImageButton btnCellDelete = new ImageButton() { Source = "Delete" };
gridData.Children.Add(lblText, 0, 0);
gridBase.Children.Add(gridData, 0, 0);
gridBase.Children.Add(btnCellDelete, 1, 0);
gridData.SwipeLeft += GridTemplate_SwipeLeft;
gridData.SwipeRight += GridTemplate_SwipeRight; ;
gridData.Tapped += GridTemplate_Tapped; ;
btnCellDelete.Clicked += BtnCellDelete_Clicked; ;
return new ViewCell
{
View = gridBase,
Height = 60,
};
});
#endregion
for (int i = 1; i <= 100; i++)
{
lstData.Add(i.ToString());
}
lsvData.ItemTemplate = ListDataTemplate;
lsvData.ItemsSource = lstData;
Content = lsvData;
}
SwipeLeft to show DeleteButton
private void GridTemplate_SwipeLeft(object sender, EventArgs e)
{
try
{
if (sender is SwipeGestureGrid)
{
var templateGrid = ((SwipeGestureGrid)sender).Parent;
if (templateGrid != null && templateGrid is Grid)
{
var CellTemplateGrid = (Grid)templateGrid;
CellTemplateGrid.ColumnDefinitions[1].Width = new GridLength(60, GridUnitType.Absolute);
}
}
}
catch (Exception ex)
{
}
}
swiperight to hide delete button
private void GridTemplate_SwipeRight(object sender, EventArgs e)
{
try
{
if (sender is SwipeGestureGrid)
{
var templateGrid = ((SwipeGestureGrid)sender).Parent;
if (templateGrid != null && templateGrid is Grid)
{
var CellTemplateGrid = (Grid)templateGrid;
CellTemplateGrid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Absolute);
}
}
}
catch (Exception ex)
{
}
}
Delete button click event
private void BtnCellDelete_Clicked(object sender, EventArgs e)
{
try
{
if (sender is ImageButton)
{
var templateGrid = ((ImageButton)sender);
//templateGrid.Parent = gridBase
//templateGrid.Parent.Parent = cell
if (templateGrid.Parent != null && templateGrid.Parent.Parent != null && templateGrid.Parent.Parent.BindingContext != null && templateGrid.Parent.Parent.BindingContext is string)
{
var deletedate = templateGrid.Parent.Parent.BindingContext as string;
lstData.RemoveAll(f => f == deletedate);
lsvData.ItemsSource = null;
lsvData.ItemsSource = lstData;
}
}
}
catch (Exception ex)
{
}
}
Source can be find in my github https://github.com/act70255/ListViewSwipeGesture
Upvotes: 1