hello, I implemented and modified the swipe view dle segunte link:
matchboxmobile.com/blog/xamarin-forms-swipecard-tutorial/
But everything works on Android, while on ios does not recognize the clicks.
Things might be?
The following is my code:
My Xaml:
<ContentView.Content>
<StackLayout BackgroundColor="White" InputTransparent="True">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label x:Name="_Name" FontSize="22" Margin="10,5,10,5" TextColor="{StaticResource primaryColor}"
HorizontalTextAlignment="Center" InputTransparent="True"></Label>
<iconize:IconImage Margin="10,5,10,5" x:Name="favoriteButton" HeightRequest="30" HorizontalOptions="EndAndExpand" WidthRequest="30" IconColor="Red" />
</StackLayout>
<Image x:Name="_Photo" Aspect="AspectFill" InputTransparent="True">
<Image.HeightRequest>
<OnPlatform x:TypeArguments="x:Double"
iOS="200"
Android="200"/>
</Image.HeightRequest>
</Image>
<Label x:Name="_Description" FontSize="18" TextColor="Gray"
HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand"
InputTransparent="True"></Label>
<StackLayout VerticalOptions="EndAndExpand">
<customControl1:RoundedButton TypeButton ="Primary" Text="Contatta" Command="{Binding contactUser}"/>
</StackLayout>
<BoxView Margin="10,0,10,0" HeightRequest="1" HorizontalOptions="Fill" BackgroundColor="Gray" VerticalOptions="End"/>
<StackLayout VerticalOptions="End" HorizontalOptions="Center" Orientation="Horizontal" Margin="10">
<Label x:Name="_CurrentItem" FontSize="12" TextColor="Gray" HorizontalTextAlignment="Center" InputTransparent="True"></Label>
<Label Text="di" TextColor="Gray" FontSize="12" HorizontalTextAlignment="Center" InputTransparent="True"></Label>
<Label x:Name="_TotalItems" FontSize="12" TextColor="Gray" HorizontalTextAlignment="Center" InputTransparent="True"></Label>
</StackLayout>
</StackLayout>
</ContentView.Content>
My xaml.cs:
public partial class CardViewCust : ContentView
{
public Label Name { get; set; }
public Image Photo { get; set; }
// public Label Location { get; set; }
public Label Description { get; set; }
public Label CurrentItem { get; set; }
public Label TotalItems { get; set; }
public CardViewCust()
{
InitializeComponent();
Name = _Name;
Photo = _Photo;
//Location = _Location;
Description = _Description;
CurrentItem = _CurrentItem;
TotalItems = _TotalItems;
favoriteButton.Icon = "fa-heart-o";
favoriteButton.GestureRecognizers.Add(new TapGestureRecognizer(OnTap));
// _Photo.GestureRecognizers.Add(new TapGestureRecognizer(OnTap));
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, "tap");
_Photo.GestureRecognizers.Add(tapGestureRecognizer);
}
private void OnTap(View view, object o)
{
favoriteButton.RotateXTo(360);
favoriteButton.Icon = "fa-heart";
}
}
}
My CardViewStack:
public class CardStackView : ContentView
{
public class Item
{
public int Index { get; set; }
public string Name { get; set; }
public string Photo { get; set;}
public string Location { get; set;}
public string Description { get; set;}
};
// back card scale
const float BackCardScale = 0.8f;
// speed of the animations
const int AnimLength = 250;
// 180 / pi
const float DegreesToRadians = 57.2957795f;
// higher the number less the rotation effect
const float CardRotationAdjuster = 0.3f;
// distance a card must be moved to consider to be swiped off
public int CardMoveDistance {get; set;}
// two cards
const int NumCards = 2;
public CardViewCust[] cards = new CardViewCust[NumCards];
// the card at the top of the stack
int topCardIndex;
// distance the card has been moved
float cardDistance = 0;
// the last items index added to the stack of the cards
int itemIndex = 0;
bool ignoreTouch = false;
// called when a card is swiped left/right with the card index in the ItemSource
public Action<int> SwipedRight = null;
public Action<int> SwipedLeft = null;
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create(nameof(ItemsSource), typeof(System.Collections.IList), typeof(CardStackView), null,
propertyChanged: OnItemsSourcePropertyChanged);
public List<Item> ItemsSource {
get {
return (List<Item>)GetValue (ItemsSourceProperty);
}
set {
SetValue (ItemsSourceProperty, value);
itemIndex = 0;
}
}
private static void OnItemsSourcePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((CardStackView)bindable).Setup();
}
public CardStackView ()
{
RelativeLayout view = new RelativeLayout ();
// create a stack of cards
for (var i = 0; i < NumCards; i++) {
var card = new CardViewCust();
cards[i] = card;
card.InputTransparent = true;
card.IsVisible = false;
view.Children.Add(
card,
Constraint.Constant(0),
Constraint.Constant(0),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.RelativeToParent((parent) => parent.Height)
);
}
this.BackgroundColor = Color.Black;
this.Content = view;
var panGesture = new PanGestureRecognizer ();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add (panGesture);
}
void Setup()
{
// set the top card
topCardIndex = 0;
// create a stack of cards
var j = Math.Min(NumCards, ItemsSource.Count);
for (int i = 0; i < Math.Min(NumCards, ItemsSource.Count); i++) {
if (itemIndex >= ItemsSource.Count)
{
itemIndex = 0;
//break;
}
var card = cards[i];
card.Name.Text = ItemsSource[itemIndex].Name;
// card.Location.Text = ItemsSource[itemIndex].Location;
card.Description.Text = ItemsSource[itemIndex].Description;
card.CurrentItem.Text = ItemsSource[itemIndex].Index.ToString();
card.TotalItems.Text = ItemsSource.Count.ToString();
card.Photo.Source = ImageSource.FromFile(ItemsSource[itemIndex].Photo);
card.IsVisible = true;
card.Scale = GetScale(i);
card.RotateTo (0, 0);
card.TranslateTo (0, - card.Y, 0);
((RelativeLayout)this.Content).LowerChild (card);
itemIndex++;
}
}
void OnPanUpdated (object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType) {
case GestureStatus.Started:
HandleTouchStart();
break;
case GestureStatus.Running:
HandleTouch((float)e.TotalX);
break;
case GestureStatus.Completed:
HandleTouchEnd();
break;
}
}
// to hande when a touch event begins
public void HandleTouchStart()
{
cardDistance = 0;
}
// to handle te ongoing touch event as the card is moved
public void HandleTouch(float diff_x)
{
if (ignoreTouch) {
return;
}
var topCard = cards [topCardIndex];
var backCard = cards [PrevCardIndex (topCardIndex)];
// move the top card
if (topCard.IsVisible) {
// move the card
topCard.TranslationX = (diff_x);
// calculate a angle for the card
float rotationAngel = (float)(CardRotationAdjuster * Math.Min (diff_x / this.Width, 1.0f));
topCard.Rotation = rotationAngel * DegreesToRadians;
// keep a record of how far its moved
cardDistance = diff_x;
}
// scale the backcard
if (backCard.IsVisible) {
backCard.Scale = Math.Min (BackCardScale + Math.Abs ((cardDistance / CardMoveDistance) * (1.0f - BackCardScale)), 1.0f);
}
}
// to handle the end of the touch event
public async void HandleTouchEnd()
{
ignoreTouch = true;
var topCard = cards [topCardIndex];
// if the card was move enough to be considered swiped off
if (Math.Abs ((int)cardDistance) > CardMoveDistance) {
// move off the screen
await topCard.TranslateTo (cardDistance>0?this.Width:-this.Width, 0, AnimLength/2, Easing.SpringOut);
topCard.IsVisible = false;
if (SwipedRight != null && cardDistance > 0) {
SwipedRight(itemIndex);
}
else
{
SwipedLeft?.Invoke(itemIndex);
}
// show the next card
ShowNextCard ();
}
// put the card back in the center
else {
// move the top card back to the center
topCard.TranslateTo ((-topCard.X), - topCard.Y, AnimLength, Easing.SpringOut);
topCard.RotateTo (0, AnimLength, Easing.SpringOut);
// scale the back card down
var prevCard = cards [PrevCardIndex (topCardIndex)];
await prevCard.ScaleTo(BackCardScale, AnimLength, Easing.SpringOut);
}
ignoreTouch = false;
}
// show the next card
void ShowNextCard()
{
if (cards[0].IsVisible == false && cards[1].IsVisible == false) {
Setup();
return;
}
var topCard = cards [topCardIndex];
topCardIndex = NextCardIndex (topCardIndex);
// if there are more cards to show, show the next card in to place of
// the card that was swipped off the screen
if (itemIndex < ItemsSource.Count) {
// push it to the back z order
((RelativeLayout)this.Content).LowerChild(topCard);
// reset its scale, opacity and rotation
topCard.Scale = BackCardScale;
topCard.RotateTo(0, 0);
topCard.TranslateTo(0, -topCard.Y, 0);
// set the data
topCard.Name.Text = ItemsSource[itemIndex].Name;
// topCard.Location.Text = ItemsSource[itemIndex].Location;
topCard.Description.Text = ItemsSource[itemIndex].Description;
topCard.CurrentItem.Text = ItemsSource[itemIndex].Index.ToString();
topCard.TotalItems.Text = ItemsSource.Count.ToString();
topCard.Photo.Source = ImageSource.FromFile(ItemsSource[itemIndex].Photo);
topCard.IsVisible = true;
itemIndex++;
}
}
// return the next card index from the top
int NextCardIndex(int topIndex)
{
return topIndex == 0 ? 1 : 0;
}
// return the prev card index from the yop
int PrevCardIndex(int topIndex)
{
return topIndex == 0 ? 1 : 0;
}
// helper to get the scale based on the card index position relative to the top card
float GetScale(int index)
{
return (index == topCardIndex) ? 1.0f : BackCardScale;
}
}