Xamarin.Forms: xaml. Add "click" animation to button - xaml

so I have this button:
<ImageButton
Aspect="AspectFit"
Grid.Column="1"
x:Name="btn_mymatches_mainmenu"
Source="btn_emptydummy.png" BackgroundColor="#00000000"/>
When the user clicks on it, there is no animation visible as if I just were to take the standard "Button". How can I add this little animation to also play on my image button? On Android, this is like a little grey "wave". Any animation would be awesome...
Thank you!

here is a starting point.
<ImageButton
Aspect="AspectFit"
Grid.Column="1"
x:Name="btn_mymatches_mainmenu"
Source="btn_emptydummy.png"
BackgroundColor="#00000000"
Clicked="btn_mymatches_mainmenu_Clicked" />
Then in your code behind :
public async void btn_mymatches_mainmenu_Clicked(object sender, EventArgs e)
{
await btn_mymatches_mainmenu.ScaleTo(0.75, 100);
await btn_mymatches_mainmenu.ScaleTo(1, 100);
}
There is also Fade animations, and a lot of other. Just take a look at the Xamarin Forms documentation.
If you want, you can create a class which inherit from ImageButton and perform the animation inside so all your controls will have the animation without any code.

You can create an ImageButton Renderer by setting a custom background to achieve that .
[assembly: ExportRenderer(typeof(Xamarin.Forms.ImageButton), typeof(CustomImageButtonRenderer))]
namespace AppImageXml.Droid
{
public class CustomImageButtonRenderer : ImageButtonRenderer
{
public CustomImageButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ImageButton> e)
{
base.OnElementChanged(e);
SetBackgroundResource(Resource.Drawable.ripple_bg);
// Set a background to be like a Ripple animation
}
}
}
ripple_bg.xml :
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/darker_gray">
<!--Ripple color-->
<item>
<shape android:shape="rectangle">
<!-- background color-->
<solid android:color="#android:color/white"/>
</shape>
</item>
</ripple>
Then the ImageButton used in Xaml can show the Ripple animation :
<ImageButton Aspect="AspectFit"
Grid.Row="1"
Grid.Column="0"
x:Name="btn_mymatches_mainmenu"
Source="heart.png"
BackgroundColor="#00000000" />
The effect :

Related

How do you find the newly focused element in .net-maui (used inside unfocused event handler)

Case:
I want to keep an element focused unless the element that tries to grab focus is a another Entry element.
I have this component (SearchBar.xaml)
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:localization="clr-namespace:POS365.Src.Extensions"
xmlns:fontAwesome="clr-namespace:FontAwesome"
x:Class="SomeApp.Src.Components.SearchBar">
<Grid ColumnDefinitions="32,*">
<Label Grid.Column="0" FontFamily="FAS" Text="{x:Static fontAwesome:FontAwesomeIcons.MagnifyingGlass}" FontSize="Large" Style="{DynamicResource HeaderBarSearchIconStyle}"/>
<Entry Grid.Column="1" x:Name="SearchField" MaxLength="20" Text="" HeightRequest="32" />
</Grid>
</ContentView>
and (SearchBar.xaml.cs)
using System.ComponentModel;
namespace SomeApp.Src.Components;
public partial class SearchBar : ContentView
{
public SearchBar()
{
InitializeComponent();
SearchField.Unfocused += OnLostFocus;
}
public void OnLostFocus(object sender, FocusEventArgs e)
{
// TODO: Find out when to focus this, probably based on what takes focus if possible
// FocusSearchField();
}
// Used by Loaded event elsewhere
public void FocusSearchField()
{
SearchField.Focus();
}
}
It seems that OnLostFocus only gets the element that lost focus and not the element that took focus.
How do I get the current focused element, so I can see which type of element it is?
You can determine this by iterating through root's child view and calling the view.IsFocused method.
var views = rootLayout.Children;
foreach (View view in views)
{
if (view != null && view.IsFocused)
{
System.Diagnostics.Debug.WriteLine("view focused is : " + view);
}
}
Note:
rootLayout is the parent view of current page.

WebView GestureRecognition not working in Xamarin forms

I have a webview When this webview is tapped I need to make visible of a button the problem Is Gesture recognition is not working
my Xaml
<customRenderer:CustomWebView Uri="{Binding SelectedJournal.Uri}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="CustomWebView" AbsoluteLayout.LayoutBounds="0,50,1,1" AbsoluteLayout.LayoutFlags="SizeProportional" >
<customRenderer:CustomWebView.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped2" NumberOfTapsRequired="1" ></TapGestureRecognizer>
</customRenderer:CustomWebView.GestureRecognizers>
</customRenderer:CustomWebView>
<customRenderer:NavigationImageButton ItemTapped="FullScreenOnTapped" Source="full.jpg" AbsoluteLayout.LayoutBounds="0.5,1,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional" HeightRequest="60" WidthRequest="60" x:Name="FullScreenBtn" IsVisible="False" >
In the code behind i called like this
private void TapGestureRecognizer_OnTapped2(object sender, EventArgs e)
{
FullScreenBtn.IsVisible = true;
}
This should work but this is not working
also my custom rendering web view class
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create<CustomWebView, string>(p => p.Uri, default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
How to Achive this
Instead of using the gesture recognizer on your webview, you can use the 'Focused' event of your view to display your button. You can do something like this:
var wb = new WebView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Source = "https://stackoverflow.com/questions/56320611/webview-gesturerecognition-not-working-in-xamarin-forms",
};
wb.Focused += (s, e) =>
{
//Handle your logic here!
wb.Unfocus();
};
Here, Unfocus() is used if you wish to implement your logic everytime the webview is tapped.
A WebView is used in my application to display formatted text. Tapping the text should open an editor to modify the text. The suggested Focused event works on Android but not iOS (as of iOS 15.0 simulator at least). I found the solution in the comments for https://bugzilla.xamarin.com/42/42596/bug.html#c4. Adding an empty label to the xaml as a transparent overlay of the WebView registers the tap event and enables the gesture recogniser.
<Grid HeightRequest="132">
<WebView Grid.Column="0" Grid.Row="0"
Source="{Binding FormattedDescription, Converter={tr:StringToWebViewSourceConverter}}"
HeightRequest="132"/>
<Label Grid.Column="0" Grid.Row="0" Text=""
HeightRequest="132" HorizontalOptions="Fill">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding EditDescriptionCommand}"/>
</Label.GestureRecognizers>
</Label>
</Grid>

Disable ScrollView in Xamarin Forms without disabling buttons

I have the following XAML. I want to target phones with a scrollview, and want scrolling disabled on a tablet.
<ScrollView InputTransparent="False" Orientation="Both" >
<ScrollView.IsEnabled>
<OnIdiom x:TypeArguments="x:Boolean">
<OnIdiom.Phone>True</OnIdiom.Phone>
<OnIdiom.Tablet>True</OnIdiom.Tablet>
</OnIdiom>
</ScrollView.IsEnabled>
<StackLayout VerticalOptions="FillAndExpand" BackgroundColor="White" >
<StackLayout.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>FillAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</StackLayout.HorizontalOptions>
<Grid BackgroundColor="White" HeightRequest="65" MinimumHeightRequest="65">
<Grid.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</Grid.HorizontalOptions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<WebView x:Name="webViewBtn1" HeightRequest="65" Grid.Column="0" Grid.ColumnSpan="1" VerticalOptions="FillAndExpand" BackgroundColor="White">
<WebView.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</WebView.HorizontalOptions>
<WebView.WidthRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Tablet>770</OnIdiom.Tablet>
<OnIdiom.Phone>300</OnIdiom.Phone>
</OnIdiom>
</WebView.WidthRequest>
</WebView>
<Button Grid.Column="0" Grid.ColumnSpan="1" x:Name="btn1" Clicked="btn1_Clicked" BackgroundColor="Transparent" TextColor="Transparent" BorderColor="White" />
</Grid>
</StackLayout>
</ScrollView>
the buttons no longer allow the user to click on them if I set ScrollView.IsEnabled the following way:
<OnIdiom.Tablet>False</OnIdiom.Tablet>
My assumption that using InputTransparent was not correct. Is there a way to make the buttons clickable inside a scroll view that has scrolling disabled?
I essentially am looking for something like Orientation=None, but that is not an option.
You need to write a CustomRenderer for disabling the scroll.
On iOS UIScrollView has a ScrollEnabled property
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
// IsScrollEnabled just a custom property
// handled it in OnPropertyChanged too
ScrollEnabled = Element.IsScrollEnabled;
}
Android it is a bit tricky, there is not direct property. We intercept the touch event and return without handling it.
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (Element.IsScrollEnabled)
{
return base.OnInterceptTouchEvent(ev);
}
else
{
return false;
}
}
public override bool OnTouchEvent(MotionEvent ev)
{
if (Element.IsScrollEnabled)
{
return base.OnTouchEvent(ev);
}
else
{
return false;
}
}
I ended up using this approach to disable vertical scrolling on an iPad, which is my target device. Not perfect for android 7 inch tablets, but oh well:
<ScrollView.Orientation>
<OnPlatform x:TypeArguments="ScrollOrientation">
<On Platform="iOS">
<OnIdiom x:TypeArguments="ScrollOrientation">
<OnIdiom.Phone>Both</OnIdiom.Phone>
<OnIdiom.Tablet>Horizontal</OnIdiom.Tablet>
</OnIdiom>
</On>
<On Platform="Android">
<OnIdiom x:TypeArguments="ScrollOrientation">
<OnIdiom.Phone>Both</OnIdiom.Phone>
<OnIdiom.Tablet>Both</OnIdiom.Tablet>
</OnIdiom>
</On>
<On Platform="UWP">Both</On>
</OnPlatform>
</ScrollView.Orientation>
In the latest version of Xamarin Forms, you can set the Orientation to Neither.
scrollV.Orientation = ScrollOrientation.Neither;
Cool and compact way to disable scrolling in Xamarin Forms without affecting it's children through ScrollEnabled extension method:
public static class ScrollViewEx
{
/// <summary>
/// Disables scrollview by modifying Scrolled Event and attaching itself to ScrollView's binding context
/// Scrolled event sends it back to the original x,y
/// </summary>
public class DisabledScrollClass : IDisposable
{
private double ScrollX;
private double ScrollY;
private object OldContext;
private ScrollView Parent;
public DisabledScrollClass(ScrollView parent)
{
Parent = parent;
ScrollX = parent.ScrollX;
ScrollY = parent.ScrollY;
OldContext = parent.BindingContext;
parent.Scrolled += Scrolled;
parent.BindingContext = this;
}
private void Scrolled(object sender, ScrolledEventArgs e)
{
(sender as ScrollView)?.ScrollToAsync(ScrollX, ScrollY, false);
}
public void Dispose()
{
Parent.Scrolled -= Scrolled;
Parent.BindingContext = OldContext;
}
}
public static ScrollView ScrollEnabled(this ScrollView scroll, bool isEnabled)
{
DisabledScrollClass binding = scroll.BindingContext as DisabledScrollClass;
if (isEnabled && binding != null)
binding.Dispose();
if (!isEnabled && binding == null)
_ = new DisabledScrollClass(scroll);
return scroll;
}
}

Is it possible to popUp a lottie animation View while an async Task is request

I have created a content view , and inside this content view I've insert a lottie animation :
I'm trying to make it a common animation view so I can use it to multiple async Task
LoadingAnimation.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:lottie="clr-namespace:Lottie.Forms;assembly=Lottie.Forms"
x:Class="Fit_Plans.Views.Common.LoadingAnimation">
<ContentView.Content>
<StackLayout>
<lottie:AnimationView
Grid.Column="0"
Margin="-20"
x:Name="LoadingAnimationView"
Animation="loading_animation.json"
AutoPlay="false"
HeightRequest="160"
WidthRequest="160"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"/>
</StackLayout>
</ContentView.Content>
</ContentView>
Now in my SomeView.Xaml.cs
async protected override void OnAppearing()
{
Product produits = new Product();
if(getListProduit ==null || getListProduit.Count<=0)
{
getListProduit = await produits.loadMenuAsync(api, siteUrl);
PopulateProductsLists(getListProduit);
}
base.OnAppearing();
}
You can notice that I have a await asynch task :
getListProduit = await produits.loadMenuAsync(api, siteUrl);
Is it possible to make my lottie animation pop-up the animation.jason , and when the task is done close the popup? Or , what would be the best way to do such thing?
If you want to show lottie animation in a popup, I encourage you to use the great Rg.Plugins.Popup library. You can get it from nuget and then create a popup page in which you should add your lottie animation (the same as you did above). This way you'll be able to reuse this popup animation page.
XAML of your popup page would look similar to this:
<pages:PopupPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
x:Class="MyProject.MyPopupPage">
<!--You can set an animation in the xaml file or in the csharp code behind-->
<pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="400"
DurationOut="300"
EasingIn="SinOut"
EasingOut="SinIn"
HasBackgroundAnimation="True"/>
</pages:PopupPage.Animation>
<!--You can use any elements here which are extended from Xamarin.Forms.View-->
<lottie:AnimationView
Grid.Column="0"
Margin="-20"
x:Name="LoadingAnimationView"
Animation="loading_animation.json"
AutoPlay="true"
HeightRequest="160"
WidthRequest="160"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"/>
</pages:PopupPage>
Here you can find the code to use your new popup page.

Xamarin forms button with no border issue

I try to render a list of clickable items in a view. I would like to add a button with an image and a white border (the first one). I discovered that the buttons in my StackLayout/ViewCell can't render a border.
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
x:Class="*.PlacesPage"
Title="TEST">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentPage.Content>
<Grid>
<ListView x:Name="lvPlaces" ItemsSource="{Binding Places}" SeparatorColor="Gray" SeparatorVisibility="Default" RowHeight="120" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal">
<Button HorizontalOptions="Center" VerticalOptions="Center" BorderWidth="3" BorderColor="White" Text="IMG"></Button>
<Button Text="{Binding Name}" BorderWidth="0" FontSize="20" BackgroundColor="Transparent" Clicked="OnButtonClickedPlace"></Button>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage.Content>
I'm using Xamarin.Forms 2.3, and I was also trying to create a button, with no border radius, a background color set to white, and a border color & width, and none of the above answers worked for me.
Actually I still had to set the BorderRadius to 1 (my width was 2), AND add another workaround that I just cannot understand :
In my Android project, I added a Custom renderer, for Button, with nothing in it. Absolutely nothing.
So the behavior of Xamarin forms, is different on Android when you use the Default renderer, and when you use a custom renderer that inherits from the default renderer, and yet with no line of code in it.
My Renderer:
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(GenericButtonRenderer))]
namespace Express.CustomRenderers
{
public class GenericButtonRenderer : Xamarin.Forms.Platform.Android.ButtonRenderer
{
}
}
There seems to be a issue in Xamarin.Forms where Button borders don't show on Android when the ButtonRadius is 0. (It doesn't appear that this issue is fixed as of Xamarin.Forms v2.0.0.6482.) It's not ideal since it will slightly change the look of the button, but you can work around it by setting BorderRadius = 1 for just Android, or all platforms, giving a slightly perceptible rounding to the corners.
Workaround (code)
// HACK: fixes a bug where border doesn't work without a radius.
yourButton.BorderRadius = Device.OnPlatform<int>(iOS: 0, Android: 1, WinPhone: 0);
Workaround (XAML)
<Button
x:Name="YourButton"
Text="Some Button Text"
TextColor="Black"
Clicked="OnClickedDiscover"
BackgroundColor="Aqua"
BorderColor="Red"
BorderWidth="1">
<Button.BorderRadius>
<!-- HACK: fixes a bug where border doesn't work without a radius. -->
<OnPlatform x:TypeArguments="x:Int32">
<OnPlatform.Android>1</OnPlatform.Android>
</OnPlatform>
</Button.BorderRadius>
</Button>
Are you using Android? If yes, then:
On Android this property will not have an effect unless
VisualElement.BackgroundColor is set to a non-default color.
In Xamarin.Forms 2.5.0, the patch has been reverted :
"Revert "Fix border on android buttons (#941)" (#1192)"
You have to use a custom renderer for now...
This bug has been fixed in the last version of Xamarin Forms 2.4.0 :
> 36031 - "Button border not drawn on Android without a BorderRadius" (PR)
in Android project go to MainActivity and change it to be inhereted
from
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
to
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
now you won't have issue to use the Border
<Button Text="test" TextColor="White"
BackgroundColor="#FFA733" BorderRadius="15"
BorderColor="White" BorderWidth="2" HorizontalOptions="FillAndExpand" />
Got the some problem. I did two things to solve it:
I don't set background color to the buttons for Android (only for iOS)
<Setter Property="BackgroundColor">
<OnPlatform x:TypeArguments="x:String">
<OnPlatform.iOS>Transparent</OnPlatform.iOS>
</OnPlatform>
</Setter>
Manually setting a background drawable to the buttons
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="2px" android:color="#ffffff" />
</shape>
I found this solution, don't know why is working but it works.
In PCL
namespace xxx.Renderers
{
public class WhiteButton : Button
{
public WhiteButton()
{
}
}
}
Then you have to make the render in android and DO NOTHING
[assembly: ExportRenderer(typeof(WhiteButton), typeof(WhiteButtonRenderer))]
namespace xxxx.Droid.Renderers
{
public class WhiteButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var newElement = e.NewElement as WhiteButton;
if (newElement != null)
{
}
}
}
}
}
Then you only have to call instantiate the button and do the border that you want
var myButton = new WhiteButton()
{
BackgroundColor = Color.Transparent,
TextColor = Color.White,
Text = "Desconectarse",
BorderRadius = 45/2,//rounded border Heightbutton/2
BorderWidth = 2,
BorderColor = Color.White
};
If nobody knows why is working please explain me , I have tried the same but with no render only using the class Button normally and if I do this I don't get the expected result.
in Android project create ButtonRenderer and paste code
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (Control != null)
{
var roundableShape = new GradientDrawable();
roundableShape.SetShape(ShapeType.Rectangle);
roundableShape.SetStroke((int) Element.BorderWidth,Element.BorderColor.ToAndroid());
roundableShape.SetColor(Element.BackgroundColor.ToAndroid());
roundableShape.SetCornerRadius(Element.BorderRadius * Resources.DisplayMetrics.Density);
Control.Background = roundableShape;
Control.TransformationMethod = null;
Control.Elevation = 0;
}
base.OnElementPropertyChanged(sender, e);
}