Fullscreen background image with Flex
I want to load an image into the background of my Flex app. However, I am wondering about a few things, and have a few contraints.
I want it to be much like the way it's done with CSS. See this example of fullscreen background images with CSS.
It is very important that there is no white-space (background colour) showing behind the image, and that the image is not stretched. This would mean some of the image would be cut off. This is absolutly fine. Actually, the first five points in the bulleted list on the linked page above are all exactly what I am after.
I am relitivly new to the Flex framework, but have a strong AS3 background. So I can do this easily with actionscript using a mask, stage.width/height, the stages RESIZE event, and a little bit of Math. But I am wondering what would be the "Flex" way of doing this?
I don't want to narrow the answers, but 开发者_开发知识库would I create my own component, that extends canvas, that I put behind all my other content? Or to I set some property of the application? Or what?
Thanks.
Here's a custom component that will fill any rectangle with an image. It will not stretch the image if the rectangle aspect ratio is not the same as the image, nor will it show white space, but rather it will clip the edges of the image. The image will be scaled. Always at least one dimension will be 100% filling the rectangle, but the other dimension will be clipped.
This is based on Flex's UIComponent, component life-cycle, and Image.
ClippedImage.as
package com.preston.www.view.background.components {
import flash.events.Event;
import flash.geom.Rectangle;
import mx.controls.Image;
import mx.core.UIComponent;
//--------------------------------------
// Events
//--------------------------------------
[Event(name="complete", type="flash.events.Event")]
public class ClippedImage extends UIComponent {
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
public function ClippedImage() {
image = new Image();
image.addEventListener(Event.COMPLETE,image_completeHandler);
addChild(image);
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
private var image:Image;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// source
//----------------------------------
public function get source():Object {
return image.source;
}
public function set source(value:Object):void {
image.source = value;
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
var imageMeasuredWidth:Number = image.measuredWidth;
var imageMeasuredHeight:Number = image.measuredHeight;
var imageAspectRatio:Number = imageMeasuredWidth / imageMeasuredHeight;
var imageWidth:Number;
var imageHeight:Number;
// try setting image according to width first
imageWidth = unscaledWidth;
imageHeight = imageWidth / imageAspectRatio;
// if a gap exists vertically, set image according to height
if (imageHeight < unscaledHeight) {
imageHeight = unscaledHeight;
imageWidth = imageAspectRatio * imageHeight;
}
image.setLayoutBoundsSize(imageWidth, imageHeight);
// set image x and y
var imagex:Number = (unscaledWidth - imageWidth) / 2;
var imagey:Number = (unscaledHeight - imageHeight) / 2;
image.setLayoutBoundsPosition(imagex, imagey);
scrollRect = new Rectangle(0, 0, unscaledWidth, unscaledHeight);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
private function image_completeHandler(event:Event):void {
dispatchEvent(event);
}
}
}
Then, in your app you just set an mxml tag for this component as follows:
<components:ClippedImage id="background" width="100%" height="100%"
source="assets/images/winery.jpg"/>
There are probably one million ways to skin this cat. One approach: in our flex application, we have a canvas behind our primary container as in
<mx:Canvas id="bgImg" width="1280" height="800" backgroundImage="assets/background.jpg" />
<containers:FlashContainer id="mainContainer">
<!-- HBoxs, VBoxes and loads of other components -->
</containers:FlashContainer>
If you like, you can bind values to the width and height and turn off the scroll bars (so they don't pop up if the image is bigger than the window. Something along the lines of:
<mx:Canvas id="bgImg" width="{someVariable}" height="{someOtherVariable}" backgroundImage="assets/background.jpg" horizontalScrollPolicy="off" verticalScrollPolicy="off" />
You could also play around with the "styleName" property, in conjunction with a Style Sheet and change other properties. As in:
<mx:Style source="/mainStyle.css"/>
<mx:Canvas id="bgImg" styleName="bgStyle" width="{someVariableOrCalculationOrFunctionCall}" height="{someOtherVariableOrCalculationOrFunctionCall}" backgroundImage="assets/background.jpg" horizontalScrollPolicy="off" verticalScrollPolicy="off" />
Where mainStyle.css is a Style Sheet with a target along the lines of:
.bgStyle
{
styleName1: styleValue1;
styleName2: styleValue2;
styleName3: styleValue3;
}
Forgive me, I don't know what styles can be set off the top of my head but they're easy to look up.
In our application, the window size is fixed and our background never needs to change size. But if it did, I would either
1) bind the canvas width/height to a simple calculation or 2) add a listener that responds to resize events and sets the bound width & height variables or 3) experiment with CSS on the canvas image and see what I can do
Note: to create a bindable variable you write something along the lines of
[Bindable]
var imageWidth:int;
or
Use the <mx:Binding>
tag
I hope all this helps or, at least, points you in the direction of help! -kg
Although this is a pure as3 solution it may get you in the right direction, this scales the image from it's point 0,0 , but wouldn't be hard to change it to scale from the center. Here is the code:
stage.align = "TL";
stage.scaleMode = "noScale";
// store original image size
var imgW:Number = img.width;
var imgH:Number = img.height;
// stage dimensions
var sW:Number = stage.stageWidth;
var sH:Number = stage.stageHeight;
resizer(null);
stage.addEventListener(Event.RESIZE, resizer);
private function resizer(e:Event):void
{
// current stage dimension
sW = stage.stageWidth;
sH = stage.stageHeight;
// check for proportions to make the resize based on right axis
if ((sW / imgW) > (sH / imgH)) {
img.width = sW;
img.height = imgH * (img.width / imgW);
} else {
img.height = sH;
img.width = imgW * (img.height / imgH);
}
// here you may want to deal with resize from center
img.x = 0;
img.y = 0;
}
For some reason you can't do this particularly easily in Flex. You could use the CSSSkin from Degrafa (http://www.degrafa.org/) to do it though, I'm sure.
Have you tried
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundImage="@Embed(source='something.jpg')"
backgroundAttachment="fixed" ...
This should place image something.jpg to background without resizing. And those "background" properties are styles, so you can put them to css.
精彩评论