I have a page that is quite heavy and its loading for about 1-2 sec after click. During this time I see loading page header and old page content, it looks so irresponsive. All I want to achive is to display temporary Label with content like "Loading..." or activityindicator as long as new page is loading but I have no idea how to do this. What is the better way to achive this? Thanks in advance
Based on your comments, you just want to display Busy indicator while you are loading the Data from your Api. You didn't posted your UI but I hope you understand how to use the below:
<Grid>
<YOUR-UI>
.....
.........
</YOUR-UI>
<ActivityIndicator VerticalOptions="Center" IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}"/>
</Grid>
In your ViewModel, Add IsBusy Property as below:
private bool _isBusy;
public bool IsBusy
{
get{return _isBusy;}
set { _isBusy=value; RaisePropertyChanged(); }
}
Then when you are Calling the API to load your Data do something like:
public async void LoadDataFromApi()
{
IsBusy=true; //Show the Indicator
var response= await YourService.Method(); //this is where you calling your api
//do other stuffs if you need to do;
IsBusy=false; //Hide the Indicator
}
Let me know if you need anymore help.
Based on your comments on other answer - instead of ActivityIndicator - you could use a simple frame that covers all the layout and make it visible only when data are loading i.e. Binding IsVisible to IsBusy property. Then set IsBusy to true before doing the heavy load job and set back to false afterwards as shown in previous answer.
For instance, assuming your UI is based on a Grid layout (in this example 3 rows/2 columns):
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Some XAML for the grid content -->
<!-- Here, Frame covers all the possible space defined using RowSpan/ColumnSpan -->
<Frame Grid.RowSpan="3" Grid.ColumnSpan="2" IsVisible="{Binding IsBusy}" BackgroundColor="LightGray">
<Label VerticalOptions="Center" HorizontalOptions="Center" Text="Loading Samples..." />
</Frame>
</Grid>
-------------------------------------------------
EDIT based on OP comments:
Bases on the code you provided (better paste it in SO next time ;)), you could try this:
Add a grid layout and a frame to the xaml 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"
x:Class="MyApp.Namespace"
xmlns:tabView="clr-namespace:Syncfusion.XForms.TabView;assembly=Syncfusion.SfTabView.XForms"
xmlns:sfPopup="clr-namespace:Syncfusion.XForms.PopupLayout;assembly=Syncfusion.SfPopupLayout.XForms"
BackgroundColor="#d4d4d4">
<ContentPage.ToolbarItems>
<ToolbarItem Icon="search_white_90.png"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<Grid>
<tabView:SfTabView x:Name="ProductsTabView" VisibleHeaderCount="3" TabHeaderBackgroundColor="#A74B40" Items="{Binding}">
<tabView:SfTabView.SelectionIndicatorSettings>
<tabView:SelectionIndicatorSettings
Color="#fff" StrokeThickness="3"/>
</tabView:SfTabView.SelectionIndicatorSettings>
</tabView:SfTabView>
<Frame x:Name="theFrame" BackgroundColor="White">
<Label VerticalOptions="Center" HorizontalOptions="Center" Text="Loading Samples..." />
</Frame>
</Grid>
</ContentPage.Content>
</ContentPage>
ProductsTabView and theFrame will cover the same space on screen and frame will be available in code behind. Then you can show/hide theFrame before/afrer the hard work using IsVisible property:
public partial class ProviderPage : ContentPage
{
public ProviderPage()
{
InitializeComponent();
theFrame.IsVisible = true; // Show the Frame on top of tabView
ProductsTabView.Items = GetTabItemCollection();
theFrame.IsVisible = false; // Hide the Frame
}
...
As a side note, you don't use ViewModel at all. I strongly recommand you to check about what a ViewModel is and how to use them with MVVM pattern. It will make your life easier in the long run using Binding!
HIH & Happy coding!
Try https://github.com/aritchie/userdialogs, It's make you easily to implement loading
for example:
using (this.Dialogs.Loading("Loading text"))
{
//Do something i.e: await Task.Delay(3000);
}
OR
this.Dialogs.ShowLoading("Loading text");
//Do something i.e: await Task.Delay(3000);
this.Dialogs.HideLoading();
OR
https://github.com/aritchie/userdialogs/blob/master/src/Samples/Samples/ViewModels/ProgressViewModel.cs
I have a project for advanced page transitions in Xamarin.Forms that may help you. Try this:
Install this nuget: http://www.nuget.org/packages/Xamarin.Forms.Segues (it is currently only prerelease, so you'll need to check the box to see it)
Add this sample to your project: https://github.com/chkn/Xamarin.Forms.Segues/blob/master/Sample/Shared/Custom%20Segues/SpinnerSegue.cs
In the DoWork method of SpinnerSegue add the code to load the data.
In your code that navigates to the other page, replace Navigiation.PushAsync(new MyNewPage()) with new SpinnerSegue().ExecuteAsync(this, new MyNewPage())
Related
I am showing 2 different documents of the same length in a webview, however 1 document respects the heightrequest(kinda) and is scrollable, the other ignores it and does not scroll.
I am uncertain as to what is the cause of this.
EDIT: I have created a github with the (slightly edited) documents this way you guys can just clone it. To change the contract you can just change the htmlwebviewsource html https://github.com/MaoUyen/wtf
In my xaml i have the following code in my content
<VerticalStackLayout>
<HorizontalStackLayout Spacing="200" VerticalOptions="Start" HorizontalOptions="Center">
<Button Text="Cancel" Clicked="Cancel_Clicked" BackgroundColor="#8244E7" TextColor="White" FontSize="Large" WidthRequest="120" HorizontalOptions="Center"/>
<Button Text="Sign" Clicked="Sign_Clicked" BackgroundColor="#8244E7" TextColor="White" FontSize="Large" WidthRequest="120" HorizontalOptions="Center"/>
</HorizontalStackLayout>
<WebView x:Name="Pagina" HeightRequest="50000">
</WebView>
in my cs i have the following code
protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
string string1 = "long html doc i cant fit in here";
string string2 = "long htmldoc2 that i cant fit either";
Pagina.Source = new HtmlWebViewSource { Html = string1 };
}
private async void Sign_Clicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("page");
}
private async void Cancel_Clicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("page2");
}
can anyone help me make heads or tails of why it doesnt just show the content completely of both?
i tried to add some parameters to the webview like heightrequest, i tried to put in a scrollview (it stopped scrolling)
without anything else the webview seems to work correctly but i need to have buttons to be able to go to the signing page...
i just want to be able to see my 2 page htmldoc in my webview and then click on the sign button.
EDIT: I have created a github with the (slightly edited) documents this way you guys can just clone it. To change the contract you can just change the htmlwebviewsource html https://github.com/MaoUyen/wtf
thank you for your time
alright so i took a long break and tried something else this seems to work
i don't understand why a verticalstacklayout generates so much problems but the grid seems to resolve this issue
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<HorizontalStackLayout Spacing="200" VerticalOptions="Start" HorizontalOptions="Center">
<Button Text="Cancel" Clicked="Cancel_Clicked" BackgroundColor="#8244E7" TextColor="White" FontSize="Large" WidthRequest="120" HorizontalOptions="Center"/>
<Button Text="Sign" Clicked="Sign_Clicked" BackgroundColor="#8244E7" TextColor="White" FontSize="Large" WidthRequest="120" HorizontalOptions="Center"/>
</HorizontalStackLayout>
<WebView x:Name="Pagina" Grid.Row="1">
</WebView>
</Grid>
I have a ListView in my ContentPage. Inside ListView.ItemTemplate, I have user control. In user control, there are image buttons. On Click of ImageButton, I want to move another page but it's not working. The code is run without error but nothing happened. The same code of PushAsync is working from all other content pages but not in user control. Please help me in this regard to what should I do.
ListView Code inside ContentPage:
<ListView x:Name="lvPosts" HasUnevenRows="True" SeparatorVisibility="None"
IsVisible="False">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<controls:CardView/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
UserControl CardView:
<Frame 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:MyApp.General"
VerticalOptions="Start"
x:Class="MyApp.Controls.CardView">
<Frame.Content>
<Grid Padding="10" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Column="0"
Grid.ColumnSpan="4"
Grid.Row="0"
Text="{Binding Title}"
HorizontalOptions="FillAndExpand"
TextColor="#479774"
FontSize="Medium"
Style="{StaticResource DefaultFontStyle}"
Opacity="0.8">
</Label>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="0">
<ImageButton
x:Name="imgPdf"
Source="pdf.png"
Aspect="AspectFill"
Clicked="imgPdf_Clicked"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<ImageButton
x:Name="imgContent"
Source="document2.png"
Aspect="AspectFill"
Clicked="imgContent_Clicked"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="2">
<ImageButton
x:Name="imgSummary"
Source="document.png"
Aspect="AspectFill"
Clicked="imgSummary_Clicked"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="3">
<ImageButton
x:Name="imgVideo"
Source="video1.png"
Aspect="AspectFill"
Clicked="imgVideo_Clicked"/>
</StackLayout>
</Grid>
</Frame.Content>
</Frame>
And Code behind on ImageButton:
private async void imgVideo_Clicked(object sender, EventArgs e)
{
Post post = this.BindingContext as Post;
await Navigation.PushAsync(new WebViewPage(post));
}
The above answer isn't quite correct, and makes some assumptions. Navigation is available and can be used by any Xamarin Forms component that inherits NavigableElement and has a NavigationPage as an ancestor in its parental hierarchy. It's not limited to ContentPage by any means. Internal to Xamarin Forms, NavigableElements access their ancestral NavigationPage's Navigation stack via a series of internal NavigationProxy classes that get set and bound to their parent's NavigationProxy when each element's parent is set. Externally, we see these proxies as their interface type of INavigation, typically as the Navigation property of whatever element we're using.
ViewCell does not inherit NavigableElement (why, I'm not entirely sure, since it's parented to its container like any other component), and thus doesn't have a Navigation property. In your case, your ViewCell contains another View, which does inherit NavigableElement, but because its parent (ViewCell) isn't a NavigableElement, the chain of NavigationProxies is broken. Thus, you can try to make calls to Navigation on your CardView, but it's not hooked up to anything, and thus won't do anything.
The solution of directly accessing the Application's Navigation property (I assume the above poster meant Application.Current.MainPage.Navigation, as Application doesn't have a Navigation property itself) only works if your Application's MainPage is the only NavigationPage in your app. However, this isn't guaranteed to be the case; for example, a TabbedPage component could contain its own NavigationPages for each of its tabs, and accessing Application.Current.MainPage.Navigation will only get you the NavigationProxy for navigating the MainPage. ViewCells in a tabbed NavigationPage would be unable to navigate within their tab via this solution.
What you can do instead is something like this:
public MyViewCell : ViewCell
{
private INavigation Navigation { get; set; }
protected override void OnParentSet()
{
base.OnParentSet();
Navigation = (Parent as NavigableElement)?.Navigation;
}
}
Your ViewCell now has access to its parent's navigation stack, which you can do with as you please. You could pass it into your cell's child View, if you wanted, or just do your navigation here. Why ViewCell doesn't already do this under the hood, I don't fully understand.
Note: Depending on the CacheStrategy you set on your ListView (or whatever View component is using your ViewCell as a template), it's possible your custom ViewCell may be handed a null Parent from time to time, which would yield a null Navigation property. Usually this shouldn't be a problem, as a null Parent generally indicates the cell isn't actively being displayed, but it's worth keeping in mind in case your custom ViewCell could potentially try to access Navigation without user input via some automated business logic.
We could only invoke the method Navigation.PushAsync in a ContentPage . In your case , CardView is a subclass of a Frame , so it will never work .
The best solution is to invoke the method in Code Behind (ViewModel or ContentPage) . Since you had used Custom View . It would be better to handle the logic by using Data-binding .
If you do want to invoke the method in CardView, you could define a property in App and pass the current Navigation from ContentPage .
in App.xaml.cs
public INavigation navigation { get; set; }
in ContentPage
Note : You need to invoke the following lines in each ContentPage .
public xxxContentPage()
{
InitializeComponent();
var app = App.Current as App;
app.navigation = this.Navigation;
}
in CardView
var app = App.Current as App;
var navigation = app.navigation;
navigation.PushAsync(xxx);
I want to be able to resize animatedly the button from both sides for now I was able to do it from one side right to left.
Code ->
double Height = Button1.Height;
bool x = await Button1.LayoutTo(new Rectangle(new Point(Button1.X, Button1.Y), new Size(150, Height)), 1200,Easing.Linear);
Button ->
<StackLayout VerticalOptions="Center">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Button1" Grid.Row="0" Clicked="Button1_Clicked" BorderRadius="20" HorizontalOptions="CenterAndExpand" WidthRequest="1500" />
<!--<ActivityIndicator Grid.Row="1" IsRunning="true" ></ActivityIndicator>-->
</Grid>
</StackLayout>
(Before animation) ->
(After animation) ->
(I want) ->
If Resize is all you intend to do, use ScaleXTo with AnchorX set to 0.5(default).
Set AnchorX in XAMl:
<Button
x:Name="Button1"
Grid.Row="0"
Clicked="Button1_Clicked"
BorderRadius="20"
AnchorX="0.5"
HorizontalOptions="CenterAndExpand"
WidthRequest="1500" />
Use ScaleXTo in cs
void Button1_Clicked(System.Object sender, System.EventArgs e)
{
if (Button1.ScaleX < 1)
{
Button1.ScaleXTo(1);
}
else
{
Button1.ScaleXTo(0.5);
}
}
Give it a whirl and comment if further info is needed. Hope it helps.
After reading about LayoutTo method i found this Article
Quoting:
First what it is meant for. LayoutTo is actually used cause a child to
be layed out in a series of animated steps to a new location. This
sounds useful but there are a couple important things to note.
It was only intended to be used by Xamarin.Forms.Layout subclasses,
not externally.
It is stupidly exposed in the same way the other
animation methods are.
It will initially appear to do what you want,
but anything that triggers a relayout will cause your views position
to reset to where it started.
So i'm guessing that LayoutTo doesn't take take in acount the LayoutOptions for that element, so a better solution would be using other animation methods like TranslateTo or Animation
I'm new to Xamarin and would like to know where to start with this.
I have a need to make a Xamarin Forms custom Entry. That Entry needs an Icon and a border with rounded corners and a place holder label. This is a mock up of what is needed:"
The Behavior is that the Text "Input" will show the placeholder text until the user starts typing then the "Label" will appear with the text form the place holder. So the "Label" will be hidden until the user starts typing.
(with placeholder text)
So is it possible to build this Entry without a custom entry renderer? How would would put the label in a custom renderer if needed.
I would apprentice any help in getting started with this.
You could roll this yourself, but someone else has already done all the hard work for you. Take a look at the Xfx.Controls library. The XfxEntry looks to be exactly what you're looking for. All you need to do is:
Grab the nuget package, and install it in your main and platform projects.
Make sure that you initialize the library in your Android and iOS projects.
At the top of the xaml page it's going to be used in, import the library in with something like xmlns:xfx="clr-namespace:Xfx;assembly=Xfx.Controls".
Use the control, with something like:
<xfx:XfxEntry Placeholder="Email"
Text="{Binding Email}" />
After that you would need to create your own custom control and place the control in it. To get the rounded corners, you'll want your control to inherit from frame. This might look something like
<Frame x:Class="App1.MyCustomEntry"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xfx="clr-namespace:Xfx;assembly=Xfx.Controls"
BorderColor="LightBlue"
CornerRadius="15" HorizontalOptions="FillAndExpand">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="8*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="email.png" />
<xfx:XfxEntry Grid.Column="1" Placeholder="Email*" />
</Grid>
Notice the BorderColor and CornerRadius properties. Also, if you just add a new content view, you'll need to change the code behind file to inheriate from Frame: public partial class MyCustomEntry : Frame.
From there, it's a simple matter of inserting the control into your page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<local:MyCustomEntry VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>
This should give you something like:
You can tweak the layout options as needed.
So I was thinking of displaying a small statusbar during the debugging over my navigation page. Basically something like this:
<?xml version="1.0" encoding="utf-8" ?>
<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Drivr.Pages.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Text="Status of app" Grid.Row="0" />
<NavigationPage x:Name="MainNavigation" Grid.RowSpan="2" Grid.Row="0"></NavigationPage>
</Grid>
</NavigationPage>
Not exactly that of course, but you have the idea. So when there is like an error or I want to try something I could just display it there instead of outputting it to the console. Is it possible of doing something similar to this?
Yes, but not like this.
The NavigationPage is a construct that allows you to maintain a navigation stack - that is a set of pages where the top page is the currently visible one and clicking "Back" button removes (pops) the top page so the previous one becomes the top one.
You could also pop all the way to the root of the navigation stack so you can go "home". With several NavigationPages where a one is put (pushed) you could create a set of checkpoints so the user can quickly go back to a previous page that may be further than one step back.
In your case you could add to App.cs' constructor:
MainPage = new NavigationPage(new ContentPage{
Content = new Label { Text = "here we are" }
});
This sets up a root NavigationPage, so in your other pages you can do:
async void OnButtonClick(...){
await Navigation.PushAsync(new MyNextPage());
}
Normally the "Back" button will show up by itself, and now you'd have a simple 2-page app.