Strange behaviour when dynamically resizing Flash / Flex embed object - apache-flex

I have a simple Flex application that is a panel with a repeater inside of it; albeit a little simplified, it is like such:
<mx:Panel id="pnl">
<mx:Repeater id="rp">
<mx:Label text = "foo" />
&lt/mx:Repeater>
&lt/mx:Panel>
I am then embedding this Flex application into an HTML wrapper. I am then attempting to dynamically re size the embedded Flash object in the HTML as the Flex panel changes size (thus allowing the Flex application to consume as much of the HTML page as it needs).
I am doing this by doing the following actionscipt:
pnl.addEventListener(ResizeEvent.RESIZE,function(event:Event):void {
ExternalInterface.call("resize",event.target.height);
});
which in turn calls this javascript function:
function resize(height) {
// the embed or object that contains the flex app
var e = document.getElementById('flex_object');
if(e) e.height = height;
}
This seems to work perfect in IE, however I get strange results in Firefox / Safari, the repeater works for n number of times, and then the text seems to get cut off / disappear in the repeater, see the attached image:
alt text http://img528.imageshack.us/img528/9538/rpre0.jpg
Can anyone explain why this is happening, and if there are any workarounds / ways of doing the same thing?

I'm currently working in the same thing (a swf that dynamically changes it's height depending on the content it's currently holding). I also had a similar problem to yours trying to make a multi-line button.
I'm new to flex but I managed to solve the problem manually invoking the updateDisplayList() of the container... I think it "forces" a render somewhere... it's parameters are the width and height of some area where the changes happen. Sorry for not knowing the details... But it worked for me.

Why not simply using percent width and height on your HTML page for your Flash object ? This way you event don't have to do anything to resize your SWF...

That's very strange - it looks like Firefox/Safari are expanding the draw area of the embed, but somehow Flash is not getting the message that it needs to render the new pixels.
You could probably work around this by doing something to force Flash to update itself, but since the communication between the browsers and the embed seems to be confused it would probably be less hackish to take a different approach, that fits into the browsers' event flow without bugging.
For example, instead of resizing the embed, you might try putting Flash inside a DIV, setting the Flash's size to 100%, and then resizing the DIV. That seems a lot less likely to misbehave.

My experience is that Flex's resizing abilities are... funny. Sometimes they work the way one would expect, other times they do not. There are a couple of things you could try: first, trace the value you expect to get in Flex for the height or even ExternalInterface.call("alert",event.target.height); This will let you know if it is a JavaScript or a Flex problem for sure (but I suspect it is Flex).
Your problem might have to do with the scaling of the component:
Setting [the height] property causes a resize event to be dispatched. See the resize event for details on when this event is dispatched. If the component's scaleY property is not 100, the height of the component from its internal coordinates will not match. Thus a 100 pixel high component with a scaleY of 200 will take 100 pixels in the parent, but will internally think it is 50 pixels high.
If it is Flex and that does not help, I would try using callLater in front of the ExternalInterface call, often that will allow Flex enough time to figure out what the heck it is doing. Occasionally, setTimeout is needed, but I find that awkward.

Related

Creating a parallax affect with react-scroll-parallax and image masks

Here is the desired outcome I'm looking to achieve by scrolling using react-scroll-parallax.
On Mobile browser
View web browser example here
Description
I want to create a website with the parallax affect shown above. The key elements being a website build in react containing three pages.
While scrolling from Page 1 to Page 2 I want the mobile device mock to start halfway on the screen (as to avoid the other content of page 1), then move to being basically centered.
While scrolling from Page 2 to Page 3, the website and components stick and once again act like a normal website scroll.
Additionally, during the scroll from Page 1 to Page 2, I want the content inside the device mock to scroll as well.
What I tried
For starters I was able to get nearly the affect I wanted by using a div with it's z-index and absolute position set, and parallax on translateY of -50, 125.
<div className={"absolute z-10 w-full"}>
<Parallax translateY={[-50, 125]}></Parallax>
</div>
The problem became however when I wanted to place content inside the div. Having another div within the parallax that also had z-index set seemed to mess with the parallax affect.
Important notes
Content inside device mock
One issue I found that was tricky was trying to place the content inside the device mock. I want a parallax both on the device mock itself, and the content within it.
I'm not entirely sure how I should crop the content inside the device mock.
The device mock svg frame and device mock mask can be found here if you want to give it a try
Device mock svg and mask
I tried imgs with various z-indexes, masking the div with an svg mask, using image backgrounds. Nothing is quite getting the preferred outcome.
Scaling of device mock
I want to make sure this works well on both mobile and browser. With that said I was trying to use margins to scale the device mock but I had a hard time with trying to then correctly get the mask to work for the content within the mock.
I'm not sure if using dedicated width and height sizes would be the ideal way to go, but very open to suggestions! It seems hard to scale the device frame and the mask properly.
Parallax of device and parallax of device content
I want the content inside the device mock to be html so that I can change it more than just an image. That being said the most important feature I want is for both the device and the content inside to have a parallax scroll affect.
Summary
I know this is a bit much for a quick simple stack overflow issue, but I've been trying a lot to get this to work and just can't seem to nail down the little details correctly. I sincerely appreciate all help and suggestions and if there is anything else I can provide please let me know!
The trickier part of the request was blowing up the <svg>, adding new <path /> and <clipPath /> for the color swap inside the phone mock.
Eventually I got it working here. The part linking the clipPath transition to the scroll progress looks like this:
const [y, setY] = React.useState(1739);
const onProgressChange = React.useCallback(
(a) =>
setY(Math.max(Math.min(1739, 1739 - ((a - 0.24) / 0.0018) * 17), 36)),
[setY]
);
const { ref } = useParallax({
translateY: [0, 185],
onProgressChange
});
The 1739 and 36 are max and min values for the translation and they are strictly related to the svg's viewBox. The other values allow tweaking the start, end and speed of animation, with regards to overall scroll progress.
This, together with some CSS, took care of binding the right animations to the correct scroll progress.
Feel free to tweak it some more, especially if you add more markup.
The other thing I wanted was a function activated shortly after scrolling, which would snap the scroll to certain positions. Namely, to the .page elements.
I used gsap's ScrollTrigger plugin for the task, for multiple reasons:
I'm somewhat familiar with it (used it before)
it's performant, light and non-obtrusive (basically quits when it detects another user scroll)
listens to all relevant events (touch, mouse pointer, keyboard) without me having to make sense of them, providing a unified interface.
uses inertia (if you scroll down faster from page 1 it will scroll past page 2, directly to page 3 - other scroll plugins limit you to having to scroll once for each page change)
works well on mobile devices
There are other libs/plugins out there for the task, you don't have to use gsap (although I do think it's awesome). If you end up including it in your project, make sure you comply with their licensing (which is not MIT).
By the way, my first choice for the parallax effect per-se would also be gsap, as their timelines provide a lot of flexibility and options.
Their most advanced stuff is reserved for subscribers, but even if you limit yourself to the free plugins, you're still getting more than from alternative libs/plugins, IMHO.
See it working.

Center content in android 4.4 webview

I'm displaying mathematical expressions in a webview (using jqmath library and some CSS). One requirement is that expressions should be centred, and here's what I use to achieve that:
<html><head><style type='text/css'>html,body {margin: 0;padding: 0;width: 100%;height: 100%;}html {display: table;}body {display: table-cell;vertical-align: middle;text-align: center;}</style></head><body><p>here goes the expression</p></body></html>
Since rendering math takes some time, the webview is hidden while the expression is rendering, and displayed only when it is ready (once the WebViewClient's onPageFinished has been called). This worked well until Android 4.4.
The problem with the new webview seems to be that it only applies CSS when it is visible on screen. So after revealing the hidden webview, the expression first appears in the top left corner, and only after ~0.1 seconds "jumps" to the center. This looks ugly, since I have to display many expressions in quick succession.
A related problem is described in this question: width:100% in CSS not rendering well in Android 4.4. The asker was able to solve his problem by removing the display: table; from html, but that doesn't work in my case.
So is there a way to either:
(a) force the new (Chromium-based) webview to render content while it is not visible, or
(b) display the content at the center from the beginning (without first displaying it in the top left corner).
It is not true that the KK WebView applies CSS only when visible on screen:
the WebView will not size itself if it has visibility set to GONE because the Android framework will call layout-related methods on it (like layout and onSizeChanged). This might be what you're seeing. Try setting the visibility to INVISIBLE instead.
WebViewClient.onPageFinished is not a reliable trigger for showing your WebView. What the callback really means is that the resource for the main frame had been loaded from the network. Unfortunately there never was a reliable callback that would tell you 'your content is ready to be displayed' - what you're describing probably happened to work because of particular timing. The most reliable way to not show unfinished content would be to do so in the HTML/CSS.
you might be using WebView.loadDataWithBaseUrl to load your contents into a new/blank WebView - this API is has an effect similar to re-writing the page's content (rather than issuing a 'real' navigation) and can result in weird layout. If possible use loadData or loadUrl. If neither of those are feasible try calling loadUrl("data:text/html,<body style=\"margin: 0px;\"/>"); before loading the real content (wait at least till you get an WebViewClient.onPageStarted callback for that bootstrap URL).
you might be setting height to WRAP_CONTENTS. This is very unlikely to cause the issues you're describing, but it would be good to rule out. Try setting a width of MATCH_PARENT and a height with a fixed number of pixels.

Prevent Direct3D viewport image from scaling (SlimDX)

I have a Direct3D11 scene set up in SlimDX in a window. The rendering is done in a separate thread.
Is there a way to keep the renderer from stretching the image when it draws to the resized control? I've tried ModeDescription.Scaling = DisplayModeScaling.Centered and it doesn't seem to have any effect. Is there something I'm missing?
(I already am updating the render target size. The reason I ask this is that when I resize the control it stretches the image to fill the control for a split second before the render target gets updated with the new size. This has the result that as I resize it, it flickers terribly. If I could reset the render target just slightly faster it might get rid the the flicker. Keeping the image in the corner without scaling it is perfectly fine since ultimately it won't be scaling at all.)
Workaround 1: One can put the render target inside a control. When the window resizes only resize the control though a special method that first stops the rendering, then update the buffers and begins rendering again. It's a bit of hack, though. I have to wait for the render cycle to complete, then block it, then resize, then unblock.
Workaround 2: A similar workaround is to check for a resize flag in the render loop rather than interrupting it. The renderer should be able to draw directly without scaling. This is much more acceptable performancewise. However, a blocking call to the UI thread must be made to execute the actual resize.
Workaround 3: Rather than resizing the control at all, one could make it as large as the maximum size it could be, but clipped (inside the window). No resize is necessary, but a scissor rectangle must be maintained in a similar manner to the workarounds above unless you don't mind rendering a whole lot of offscreen pixels. Rendering twenty or so extra rows and columns of pixels does have the favorable effect of supplying immediate image at the edge when the window is resized back larger.
Ideally the resize should be done directly from the UI thread (no fooling around with delaying it and reentering the UI thread from the render thread). It's not the render thread's responsibility and it slows it down. Likewise, the buffer resize should be done in the render thread for maximum performance (no fooling around with waiting/blocking/resizing/unblocking). The only reason this does not work is that the render thread scales if the resize is done before the buffers are resized.
So my question still stands: Is there a way to render without scaling?
I am going to answer this in terms of the raw Win32 APIs involved, which might require a bit of finesse to translate to a managed .NET environment & SlimDX.
When you are dragging or resizing a window, windows basically hijacks your message pump and creates a new one specifically designed to do the resizing logic efficiently. This operation is more or less modal until it is completed. Many messages you would normally get are quite literally blocked until the resize or drag is completed. In the app terms you get a WM_ENTERSIZEMOVE when this behavior begins, and either WM_EXITSIZEMOVE or WM_CAPTURECHANGED when it ends. You need to check both of these messages, as alt-tabing out when doing a drag will send WM_CAPTURECHANGED and never a WM_EXITSIZEMOVE!
All this means that when you get a WM_ENTERSIZEMOVE you can set a flag and know that all WM_SIZE and WM_MOVE messages that occur afterwards are for the drag operation. Typically resizing rendertargets and tracking down and de-allocating all default pool resources is a very slow operation, and well worth defering until the drag/resize has completed. This has the side effect of making the window stretch which is exactly the same problem you are describing here, and you want to fix that.
It should be possible to add special handlers in WM_SIZE, WM_MOVE, or WM_SIZING, and WM_MOVING that forces a syncronous render and repaint via SendMessage (as opposed to PostMessage) when they occur, but you will need to make sure you only do this when inside the modal loop owned by WM_ENTERSIZEMOVE.
I would recommend either forcing the window to a fixed size (which seems rather common) or not redrawing the D3D control until the changes are done (that or simply clear it black).
There seems to be a way to do what you want, as I have seen games capable of changing size with no flicker, but I've no idea how that's done, unfortunately. Locking the window size and providing a menu was the old solution.

Height adjustments in Flex NavigatorContent

How is it possible to (automatically) adjust the height of a Flex (4) application at runtime so that only the HTML-page scroll bar is shown, not any Flex scroll bar?
I'm using a ViewStack control which will change always its content. So every time some new content (NavigatorContent controls) is shown (which apparently will have different heights) i want the application height to adjust its height in a way it is reflected in changing only the height of the HTML-page.
I have the slight feeling that this means changing the height of the SWF at runtime! Is this true? If yes how to tell the page ? Is this possible?
I hope i explained my problem as close as possible.
Thanks in advance.
If you haven't already come across a solution to this here's a blog post described a solution for this : http://blog.wezside.co.za/blog/fullscreen-flash-with-browser-scrollbar/
It's a little more then you may be looking for so here's the general gist of it:
Set the embedded swf in the html height to 100%
Then on page change in flash, use an ExternalInterface call to set the height of the container div to your flash content.
Enjoy browser scrolling for your flash/flex app :P
This is the solution which worked (for me)!

Replacing ScrollPane Scrollbar with OS Native Scrollbar

Is there an easy way to replace the ScrollPane scrollbar with the OS's native scrollbar?
Flash applications look much more integrated if they have the same skinning as the user's operating system -- which isn't always easy to detect (Vista Aero vs. Classic?).
Have you guys come across any examples of Flash apps doing this?
To set up something like this would be a big and dirty job. If you're that concerned with OS look-and-feel integration, you're probably better off using native browser controls rather than Flash or another plugin.
Arguably, you could break up your Flash application into separate SWF modules and put each of them into their own scrolling div or iframe in the page. You'd then have to communicate through ExternalInterface or LocalConnection to pass data between the SWFs. Personally, I'd only be willing to try that as a technical challenge to myself, but I doubt it would be worth the effort for a production application.
For the curious, we separated the scrollpane component into a self-contained swf and placed a set of two nested divs along the right and bottom side of the widget.
Using the vertical scrollbar as an example, the outer div was set to the height of the scrollpane and had a CSS overflow-x of hidden, and an overflow-y of auto. The child div was then set to some arbitrary width and a height equal to the height in px of the scrollpane's content.
The browser would display an appropriately sized "scroll grip" and we could quickly read the vertical scroll offset on the outer div to know how far to offset the Flash scrollpane. The same technique, with appropriate modifications, was used for the horizontal scrollbar.
We also included some logic to auto-hide the containers based on their overflow. The result matched native OS behavior pretty closely.
While this may sound like a huge hack, we were able to widely deploy the solution (scribd.com) without any major issues.
Hate to say it, but there is no way to do this. You could use an OS inspired skin/theme, but even then there's possibilities that the user could have modified their appearance settings with custom colors, sizes, etc.

Resources