Xamarin Forms button with loading indicator - xamarin

I'm into Xamarin since about week and have a question about the possibility of making loading icon inside a button.
I would like to achieve something similiar to this:
https://jsfiddle.net/mr8fwtcv/
I was trying to achieve this effect with FontAwesome but had a problem animating it, so it would be not bad to use Activity Indicator in the solution.
My button is placed inside Stack Layout, and here is the code:
var loginButton = new Button
{
BackgroundColor = Color.FromHex("689F38"),
TextColor = Color.White,
HeightRequest = 46,
Text = "Log in",
FontAttributes = FontAttributes.Bold,
FontSize = 18,
Margin = margin
};
I was already looking for some plugins / solutions but couldn't find any.
Thanks in advance.

You will have to use a Layout to have more than one control in it. If you are not looking for CustomRenderers then what you could do is have a RelativeLayout and inside that both the Button and the Activity Indicator. You will also have to write a Converter for the button text that will set the text to string.Empty when the IsBusy is true.
For example:
<StackLayout>
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" />
<Button Text="{Binding ButtonText, Converter={StaticResource ButtonTextConverter}, ConverterParameter={Binding IsBusy}}" />
</StackLayout>
Also if you are planning to use this in multiple places you can create this as a custom control.
You can check out the custom control code here.
The full project is available here.

Related

Xamarin GIF animation

I just started developing Xamarin
But I encountered a problem
I have a login screen and I want to play gif there
but unfortunately no images are coming
Works well for png and jpeg files
my code is below;
Content = new StackLayout
{
Padding = new Thickness(10, 40, 10, 10),
Children = {
new Label { Text = "Versiyon:"+DependencyService.Get<INativeCall>().getApplicationVersion(), FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), TextColor = Color.White, HorizontalTextAlignment=TextAlignment.Center },
new Image { Source = "a.gif" },
username,
password,
btnLogin,
indicator,
infoServer,
infoUpdate
}
};
By default, when an animated GIF is loaded it will not be played. This is because the IsAnimationPlaying property, that controls whether an animated GIF is playing or stopped, has a default value of false. This property, of type bool, is backed by a BindableProperty object, which means that it can be the target of a data binding, and styled.
Therefore, when an animated GIF is loaded it will not be played until the IsAnimationPlaying property is set to true.
Modify code of Image as bellow :
new Image { Source = "a.jpg", IsAnimationPlaying = true}
For example , this is my gif file :
Xaml code :
<Label Text="Welcome to Xamarin.Forms!" HorizontalOptions="Center" VerticalOptions="Start" />
<Image Source="timg.gif" IsAnimationPlaying="True"/>
The effect :
Please use the nuget package - Xamarin.FFImageLoading.It processes GIFs quickly.
eg XAML -
<ffimageloading:SvgCachedImage Grid.Row="3" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Source="celebrate.gif" />

How to make ActivityIndicator overlay full screen?

I have a StackLayout and a number of elements inside (buttons, texts etc).
I want the ActivityIndicator to overlay the entire screen and make it not able to do anything to those elements.
I have put ActivityIndicator inside the StackLayout but wrapped it with AbsoluteLayout thinking that AbsoluteLayout can easitly overlap everything:
<StackLayout>
<AbsoluteLayout>
<ActivityIndicator ... />
</AbsoluteLayout>
<...other elements...>
</StackLayout>
Instead activity indicator is displayed at the top of the StackLayout and other elements are available for affecting. I'm new in Xamarin and layouts, what am I doing wrong? All samples in the Internet have single ActivityIndicator per page...
It is better said that an AbsoluteLayout's children can easily overlap each other. Just as a StackLayout lets you stack controls inside , vertically or horizontally, an AbsoluteLayout lets you position controls inside using absolute or proportional values, thus if two controls have the same absolute positioning set, they will overlap 100%.
Therefore, you want to wrap your StackLayout and another StackLayout that has your ActivityIndicator inside an AbsoluteLayout using proportional sizing, e.g:
<AbsoluteLayout>
<StackLayout
x:Name="mainLayout"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" >
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Do Something"
Clicked="DoSomethingBtn_Clicked" />
</StackLayout>
<StackLayout
x:Name="aiLayout"
IsVisible="False"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Gray" Opacity="0.5">
<ActivityIndicator
x:Name="ai"
IsRunning="False"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Color="Black"/>
</StackLayout>
</AbsoluteLayout>
The above sets the two StackLayouts to both take up the full size of the parent container of the AbsoluteLayout, which is presumably a Page. The StackLayout that has the indicator is initially hidden. IN the page code behind for the above example, I show the second StackLayout and start the activity indicator and show it for 2 seconds, and then hide it again:
private async void DoSomethingBtn_Clicked(object sender, EventArgs e)
{
ai.IsRunning = true;
aiLayout.IsVisible = true;
await Task.Delay(2000);
aiLayout.IsVisible = false;
ai.IsRunning = false;
}
Here is what it looks like:
And since the second StackLayout completely covers the first, none of the controls in the first StackLayout are clickable.
Might be worth going over the docs for the AbsoluteLayout to understand the AbsoluteLayout.LayoutBounds and AbsoluteLayout.LayoutFlags:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/absolute-layout
If you want to "overlap", you need to be outside of the StackLayout. A Grid is the most common control for this:
<Grid>
<StackLayout>
<...other elements...>
</StackLayout>
<ActivityIndicator ... />
</Grid>
Here's a hacked-up control for making things full-screen via the horribly-named RelativeLayout (tested in Android only)
[ContentProperty("ContentInner")]
public class FullScreenLayout : ContentView
{
public View ContentInner
{
get => ((RelativeLayout) Content).Children[0];
set
{
var display = DeviceDisplay.MainDisplayInfo;
var screenWidth = display.Width / display.Density;
var screenHeight = display.Height / display.Density;
var wrapper = new RelativeLayout();
wrapper.Children.Add(value, () => new Rectangle(0, 0, screenWidth, screenHeight));
Content = wrapper;
}
}
}
It can be used like this:
<controls:FullScreenLayout>
<!-- Anything you want fullscreen here -->
</controls:FullScreenLayout>
Unfortunately, if you use NavigationPage, this won't overlap the navigation bar. Every other solution currently on this page has the same issue. According to this question, it's not possible to solve this without using platform-specific customer renderers. Ugh.
If you don't mind the page being dimmed, you can use Rg.Plugins.Popup which implements the custom renderers needed.
I ended up solving my similar problem (dimming most of the screen) by implementing a custom renderer for the navigation page itself.

Custom navigation bar using Xamarin forms with prism broken

I'm using Prism Library for Xamarin.Forms.
And I'm going to create custom navigation bar via Control template. (Reason of creating custom navigation bar - I didn't find solution to make navigation bar transparent for display background image, also I will probably customize my navigation bar and add some controls on it).
<ControlTemplate x:Key="NavigationPageTemplate">
<AbsoluteLayout BackgroundColor="Transparent">
<Image AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Aspect="AspectFill"
Source="{TemplateBinding BackgroundImageEx}" />
<ContentView Padding="0,50,0,0"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<ContentPresenter />
</ContentView>
<!--Navigation bar started here -->
<ContentView AbsoluteLayout.LayoutBounds="0,0,1,AutoSize"
AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
BackgroundColor="Transparent">
<ContentView.Padding>
<OnPlatform x:TypeArguments="Thickness"
Android="10"
iOS="10, 20, 10, 0" />
</ContentView.Padding>
<controls:ImageButton Command="{TemplateBinding GoBackCommand}"
HeightRequest="30"
HorizontalOptions="StartAndExpand"
Source="ic_back.png"
WidthRequest="30">
</controls:ImageButton>
</ContentView>
</AbsoluteLayout>
</ControlTemplate>
And my problem is to process back button press with Prism Navigation.
I've tried to process click on MyApp.xaml.cs file.
private void Button_OnClicked(object sender, EventArgs e)
{
NavigationService.GoBackAsync();
}
And it seems to have different navigation stack because it shows after press my first page.
I had Navigation this way:
Navigate("FirstPage"); -> Navigate(MasterDetail/NavigationPage/ViewA) -> Navigate("ViewB")
ViewB - uses Control template.
When I click custom back button on ViewB NavigationService back me to FirstPage. It is incorrect for me. I should back to ViewA!
Another question Should first page be saved when we change App.MainPage?
See the discussion of described problem on https://github.com/PrismLibrary/Prism/issues/1262
To navigate back from ViewA to FirstPage you can intercept the back event and go back again if a variable is passed with a specific value from the ViewB page. Code Example:
Sender:
var navigationParams = new NavigationParameters();
navigationParams.Add("yourVariableName", "YourVariableValue");
_navigationService.GoBackAsync(navigationParams);
Receiver:
public void OnNavigatedTo(NavigationParameters parameters)
{
string myVar = null;
if (parameters.ContainsKey("yourVariableName"))
{
myVar = (string)parameters["yourVariableName"];
}
if(myVar=="YourVariableValue"){
NavigationService.GoBackAsync();
}
}
I don't understand your second question.

Xamarin Forms InputTransparent doesn't work on Android

Here is my xaml. InputTransparent is set to true, but Entry still catches the input.
<Grid>
<DatePicker
Date="{Binding FundraiserEndDate}" />
<Entry
Text="{Binding FundraiserEndDateText}"
TextColor="Gray"
FontSize="13"
HorizontalTextAlignment="Center"
InputTransparent="True" />
</Grid>
Found a couple of bug reports about this, and it seems more universal than just with an Entry and DatePicker in a Grid.
See:
https://bugzilla.xamarin.com/show_bug.cgi?id=50992
https://bugzilla.xamarin.com/show_bug.cgi?id=50362
I added the info from this question to the reports to let them know that it seems more universal than just the specific scenarios noted in the above bug reports.
I had the same prob (InputTransparent not working issue is still actual)
I wanted to avoid user inputs in a custom hydrated form object w/o having to handle disabled inputs rendering (example of a switch disabled which is grey even if toogled).
For that I simply used a grid as example with a stackLayout on top of it so user cannot interact with all my form (entry, switches and so) :
grid.Children.Add(form.MainLayout);
//Trick to avoid user inputs
grid.Children.Add(new StackLayout { BackgroundColor = Color.Transparent, VerticalOptions = LayoutOptions.FillAndExpand, HorizontalOptions = LayoutOptions.FillAndExpand });
scrollView.Content = grid;
Content = scrollView;

Arbitrary Drag and Drop for WP7

I'm trying to find a method of displaying a text block or that will allow me to arbitrarily drag and drop drop that control around the screen.
I've scoured google and here, but every drag and drop related question I find is around exchanging data, not just position.
Is anyone aware of something ready to go, or can you point me in the direction I should be looking?
You can do this by using behaviors:
<TextBlock Text="Hello!">
<i:Interaction.Behaviors>
<el:MouseDragElementBehavior ConstrainToParentBounds="True"/>
</i:Interaction.Behaviors>
</TextBlock>
You need to add a reference to Microsoft.Expression.Interactions in your solution, and the following namespace at the top of your XAML file:
xmlns:el="clr-namespace:Microsoft.Expression.Interactivity.Layout;assembly=Microsoft.Expression.Interactions"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
The xaml:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Height="30" Margin="125,132,0,0"
Name="textBlock1" Text="TextBlock"
Width="83" MouseMove="textBlock1_MouseMove" />
</Grid>
and the code behind:
private void textBlock1_MouseMove(object sender, MouseEventArgs e)
{
TextBlock realSender = (TextBlock)sender;
var theParent = (Grid)realSender.Parent;
var position = e.GetPosition(theParent);
realSender.Margin = new Thickness(
position.X - realSender.Width / 2,
position.Y - realSender.Height / 2, 0, 0);
}
The toolkit sample used to include an example of doing this.
Not sure if it's still in there though as it was based on the gesture support which has since been deprecated. If it's gone check the August 2011 version.

Resources