A page has ContentView as child, and it has animations from code behind on Tapped event of one of it's children.
When we navigate back away from this page, and then again into it,
The ContentView still has the last animation applied even though it was constructed anew.
We see both the view as it was with the last animation, and on top of it the view as it should be.
Do we have to dispose the ContentView, or do something on Page's OnDisappearing?
ContentView's code behind:
private async void OnPlaceTapped(object sender, EventArgs e)
{
await ExitFocusMode();
}
private async void OnDummyBorderTapped(object sender, EventArgs e)
{
await EnterFocusMode();
}
private async Task EnterFocusMode()
{
await Task.WhenAll(
DummySearchBox.TranslateTo(0, 0, 500),
DummySearchBox.ScaleXTo(1.2, 500),
SearchResultsGrid.FadeTo(1, 500),
DummySearchBox.FadeTo(0, 200)
);
SearchResultsGrid.InputTransparent = false;
DummySearchBox.InputTransparent = true;
SearchBox.Focus();
}
private async Task ExitFocusMode()
{
await Task.WhenAll(
DummySearchBox.FadeTo(1, 200),
SearchResultsGrid.FadeTo(0, 500),
DummySearchBox.TranslateTo(30, 24, 500),
DummySearchBox.ScaleXTo(1, 500)
);
SearchResultsGrid.InputTransparent = true;
DummySearchBox.InputTransparent = false;
DummySearchBox.Focus();
SearchBox.Unfocus();
}
ContentView's xaml(partial):
<border:SfBorder x:Name="DummySearchBox"
BorderWidth="0"
CornerRadius="10"
HasShadow="True"
InputTransparent="False"
ShadowColor="{StaticResource SilverSemiTransparent}"
HorizontalOptions="Fill"
VerticalOptions="Start"
TranslationX="30"
TranslationY="24"
Margin="0,0,60,0">
<border:SfBorder.GestureRecognizers>
<TapGestureRecognizer Tapped="OnDummyBorderTapped" />
<TapGestureRecognizer Command="{Binding OpenSearchCommand}" />
</border:SfBorder.GestureRecognizers>
</border:SfBorder/>
Edit 1:
The navigate back command execute, on the BaseViewModel:
public virtual void OnNavigateBackPressed()
{
NavigationService.PopAsync();
}
The navigate forward command execute from ViewModel A:
private async Task ContinueCommandExecute()
{
await IOC.Resolve<INavigationService>().NavigateToAsync<ViewModelB>();
}
Navigation service NavigateToViewModel implemenation:
Page page = CreatePage(viewModelType, parameter);
if (root)
{
if (Application.Current.MainPage is NavigationPage mainPage)
{
for (int i = 0; i < mainPage.Navigation.NavigationStack.Count - 1; i++)
{
var pageToNotify = mainPage.Navigation.NavigationStack[i];
if (pageToNotify.BindingContext is InfraViewModelBase viewModelBaseToDestory)
await viewModelBaseToDestory.OnDestroyAsync();
}
}
Application.Current.MainPage = new NavigationPage(page);
}
else
{
if (Application.Current.MainPage is NavigationPage navigationPage)
{
await navigationPage.PushAsync(page);
}
else
{
Application.Current.MainPage = new NavigationPage(page);
}
}
if (page.BindingContext is InfraViewModelBase viewModelBase)
await viewModelBase.InitializeAsync(parameter);
Related
Update:
It's playing well, but when finished playing it's not showing the play button. I have tried I couldn't get it well. Maybe I spiked something else were.
How can I show the play button when a player finished playing?
HomePage.xaml
<Button ImageSource="{Binding PlayIcon}"
Command="{Binding PlayCommand}"
HorizontalOptions="End"
VerticalOptions="End"/>
HomePage.xaml.cs
public HomePage()
{
InitializeComponent();
isPlaying = true;
}
private bool isPlaying;
public bool IsPlaying
{
get { return isPlaying; }
set
{
isPlaying = value;
OnPropertyChanged(nameof(PlayIcon));
}
}
public string PlayIcon { get => isPlaying ? "play.png" : "pause.png"; }
public ICommand PlayCommand => new Command(Play);
private async void Play()
{
if (isPlaying)
{
await CrossMediaManager.Current.Play("file:///android_asset/running.mp3");
IsPlaying = true; ;
}
else
{
await CrossMediaManager.Current.Pause();
IsPlaying = false; ;
}
}
Thank you for your contribution.
to play an asset, use this syntax
private async void PlayButtonClicked(object sender, EventArgs e)
{
// update the button's image
((Button)sender).ImageSource = ImageSource.FromFile("pause.png");
wait CrossMediaManager.Current.Play("file:///android_asset/long-test.mp3");
}
ref: https://github.com/Baseflow/XamarinMediaManager/issues/840
the docs contains a list of events supported by the control, including a MediaItemFinished event
Hi StackOverflow Team,
I am trying to run a background process in my App. This background process should update just Background image on one of the pages in the App every 15 seconds. So far, I tried to create a timer in the App OnStart() method and update the backgroundimage of the page in the BeginInvokeOnMainThread() method but with no success. Can anyone help me with this?
My Code -
{
private static Stopwatch stopWatch = new Stopwatch();
private const int defaultTimespan = 20;
private readonly HomePage homePage;
public App()
{
InitializeComponent();
try
{
MainPage = new MainPage();
homePage = new HomePage();
}
catch(Exception ex)
{
string str = ex.Message;
}
}
protected override void OnStart()
{
if (!stopWatch.IsRunning)
{
stopWatch.Start();
}
Device.StartTimer(new TimeSpan(0, 0, 10), () =>
{
// Logic for logging out if the device is inactive for a period of time.
if (stopWatch.IsRunning && stopWatch.Elapsed.Seconds >= defaultTimespan)
{
//prepare to perform your data pull here as we have hit the 1 minute mark
// Perform your long running operations here.
Device.BeginInvokeOnMainThread(() =>
{
// If you need to do anything with your UI, you need to wrap it in this.
// homePage.BackgroundImageSource = "goldengate.jpg";
homePage.ChangeBackgroundImage();
});
stopWatch.Restart();
}
// Always return true as to keep our device timer running.
return true;
});
}
protected override void OnSleep()
{
//stopWatch.Reset();
}
protected override void OnResume()
{
//stopWatch.Start();
}
//void ChangeHomePageImage()
//{
// Navigation.PushAsync(new HomePage(appBackground));
// Navigation.RemovePage(this);
//}
}
MainPage -
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:Excercise.Views"
x:Class="Excercise.MainPage" IsPresented="False">
<MasterDetailPage.Master>
<local:MenuPage x:Name="menuPage"></local:MenuPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:HomePage x:Name="homePage"></local:HomePage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
HomePage -
public partial class HomePage : ContentPage
{
private SQLiteAsyncConnection _connection;
public HomePage()
{
InitializeComponent();
// BindingContext = new HomePageViewModel();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
loadData("");
}
public HomePage(string BackgroundimgPath)
{
InitializeComponent();
// BindingContext = new HomePageViewModel();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
loadData(BackgroundimgPath);
}
public HomePage(string City, string LocationKey, string StateID)
{
InitializeComponent();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
// BindingContext = new HomePageViewModel();
try
{
// Method Calls
}
catch (Exception)
{
DisplayAlert("Error", "There was an error loading this page.", "OK");
}
}
protected override void OnAppearing()
{
this.Title = App.AppTitle;
this.firstStacklayout.Margin = new Thickness(0, (Application.Current.MainPage.Height * 0.25), 0, 0);
base.OnAppearing();
}
you are creating an instance of HomePage and trying to update it, but it is NOT the same instance that is being displayed in your MasterDetail
try something like this
var md = (MasterDetailPage)MainPage;
var nav = (NavigationPage)md.DetailPage;
var home = (HomePage)nav.CurrentPage;
home.ChangeBackgroundImage();
alternately, you could use MessagingCenter to send a message to HomePage requesting that it udpate
I am sorry to be asking what seems really obvious question but I've been unable to set the properties (e.g. background color) of the list view / contents when using the picker
The Picker properties style what you see before you expand the list to select contents, but I cannot see or find how to affect the latter
In this example from my XAML the collapsed view of the Picker is styled correctly, but when it opens the background is white / transparent
Sorry, I have looked in many links and just can't find the info
<Picker
VerticalOptions="CenterAndExpand"
Grid.Column="1"
Grid.Row="1"
Title="PICKER"
BackgroundColor="Transparent"
TitleColor="White"
FontSize="Medium"
Style="{StaticResource AlphabetPicker}"
x:Name="AlphabetPicker"
ItemsSource="{Binding Alphabet}"
SelectedIndexChanged="GetLetterSelected"
HorizontalOptions="Start">
You could use custom renderer.
I follow the code in the link: Customize the Xamarin.Forms Picker Popup List
MyPicker.cs
public class MyPicker : Xamarin.Forms.Picker
{
}
MyPickerRenderer.cs
[assembly: ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace XamarinDemo.Droid.Renderer
{
class MyPickerRenderer : PickerRenderer
{
IElementController ElementController => Element as IElementController;
public MyPickerRenderer(Context context) : base(context)
{
}
private AlertDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null || e.OldElement != null)
return;
Control.Click += Control_Click;
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click;
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Xamarin.Forms.Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
// set style here
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetBackgroundColor(Android.Graphics.Color.Yellow);
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetNegativeButton("Cancel ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Ok ", (s, a) =>
{
ElementController.SetValueFromRenderer(Xamarin.Forms.Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
}
Xaml:
<StackLayout>
<local:MyPicker x:Name="picker"
Title="Select a monkey"
TitleColor="Red">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</Picker.ItemsSource>
</local:MyPicker>
</StackLayout>
I have added a tap gesture recognizer to my StackLayout and I want to change the background color when it is tapped so that the user recognizes that the layout has been tapped
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Tapped="Preferences_Clicked"
NumberOfTapsRequired="1"/>
</StackLayout.GestureRecognizers>
Should I use animation for this?
UPDATE:
by changing background color, I mean an effect, something like a highlight, just like when you selsct an item in a ListView
Use this code for toggle color
int tapCount=0;
void Preferences_Clicked(object sender, EventArgs args)
{
tapCount++;
var stackLayout = (StackLayout)sender;
if (tapCount % 2 == 0) {
stackLayout.BackgroundColor = Color.Default;
} else {
stackLayout.BackgroundColor = Color.Accent;
}
}
I could find my answer, I simply added this bit of code to the Tapped method, and got what I wanted
public async void Preferences_Clicked(object sender, EventArgs e)
{
const int _animationTime = 50;
try
{
var layout = (StackLayout)sender;
await layout.FadeTo(0.5, _animationTime);
await layout.FadeTo(1, _animationTime);
}
catch (Exception ex)
{
}
}
I want to add a button which should be above the listView as same as how the whatsapp people have done and i want the same thing by using Xamarin Forms, i have tried doing with the xlab PopupLayout but i was unable to fix the position of the button as shown in the image the problem is with the different screen sizes and orientations..
So can any1 help me how to fix the location of the popup by using xlab popuplayout in xamarin forms and it should handle all the screen sizes and orientations.
Have a look at this great post by Alex Dunn. He implements a Floating Action Button (as it is called) on Android and iOS through Xamarin.Forms. It is basic, but you can extend on it yourself.
The gist is you create a control in your shared code, like this:
public partial class FloatingActionButton : Button
{
public static BindableProperty ButtonColorProperty = BindableProperty.Create(nameof(ButtonColor), typeof(Color), typeof(FloatingActionButton), Color.Accent);
public Color ButtonColor
{
get
{
return (Color)GetValue(ButtonColorProperty);
}
set
{
SetValue(ButtonColorProperty, value);
}
}
public FloatingActionButton()
{
InitializeComponent();
}
}
Now on Android implement a custom renderer, like this:
using FAB = Android.Support.Design.Widget.FloatingActionButton;
[assembly: ExportRenderer(typeof(SuaveControls.Views.FloatingActionButton), typeof(FloatingActionButtonRenderer))]
namespace SuaveControls.FloatingActionButton.Droid.Renderers
{
public class FloatingActionButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<SuaveControls.Views.FloatingActionButton, FAB>
{
protected override void OnElementChanged(ElementChangedEventArgs<SuaveControls.Views.FloatingActionButton> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
return;
var fab = new FAB(Context);
// set the bg
fab.BackgroundTintList = ColorStateList.ValueOf(Element.ButtonColor.ToAndroid());
// set the icon
var elementImage = Element.Image;
var imageFile = elementImage?.File;
if (imageFile != null)
{
fab.SetImageDrawable(Context.Resources.GetDrawable(imageFile));
}
fab.Click += Fab_Click;
SetNativeControl(fab);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
Control.BringToFront();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var fab = (FAB)Control;
if (e.PropertyName == nameof(Element.ButtonColor))
{
fab.BackgroundTintList = ColorStateList.ValueOf(Element.ButtonColor.ToAndroid());
}
if (e.PropertyName == nameof(Element.Image))
{
var elementImage = Element.Image;
var imageFile = elementImage?.File;
if (imageFile != null)
{
fab.SetImageDrawable(Context.Resources.GetDrawable(imageFile));
}
}
base.OnElementPropertyChanged(sender, e);
}
private void Fab_Click(object sender, EventArgs e)
{
// proxy the click to the element
((IButtonController)Element).SendClicked();
}
}
}
And on iOS, like this:
[assembly: ExportRenderer(typeof(SuaveControls.Views.FloatingActionButton), typeof(FloatingActionButtonRenderer))]
namespace SuaveControls.FloatingActionButton.iOS.Renderers
{
[Preserve]
public class FloatingActionButtonRenderer : ButtonRenderer
{
public static void InitRenderer()
{
}
public FloatingActionButtonRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
return;
// remove text from button and set the width/height/radius
Element.WidthRequest = 50;
Element.HeightRequest = 50;
Element.BorderRadius = 25;
Element.BorderWidth = 0;
Element.Text = null;
// set background
Control.BackgroundColor = ((SuaveControls.Views.FloatingActionButton)Element).ButtonColor.ToUIColor();
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
// add shadow
Layer.ShadowRadius = 2.0f;
Layer.ShadowColor = UIColor.Black.CGColor;
Layer.ShadowOffset = new CGSize(1, 1);
Layer.ShadowOpacity = 0.80f;
Layer.ShadowPath = UIBezierPath.FromOval(Layer.Bounds).CGPath;
Layer.MasksToBounds = false;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "ButtonColor")
{
Control.BackgroundColor = ((SuaveControls.Views.FloatingActionButton)Element).ButtonColor.ToUIColor();
}
}
}
}
You should now be able to use your button from XAML and code as you like.
Here is the XAML sample:
<?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:SuaveControls.FabExample" xmlns:controls="clr-namespace:SuaveControls.Views;assembly=SuaveControls.FloatingActionButton" x:Class="SuaveControls.FabExample.MainPage">
<StackLayout Margin="32">
<Label Text="This is a Floating Action Button!" VerticalOptions="Center" HorizontalOptions="Center"/>
<controls:FloatingActionButton x:Name="FAB" HorizontalOptions="CenterAndExpand" WidthRequest="50" HeightRequest="50" VerticalOptions="CenterAndExpand" Image="ic_add_white.png" ButtonColor="#03A9F4" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
Please note that all credits for this go out to Alex. All his code for this is up here. In the past I have also used the NControls code code to create something like this. And I'm sure there are more awesome libraries out there. However, have a good look at the support for libraries. If I'm not mistake the XLabs packages aren't supported anymore.