Xamarin forms how to keep label text after label animation - c#

I would like to figure out, how to keep my label text appear after label animation completion. My idea is that I have Label on top and Entry field behind it. Until there isn't any text in entry, my label is empty, but when I starting to type my label appear with animation over and over after each newly typed character. I already did that, but I wan't that it will appear with animation one time, and then keep showing my regular label without repeating animation. Because now my label shows with animation and do no keep, it disappears immediately.
Here is my xaml code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Project.MyPage">
<ContentPage.Content>
<StackLayout Padding="7,7,7,7" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Spacing="0">
<StackLayout BackgroundColor="White">
<Label x:Name="NameText" />
<Entry x:Name="Name" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
and here is my C# code with EventHandler: TextChange
public MyPage()
{
InitializeComponent();
Name.TextChanged += Name_TextChanged;
}
private async void Name_TextChanged(object sender, TextChangedEventArgs e)
{
NameText.Animate("nameAnimation", new Animation(v => NameText.Scale = v, 1, 2, Easing.SpringIn));
NameText.Text = "MyLabel";
}
How to my label appear and complete animation action only one time?
Thank you for answers or suggestions.

Detach your handler after the animation:
async void Name_TextChanged(object sender, TextChangedEventArgs e)
{
NameText.Animate("nameAnimation", new Animation(v => NameText.Scale = v, 1, 2, Easing.SpringIn));
NameText.Text = "MyLabel";
Name.TextChanged -= Name_TextChanged;
}

Related

Change focus on entry completed with behavior in Xamarin.Forms

I want to change focus from one entry to other entry.
At first, I changed with Focus() method for all entry. But I think it's not good code, because the more entry, the more difficult to edit.
So I found reference from here https://adenearnshaw.com/focus-next-element-on-enter/
First, create behavior
public class SetFocusOnEntryCompletedBehavior : Behavior
{
public static readonly BindableProperty TargetElementProperty
= BindableProperty.Create(nameof(TargetElement), typeof(VisualElement), typeof(SetFocusOnEntryCompletedBehavior));
public VisualElement TargetElement
{
get => (VisualElement)GetValue(TargetElementProperty);
set => SetValue(TargetElementProperty, value);
}
protected override void OnAttachedTo(BindableObject bindable)
{
base.OnAttachedTo(bindable);
if (bindable is Entry entry)
entry.Completed += Entry_Completed;
}
protected override void OnDetachingFrom(BindableObject bindable)
{
if (bindable is Entry entry)
entry.Completed -= Entry_Completed;
base.OnDetachingFrom(bindable);
}
private void Entry_Completed(object sender, EventArgs e)
{
TargetElement?.Focus();
}
}
Next, implement in xaml
<ContentPage x:Class="NextFormFieldSample.Forms.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:behaviors="clr-namespace:NextFormFieldSample.Forms.Behaviors">
<StackLayout Margin="20">
<Entry Placeholder="Field 1">
<Entry.Behaviors>
<behaviors:SetFocusOnEntryCompletedBehavior TargetElement="{x:Reference Entry2}" />
</Entry.Behaviors>
</Entry>
<Entry x:Name="Entry2" Placeholder="Field 2"/>
</StackLayout>
</ContentPage>
But!!!! I have to add one more thing for using this.
I have to receive result after entry completed event; If the result is true, focus changed. If not, focus stayed again.
I tried to make behaviors. But it's very difficult for me.
Are there anybody help me?
That is, with some result from database, if the result is true, focus
is changed. But if that is false, focus stay on same entry. Not only
just change the focus of entry, but watch the result from database.
Then you can add some logical judgment to the event Entry_Completed.
Please refer to the following code:
<ContentPage.Content>
<StackLayout Margin="20">
<Entry x:Name="Entry1"
Placeholder="Field 1"
Completed="Entry_Completed"
TabIndex="1">
</Entry>
<Entry x:Name="Entry2"
Placeholder="Field 2"
Completed="Entry_Completed"
TabIndex="2">
</Entry>
<Entry x:Name="Entry3"
Placeholder="Field 3"
Completed="Entry_Completed"
TabIndex="3">
</Entry>
<Entry x:Name="Entry4"
Placeholder="Field 4"
Completed="Entry_Completed"
TabIndex="4" />
</StackLayout>
</ContentPage.Content>
Event Entry_Completed in YourPage.xaml.cs
private void Entry_Completed(object sender, EventArgs e)
{
var entry = sender as Entry; // .. and check for null
// get result from database here
if (entry.Text.Length == 2) // here I used string's length(2) as the logical condition
{
var list = (entry.Parent as StackLayout).Children; //assumes a StackLayout
var index = list.IndexOf(entry); //
var nextIndex = (index + 1) >= list.Count ? 0 : index + 1; //first or next element?
var next = list.ElementAt(nextIndex);
next?.Focus();
}
}

Xamarin Forms - How to select a ListView item when its image is clicked?

I have a data template coded in xaml where the ListViewItem has an ImageButton:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="George.KeySave.FilesList"
xmlns:localImg="clr-namespace:George.Image"
Title="KeySave">
<ContentPage.Content>
<ListView x:Name="Flist" ItemSelected="Flist_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5,0,0,0">
<Label x:Name="SelFileName" Text="{Binding fname}" FontSize="Medium" TextColor="Blue" VerticalOptions="Center"/>
<ImageButton HeightRequest="33" WidthRequest="33" Source="{localImg:Emb ResId=George.Image.deer.png}"
x:Name="delete" Clicked="delete_Clicked" HorizontalOptions="EndAndExpand"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
But it fails under these conditions. Suppose I click the name of the second item so that the second item is selected. The problem is if I now click the ImageButton of the first item, the wrong file will be deleted because the second item is still selected.
This code shows how I handle the ImageButton.Click and the ListView.ItemSelected events.
public partial class FilesList : ContentPage
{
private void delete_Clicked(object sender, EventArgs e)
{
DisplayAlert("delete file", $"{TdelFile.fname}", "ok");
}
listdatas TdelFile;
private void Flist_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var delFile = e.SelectedItem as listdatas;
TdelFile = delFile;
}
}
The problem: The incorrect file pops up when I click the ImageButton of the first item while the second item is selected.
As your code is written now, you would look at the sender argument of your ImageButton.Click handler which will be the ImageButton. The BindingContext of the ImageButton will be the item itself and you can set FList.SelectedItem from that. Then, the user is given a confirmation prompt before proceeding (or not) with the file deletion.
private async void delete_Clicked(object sender, EventArgs e)
{
if (sender is ImageButton imageButton)
{
Flist.SelectedItem = imageButton.BindingContext;
var fileName = ((DataModel)Flist.SelectedItem).fname;
if (await App.Current.MainPage.DisplayAlert(
"delete file",
fileName, accept: "OK",
cancel: "CANCEL"))
{
System.Diagnostics.Debug.WriteLine($"DELETED {fileName}");
}
else
{
System.Diagnostics.Debug.WriteLine("Cancelled!");
}
}
}

Call a stack layout from another page

I'm creating a Xamarin.Forms app using c#.
There is a Button in a Page and i want to add a new Label in StackLayout that is in the Main Page when the Button is clicked.
I tried to set the FieldModifier property of the StackLayout public in the XAML file, but it didn't work...
This is the layout code (i want to add the label into MainStackLayout) and the cs method of the Button click:
<ContentPage.Content>
<ScrollView>
<StackLayout BackgroundColor="white">
<StackLayout Orientation="Horizontal" x:Name="MainStackLayout" x:FieldModifier="public" >
</StackLayout>
<Button
Text="Add Counter"
BackgroundColor="darkgreen"
HorizontalOptions="FillAndExpand"
CornerRadius="0"
HeightRequest="80"
TextColor="white"
FontAttributes="Bold"
x:Name="AddCounter_btn"
Clicked="AddCounter_btn_Clicked"
>
</Button>
</StackLayout>
</ScrollView>
</ContentPage.Content>
private void StartCount_btn_Clicked(object sender,EventArgs e)
{
Label NCounterName =new Label();
NCounterName.Text = counter_txt.Text.ToString();
Label NCounterNumber = new Label();
NCounterNumber.Text = "0000";`enter code here`
}
Let's say you have a button in Page1 which is StartCount_btn, and when you click this button, you want to add some labels to MainStackLayout in Page2.
In Page1, send a addLabelNotification when you click the StartCount_btn button:
private void StartCount_btn_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send<Object>(this, "addLabelNotification");
}
In Page2, Subscribe to the message and add labels when receive the message:
public partial class Page2 : ContentPage
{
public Page2()
{
InitializeComponent();
MessagingCenter.Subscribe<Object>(this, "addLabelNotification", (sender) =>
{
// Do something whenever the "addLabelNotification" message is received
Label NCounterName = new Label();
NCounterName.Text = "counter_txt";
Label NCounterNumber = new Label();
NCounterNumber.Text = "0000";
MainStackLayout.Children.Add(NCounterName);
MainStackLayout.Children.Add(NCounterNumber);
});
}
}
Refer: messaging-center
I wrote this code here, could not check it but it will work. Your button gives you enough information to reach any View. You just use parent-child controls.
private void StartCount_btn_Clicked(object sender,EventArgs e)
{
if(sender is Button myButton)
{
if(myButton.Parent is StackLayout myStackLayout)
{
Label NCounterName =new Label();
//set your label's text
myStackLayout.Add.Children(NCounterName);
}
}
}

Xamarin Forms PanGesture within a View

I'm having a problem with the PanGestuer behaviour in Xamarin Form. This is my page:
<?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:local="clr-namespace:Xamarin_Test"
x:Class="Xamarin_Test.MainPage">
<StackLayout x:Name="parentFrame" Margin="100" BackgroundColor="Gray">
<AbsoluteLayout x:Name="parentLayout" BackgroundColor="Red">
<local:PanContainer x:Name="parentContainer" BackgroundColor="Yellow">
<Image x:Name="panImage" Source="MonoMonkey.jpg"
WidthRequest="{Binding Path=Width, Source={x:Reference Name=parentFrame}}"
HeightRequest="{Binding Path=Height, Source={x:Reference Name=parentFrame}}"/>
</local:PanContainer>
</AbsoluteLayout>
</StackLayout>
</ContentPage>
PanContainer.cs
public class PanContainer : ContentView
{
double x, y;
public PanContainer()
{
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;
}
}
}
The image loads with correct size (within the StackLayout borders, for better testing I colorized the elements). The panning works to the left and to the upper way of the image, but overlays the white area. How can I handle panning, so that the moved image is only visible within my panContainer?

Xamarin Forms PCL - DatePicker doesn't open correctly on UWP

I don't get something, I would like, from a button, open my DatePicker. So I coded that:
private void OnDateClicked(object sender, EventArgs ea)
{
Debug.WriteLine("PLOPPP");
//DatePickerControl.IsVisible = true;
//DatePickerControl.Focus();
Device.BeginInvokeOnMainThread(() => {
DatePickerControl.Focus();
});
}
Once the button got clicked/touched by the user, nothing happens.. Why? I'm just searching to open the Date Selector but I can't figure out why it doesn't work ><
The XAML part is looking like that:
<AbsoluteLayout x:Name="LayoutTools"
AbsoluteLayout.LayoutBounds="0.5, 0.05, 0.9, 0.075"
AbsoluteLayout.LayoutFlags="All">
<!-- DATE -->
<!--<control:SquareLayout x:Name="DateButton" BackgroundColor="{x:StaticResource NL_BlueNight}" ScalingBase="Height"
AbsoluteLayout.LayoutBounds="0, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All"/>-->
<AbsoluteLayout x:Name="DateButton" BackgroundColor="{x:StaticResource NL_BlueNight}" Opacity="0.8"
AbsoluteLayout.LayoutBounds="0, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All">
<control:CustomLabel Text="{Binding DaySelected}" FontFamily="{extension:FontFamily Roboto_Light}" FontSize="20" TextColor="Gray"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All"/>
<Button Clicked="OnDateClicked" BackgroundColor="Transparent" BorderColor="Transparent"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All"/>
</AbsoluteLayout>
</AbsoluteLayout>
<!-- <control:CustomDatePicker.../> -->
So here, the CustomLabel is bind to an object which give the number of the current day. Over it, a Button which call the private void OnDateClicked(object sender, EventArgs ea) method.
Then, in this method, I'm trying to open the DatePicker I have put in the XAML part:
<!-- code above -->
<control:CustomDatePicker x:Name="DatePickerControl" Format="dd-MM-yyyy" Date="{Binding CurrentDate}" IsVisible="False"
MinimumDate="{Binding CurrentDate}"
FontFamily="{extension:FontFamily Roboto_Light}" FontSize="20" TextColor="White"
XAlign="Center" HasBorder="false" BackgroundColor="Transparent"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All"/>
The idea is just to open the selector, then I save the all date but only display the day of this selected date, in the Label.
Thank in advance !
It's known issue. Maybe it would be fixed in the future. I could suggest my workaround with using renderer for UWP:
[assembly: ExportRenderer(typeof(DatePickerRenderer), typeof(SomeDatePickerRenderer))]
namespace SuperForms.UWP.Renderers
{
public class SomeDatePickerRenderer : DatePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
// TODO: Focus() doesn't open date picker popup on UWP, it's known issue
// on Xamarin.Forms and should be fixed in 2.5. Had to open it manually.
var flyout = new DatePickerFlyout() { Placement = FlyoutPlacementMode.Top };
flyout.DatePicked += (s, args) =>
{
Control.Date = args.NewDate;
};
FlyoutBase.SetAttachedFlyout(Control, flyout);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
{
if (Element.IsFocused)
{
FlyoutBase.ShowAttachedFlyout(Control);
}
}
}
}
}
Now it's being shown each time when IsFocus change to true, so you need to set up it due to your requirements.

Categories

Resources