I have an app in which I have a lot of references and the load time was not acceptable to me. I have removed the splash screen image and created an animated loading screen by having a separate project with no reference to the main application which then navigates to the first page of the rest of the app. It does start up fast now but it's a little lacking still.
I would like to do another animation right before the load screen goes away. The only way I can think of to do this is to actually preload the assemblies needed for the navigation to the next page, do an animation, and then navigate.
I have tried
OnNavigatedFrom but the animation doesn't have time to run since the page will be replaced by the new page very quickly from that point.
OnNavigatingFrom is no help either as it is called as soon as I call NavigationService.Navigate();
Searching the web and Stack Overflow :)
I also considered faking it a bit by having the next page show a duplicate of the load screen and do the last animation there, but it can't match the current state of the load screen animation and is harder to maintain
Thanks for any ideas!
If you want to force the loading of an assembly, just reference a type from this assembly.
For instance, something like Console.WriteLine(typeof(YourAssembly.SomeType)); will force the loading of YourAssembly.
Now for your problem, maybe you can use usercontrols? Put the content of your main page in a user control. Display the loading page, create the usercontrol in the background, let the animation play, then when the animation is done playing replace the page's content with the usercontrol.
It turns out that you can preload by just creating a new instance of the page you are going to navigate to. Unfortunately that has to be done on the UI thread which can cause animation slowdown, at least in my experience.
Here is a sample of how to do an animation, then preload, then do another animation before navigating. :
public partial class LoadScreen : PhoneApplicationPage
{
public LoadScreen()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var sb = new Storyboard();
// create your animation here
sb.Completed += (sender, args) => PreLoad();
sb.Begin();
}
private void PreLoad()
{
// this is the part that actually takes time and causes things to get loaded
// you may need it in a try/catch block depending on what is in your constructor
var page = new PageToNavigateTo();
// now create an animation at the end of which we navigate away
var sbOut = new Storyboard();
// create your animation here
sbOut.Completed += (sender, args) => NavigateToNextScreen();
sbOut.Begin();
}
private void NavigateToNextScreen()
{
// navigate here
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// remove the loading screen from the backstack so the user doesn't see it again when hitting the back button
NavigationService.RemoveBackEntry();
}
}
Related
I have an application that I added a launch page to in the iOS and Android code. However when the app starts there is still quite a long delay while it fetches data. At this time there's a blank screen where I assume the app is still setting up the constructor.
I am trying to have an in-between page where that appears that loads the data. Not sure if this is the best way to do this but so far it's all that I have.
Here's the code that I have so far:
public App()
{
InitializeComponent;
MainPage = new NavigationPage(new Test.LoginPage())
{
};
}
My Test.LoginPage is a simple empty Xaml page with this C# back end:
public partial class LoginPage : ContentPage
{
public LoginPage()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
await LongRunningTask();
App.MainPage = new AppShell(); // I want to start a shell app
}
}
public partial class AppShell : Shell
{
public AppShell()
{
Routing.RegisterRoute("HomeTab/QHPage", typeof(QHPage));
// etc
But the code has issues in that first of all I am not sure I am doing it correctly and secondly it says an object reference is required for App.MainPage.
Can anyone point me in the right direction and suggest how I could display this intermediate page and then display the real app pages?
Note that at some point I would also like to have a button on the login page that when clicked takes me to the app. But at this time I just want to get even the most simple version working so I am looking for some advice with that.
The easy way is to set the AppShell as MainPage. The code below works for me.
Application.Current.MainPage = new AppShell();
I've got this code for creating a WebView:
public class SessionsActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.discover);
//declare webview and tell our code where to find the XAML resource
WebView discoverWebView = FindViewById<WebView>(Resource.Id.webViewDiscover);
//set the webview client
discoverWebView.SetWebViewClient(new WebViewClient());
//load the subscription url
discoverWebView.LoadUrl("https://www.bitchute.com/");
//enable javascript in our webview
discoverWebView.Settings.JavaScriptEnabled = true;
//zoom control on? This should perhaps be disabled for consistency?
//we will leave it on for now
discoverWebView.Settings.BuiltInZoomControls = true;
discoverWebView.Settings.SetSupportZoom(true);
//scrollbarsdisabled
// subWebView.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
discoverWebView.ScrollbarFadingEnabled = false;
}
}
but when I click on links inside my app, the page loads at the same spot as the last page was, which makes navigation very difficult, because mobile pages are supposed to load from the top, not from the middle. So basically, if I am in my subscriptions feed, and then I scroll down to find more content, I click on a user, and their video page loads videos from weeks ago, because it loaded with the same view elevation as the root page.
The site I'm using WebView with is also designed for mobile users, if that matters. The weird thing is that this used to not happen until recently... don't know what changed. How can I have the WebView load at top of page on each click?
I'm using TabHost for this .. here's my full code for context
https://github.com/hexag0d/BitChute_Mobile_Android_a2/blob/2.68/MainActivity.cs
thanks in advance!
I have 2 pages in my Xamarin Forms app. My first page has 4 icons in the toolbar. My second page is a login page and has a tick and a cross in the toolbar.
I can't get the login page to show any icons unless I make it a navigation page. I also have to clear ToolBarItems on the first page before calling PushAsync() otherwise it complains there are too many toolbar items.
If I call PopAsync() on the login page it does not return to the first page. I'm guessing this is due to their being 2 navigation pages. I also tried PopToRootAsync().The back button works however.
My question is - how do I show different toolbar icons on 2 different pages in a way that allows navigation to work?
I'm testing this on Windows Phone 8.0
Here is the code calling the login page:
private async void ShowLoginPage()
{
ToolbarItems.Clear();
var page = new NavigationPage(new LoginPage());
await Navigation.PushAsync(page);
}
and here is the code to return to the first page:
private void Cancel()
{
Navigation.PopToRootAsync();
}
I'm running Xamarin.Forms v1.2.2.6243
One thing you could try is to keep your Login Page inside of a NavigationPage, and then instead of running PopAsync() within the Login Page after they have logged in successfully, simply replace the MainPage with your old Navigation page:
In your App class:
public NavigationPage AppNavPage = new NavigationPage(new FirstPage());
public App() {
MainPage = AppNavPage;
}
In your FirstPage:
private async void ShowLoginPage() {
ToolbarItems.Clear();
var page = new NavigationPage(new LoginPage());
await Navigation.PushAsync(page);
}
In Login Page:
private async void OnCreateClicked(object sender, EventArgs e) {
bool loginInfoIsGood = CheckLoginInfo(); //Check their login info
if(loginInfoIsGood) {
Application.Current.MainPage = App.AppNavPage;
}
}
Otherwise, I have also done a custom renderer for the NavigationRenderer on iOS to insert toolbar items onto the right side of the Navigation Bar and have overridden some Menu related stuff on Android to change the icon text/colors.
One option that you have, and one that I implemented in my own app, is a custom renderer that removes the navigation header from the app and then you could build your own custom header. With this approach, you do lose some of the native feel of the app, and you have to implement much of the transitional functionality your self. However, it gives you alot more control over the look.
CustomRenderer that removes the navigationBar:
//add using statements
// add all view here that need this custom header, might be able to build a
//base page that others inherit from, so that this will work on all pages.
[assembly: ExportRenderer(typeof(yourView), typeof(HeaderRenderer))]
class HeaderRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.NavigationController.SetNavigationBarHidden(true, true);
}
}
After this you can build a header view that can be placed on the top of every page (I am using xaml) so I don't know if it is relevant in you application.
Edit: You might need to change this renderer for differnt page types.
In a windows phone app,a page is navigated to another page and on pressing back button, goes back to previous page.Now in previous page the previous data has to be displayed. But its not displaying immediately and takes some time to load. How to solve this issue?
Overall the question is how to maintain the content of page(containing dynamic data) displayed in back navigation?
Use PhoneApplicationService class to keep the data while you navigate between the pages. Here is some samples. Actually, it's very easy:
protected override void OnNavigatedFrom(NavigationEventArgs args)
{
if (ContentPanel.Background is SolidColorBrush)
{
Color clr = (ContentPanel.Background as SolidColorBrush).Color;
if (args.Content is MainPage) (args.Content as MainPage).ReturnedColor = clr;
// save color
PhoneApplicationService.Current.State["Color"] = clr;
}
base.OnNavigatedFrom(args);
}
protected override void OnNavigatedTo(NavigationEventArgs args)
{
// restore color
if (PhoneApplicationService.Current.State.ContainsKey("Color"))
{
Color clr = (Color)PhoneApplicationService.Current.State["Color"];
ContentPanel.Background = new SolidColorBrush(clr);
}
base.OnNavigatedTo(args);
}
How to preserve and restore page state for Windows Phone
You can use single ton object of View Model to store data in a page provided all the controls are bind to a property in View Model.
Then if you do not clear the values of the controls when navigating away from the page, the data will be displayed in the page when you navigate back to that screen provided all the controls
I taken two Images & added event (MouseButtonDown) for them.
When first image handles event to open Gallery. Second image handles events for open camera.
When user has choosed his image from the gallery, I want to navigate to next page. Its navigates. But before completing navigation process, it displays MainPage & then moves toward next page. I didnt want to display the MainPage once user chooses the image from the gallery.
Plz help.
Thanks in advance.
public partial class MainPage : PhoneApplicationPage
{
PhotoChooserTask objPhotoChooser;
CameraCaptureTask cameraCaptureTask;
// Constructor
public MainPage()
{
InitializeComponent();
objPhotoChooser = new PhotoChooserTask();
objPhotoChooser.Completed += new EventHandler<PhotoResult>(objPhotoChooser_Completed);
cameraCaptureTask = new CameraCaptureTask();
cameraCaptureTask.Completed += new EventHandler<PhotoResult>(objCameraCapture_Completed);
}
void objPhotoChooser_Completed(object sender, PhotoResult e)
{
if (e != null && e.TaskResult == TaskResult.OK)
{
//Take JPEG stream and decode into a WriteableBitmap object
App.CapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
//Delay navigation until the first navigated event
NavigationService.Navigated += new NavigatedEventHandler(navigateCompleted);
}
}
void navigateCompleted(object sender, EventArgs e)
{
//Do the delayed navigation from the main page
this.NavigationService.Navigate(new Uri("/ImageViewer.xaml", UriKind.RelativeOrAbsolute));
NavigationService.Navigated -= new NavigatedEventHandler(navigateCompleted);
}
void objCameraCapture_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
//Take JPEG stream and decode into a WriteableBitmap object
App.CapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
//Delay navigation until the first navigated event
NavigationService.Navigated += new NavigatedEventHandler(navigateCompleted);
}
}
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
private void image1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
objPhotoChooser.Show();
}
private void image2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
cameraCaptureTask.Show();
}
To my knowledge when you use one of the choosers, like the Photo gallery or the camera, when your application is activating it will take it back to the page you left it. I don't think there is a way to get around this itself. What you would have to do is catch the Activating event in your main page code and Navigate to the desired page from there.
Now I am not completely sure how you would pass the image from the MainPage to the target page. It does not look like there is a property in the Navigation service to store this value. But you could either set it in an application wide variable, ModelView or even store it in the Isolated Storage area.
You could work around this by navigating to an intermediate blank page and have that intermediate page launch the tasks. When the tasks are completed you can then navigate as normal to your new page and only this blank page will show in transit.
Chris is correct that some of the tasks will navigate away from your app (effectively tombstoning it) and will the re-activate your application when the user returns from the task. For the camera this is particularly difficult, as to my knowledge there is no simple way to detect when you are returning from the camera. Also the camera doesn't work when attached to the debugger or Zune software (at least this is true on my HTC Surround), which makes troubleshooting quite difficult!
In my WP7 Barcode Scanning application I ended up using flags on the PhoneApplicationService class to help track where the navigation events are coming from. Something like:
PhoneApplicationService.Current.State["ReturnFromSampleChooser"] = true;
You can then check for these flags in the PhoneApplicationPage_Loaded or OnNavigatedTo method of your main page and redirect to the desired page as needed. Just make sure to clear the flag and be careful to not cause any loops in the navigation, as that might make your app fail certification (back button must ALWAYS work correctly).
For an example of how to use the camera and set/clear flags using PhoneApplicationService check out the source code for the Silverlight ZXing Barcode Library. You can download the full source here or browse the files online.