I've recently finished a small side project in Flutter and when I tried to implement theme changing in runtime, most answers I came upon involved either putting my MaterialApp (which has the Theme) below a StatefulWidget or a Consumer<> of some sorts.
From what I understand, both these solutions proceed to redraw the entire widget tree below the MaterialApp when some change is encountered (either a state change in the case of the StatefulWidget or a change in whatever ChangeNotifier I provided to Consumer).
So my main questions are: Isn't that very expensive and not recommended? Is my entire app widget tree being redrawn (assuming most of it is below the MaterialApp)?
And secondly: why aren't the build methods of some of my own widgets deep below the MaterialApp tree being called? This would imply that the expensive rebuilds that the documentation implies aren't actually being done. What gives?
Thanks in advance!
As I understand it if you wrap your MaterialApp in a Consumer that references a provider that only emits a value when your theme changes then this isn't terribly inefficient. Yes, it will redraw the app when you change your theme, however it won't redraw your app on every state change, only the change in that value. If you have a Provider that notifyListeners a lot, than you can use a Selector widget to only focus on your one value for theme.
However that said redrawing your app once when the user changes theme is not going to be expensive and will be done rather quickly. There is no way around redrawing your app on a theme change. If you are concerned you can use the Profiler tooling to test this, but you will find little to no issue on theme change.
Related
Following the instructions in this documentation about Animations and Transitions, it is noted that animation done on the Form level requires taking the contentpane as the actual Container. So instead of
form.animateLayout(1000);
one has to do
form.getContentPane().animateLayout(1000);
While the documentation points out this exception, wouldnt it be easier and more user-friendly to update the animateLayout() function to check whether the intended Component to do the animation for is a Form itself and if so, automatically getting its content pane?
This would remove this exception handling from the user side and make it more intuitive.
Yes that makes sense. There are a lot of methods that constantly get added/changed and we still didn't add everything that needs adding. In this commit I added a few: https://github.com/codenameone/CodenameOne/commit/4b848039ec6619bf3d6dae3cfe6b8b8d9a7ff115
I am working with flex for the last two years on some desktop apps. Until now I never had any performance related issues but today as we completed a mobile application for the iPad, I'm facing a challenge, the application is incredibly slow on the iPad.
http://i.stack.imgur.com/qkbWn.png
Slow, means that when I press a button in the menu to change the splitview I must wait something like 5s. Then scrolling is really slow two, with less than one fps and my TextInput starts to bug (the text is not in his box anymore).
I started to read a lot of blog post and presentation about optimisation for the mobile platform and then I rewrite some of the components I use. I removed the SkinnableContainer for instance and replaced it by a VGroup including some actionScript based drawing.
Now what you see is a VGroup (the dark grey one) containing some others VGroup (the group with title here) and then each widget is an HGroup with a label and a Widget. I only use Label and TextInput for the text.
Creation time is slow even (several seconds to create the view) for another page where there is only 4 text widget on it, or another one with only a list with a custom item renderer where each row is a set of 4 labels.
The whole things is cabled with RobotLegs, with nothing fancy, one models is injected in the view and at the beginning I set a member variable on the view with this object to bind my variables.
Frankly my thinking right now is : it smells fishy because if I've done everything right it is impossible to have such low performance and thinks that flex is competitive on the mobile platform. So right now I'm trying to disable the application piece by piece to try to locate what could slow it like that. I've got a couple suspects to check, for instance I've got some binding warning to check, and then see if robotlegs has got its share of the problem.
So my main question here is what do you think, and could you have some ideas about "is there a problem" and "how do we solve it".
Thanks
Run profiler for startup and separatelly for each operation that takes longed that it needs. Then prioritize the problems and try to solve them with basic optimization techniques.
Some problems you will not be able to solve fast - e.g. time for creating big components. The only option there is to rewrite those components with AS3 without MXML, styles and anything. I'm sure that flash.text.TextField is created many times faster than mx.controls.Label. The same for other components.
When component is created, it can be reused at a very low price. In your app there must be a lot of places where you recreate while you can reuse old components. It will save you memory and time.
Layouts tend to redraw even when it's not needed. If you have a lot of nested layouts, find the most critical places and replace a series of layouts with one custom layout or even component.
This all is very developer time consuming. At the end you will not get a smooth app anyway, but I believe that it can become usable.
I need to change the Background Image of my Application if user changes theme from "Light" to "Dark" or vice-vesa in code behind. I hope these should be done in Page Loded event
#TimDams pointed you to one of the nice ways to detect what-theme-is-now-set, but I didn't notice there any information how to detect a change to the theme during the application runtime. The user could start your app, then bump forward to the menu, change the theme, and get back to your app. While you may think that your app will be tombstoned and then restarted and renavigated to your page with full cycle with all pageloads -- it is not 100% true.
Firstly, the PageLoaded is NOT a good place to do the initial check-and-set-styles, because, if you get that event called, then the page, probably, has already rendered once. If I remember well, the PageLoaded is invoked just after the first render. If this is true, then you will have to detect the colors earlier, for example in the LayoutUpdated (warning: this event is a great spammer. I mean, it gets called gazillions times. Attach a single-shot handler, you know, such that will instantly unattach-self on first invocation). Maybe you will be able to do it in the Page's .ctor, just after InitializeComponent. Or in the OnApplyTemplate or MeasureOverride, or at least ArrangeOverride -- the visuals should be mostly/fully available there.
Buuuut. I've intentionally 'bolded-out' the word "initial". With Mango, there's some multitasking getting more and more common, but even the pre-Mango 7.0 version does not guarantee that your app will be tombstoned. From my observations in early 7.0, for example, starting the MediaPlayer from WebBrowser component does not tombstone your app:) If you have some time to read, check WP7 recover from Tombstone and return to page for details on the "pause" vs "tombstone".
Anyways, if your app gets "paused" and the user switches themes in the meantime, I think (I've NOT checked) that your page will (in most of the cases) be just temporarily hidden and upon returning to the screen, it will probably not be re-created and will not be re-(Page)Loaded. If it is true, then you will have not so easy problem to solve, because your app may be paused, the OS rethemed, and your app unpased virtually in any moment of time and the only events you will get in the mean time are .... global events of App.Deactivated and App.Activated. It is possible that completely none of per-page events will fire [but I've not checked - before you do anything I suggest below, CHECK IT].
If this pessimistic view is really true, than in those events, you will have to detect the current theme (->Tim's post), then somehow inform your current Page that themes changed - or not. If you have your ViewModel at least a bit separated from the rest of the app (as it should be:) ) you have an easy option to do it: create in that ViewModel a set of properties (dp or inotif) like Brush Background, Brush Foreground, Brush Hightlight, and other that you need, and instead of harcoding colours in your XAML - bind to those properties. You may event want to create a separate class for all those many Brushes and other Styles, let's say "pub class MyCurrentAppTheme" and keep that props there, and expose such object from ViewModel - whatever. Just Bind your colors to whatever -- but whatever that will be "logically global" and that will be easily accessible from the App.Acticated event handler. Having that done, in the App.Activated, detect the current theme and if changed, so through all the colors kept in VM and set them appropriatelly. Voil'a, whole your App gets recoloured properly.
But mind that still - there might be some transient blinks and flashes between the rendering of cached old theme, refreshing databound objects, and redrawing fresh theme. I hope not, but I sense it may occur, especially when returning from fast-switch tool (long back press): I think that the device captures the 'last screenshot' of your app in the backbuffer and uses that throughout all the time the app is 'minimalized' to do transitions animations, to show the fast-app-switch overview and so on.. again, I've not checked, but I doubt that during such animations the pagecontents are 'live', it could be very demaning on CPU/GPU resources. Any one knows anything on that? It could be a nice test to have some looping animation on the page and then to switch out and check in the fast-switch overview, whether the animation moves or is halted!:)
If your application is tombstoned, all your controls will be recreated and the new theme will be applied. If you'd like to manage your light/dark specific styles in a similar vein to normal themes, you might want to take a look at a custom ResourceDictionary I blogged about a while back.
Unfortunately, as of Mango there, is a bug (?) related to fast application switching that causes the theme to remain unchanged in your application. The bug is outlined in this question and its linked posts:
Is there a bug when changing themes when app is deactivated and reactivated in Windows Phone Mango
My ResourceDictionary is still useful for the initial startup but it appears, unfortunately, that nothing can be done to workaround the Mango bug.
For this no event exists. You need to figure this out manually by comparing the PhoneBackgroundBrush color to see if the user has the dark or light theme and compare it with your last stored value.
Were you able to do some test on the App.Activate - Deactivate?
I decided to use a different path to solve the issue of dynamic theme change.
I've assigned to all text and buttons only system resource colors.
For the icons inside the buttons in the window instead of using PNG images-icons I used the in XAML and assing it a Foreground color from system resource.
For the buttons in the SystemMenuBar there is no issue as they are always on a dark gray background so the black PNG images work just fine.
Hoping this helps.
You can check if the dark theme is in use with this simple check:
public static bool CurrentThemeIsDark
{
get
{
return (Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible;
}
}
when i use pivot with in the panorama .pivot are used as a gallery view. i want to move pivot when i swipe it .but the problem is this because of both panorama and pivot are the same gesture event so both are they move .
i want swipe only my pivot view .
I would like some sample code or any other suggestion to do this.
so please give me a solution for doing this and
also give me a link where i easily understand this. Thanx in advance
You shouldn't have a Pivot in a Panorama control. End of discussion.
I believe it is achievable, because I've already solved similar issues with having WebBrowser control inside a custom horizontal-scrollable overview container like Pivot/Panorama, but believe me, it is NOT worth it. I've had to dig very deep into the visualstructure of the controls and attach my own manipulation-handlers to their viscera, manually choose which horiz/verti events to pass and which to cancel, and so on. This is not so easy, takes a lot of time, and doesn't guarantee that on the end you will have something behaving in a way you wanted to achieve in the first place. If you are not bound by some contract to preserve the shape of the UI, please, drop the idea and redesign your UI, just to save on your sanity and nerves.
But, if you are already insane or really want to dig where noone should, start on analysing your UI as a two rectangles: large pano and small pivo, and think which part should behave how on different possible touches/h-v swipes/h-v pans/pinches/so on. Write it down just to for reference, or soon you will probably start making small mistakes that will interfere with your understaning of the flow of the events.
I've checked the version I have, and "my" Panorama uses internally the UIElement.ManipulationXXXX events. In that case:
Display visualtrees of your UI and try attaching manipulation-events to every control. In those events, write/log which control's which handler was invoked. Then make some swipe/scroll on your APP and observe events. Analyze how they were bubbling and try cancelling (e.Handled=true) the manipulation-completed and/or manipulation-delta events somewhere between pivot and panorama. Your goal is to have the panorama see that e.Handled=true, while your pivot must see e.Handled=false. Your Pivot will probably see the event sooner than the Pano, so that point should be relatively easy.
If it fails to work, then you should check your version of the Pano, and check how it detects movements. If, for example, it uses the GestureListener - try the same trick with it. Etc.
And remember, you can always make your own horizontal-overwiew-container that will look like Pano, behave like Pano, and that will work with Pivo better - because it will be your code and you will tell it what and when to move. if you want to go this way, start on google and check all the preliminary Panorama previews that random people have published before that control was published by MS.
Is there any way to control the threshold of the flick action to on/off a toggle switch so that it doesn't mess with the pivot control's navigation?
Sorry, but I'm going to avoid you're question (I can't answer it anyway) and suggest you use a different approach.
You could (I assume) use a checkbox to just as easily provide the option to the person using the application. Afterall a toggle switch has the same functionality as a checkbox (specify/choose between two states) it just implements the interaction differently.
The toggle switch has not been designed/built (AFAIK) to support being used on top of something which also supports the same gesture.
As a general rule of usability, having controls on top of each other (or even next to each other) which support the same gesture is likely to cause problems for the user. Even if the problems are through accidentaly triggering the wrong gesture or expectations about how their gesture will be interpretted.
In summary: this is a really tricky problem to solve; I don't think you can with the controls as they are; and the problem goes away entirely if you use a different control for toggling anyway.
I've had the same problem with my codermate, we've been digging this for many hours and we finally reached the top of the hill and we came up with a solution.
This solution works for the bing map control:
on mouse enter: myMapControl.CaptureMouse();
on mouse leave: myMapControl.ReleaseMouseCapture();
And there you go, when you'll navigate inside the map the pivot won't do transition ;)
If you don't get the point, just poke me and I'm going to explain with real code (I'm quite busy right now).
Cheers
This solution posted recently seems to be working out for people for dealing with gesture conflicts on pano / pivot. You might like to check it out.
Preventing the Pivot or Panorama controls from scrolling
Set the IsHitTestVisible = false in your root pivot control
The solution to this is simple, and comes from my experience with Android and iPhone application development.
simply make sure you only tap into the OnMouseLeave event - not the OnChecked or the OnMouseClick as these will accidentally fire just by touching the toggle.
You want make sure that they were touching it when they let go of the screen, and this (unless you put the toggle on the edge of the screen will almost never be the case