I'm removing an UIComponent but parts of it last being visible.
It redraws only when I move mouse around or something. I tried to do validateNow() on its parent, tried to do setTimeout(validateNow, 100) but it doesn't help. When I call it by setTimeout it seems these artifacts shown more rarely but it doesn't solve a problem in all cases. Please guide me someone to read about validateNow(), how it works and how to make these things correctly.
The code is below:
protected var bubble: SpeechBubble;
// creation
bubble = new SpeechBubble();
map.addChild(bubble);
//...
// removing
bubble.visible = false;
map.removeChild(bubble);
map.validateNow();
setTimeout(map.validateNow, 100);
map is Google Map for Flex.
The reason this is happening is because you're messing with the Google Maps drawing logic. You should look at the developer guide provided by google. It mentions in the controls section that to create a custom control, you need to extend ControlBase.
You may need to trigger invalidation before calling validateNow(). The call to validate now causes the code to check if any of the invalidation flags are set (properties, display list, or size) then for each calls the appropriate method to correct the invalidation (commitProperties, updateDisplayList, measure) in your case it sounds like it's just not doing the clear call to the graphics or redrawing appropriately so you may need to call
bubble.invalidateDisplayList();
bubble.validateNow();
Also hope one of these solutions works out for you, generally speaking forcing validation at a given time is not usually a good idea as the framework components should trigger the appropriate invalidation and subsequent validation in it's life cycle, but I can't say I haven't done this myself :).
Shaun
You may use includeInLayout property
bubble.visible = false;
bubble.includeInLayout = false;
Example demonstrates this property
The Beauty of includeInLayout
hopes that helps
Related
Debugging an app & I stumbled upon something I never noticed before. For a quick example, I've got a simple link with 2 helpers to style it, like this:
<a class="{{tabHasError}} {{activeTab}}">Test</a>
The helpers that go into this are as follows:
tabHasError: function() {
console.log('invalidated!');
}
activeTab: function() {
if (Session.equals('activeTab', this.tabIdx)) return 'active';
}
Now, every time the Session var changes, activeTab gets invalidated, which is expected. What's not expected is that tabHasError is also invalidated. Why does this happen? Is this normal? Is it because they're both attached to the same element? Aside from merging the functions, any way to avoid this? Or even better, why did MDG make this design decision?
With iron-router, it's normal to observe the behavior you're describing.
The current template in use will be refresh as soon as there is a change into the main computation dependencies. Calling Session.set will call the refresh of the template variable. For sure, it's a lot, but it is one of the simplest way to be sure the template is always up-to-date.
If you're looking for larger app, you could have a look on React.js integration, which will give you the ability to refresh only the good variable on your template.
In fact, in your example, the value of tabHasError should not change, but the re-rendering of the template will called the function tabHasError to check if there is any change. In this case, no.
I'm around if the behavior isn't clear enough. Have a tremendous Sunday!
I noticed that this only happens in an element's attributes. I think this behaviour is very specify, according to Event Minded videos regarding the previous UI engine (Shark): it only rerenders affected DOM elements.
Having in consideration that in your code Blaze is rerendering the DOM element, it makes sense to invalidate previous computations related to it. If you place this helper inside the a element it won't be invalidated.
I have a problem.
My app is a tab bar controller and its first view controller is a split view controller.
This seems to be not ok for Apple because documents say a split voew controller must be the root, so perhaps that is the reason of my problems.
The problem is that sometimes, willHideViewController from UISplitViewControllerDelegate is not called, so, for this reason, the upper/left button sometimes is not created, which is anoying.
I realised, to reproduce this error, try several times this:
-Landscape mode.
-Select a tab different to split view controller tap.
-Move the iPad to portrait in that tab.
-Go to the split view controller tab, and sometimes, willHideViewController is not called so you will not see the upper button. However if I rotate my iPad to landscape and after that to portrait, it's fixed.
I tried to force manually several rotations to work around this problem, but no luck.
I still have to try any split view controller clone class from github or similar.
Do you have idea what's going on or any work around?
Here I show you two examples working properly.
Thanks a lot for your help.
Where do you set the splitViewControllers delegate? Perhaps you can set the delegate when you load the tab. It sounds like you set it only when you have rotated once?
Otherwise, see this example
Here they have the TableViewController be the delegate of the splitviewcontroller. Perhaps you could do the same with the TabBarController?
I've concluded that this can't be done in any way that I consider 'sufficiently' legitimate. It's possible to get frustratingly close, but the issue of having the willShow..., willHide disseminated to the split view controllers under each tab remains.
The solution that seems most likely to work is,
https://github.com/grgcombs/IntelligentSplitViewController/blob/master/IntelligentSplitViewController.m
Though this code is undoubtedly clever, it's a bit too 'side door' for me. I suspect (but don't know) that just invoking the delegate methods is not sufficient. Surely the UISplitViewController itself needs to change it's internal state as well as calling the delegate methods? This method 'just' invokes the delegate methods when there's an orientation change.
So... I've decided on a more legitimate solution, which is to use the new method introduced in iOS 5.
- (BOOL) splitViewController:(UISplitViewController *)svc
shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}
So, the master menu is never hidden, and therefore the problem of managing the popover doesn't arise.
Of course, this is still not totally 'legit' as it still includes UISplitViewControllers that are not at the top level (the UITabViewController is at the top level, and the split views are on each tab)
Good luck with whichever solution you choose.
I'll update this reply when I've confirmed Apple will approve an app using this solution.
How can I remove all event listeners on all components at once, especially when it is not known what listeners are attached to each component?
You can override mx.core.FlexSprite, which UIComponent inherets from, and generate an array of listeners created. Doug Mc Cune put up source code here.
His blog says: removeAllEventListeners() – removes all event listeners of all types. This completely wipes out all event listeners for the component all at once.
Let us know if this does the job!
No!
You might be able to mock something up with hasEventListener and willTrigger. But, there doesn't appear to be an obvious way to remove the event listeners without actually knowing the method name.
What do you want to do this for?
There is an issue in Adobe JIRA for this task, please vote if you feel that it important for you
https://bugs.adobe.com/jira/browse/SDK-14127
Elad Elrom has a post on his implementation to store event listener references, and be able to remove them all at once:
http://elromdesign.com/blog/2010/07/16/easy-way-to-store-event-listeners-reference-prevent-memory-leaks/
I am able to render a google map on a flex canvas. I create the map using the code below and then place markers on it in the onMapReady method (not shown)
var map:com.google.maps.Map=new com.google.maps.Map();
map.id="map";
map.key="bla bla";
_mapCanvas.addChild(map);
map.addEventListener(MapEvent.MAP_READY,onMapReady);
It all works fine. However, if I remove the map and then set _mapCanvas to null, then run exactly the same code again, the onMapReady event does not fire. It is weird, but once a map has been created and deleted, the onMapReady event never seems to fire again.
Anyone got any ideas?
Thanks.
I still don't know why this was happening, but I worked around the issue by creating the map as an application-level variable, only instantiating it once, and then adding and removing it from canvases as required. Not ideal, but at least I can now display and remove a map dynamically, even if it exists in memory between invocations.
First and foremost, I apologize for any vagueness in this question. At this point, I'm simply trying to get some new ideas of things to try in order to diagnose this bug.
Anyway, the problem I'm having is with an application that's using a custom moduleloader. That moduleloader has been compiled into an swc and the moduleloader is being instantiated via its namespace. This all works perfectly fine. The problem I'm encountering is specific to mx:button controls used within modules. For whatever reason, their labels are being truncated so, for example, Sign In is showing up with an ellipsis, as Sign ...
After quite a bit of fooling around I have been able to establish the following:
This problem only seems to occur within modules. If a button control is used in the main mxml, the label does not get truncated.
The button control whose label is being truncated does not have a width specified (setting its width to 100% or a specific pixel width doesn't fix the issue)
The button control is using the default padding (messing with the padding by setting left and right to 5 or any other value doesn't help matters either).
We are not using any embedded fonts so I've ruled that out as a possibility as well.
mx:CheckBox and mx:LinkButton are equally impacted by this problem although mx:CheckBox also seems to not want to show its checkbox, it just shows the truncated label.
A potential side affect of this is that attaching a dataprovider to mx:ComboBox causes the combobox control to throw a drawing error but I'm not entirely certain that it's related to the above problem.
One interesting thing I did find while perusing the net for an answer was a mention of fontContext and its relationship to IFlexModuleFactory. There's no specification for fontContext within our implementation of moduleloader so I'm not entirely certain if this could be the issue. In any case, if anyone has any ideas, it would be hugely appreciated. On the other hand, if you know exactly what ails me and can provide me with an answer, I might just wet myself with excitement. It's late. I'm tired. I NEED my Flex app to play nice.
Thanks in advance,
--Anne
Edit: To clarify what I'm looking for with this question, I really just need to know the following:
Could this issue be caused by a namespace conflict?
What else can potentially override the default behavior of labels if no CSS has been implemented?
Has anyone encountered a problem with inheritance being lost while using a custom implementation of moduleloader?
Has anyone encountered this problem or a similar problem with or without using moduleloader?
I'm not sharing any code with this question simply because I'd have to share the entire application and, unfortunately, I can't do that. Again, I'm not looking for the end all, be all solution, just some suggestions of things to look out for if anyone has any ideas.
I've been dealing with this issue myself, off and on and in various forms, for a year, and while I haven't figured out just what's causing it yet, there's clearly a mismeasurement happening somewhere along the line.
What I have been able to to, though, is work around it, essentially by subclassing button-type controls (in my case, Button, LinkButton, PopUpButton, et. al.) and assigning their textField members instances of a UITextField extension whose truncateToFit element simply returns false in all cases:
public class NonTruncatingUITextField extends UITextField
{
public function NonTruncatingUITextField ()
{
super();
}
override public function truncateToFit(s:String = null):Boolean
{
return false;
}
}
The custom component just extends Button (or whatever other button-type control is the culprit -- I've created a half-dozen or so of these myself, one for each type of control), but uses a NonTruncatingTextField as its label, where specified by the component user:
public class NonTruncatingButton extends Button
{
private var _truncateLabel:Boolean;
public function NonTruncatingButton()
{
super();
this._truncateLabel = true;
}
override protected function createChildren():void
{
if (!textField)
{
if (!_truncateLabel)
textField = new NonTruncatingUITextField();
else
textField = new UITextField();
textField.styleName = this;
addChild(DisplayObject(textField));
}
super.createChildren();
}
[Inspectable]
public function get truncateLabel():Boolean
{
return this._truncateLabel;
}
public function set truncateLabel(value:Boolean):void
{
this._truncateLabel = value;
}
}
... so then finally, in your MXML code, you'd reference the custom component thusly (in this case, I'm telling the control never to truncate its labels):
<components:NonTruncatingButton id="btn" label="Click This" truncateLabel="false" />
I agree it feels like a workaround, that the component architecture ought to handle all this more gracefully, and that it's probably something we're both overlooking, but it works; hopefully it'll solve your problem as you search for a more definitive solution. (Although personally, I'm using it as-is, and I've moved on to other things -- time's better spent elsewhere!)
Good luck -- let me know how it works out.
I've used the custom button and link button class solutions and still ran into problems - but found a workaround that's worked every time for me.
Create a css style that includes the font you'd like to use for you label. Be sure to check 'embed this font' right under the text selection dropdown. Go back and apply the style to your button (or your custom button, depending on how long you've been bashing your hear against this particular wall), and voila!
Or should be voila...
I just came across this issue and solve it this way:
<mx:LinkButton label="Some label"
updateComplete="event.target.mx_internal::getTextField().text = event.target.label"
/>;
I've had some success preventing Flex's erroneous button-label truncation by setting labelPlacement to "bottom", as in:
theButton.labelPlacement = ButtonLabelPlacement.BOTTOM;
Setting the label placement doesn't seem to help prevent truncation in some wider button sizes, but for many cases it works for me.
In cases where you can't use a bottom-aligned button label (such as when your button has a horizontally aligned icon), janusz's approach also seems to work. here's a version of janusz's .text reassignment technique in ActionScript rather than MXML:
theButton.addEventListener(FlexEvent.UPDATE_COMPLETE, function (e:FlexEvent):void {
e.target.mx_internal::getTextField().text = e.target.label;
});
The preceding code requires you to import mx_internal and FlexEvent first, as follows:
import mx.events.FlexEvent;
import mx.core.mx_internal;
And here are the results…
Before (note truncation despite ample horizontal space):
After:
The only downside to this approach is you lose the ellipsis, but in my case I considered that a welcome feature.