Flex中,跨List实现SHIFT多选的例子

最近工作中遇到的问题,客户要求做这么个东西。还是稍微花了点时间做了个DEMO的,凭记忆回来整理出来,以供以后查阅。

方法其实很简单,就是自己写代码判断用户选的开始的位置和结束的位置,然后把中间的都选中就OK了。但是做起来,确实还是需要小心些的。

 

简单来说,这个DEMO中有3个List,但是用户会感觉在操作一个List,尤其是在多选的时候。

支持SHIFT选一段,CTRL一个一个选,以及CTRL+A选全部。

 

不废话,上代码和图~

SelectItemVO.as

================

 package
{

 // this class is used to set the data of first selection and second selection
 public class SelectItemVO
 {
  public function SelectItemVO()
  {
  }

  private var _listID:String="";

  private var _itemIndex:int=-1;


  // used to get/set item index
  public function get itemIndex():int
  {
   return _itemIndex;
  }

  public function set itemIndex(value:int):void
  {
   _itemIndex=value;
  }

  // used to get/set list id
  public function get listID():String
  {
   return _listID;
  }

  public function set listID(value:String):void
  {
   _listID=value;
  }

  // used to set value
  public function setValue(id:String, index:int):void
  {
   _listID=id;
   _itemIndex=index;
  }

  public function clean():void
  {
   _listID="";
   _itemIndex=-1;
  }
 }
}

 

ListDemo.mxml

===========

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
      xmlns:s="library://ns.adobe.com/flex/spark"
      xmlns:mx="library://ns.adobe.com/flex/mx"
      minWidth="955"
      creationComplete="init(event)"
      fontFamily="Verdana"
      minHeight="600">

 <fx:Script>
  <![CDATA[
   import mx.core.FlexGlobals;
   import mx.events.FlexEvent;

   import spark.events.IndexChangeEvent;

   // avoid hard code, always use const value is a good habit
   private const LIST:String="list";
   private const LIST1:String="list1";
   private const LIST2:String="list2";
   private const LIST3:String="list3";

   private var isCtrlDown:Boolean=false; // used to save the status of Ctrl key
   private var isShiftDown:Boolean=false; // used to save the status of Shift key
   private var valueSetFlag:Boolean=false; // used to mark wether key down or key up value set to isCtrlDown and isShiftDown already.

   private var startItem:SelectItemVO=new SelectItemVO(); // used to save the start selected item, for SHIFT - select
   private var endItem:SelectItemVO=new SelectItemVO(); // used to save the end selected item, for SHIFT - select

   // initialization
   protected function init(event:FlexEvent):void
   {
    // add global listener to handle key down / key up for CTRL and SHIFT
    FlexGlobals.topLevelApplication.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
    FlexGlobals.topLevelApplication.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);

    // add listener to lists for CTRL+A event handling
    list1.addEventListener(Event.SELECT_ALL, selectAll);
    list2.addEventListener(Event.SELECT_ALL, selectAll);
    list3.addEventListener(Event.SELECT_ALL, selectAll);
   }

   // method to set list selection from start to end
   private function selectItemFromTo(list:List, start:int, end:int):void
   {
    var selectList:Vector.<int>=new Vector.<int>();

    for (var i:int=start; i < end; i++)
    {
     selectList.push(i);
    }

    list.selectedIndices=selectList;
   }

   // method to set list selection from start to a specified index
   private function selectFromStart(list:List, index:int):void
   {
    // here, add one because the array is from 0
    // we need to add one to make sure the for-loop will run enough times to select the item you clicked
    selectItemFromTo(list, 0, index + 1);
   }

   // method to set list selection from a specified index to end
   private function selectToEnd(list:List, index:int):void
   {
    selectItemFromTo(list, index, list.dataProvider.length);
   }

   // method used to handle CTRL+A
   private function selectAll(event:Event):void
   {
    selectAllItem(list1);
    selectAllItem(list2);
    selectAllItem(list3);
   }

   // method set all items selected for a list
   private function selectAllItem(list:List):void
   {
    selectItemFromTo(list, 0, list.dataProvider.length);
   }

   // 1. when single click, clean other lists
   // 2. when SHIFT - select, clean other lists which will not in the selection range
   private function cleanSelection(list:List, doAll:Boolean=false):void
   {
    switch (list.id)
    {
     case LIST1:
      if (doAll)
      {
       list2.selectedIndex=-1;
       list3.selectedIndex=-1;
      }
      if (doAll || (startItem.listID != LIST2 && endItem.listID != LIST2))
       list2.selectedIndices=new Vector.<int>();
      if (doAll || (startItem.listID != LIST3 && endItem.listID != LIST3))
       list3.selectedIndices=new Vector.<int>();
      break;
     case LIST2:
      if (doAll)
      {
       list1.selectedIndex=-1;
       list3.selectedIndex=-1;
      }
      if (doAll || (startItem.listID != LIST1 && endItem.listID != LIST1))
       list1.selectedIndices=new Vector.<int>();
      if (doAll || (startItem.listID != LIST3 && endItem.listID != LIST3))
       list3.selectedIndices=new Vector.<int>();
      break;
     case LIST3:
      if (doAll)
      {
       list1.selectedIndex=-1;
       list2.selectedIndex=-1;
      }
      if (doAll || (startItem.listID != LIST1 && endItem.listID != LIST1))
       list1.selectedIndices=new Vector.<int>();
      if (doAll || (startItem.listID != LIST2 && endItem.listID != LIST2))
       list2.selectedIndices=new Vector.<int>();
      break;
     default:
      break;
    }
   }

   // handle user's clicking on list item (when list's select item is changing)
   protected function changingHandler(event:IndexChangeEvent):void
   {
    var list:List=event.target as List;
    if (isShiftDown) // handle SHIFT - select first
    {
     handleSHIFTSelect(list);
    }
    else if (isCtrlDown) // handle CTRL - select second
    {
     handleCTRLSelect(list);
    }
    else // handle single clicking, it's normal way in using
    {
     handleSingleClick(list);
    }
   }

   // method to handle SHIFT - select
   private function handleSHIFTSelect(list:List):void
   {
    // when handle the SHIFT - select, get end item ( second selection of range ) first
    endItem.setValue(list.id, list.selectedIndex);
    cleanSelection(list);

    // No matter select the range in UP-DOWN way or DOWN-UP way, here, change the select style to UP-DOWN
    var usedInToEndMethod:int=parseNameToID(startItem.listID) <= parseNameToID(endItem.listID) ? startItem.itemIndex : endItem.itemIndex;
    var usedInFromStartMethod:int=parseNameToID(startItem.listID) > parseNameToID(endItem.listID) ? startItem.itemIndex : endItem.itemIndex;

    // when user selects a range in same list
    if (startItem.listID == endItem.listID)
    {
     var start:int=usedInToEndMethod < usedInFromStartMethod ? usedInToEndMethod : usedInFromStartMethod;
     var end:int=usedInToEndMethod > usedInFromStartMethod ? usedInToEndMethod : usedInFromStartMethod;
     selectItemFromTo(list, start, end);
    }
    // when user selects a range between list 1 and list 2
    else if ((startItem.listID == LIST1 && endItem.listID == LIST2) || (startItem.listID == LIST2 && endItem.listID == LIST1))
    {
     selectFromStart(list2, usedInFromStartMethod);
     selectToEnd(list1, usedInToEndMethod);
    }
    // when user selects a range between list 1 and list 2
    else if ((startItem.listID == LIST1 && endItem.listID == LIST3) || (startItem.listID == LIST3 && endItem.listID == LIST1))
    {
     selectFromStart(list3, usedInFromStartMethod);
     selectAllItem(list2);
     selectToEnd(list1, usedInToEndMethod);
    }
    // when user selects a range between list 2 and list 3
    else if ((startItem.listID == LIST2 && endItem.listID == LIST3) || (startItem.listID == LIST3 && endItem.listID == LIST2))
    {
     selectFromStart(list3, usedInFromStartMethod);
     selectToEnd(list2, usedInToEndMethod);
    }
    else
    {
     // If you have other lists, terrible, try to handle all cases user selects a range from one list to another one... *_*
     // So, this is not a good Demo, but anyway, it works~ ^_^
    }
   }

   // used to get list index from a string, actually, if your list is not named in a indexable (XXX1, XXX2 ...) style
   // you may need to find a way to make sure which list is first, which one is second and so on.
   private function parseNameToID(value:String):Number
   {
    return Number(value.replace(LIST, ""));
   }

   // method to handle CTRL - select
   private function handleCTRLSelect(list:List):void
   {
    // do nothing, List will support CTRL - select by default

    // but need to set the start item ( first selection of range ), for the using in SHIFT - select
    startItem.setValue(list.id, list.selectedIndex);
   }

   // method to handle single click on list
   private function handleSingleClick(list:List):void
   {
    startItem.clean();
    endItem.clean(); // clean end item to make sure all other lists will be cleaned in following method
    cleanSelection(list, true);

    // set the start item ( first selection of range ), for the using in SHIFT - select
    startItem.setValue(list.id, list.selectedIndex);
   }

   // handle key down
   protected override function keyDownHandler(event:KeyboardEvent):void
   {
    if (!valueSetFlag) // just set the value once when key down, actually, could be removed, this flag
    {
     isCtrlDown=event.ctrlKey;
     isShiftDown=event.shiftKey;

     valueSetFlag=true;
    }
   }

   // handle key up
   protected override function keyUpHandler(event:KeyboardEvent):void
   {
    if (valueSetFlag)
    {
     isCtrlDown=event.ctrlKey;
     isShiftDown=event.shiftKey;

     valueSetFlag=false;
    }
   }
  ]]>
 </fx:Script>

 <s:VGroup width="80%"
     height="100%"
     horizontalCenter="0"
     verticalCenter="0"
     horizontalAlign="center"
     verticalAlign="middle">
  <s:Label text="List 1"
     fontSize="16"
     fontWeight="bold"
     width="70%"/>
  <s:List id="list1"
    width="70%"
    allowMultipleSelection="true"
    contentBackgroundColor="#72D9F7"
    contentBackgroundAlpha="0.75"
    changing="changingHandler(event)"
    rollOverColor="#F5F184"
    selectionColor="#F75854">
   <s:dataProvider>
    <s:ArrayCollection>
     <fx:String>List 1 - Item 1</fx:String>
     <fx:String>List 1 - Item 2</fx:String>
     <fx:String>List 1 - Item 3</fx:String>
     <fx:String>List 1 - Item 4</fx:String>
     <fx:String>List 1 - Item 5</fx:String>
     <fx:String>List 1 - Item 6</fx:String>
     <fx:String>List 1 - Item 7</fx:String>
    </s:ArrayCollection>
   </s:dataProvider>
  </s:List>
  <s:Label text="List 2"
     fontSize="16"
     fontWeight="bold"
     width="70%"/>
  <s:List id="list2"
    width="70%"
    allowMultipleSelection="true"
    contentBackgroundColor="#72D9F7"
    contentBackgroundAlpha="0.75"
    changing="changingHandler(event)"
    rollOverColor="#F5F184"
    selectionColor="#F75854">
   <s:dataProvider>
    <s:ArrayCollection>
     <fx:String>List 2 - Item 1</fx:String>
     <fx:String>List 2 - Item 2</fx:String>
     <fx:String>List 2 - Item 3</fx:String>
     <fx:String>List 2 - Item 4</fx:String>
     <fx:String>List 2 - Item 5</fx:String>
     <fx:String>List 2 - Item 6</fx:String>
     <fx:String>List 2 - Item 7</fx:String>
    </s:ArrayCollection>
   </s:dataProvider>
  </s:List>
  <s:Label text="List 3"
     fontSize="16"
     fontWeight="bold"
     width="70%"/>
  <s:List id="list3"
    width="70%"
    allowMultipleSelection="true"
    contentBackgroundColor="#72D9F7"
    contentBackgroundAlpha="0.75"
    changing="changingHandler(event)"
    rollOverColor="#F5F184"
    selectionColor="#F75854">
   <s:dataProvider>
    <s:ArrayCollection>
     <fx:String>List 3 - Item 1</fx:String>
     <fx:String>List 3 - Item 2</fx:String>
     <fx:String>List 3 - Item 3</fx:String>
     <fx:String>List 3 - Item 4</fx:String>
     <fx:String>List 3 - Item 5</fx:String>
     <fx:String>List 3 - Item 6</fx:String>
     <fx:String>List 3 - Item 7</fx:String>
    </s:ArrayCollection>
   </s:dataProvider>
  </s:List>
 </s:VGroup>
</s:Application>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值