Resizing a Flash loader after Event.COMPLETE doesn't work - android

Google suggests that the following is not that uncommon a question: having loaded something into a Flash stage using a Loader, I want to resize it. However, if you do this before the content is loaded, resizing the image causes it to disappear.
The proposed solution is usually to use an Event listener for Event.COMPLETE. Here's my code:
public function FlixelTest()
{
super();
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
myLoader = new Loader();
myLoader.x = (stage.fullScreenWidth-640)/2;
myLoader.y = (stage.fullScreenHeight-480)/2;
addChild(myLoader);
var url:URLRequest = new URLRequest("stuff.swf");
myLoader.load(url);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadProdComplete);
}
function loadProdComplete(e:Event):void{
myLoader.height = 480;
myLoader.width = 640;
}
According to every posting I can find so far online, this solution should work. When the event fires, the Loader is done, and can be resized. However, it doesn't. Commenting out the lines that modify .height and .width cause the SWF to appear, uncommenting them and running again and the SWF never loads.
Could anything else be interfering here? This is using FlashBuilder to construct an Actionscript3 -> Android project.
EDIT - The solution here doesn't appear to work either: Problem resizing loader after loading swf
UPDATE - I have a working, and horrific, solution that is as followed:
function loadProdComplete(e:Event):void{
if(myLoader.width != 0){
myLoader.width = 640;
myLoader.content.width = 640;
}
else{
timer = new Timer(500);
timer.addEventListener(TimerEvent.TIMER, timertick); // there should be a comma here but yahoo replaces it with ...
timer.start();
}
}
function timertick(e:TimerEvent){
timer.stop();
stage.dispatchEvent(new Event(Event.COMPLETE));
}
It basically uses the content's width to see if it's finished loading. If it hasn't, it waits a half second and refires the COMPLETE event. This actually helps display it (although the width hasn't been adjusted, I assume that's a separate issue) - I can't believe this is the only way to get it working...

While not strictly a solution, the way I've circumvented this is by not resizing it at all - I am instead cropping an area over the window so all that's seen is the section I wanted to display.
function loadProdComplete(e:Event):void{
var gameMask : Shape = new Shape;
gameMask.graphics.beginFill(0xffcc00);
gameMask.graphics.drawRect(myLoader.x,myLoader.y,640,480);
gameMask.graphics.endFill();
myLoader.content.mask = gameMask;
}
Since the mask would've been necessary for me anyway to hide off-stage clutter, this solved two problems at once.
I won't accept this as the answer in case anyone has any alternative insights, but if anyone comes across this question, this is a posisble solution.

Related

Making a android-desktop-style PageView

This is a very simple example to achieve the android multi screen wallpaper effect on iOS, written in Swift. Sorry for the poor and redundant English as I am a non-native speaker and new to coding.
Many android phones have a multi screen desktop with the feature that when you swipe between screens, the wallpaper moves horizontally according to your gesture. Usually the wallpaper will move in a smaller scale comparing to the icons or search boxes to convey a sense of depth.
To do this, I use a UIScrollView instead of a UIPageViewController.I tried the latter at first, which makes the viewController hierarchy become very complex, and I couldn't use the touchesMove method correctly, as when you pan around pages, a new child viewController will come in and interrupt the method.
Instead, I tried UIScrollView and here is what I have reached.
drag a wallpaper imageView into viewController, set the image, set the frame to (0,0,width of image, height of screen)
set the viewController size to freedom and set the width to theNumberOfPagesYouWantToDisplay * screenWidth (only to make the next steps easier, the width of the viewController will not affect the final result.)
drag a scrollView that fits in the viewController
add the "content UIs" into the scrollView to become a childView of it. Or you can do it using codes.
add a pageControl if you would like.
in your viewController.swift add the following code
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate{
let pagesToDisplay = 10 // You can modify this to test the result.
let scrollViewWidth = CGFloat(320)
let scrollViewHeight = CGFloat(568) // You can also modify these based on the screen size of your device, this is an example for iPhone 5/5s
#IBOutlet weak var backgroundView: UIImageView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.pagingEnabled = true
// Makes the scrollView feel like pageViewController.
scrollView.frame = CGRectMake(0,0,scrollViewWidth,scrollViewHeight)
//Remember to set the frame back to the screen size.
scrollView.contentSize = CGSizeMake(CGFloat(pagesToDisplay) * scrollViewWidth, scrollViewHeight)
pageControl.numberOfPages = pagesToDisplay
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let pageIndex = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = pageIndex
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let bgvMaxOffset = scrollView.frame.width - backgroundView.frame.width
let svMaxOffset = scrollView.frame.width * CGFloat(pagesToDisplay - 1)
if scrollView.contentOffset.x >= 0 &&
scrollView.contentOffset.x <= svMaxOffset {
backgroundView.frame.origin.x = scrollView.contentOffset.x * (bgvMaxOffset / svMaxOffset)
}
}
}
Feel free to try this on your device, and it will be really appreciated if someone could give some advice on this. Thank you.

AS3 AIR: Smooth scrolling for mobile

So, I'm building fairly simple application for portrait mode only, and it will have vertical scrolling for content.
Content is basicly a MovieClip containing image as background and other minor elements (couple small MovieClips as buttons etc).
The problem is that I don't seem to find a smooth way to scroll my content. I would love it to be smooth and accurate, and I've tried numerous different ways for it.
For testing purposes the background I'm using (inside my content MovieClip) is 533x1250 jpg from library.
This is how I add my content mc and backround into it:
scaleXFactor = stage.stageWidth / 640; //my stage is 640x960
...
addChild(content); //which is new MovieClip()
var bg:bg1 = new bg1();
bg.x = p1bg.y = 0;
bg.width = 640 * scaleXFactor;
bg.scaleY = bg.scaleX;
content.width = bg.width;
content.height = bg.height;
content.addChild(bg);
For scrolling I assumed I'd be safe by just simply using MOUSE_DOWN & MOUSE_UP event listeners and basic ENTER_FRAME function like this:
mouseLastPos = stage.mouseY;
if(MouseUpVar == 1){
mousePosDiff = (mouseOriPosY-mouseLastPos);
}
content.y -= mousePosDiff*1.2;
mouseOriPosY = stage.mouseY;
if(MouseUpVar == 0){ //Smoothening which is allowed by MOUSE_UP
if(mousePosDiff > 0){
mousePosDiff -= 0.001;
}else if(mousePosDiff < 0){
mousePosDiff += 0.001;
}
}
if(content.y < (content.height - stage.stageHeight)*-1){
content.y = (content.height - stage.stageHeight)*-1;
}else if(content.y > 0){
content.y = 0;
}
In debug player it's as smooth as you can ever imagine, but in real device (Samsung Note4) it's very laggy and clumsy.
I've also tried freshplanet's script, which is not as laggy, but still a little clumsy, and messes up my scaleY for some reason.
And IScrollerComponent seems to have some issues on AIR, and I didn't get any visual elements on my screen with it.
Rendering settings or cacheAsBitmap didn't seem to have any effect on this.
How should this be done right? Is it normal that this 'small' image (533x1250) causes bad lag?
I really need to use AS3 and AIR for this, so I'm hoping to find a good and "simple" solution (yeah, that doesn't happen too often).
Thanks,
kaarto
Try using cacheAsBitmap=true on your content and scrollRect instead of moving your content.

as3 air and screen size dection issue on devices

I have worked so hard on an app that displays perfectly on my Galaxy Note 3. However, it does not display right on iPhone and also one other Droid I tested on. My issue is with addChild() and then resizing it to fit the screen. For some reason when I add the Background (addBG(); The screen size works but if I load addChild to the BG, this works great on my Note 3 but not on the iPhone or another android device.
My issue is with the screenX, screenY var I created. They seem to be different for devices. Or it is a "rendering order issue" I am not sure. Would be so greatful for the help to fix this issue so it looks great on each phone. I have read some tuts on this subject but they are confusing. I think my code is close, I hope, and maybe it just needs a tweak. !
Here is a shot of the about screen on an IPhone. See the white does not fit the whole screen.
and Here is a shot from my Droid Note 3.
Declared Vars in a package:
This is not my full code, of course but only that which I believe is relevant.
public var screenX:int;
public var screenY:int;
public function Main()
{
if (stage)
{
setStage();
addBG();
}
}
public function setStage()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
if (flash.system.Capabilities.screenResolutionX > stage.stageWidth)
{
screenX = stage.stageWidth;
screenY = stage.stageHeight;
}
else
{
screenX = flash.system.Capabilities.screenResolutionX;
screenY = flash.system.Capabilities.screenResolutionY;
}
}
This works: addBG();
public function addBG()
{
theBG = new BG();
addChild(theBG);
theBG.width = screenX;
theBG.height = screenY;
}
This does not: addAbout();
public function addAbout()
{
About = new viewAbout();
About.width = screenX;
About.height = screenY;
theBG.addChild(About);
TweenMax.fromTo(About,1, {alpha:0}, {alpha:1, ease:Expo.easeOut} );
}
UPDATE: And yet another more complex load is also called from a button and having the same issue. I hope you see the logic of what I am trying to do. First set the BG to the device then load and resize content to fit proportionally into the BG I loaded. The reason being, the BG will be distorted to different proportions and that's ok, but the content can not. So here is the example that loads content into the BG and then content into that container.
public function addRosaryApp()
{
Rosary = new viewRosaryApp();
Rosary.width = screenX;
Rosary.height = screenY;
theBG.addChild(Rosary);
TweenMax.fromTo(Rosary,1, {alpha:0}, {alpha:1, ease:Expo.easeOut} );
contentRosary = new contentRosaryApp();
theBG.addChild(contentRosary);
contentRosary.width = screenX;
contentRosary.scaleY = contentRosary.scaleX;
contentRosary.x = screenX/2 - contentRosary.width/2;
contentRosary.y = menuBanner.height;
}
Have you tried adding the child to stage first, and then setting the size? That's the only difference I can see between addBG and addAbout
About = new viewAbout();
theBG.addChild(About); // do this first
About.width = screenX; // then set width
About.height = screenY; // and height
I think your problem may have to do with either of several things.
My findings so far from my own devices (an Ipad Air, an iphone 4S, an LG G2 and an Acer Iconia A500) is that the only device size that's being reported correctly at all times is the stage.fullScreenWidth and the stage.fullScreenHeight
1st, Android reports Capabilities.screenResolutionX as the LONG side of your Android device.
IOS devices however report the SHORT side of your device to Capabilities.screenResolutionX.
2nd, stage.stageWidth and stage.stageHeight seem to report the wrong size on both Android and IOS.
And in fact if you check these before and after setting stage.scaleMode and stage.align then the values will differ completly (although Android will show it almost correctly).
My suggestion is that you set a base size (width and height) for your app and then compare it with the actual stage.fullScreenWidth and stage.fullScreenHeight reported by the device. That way you can get some nice scaleratios to use to scale your displayobjects. That's what I'm currently on my apps and it scales just fine :-)

A riveting mystery: Android, Bitmaps (JPEGs), and the GridView of DEATH?

My app is exhibiting some very strange behavior. I have tried everything to resolve the issues I'm having, but, at this point, I'm at a total loss.
Some background information is in order (some details of the implementation that I'm providing might be overkill, but I want to make sure no stone is left unturned):
The app makes use of the device's camera, utilizing a SurfaceView with the necessary SurfaceHolder callbacks to open the device's Camera and take photos. That all works just fine.
The photos are then saved to the devices internal storage, using a FileOutPutStream. I then maintain a reference to the file path of each photo inside a plain old Java object, which is actually serialized and also written to the device's internal storage using an ObjectOutputStream.
The photos, which are in JPEG format, are later retrieved by grabbing the serialized ArrayList of my objects, grabbing the file path from those objects and passing it to my caching mechanism like so Bitmap bm = ImageCache.getSharedInstance().getBitmap(photoObject.filePath,getResources()); to return a Bitmap which I can use with an ImageView, whatever. I use this to for displaying the JPEGs in ListViews, GridViews, etc.
Here's the problem:
I have a View, which I've created programmatically, that has a sort of navigation bar at the top of it. All the navigation bar does is set the "main" part of my custom View class to display whatever other view I pass to it. So, my View class has a method like: setContent(View v) which simply removes all Views from the main part (or the area that I've carved out as the content area) and then adds the View you passed in to this content area.
So, if you click on nav button, it shows the photos along with some other data in a ListView, click another and it shows a GridView using the same photos. Right here is the problem. I like to call it THE GRIDVIEW OF DEATH. The GridView implementation is pretty straightforward and seems to work just fine when it's loaded.
mGalleryAdapter = new GalleryAdapter(MyActivity.this, list);
gridView.setAdapter(mGalleryAdapter);
Fine... but here's the issue. Once the GridView is loaded and displays the data from the adapter, if you try to start any other activity or navigate to any other are of the app, the activities in question seem to launch, but the Views inside of them never display. It is the strangest behavior. If you start with the ListView displaying and then navigate to some other tab (yea, I'm using tabs to sort of mimick iPhone style UITabs), everything is fine. The activity loads, the views display... everything is fine. But once you click to display the GridView, the app just seems to melt. Aaaaand, here's the catch. Whatever activity you've navigate to after displaying the GridView, will first display an empty, white activity (with no view). But if, for example, you long-press the home button and switch to some other running app and then come back to my app, the newly launched activities then display the views inside of them just fine and the app resumes normally. Strange indeed.
I must mention that I originally had the app crash several times because of "exceeding the VM budget." This was clearly related to issues with the JPEGs and their memory usage. From the stuff I've read online, the main fix to this is to crank up the BitmapFactory.Options sampleSize. Well, that's exactly what I've done. I've cranked it way up to reduce the image size:
public Bitmap getBitmap(String filepath, Resources resources){
SoftReference<Bitmap> reference;
if(resourcesLoaded.containsKey(filepath)){
reference = resourcesLoaded.get(filepath);
if(reference.get() == null){
int width = resources.getDisplayMetrics().widthPixels;
int height = (int) (42*((float)(((float)width)/320.0)));
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 28;
opts.outHeight = height;
opts.inTempStorage = new byte[16*1024];
opts.outWidth = width;
opts.inPurgeable = true;
Bitmap bit = BitmapFactory.decodeFile(filepath ,opts);
reference = new SoftReference<Bitmap>(bit);
resourcesLoaded.put(filepath, reference);
}
}else{
int width = resources.getDisplayMetrics().widthPixels;
int height = (int) (42*((float)(((float)width)/320.0)));
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.outHeight = height;
opts.outWidth = width;
opts.inTempStorage = new byte[16*1024];
opts.inSampleSize = 28;
opts.inPurgeable = true;
Bitmap bit = BitmapFactory.decodeFile(filepath ,opts);
reference = new SoftReference<Bitmap>(bit);
resourcesLoaded.put(filepath, reference);
}
return reference.get();
}
And, that's the weird thing, the app doesn't even crash now. Using caching and reducing the image size seems to have eliminated that crash (at least on some of the devices I've tested on), but this strange behavior, WHICH ONLY OCCURS ONCE LOADING THE GRIDVIEW OF DEATH and then navigating away from it, persists.
On a related note, I have used some third party app on my phone to see the current memory usage of my app and, at times, it creeps up to 100MB! Every time I take a photo with the app and save it to the internal storage, the memory usage seems to jump considerably (generally starts around 30-40MB and climbs from there). So clearly, there are memory issues going on. But again, the app won't crash with a "exceeded VM budget" error. On the other hand, it's hard to ignore the obvious memory issues with the app.
I fully realize that some of my implementation is not perfect, not super memory efficient, and that using singletons to hold the ArrayList of my objects, etc might not be the greatest way to go. But even still, this behavior seems inexplicable.
To summarize: the app will load completely blank activities ONCE AND ONLY ONCE you've clicked to display the images (that are stored as JPEGs on the device) in the GridView. If you never click to use the GridView, everything is fine.
What's with the Gridview of death?
(I'm happy to provide the code for any portions you think are relevant.)
UPDATE:
Thanks #CommonsWare for all your patience and advice. Really appreciate it and it's always nice to have the unofficial Android developer advocate on the case. Turns out that using Fragments did, in fact, solve all of my problems. For a moment, I thought I had fully implemented the Fragment solution, but quickly realized that I was still "setting the content" of some base View that was loaded in my Fragment to my GridView. By creating a new framgent containing the Grid View and loading it, all problems seem to be solved and the app is now stable!
UPDATE: Well, I spoke too soon :( Apparently this GridView is still causing problems. Now when I switch to a new tab, I can see that the button I'm using for the tab was clicked, but when it calsl setCurrentTab() nothing happens. App remains frozen in the GridView screen.

Phonegap android app: the initial run behaves weirdly

Actually, I am bothering the problem of screen size of phonegap apps.
I have found a solution from this site (http://ryangillespie.com/phonegap.php).
By using javascript and the feature of css3, it works.
The code is following:
var designWidth = 480; // zoom to fit this ratio
var designHeight = 762; // not 800 b/c top bar is 38 pixels tall
var scaleChange = 1; // % change in scale from above #s
function zoomScreen() {
var docWidth = window.outerWidth;
var docHeight = window.outerHeight;
if (docWidth != designWidth) {
var scaleX = docWidth / designWidth;
var scaleY = docHeight / designHeight;
if (scaleX < scaleY) {
$('body').css('zoom', scaleX);
scaleChange = scaleX;
} else {
$('body').css('zoom', scaleY);
scaleChange = scaleY;
}
}
}
But, the problem is: it only behave correctly in the initial run. When I shut down the app and restart it, the screen size behave wrong.
There is also one more weird behavior. After I try to reload the page by
window.location.reload()
The screen size behaves correctly.
How to fix it?
This is my first post. If I miss some of the information, I would clarify.
That method might only be called when the app creates the view initially, depending on how you have the app working, there may be an 'onCreate' or 'onSurfaceCreated' method that is getting called to correctly set the changes. Then when you bring the app up again, the surface has already been created, and so that app doesn't try and re-create it and somehow it's not in the right state. If you determine that you need to reload the settings every time, have the app call that reload method in the 'onSurfaceModified', or 'onResume', or whatever, or try to figure out how the view is getting modified between runs.

Categories

Resources