Flex【原创】移动设备相册图片浏览功能
Flex实现移动设备相册图片浏览功能
Flex4.6(IOS/Android)
首先贴上代码结构图:
分析2个重要视图:
1:ScanListView 作为firstView,用List呈现一个相片列表
View Code
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="照片列表"
creationComplete="creationCompleteHandler(event)">
<fx:Declarations>
<s:ArrayCollection id="imgdata">
<fx:Object source="assets/images/1.jpg" message="assets/images/1.jpg" name="sample1"/>
<fx:Object source="assets/images/3.jpg" message="assets/images/2.jpg" name="sample2"/>
<fx:Object source="assets/images/4.jpg" message="assets/images/3.jpg" name="sample3"/>
<fx:Object source="assets/images/5.jpg" message="assets/images/4.jpg" name="sample4"/>
<fx:Object source="assets/images/6.jpg" message="assets/images/5.jpg" name="sample5"/>
<fx:Object source="assets/images/7.jpg" message="assets/images/6.jpg" name="sample6"/>
<fx:Object source="assets/images/8.jpg" message="assets/images/7.jpg" name="sample7"/>
<fx:Object source="assets/images/9.jpg" message="assets/images/8.jpg" name="sample8"/>
<fx:Object source="assets/images/10.jpg" message="assets/images/9.jpg" name="sample9"/>
<fx:Object source="assets/images/11.jpg" message="assets/images/10.jpg" name="sample10"/>
<fx:Object source="assets/images/12.jpg" message="assets/images/11.jpg" name="sample11"/>
<fx:Object source="assets/images/13.jpg" message="assets/images/12.jpg" name="sample12"/>
<fx:Object source="assets/images/14.jpg" message="assets/images/13.jpg" name="sample13"/>
<fx:Object source="assets/images/15.jpg" message="assets/images/14.jpg" name="sample14"/>
<fx:Object source="assets/images/17.jpg" message="assets/images/16.jpg" name="sample15"/>
<fx:Object source="assets/images/18.jpg" message="assets/images/17.jpg" name="sample16"/>
<fx:Object source="assets/images/19.jpg" message="assets/images/18.jpg" name="sample17"/>
<fx:Object source="assets/images/20.jpg" message="assets/images/19.jpg" name="sample18"/>
</s:ArrayCollection>
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.yyf.model.MainModelLocator;
import mx.events.FlexEvent;
[Bindable]private var mainModel:MainModelLocator = MainModelLocator.getInstance();
protected function creationCompleteHandler(event:FlexEvent):void
{
mainModel.dataProvider = imgdata;
}
protected function list_clickHandler(event:MouseEvent):void
{
mainModel.selectedIndex = imgList.selectedIndex;
navigator.pushView(ScanTabView ,null,null,mainModel.xFadeTrans);
}
]]>
</fx:Script>
<s:List id="imgList" dataProvider="{mainModel.dataProvider}" width="100%" height="100%"
horizontalScrollPolicy="off" verticalScrollPolicy="on"
click="list_clickHandler(event)">
<s:layout>
<!--<s:TileLayout columnWidth="{this.width / 3}" rowHeight="{this.width / 3}" horizontalGap="0" verticalGap="0"/>-->
<s:VerticalLayout gap="0" horizontalAlign="center" verticalAlign="middle"/>
</s:layout>
<s:itemRenderer>
<fx:Component>
<!-- <s:ItemRenderer
mouseDown="sc.color = 0xFED913"
mouseUp="sc.color = 0x030303"
mouseOut="sc.color = 0x030303">
<s:Rect top="0" bottom="0" left="0" right="0">
<s:fill>
<s:SolidColor id="sc" color="0x030303"/>
</s:fill>
</s:Rect>
<s:BitmapImage source="{data.source}" width="90%" height="90%" horizontalCenter="0" verticalCenter="0"/>
</s:ItemRenderer>-->
<s:IconItemRenderer iconWidth="80" iconHeight="80" width="100%"
messageField="message" messageStyleName="articleFontStyle"
iconField="source" labelField="name"
decorator="@Embed(source='/assets/icons/sanjiao.png')">
</s:IconItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:View>
2: ScanTabView 点击List的子元素进入手势左右切换浏览相片视图
View Code
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
title="{mainModel.controlType == Config.IMAGE_TAB ? '照片列表' : '详细信息'}"
xmlns:scan="com.yyf.view.scan.*"
removedFromStage="removedFromStageHandler(event)">
<fx:Script>
<![CDATA[
import com.yyf.model.MainModelLocator;
import com.yyf.util.Config;
import mx.events.FlexEvent;
[Bindable]private var mainModel:MainModelLocator = MainModelLocator.getInstance();
protected function acbtn_clickHandler(event:MouseEvent):void
{
switch(mainModel.controlType)
{
case Config.IMAGE_TAB :
mainModel.controlType = Config.IMAGE_DETAIL;
sv.removeTabEventListeners();
sv.imgG.addGestureEventListeners();
sv.reset();
break;
case Config.IMAGE_DETAIL :
mainModel.controlType = Config.IMAGE_TAB;
sv.addTabEventListeners();
sv.imgG.removeGestureEventListeners();
sv.reset();
break;
default :
break;
}
}
protected function removedFromStageHandler(event:Event):void
{
mainModel.controlType = Config.IMAGE_TAB;
sv.imgG.removeGestureEventListeners();
sv.addTabEventListeners();
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:actionContent>
<s:Button id="acbtn" label="{mainModel.controlType == Config.IMAGE_TAB ? '操作' : '返回'}" click="acbtn_clickHandler(event)"/>
<s:Button id="backbtn" label="返回" click="navigator.popView(mainModel.xFadeTrans);"
includeInLayout="{mainModel.controlType == Config.IMAGE_TAB ? true : false}"
visible="{mainModel.controlType == Config.IMAGE_TAB ? true : false}"/>
</s:actionContent>
<scan:ScanView id="sv" width="100%" height="100%" dataProvider="{mainModel.dataProvider}" selectedIndex="{mainModel.selectedIndex}"/>
</s:View>
分析2个重要组件:
1:ScanView 呈现照片的容器 封装手势左右切换相片的相关事件
View Code
<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:scan="com.yyf.view.scan.*"
creationComplete="view_creationCompleteHandler(event)"
mouseEnabled="{active}"
enabled="{active}">
<fx:Declarations>
<s:Fade id="imgFade" target="{imgG}" alphaFrom="0.0" alphaTo="1.0"/>
<s:Fade id="focusIn" target="{pageNotice}" alphaFrom="0.0" alphaTo="1.0"/>
<s:Fade id="focusOut" target="{pageNotice}" alphaFrom="1.0" alphaTo="0.0"/>
<s:Image id="pageNotice" buttonMode="true" click="pagePrompt_clickHandler(event)" filters="{[dropShadow]}"/>
<s:DropShadowFilter id="dropShadow" alpha="0.8" blurX="8" blurY="8" distance="0" color="#030303" angle="360" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.yyf.model.MainModelLocator;
import com.yyf.util.Config;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
[Bindable]
[Embed(source="assets/icons/firstPage.png")]
private var firsttImgClass:Class;
[Bindable]
[Embed(source="assets/icons/lastPage.png")]
private var lastImgClass:Class;
[Bindable]public var dataProvider:ArrayCollection;
[Bindable]public var selectedIndex:int = 0;
[Bindable]private var active:Boolean = true;
private var runing:Boolean = false;
private var oldPoint:Point;
private const movePrecision:Number=30;//滑动翻页精度
[Bindable]private var mainModel:MainModelLocator = MainModelLocator.getInstance();
protected function view_creationCompleteHandler(event:FlexEvent):void
{
this.imgG.imgMaxWidth = this.width - 15;
this.imgG.imgMaxHeight = this.height - 10;
addTabEventListeners();
}
public function addTabEventListeners():void
{
if(!this.hasEventListener(MouseEvent.MOUSE_MOVE))
this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
if(!this.hasEventListener(MouseEvent.MOUSE_UP))
this.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
public function removeTabEventListeners():void
{
if(this.hasEventListener(MouseEvent.MOUSE_MOVE))
this.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
if(this.hasEventListener(MouseEvent.MOUSE_UP))
this.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
protected function mouseMoveHandler(event:MouseEvent):void
{
if(event.buttonDown&&!runing){
runing = true;
oldPoint = new Point(event.stageX,event.stageY);
this.mouseChildren = false;
}
}
protected function mouseUpHandler(event:MouseEvent):void
{
if(runing){
this.mouseChildren = true;
runing = false;
if((event.stageX - oldPoint.x) > movePrecision){//right
prev();
}else if((event.stageX - oldPoint.x) < movePrecision){//left
next();
}
}
}
private function prev():void{
if(selectedIndex == 0)
{
selectedIndex = 0;
active = false;
mblbl.visible = true;
pageNotice.source = firsttImgClass;
PopUpManager.addPopUp(pageNotice,this);
PopUpManager.centerPopUp(pageNotice);
focusIn.end();
focusIn.play();
return;
}
selectedIndex--;
imgFade.end();
imgFade.play();
}
private function next():void{
if(selectedIndex == dataProvider.length - 1)
{
selectedIndex = dataProvider.length - 1;
active = false;
mblbl.visible = true;
pageNotice.source = lastImgClass;
PopUpManager.addPopUp(pageNotice,this);
PopUpManager.centerPopUp(pageNotice);
focusIn.end();
focusIn.play();
return;
}
selectedIndex++;
imgFade.end();
imgFade.play();
}
protected function pagePrompt_clickHandler(event:MouseEvent):void
{
active = true;
focusOut.end();
focusOut.play();
pageNotice.source = null;
mblbl.visible = false;
}
public function reset():void{
imgG.scaleX = 1.0;
imgG.scaleY = 1.0;
imgG.rotation = 0;
}
]]>
</fx:Script>
<scan:ImageView id="imgG" source="{dataProvider.getItemAt(selectedIndex).source}" maxScale="3.0" minScale="0.5"/>
<!--show button when turn page to the last or first one-->
<s:Label id="mblbl" width="100%" height="100%" visible="false"/>
</s:SkinnableContainer>
2: ImageView 照片组件 封装对相片操作:缩放,旋转,平移的相关事件
View Code
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
x="{img.x - 3}" y="{img.y - 3}"
width="{img.width + 6}" height="{img.height + 6}"
horizontalCenter="0" verticalCenter="0">
<fx:Script>
<![CDATA[
import com.yyf.model.MainModelLocator;
import com.yyf.util.Config;
import com.yyf.util.RotatableScalable;
import mx.events.FlexEvent;
import org.tuio.TuioManager;
import org.tuio.adapters.NativeTuioAdapter;
import org.tuio.gestures.DragGesture;
import org.tuio.gestures.GestureManager;
import org.tuio.gestures.RotateGesture;
import org.tuio.gestures.TwoFingerMoveGesture;
import org.tuio.gestures.ZoomGesture;
[Bindable]public var source:* = null;
[Bindable]public var imgMaxWidth:Number;
[Bindable]public var imgMaxHeight:Number;
public var minScale:Number = 0.8;
public var maxScale:Number = 3.0;
private var imgDragEnable:Boolean = false;
[Bindable]private var mainModel:MainModelLocator = MainModelLocator.getInstance();
protected function addedToStageHandler(event:Event):void
{
if(mainModel.gestureManagerInit)return;
var tc:NativeTuioAdapter = new NativeTuioAdapter(stage);
tc.addListener(TuioManager.init(stage));
var tm:GestureManager = GestureManager.init(stage);
addGestureManager();
mainModel.gestureManagerInit = true;
}
protected function addGestureManager():void
{
GestureManager.addGesture(new DragGesture());
GestureManager.addGesture(new ZoomGesture(TwoFingerMoveGesture.TRIGGER_MODE_TOUCH));
GestureManager.addGesture(new RotateGesture(TwoFingerMoveGesture.TRIGGER_MODE_TOUCH));
}
public function addGestureEventListeners():void
{
if(!this.hasEventListener(TransformGestureEvent.GESTURE_PAN))
this.addEventListener(TransformGestureEvent.GESTURE_PAN, handleDrag);
if(!this.hasEventListener(TransformGestureEvent.GESTURE_ZOOM))
this.addEventListener(TransformGestureEvent.GESTURE_ZOOM, handleScale);
if(!this.hasEventListener(TransformGestureEvent.GESTURE_ROTATE))
this.addEventListener(TransformGestureEvent.GESTURE_ROTATE, handleRotate);
this.horizontalCenter = this.verticalCenter = undefined;
fadeIn.end();
fadeIn.play();
}
public function removeGestureEventListeners():void
{
if(this.hasEventListener(TransformGestureEvent.GESTURE_PAN))
this.removeEventListener(TransformGestureEvent.GESTURE_PAN, handleDrag);
if(this.hasEventListener(TransformGestureEvent.GESTURE_ZOOM))
this.removeEventListener(TransformGestureEvent.GESTURE_ZOOM, handleScale);
if(this.hasEventListener(TransformGestureEvent.GESTURE_ROTATE))
this.removeEventListener(TransformGestureEvent.GESTURE_ROTATE, handleRotate);
this.horizontalCenter = this.verticalCenter = 0;
}
private function handleScale(e:TransformGestureEvent):void {
var p:Point = this.localToGlobal(new Point(e.localX, e.localY));
p = parent.globalToLocal(p);
var m:Matrix = this.transform.matrix;
m.translate( -p.x, -p.y);
m.scale(e.scaleX, e.scaleY);
m.translate(p.x, p.y);
this.transform.matrix = m;
if (this.scaleX > maxScale) {
m = this.transform.matrix;
m.translate( -p.x, -p.y);
m.scale(maxScale/this.scaleX, maxScale/this.scaleY);
m.translate(p.x, p.y);
this.transform.matrix = m;
} else if (this.scaleX < minScale) {
m = this.transform.matrix;
m.translate( -p.x, -p.y);
m.scale(minScale/this.scaleX, minScale/this.scaleY);
m.translate(p.x, p.y);
this.transform.matrix = m;
}
}
private function handleRotate(e:TransformGestureEvent):void {
var p:Point = this.localToGlobal(new Point(e.localX, e.localY));
p = parent.globalToLocal(p);
var m:Matrix = this.transform.matrix;
m.translate(-p.x, -p.y);
m.rotate(e.rotation * (Math.PI / 180));
m.translate(p.x, p.y);
this.transform.matrix = m;
}
private function handleDrag(e:TransformGestureEvent):void {
this.x += e.offsetX;
this.y += e.offsetY;
}
private function stopImgDrag():void{
if(!this.hasEventListener(TransformGestureEvent.GESTURE_PAN))
{
this.addEventListener(TransformGestureEvent.GESTURE_PAN, handleDrag);
this.imgDragEnable = false;
}
}
private function startImgDrag():void{
if(this.hasEventListener(TransformGestureEvent.GESTURE_PAN))
{
this.removeEventListener(TransformGestureEvent.GESTURE_PAN, handleDrag);
this.imgDragEnable = true;
}
}
]]>
</fx:Script>
<fx:Declarations>
<s:Fade id="fadeIn" target="{boder}" alphaFrom="0.0" alphaTo="1.0"/>
</fx:Declarations>
<s:BorderContainer id="boder" left="-2" right="-2" bottom="-2" top="-2" cornerRadius="5" backgroundAlpha="0.0" visible="{mainModel.controlType == Config.IMAGE_TAB ? false : true}">
<s:borderStroke>
<s:SolidColorStroke color="0xFED913" weight="5"/>
</s:borderStroke>
</s:BorderContainer>
<s:Image id="img" source="{source}" maxWidth="{imgMaxWidth}" maxHeight="{imgMaxHeight}"
horizontalCenter="0" verticalCenter="0"
addedToStage="addedToStageHandler(event)"/>
</s:Group>
效果图:
源码下载地址:https://files.cnblogs.com/loveFlex/Sample_ScanImage.rar
请大家多多指教~