Xamarin: PanGestureRecognizer inside Scrollview (Android) - android

I've trouble to get the following to work: I have a horizontal scrollview in which a grid is placed. I want the grid to receive pan gestures.
MY XAML:
<ScrollView Orientation="Horizontal" VerticalOptions="Center">
<Grid RowSpacing="3" VerticalOptions="Center" BackgroundColor="Red" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="party.png" Grid.Row="0" Grid.Column="0" WidthRequest="30" HeightRequest="30"></Image>
<Label Grid.Row="1" Grid.Column="0" HorizontalTextAlignment="Center" FontAttributes="Bold" Text="AUSGEHEN" TextColor="#646464" />
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sep.png" Grid.RowSpan="2" Grid.Column="1" WidthRequest="1" HeightRequest="10"></Image>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="contacts.png" Grid.Row="0" Grid.Column="2" WidthRequest="30" HeightRequest="30"></Image>
<Label VerticalTextAlignment="Start" HorizontalTextAlignment="Center" FontAttributes="Bold" Grid.Row="1" Grid.Column="2" Text="KONTAKTE" TextColor="#646464" />
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sep.png" Grid.RowSpan="2" Grid.Column="3" WidthRequest="1" HeightRequest="10"></Image>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sports.png" Grid.Row="0" Grid.Column="4" WidthRequest="30" HeightRequest="30"></Image>
<Label VerticalTextAlignment="Start" HorizontalTextAlignment="Center" FontAttributes="Bold" Grid.Row="1" Grid.Column="4" Text="SPORT" TextColor="#646464" />
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sep.png" Grid.RowSpan="2" Grid.Column="5" WidthRequest="1" HeightRequest="10"></Image>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="dating.png" Grid.Row="0" Grid.Column="6" WidthRequest="30" HeightRequest="30"></Image>
<Label VerticalTextAlignment="Start" HorizontalTextAlignment="Center" FontAttributes="Bold" Grid.Row="1" Grid.Column="6" Text="DATING" TextColor="#646464" />
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sep.png" Grid.RowSpan="2" Grid.Column="7" WidthRequest="1" HeightRequest="10"></Image>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="culture.png" Grid.Row="0" Grid.Column="8" WidthRequest="30" HeightRequest="30"></Image>
<Label VerticalTextAlignment="Start" HorizontalTextAlignment="Center" FontAttributes="Bold" Grid.Row="1" Grid.Column="8" Text="KULTUR" TextColor="#646464" />
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="sep.png" Grid.RowSpan="2" Grid.Column="9" WidthRequest="1" HeightRequest="10"></Image>
<Image Aspect="AspectFit" HorizontalOptions="Center" VerticalOptions="Center" Source="food.png" Grid.Row="0" Grid.Column="10" WidthRequest="30" HeightRequest="30"></Image>
<Label VerticalTextAlignment="Start" HorizontalTextAlignment="Center" FontAttributes="Bold" Grid.Row="1" Grid.Column="10" Text="ESSEN" TextColor="#646464" />
<Grid.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Grid.GestureRecognizers>
</Grid>
</ScrollView>
The problem is that the scrollview "swallows" the vertical swipe gestures. This means that "OnPanUpdated" is not called when the scrollview is horizontally scrolled. If I swipe up/down carefully without moving the scrollview horizontally, "OnPanUpdated" is called.
What I am basically trying to achieve is that if I swipe up or down on my grid inside the scrollview the "OnPunUpdated" should be called. If I swipe horizontally, I want the scrollview to normally scroll horizontally. I wouldn't care if both are called as long as "OnPunUpdated" is called as soon as I swipe over it.
I tried several custom renderers for Android but no luck.
I would be very grateful if someone found some time to help me solve my issue.
NOTE: Only tested on Android.

there's a horizontal scrollview and I want to swipe it up with a pan gesture. when a user swipes left or right the scrollview should be triggered and when up or down the slide
You could create a Pan Container and place your ScrollView inside this Container:
public class PanContainer : ContentView
{
double x, y;
public PanContainer()
{
// Set PanGestureRecognizer.TouchPoints to control the
// number of touch points needed to pan
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
}
void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
Content.TranslationX = Math.Max(Math.Min(0, x + e.TotalX), -Math.Abs(Content.Width - App.ScreenWidth));
Content.TranslationY = Math.Max(Math.Min(0, y + e.TotalY), -Math.Abs(Content.Height - App.ScreenHeight));
break;
case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}
}
In your .xaml:
<ContentPage.Content>
<local:PanContainer>
<ScrollView Orientation="Horizontal" VerticalOptions="Center">
...
</ScrollView>
</local:PanContainer>
</ContentPage.Content>
Effect.

Related

.Net MAUI: Different result for CollectionView/DataTemplate between Android and iOS

I wrote a simple CollectionView (.Net MAUI) with a DataTemplate and get completely different results when I deploy the code to either a Android device or a iOS device.
It would be really awesome if someone has a hint - this project drives me crazy since 4 months :D
I used the same code in Xamarin before without any issues.
EDIT:
I added the WidthRequest (and a margin) and now the style is as expected - thanks so far. (I also checked the text colors which are fine and I changed the TextColor of two lables to red - just for testing)
But I still have another issue. When the iOS App is opened, the part on the right hand side does not show up and it seems that the app is hung up. If I try to scroll, then I get a completlely random list of my items (some are missing) and everything is stuck.
<RefreshView x:DataType="local:ItemsViewModel" Command="{Binding LoadItemsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<CollectionView x:Name="ItemsListView" ItemsSource="{Binding Items}" SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10" x:DataType="model:Cryptocurrency">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding image}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" HeightRequest="50" WidthRequest="50" Margin="0,0,10,0" />
<Label Text="{Binding name}" Grid.Row="0" Grid.Column="1"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="Price" Grid.Row="0" Grid.Column="2"
LineBreakMode="NoWrap" HorizontalTextAlignment="End" Padding="0,0,20,0"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="x to ATH" Grid.Row="0" Grid.Column="3"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding market_cap_rank}" Grid.Row="1" Grid.Column="1"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<Label Text="{Binding current_price, StringFormat='{}{0:C}'}" Grid.Row="1" Grid.Column="2"
LineBreakMode="NoWrap" HorizontalTextAlignment="End" Padding="0,0,20,0"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<Label Text="{Binding RatioToATH}" Grid.Row="1" Grid.Column="3"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<Grid.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemsViewModel}}, Path=ItemTapped}"
CommandParameter="{Binding .}">
</TapGestureRecognizer>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
EDIT2:
It also works flawlessly on macOS (MacCatalyst)
You could set the constraint of Image(give it a width), please refer to the following code.
<Image Source="{Binding image}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" HeightRequest="50" WidthRequest="150" />
Yes! this is how MAUI work they will call out the native controls instead of control that is written in the middle layer like Flutter
They provide you OnPlatform so you can easily adjust the UI better
IsVisible={x:OnPlatform WinUI=true, Android=false, iOS=false, Tizen=false, MacCatalyst=false}

Xamarin - After image loads, content below the image disappears until device is rotated

Really at a loss here.
I'm loading an image into an announcement page:
if (!string.IsNullOrWhiteSpace(_announcementDetails.ImageUrl))
{
this.DefaultLogo.IsVisible = false;
this.AnnouncementImage.Source = _announcementDetails.ImageUrl;
this.ImageLogo.IsVisible = true;
}
<StackLayout Grid.Row="0" IsVisible="False" VerticalOptions="Center" Spacing="0" Padding="0,0,0,10" x:Name="ImageLogo">
<Image x:Name="AnnouncementImage"
VerticalOptions="Fill"
HorizontalOptions="Fill" ></Image>
</StackLayout>
<StackLayout Grid.Row="1" Padding="20,30,20,30" x:Name="MainContent">
<Label Margin="0,0,0,10" Text="Empty placeholder bug" x:Name="AnnouncementTitle" FontAttributes="Bold" HorizontalTextAlignment="Center" FontSize="18" />
<Label HorizontalTextAlignment="Center" Text="Empty placeholder body bug" x:Name="AnnouncementBody" Margin="0,0,0,10"/>
<Grid HorizontalOptions="CenterAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BackgroundColor="{StaticResource Primary}" BorderRadius="2" Text="{x:Static resources:AppResources.AboutLearnMore}" VerticalOptions="End" TextColor="White" x:Name="OpenWebsite"/>
<Button Grid.Column="1" BackgroundColor="{StaticResource Primary}" BorderRadius="2" Text="{x:Static resources:AppResources.OK}" VerticalOptions="End" TextColor="White" x:Name="Close"/>
</Grid>
</StackLayout>
After the image pops in, when the device is in landscape, any text below disappears. If you rotate the device to portrait and back, the text re-appears.
https://i.imgur.com/PBaOv4J.png
Rotate the device to portrait and back...
https://i.imgur.com/emfQKmo.png
Any help? No issues in portrait mode. Running on android.

FIXED: Xamarin Forms - How do i add a back button in the navigation bar?

I want to give the user the ability to go the previous page when using the app on any page. But I don't know how to go about it.
In the XAML code:
<Grid Grid.Row="0" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Image Margin="0,20,0,0"
HeightRequest="25"
HorizontalOptions="Center"
Source="back"
VerticalOptions="Center"
WidthRequest="25" />
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type vm:KlinectBaseViewModel}}, Path=BackView}" />
</Grid.GestureRecognizers>
</Grid>
CS:
public ICommand BackView => new Command(async () => await NavigationService.GoBack());
You could set the TitleView of ContentPage as you want . For example
<NavigationPage.TitleView>
<Grid Grid.Row="0" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="0.6*" />
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="0.1*"/>
</Grid.ColumnDefinitions>
<!--back to preview page-->
<ImageButton Margin="0,20,0,0"
Grid.Column="0"
HeightRequest="25"
HorizontalOptions="Center"
Source="back.png"
VerticalOptions="Center"
WidthRequest="25"
Command="{Binding xxx}"/>
<!--back to last page , if necerssary-->
<ImageButton Margin="0,20,0,0"
Grid.Column="1"
HeightRequest="25"
HorizontalOptions="Center"
Source="back.png"
VerticalOptions="Center"
WidthRequest="25"
Command="{Binding xxx}"/>
<!--Title Label-->
<Label Grid.Column="2" Text="Title" TextColor="White" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" />
</Grid>
</NavigationPage.TitleView>
For more details you could check https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical#displaying-views-in-the-navigation-bar .

Add an image to the background of a button in Xaml

I have 4 buttons arranged in a grid. I want each button to display an image exactly the size of that button, but am at a loss as to how to do this. I'm trying the following method right now, but am given the error "cannot set the content of button as it does not have a content property attribute" when I include the line.
I tried adding an image to the first button in the grid, but the image is far too large. I want the image to perfectly overlay the size of the button, regardless of the size of the phone I'm using.
This is my code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.ColumnSpan="2" Text="Welcome," HorizontalOptions="Center" FontSize="Large" TextColor="Aqua"/>
<Label Grid.Row="1" Grid.ColumnSpan="2" Text="User" HorizontalOptions="Center" FontSize="Large" TextColor="Aqua"/>
<Button Grid.Row="2" Grid.Column="0" Image="iris_light" Text="Student
Directory" TextColor="Aqua"/>
<Button Grid.Row="2" Grid.Column="1" Text="Executive
Directory" TextColor="Aqua"/>
<Button Grid.Row="3" Grid.Column="0" Text="Voting" TextColor="Aqua"/>
<Button Grid.Row="3" Grid.Column="1" Text="Map" TextColor="Aqua">
<Image Source="iris_light"/>
</Button>
</Grid>
If you want that (meaning that the Image property is not flexible enough for you), you must write a custom renderer.
Unlike Windows, iOS and Android are not based on the XAML so content of their controls is not editable that way as it is not supported by the underlying OS.
Solved my problem:
<Grid BackgroundColor="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.ColumnSpan="2" Text="Welcome," HorizontalOptions="Center" FontSize="Large" TextColor="Aqua"/>
<Label Grid.Row="1" Grid.ColumnSpan="2" Text="User" HorizontalOptions="Center" FontSize="Large" TextColor="Aqua"/>
<Image Grid.Row="2" Grid.Column="0" Source="iris_light"/>
<Button Grid.Row="2" Grid.Column="0" BackgroundColor="Transparent" Text="Student
Directory" TextColor="Aqua"/>
<Image Grid.Row="2" Grid.Column="1" Source="iris_light"/>
<Button Grid.Row="2" Grid.Column="1" BackgroundColor="Transparent" Text="Executive
Directory" TextColor="Aqua"/>
<Image Grid.Row="3" Grid.Column="0" Source="iris_light"/>
<Button Grid.Row="3" Grid.Column="0" BackgroundColor="Transparent" Text="Voting" TextColor="Aqua"/>
<Image Grid.Row="3" Grid.Column="1" Source="iris_light"/>
<Button Grid.Row="3" Grid.Column="1" BackgroundColor="Transparent" Text="Map" TextColor="Aqua"/>
</Grid>

Xamarin Button border issue

I'm trying to make an app using Xamarin.forms. The problem is that in Android version, button border are displayed, and I would like to remove them. I tried BorderColor="Transparent" but it didn't work.
Also, I've some problems with Text. In fact, I would like to have some padding between Icons and text (for example between F and Facebook). Is there a way to do that ? And how can I handle problems about the size of the text on, for example, iPhone 5 and "Fa...ook" ? I tried to put a smaller police but I guess there is a best solution ?
Here is my Xaml code:
<Grid Margin="0,20,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Text="Waka'Lokos" Margin="0,20,0,0" HorizontalOptions="Center" FontSize="22.5" TextColor="White" Grid.Row="0" Grid.Column="1"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="fb" Text="Facebook" Grid.Row="1" Grid.Column="0" Image="fb.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="contact" Text="Contact" Grid.Row="1" Grid.Column="1" Image="call.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="insta" Text="Insta" Grid.Row="1" Grid.Column="2" Image="insta.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="chants" Text="Chants" Grid.Row="2" Grid.Column="0" Image="micro.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="communaute" Text="Team" Grid.Row="2" Grid.Column="1" Image="team.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="youtube" Text="Youtube" Grid.Row="2" Grid.Column="2" Image="yt.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="partenaires" Text="Partner" Grid.Row="3" Grid.Column="0" Image="partner.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="plans" Text="Bons Plans" Grid.Row="3" Grid.Column="1" Image="money.png" TextColor="#FEF4CA"/>
<Button BackgroundColor="Transparent" FontSize="10" ContentLayout="Top" HorizontalOptions="Center" VerticalOptions="Center" x:Name="agenda" Text="Agenda" Grid.Row="3" Grid.Column="2" Image="agenda.png" TextColor="#FEF4CA"/>
</Grid>
For buttons that contain both text and images, I've always found it easiest to just use a stacklayout with an image and a label and then add a tap gesture to it. That way you have way more control over the positioning and scaling of the image as well as the text (and it takes care of your border problem). So something like:
XAML:
<StackLayout x:Name="buttonStack" WidthRequest="50">
<Image Source="fb.png" Aspect="AspectFit" HorizontalOptions="CenterAndExpand"/>
<Label Text="Facebook" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center"/>
</StackLayout>
XAML.CS
...
TapGestureRecognizer tap = new TapGestureRecognizer();
tap.Tapped += HandleClickEvent;
buttonStack.GestureRecognizers.Add(tap);
}
private void HandleClickEvent(object sender, EventArgs e)
{
//some code here
}
if you want to fake a button tap animation you can try this instead. You can tweak the 250 milliseconds to something else to get the feel right:
private async void HandleClickEvent(object sender, EventArgs e)
{
await buttonStack.FadeTo(0,250);
buttonStack.FadeTo(1,250);
//some code here
}

Categories

Resources