【问题标题】:Is it possible to make an item in a Flex List control not selectable?是否可以使 Flex List 控件中的项目不可选?
【发布时间】:2010-01-12 21:26:29
【问题描述】:

是否可以使 List 控件中的项目不可选?如果是这样,这将如何实现?

到目前为止,我已经尝试过一件事。我所做的是使用自定义项渲染器来检查 FlexEvent.DATA_CHANGE 事件时数据属性中的值。如果未设置该值,我尝试将项目渲染器的可选择属性设置为 false。不幸的是,这似乎不起作用。

有什么想法吗?

【问题讨论】:

    标签: apache-flex actionscript-3


    【解决方案1】:

    所以我找到了自己的解决方案。它与您的相似,并且似乎可以解决问题并涵盖所有基础,除了破解向上翻页和向下翻页键。我说 hack,因为我不确定它处理 caretIndex 的增加或减少的方式与 List 控件相同。基本上它只是手动将 caretIndex 设置为下一个可选项目之前的索引,并将键码更改为简单的向上或向下。

    protected function disabledFilterFunction( data:Object ):Boolean
    {
        return ( data != null && data.data == null );
    }
    
    override protected function mouseEventToItemRenderer( event:MouseEvent ):IListItemRenderer
    {
        var item:IListItemRenderer = super.mouseEventToItemRenderer( event );
    
        if( item && item.data && disabledFilterFunction( item.data ) )
            return null;
    
        return item;
    }
    
    override protected function moveSelectionVertically( code:uint, shiftKey:Boolean, ctrlKey:Boolean ):void
    {
        var i:int;
        var newIndex:int;
    
        switch( code )
        {
            case Keyboard.UP:
                newIndex = getPreviousUnselectableIndex( caretIndex - 1 );
                break;
    
            case Keyboard.DOWN:
                newIndex = getNextUnselectableIndex( caretIndex + 1 );
                break;
    
            case Keyboard.HOME:
                newIndex = getFirstSelectableIndex();
                code = Keyboard.UP;
                break;
    
            case Keyboard.END:
                newIndex = getLastSelectableIndex();
                code = Keyboard.DOWN;
                break;
    
            case Keyboard.PAGE_UP:
            {
                newIndex = Math.max( getFirstSelectableIndex(), getPreviousUnselectableIndex( caretIndex - ( rowCount - 2 ) ) );
                code = Keyboard.UP;
                break;
            }
    
            case Keyboard.PAGE_DOWN:
            {
                newIndex = Math.min( getLastSelectableIndex(), getNextUnselectableIndex( caretIndex + ( rowCount - 1 ) ) );
                code = Keyboard.DOWN;
                break;
            }
        }
    
        if( newIndex > -1 && newIndex < collection.length )
        {
            caretIndex = newIndex;
            super.moveSelectionVertically( code, shiftKey, ctrlKey );
        }
    }
    
    private function getFirstSelectableIndex():int
    {
        var result:int = -1;
    
        for( var i:int = 0; i < collection.length; i++ )
        {
            if( !disabledFilterFunction( collection[i] ) )
            {
                result = i + 1;
                break;
            }
        }
    
        return result;
    }
    
    private function getLastSelectableIndex():int
    {
        var result:int = -1;
    
        for( var i:int = collection.length - 1; i > -1; i-- )
        {
            if( !disabledFilterFunction( collection[i] ) )
            {
                result = i - 1;
                break;
            }
        }
    
        return result;
    }
    
    private function getPreviousUnselectableIndex( startIndex:int ):int
    {
        var result:int = -1;
    
        for( var i:int = startIndex; i > -1; i-- )
        {
            if( !disabledFilterFunction( collection[i] ) )
            {
                result = i + 1;
                break;
            }
        }
    
        return result;
    }
    
    private function getNextUnselectableIndex( startIndex:int ):int
    {
        var result:int = collection.length;
    
        for( var i:int = startIndex; i < collection.length; i++ )
        {
            if( !disabledFilterFunction( collection[i] ) )
            {
                result = i - 1;
                break;
            }
        }
    
        return result;
    }
    

    【讨论】:

    • 这不行。试试 LIST 控件的属性 >>。
    【解决方案2】:

    我能够解决第一个/最后一个项目不可选择的问题,只需在 caretIndex++ 和 caretIndex 之前执行此 verticalScrollPosition++ 和 verticalScrollPosition-- (在上面迈克尔链接的示例中)。我不敢相信修复如此简单,但确实如此!

    【讨论】:

      【解决方案3】:

      我能够在ComboBox example 之后添加一个分隔符组件。这是一个去掉了渲染器逻辑并保留了可选择性逻辑的示例:

      package com.example.ui  {
      import flash.events.MouseEvent;
      import flash.ui.Keyboard;
      
      import mx.controls.List;
      import mx.controls.listClasses.IListItemRenderer;
      
      public class MyList extends List
      {
          public function MyList()
          {
              super();
          }
      
      
          /** Override mouse navigation */
          protected override function mouseEventToItemRenderer(event:MouseEvent):IListItemRenderer {
              var row:IListItemRenderer = super.mouseEventToItemRenderer(event);
      
              if (row != null && isSelectable(row.data)) {
                  return null;
              }
              return row;
          }
      
          /** Override keyboard navigation */
          protected override function moveSelectionVertically(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {
              super.moveSelectionVertically(code, shiftKey, ctrlKey);
      
              if (code == Keyboard.DOWN && isSeparatorData(selectedItem)) {
                  caretIndex++;
              }
              if (code == Keyboard.UP && isSeparatorData(selectedItem)) {
                  caretIndex--;
              }
              finishKeySelection();           
          }
      
          /**
           * Define this mechanism in a way that makes sense for your project.
           */
          protected function isSelectable(data:Object):Boolean {
              return data != null && data.hasOwnProperty("type") && data.type == "separator";
          }
      
      }
      }
      

      一种更好地处理可滚动列表和连续分隔符的替代方案(仍然不完美):

          protected override function moveSelectionVertically(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {
              super.moveSelectionVertically(code, shiftKey, ctrlKey);
      
              var newCode:uint = singleLineCode(code);
              var item:Object = selectedItem;
              var itemChanged:Boolean = true;
      
              while (!isNaN(newCode) && itemChanged && isSeparatorData(item)) {
                  super.moveSelectionVertically(newCode, shiftKey, ctrlKey);
                  itemChanged = (item === selectedItem);
                  item = selectedItem;
              }
          }
      
          private function singleLineCode(code:uint):uint {
              switch (code) {
              case Keyboard.UP:
              case Keyboard.PAGE_UP:
                  return Keyboard.UP;
                  break;
              case Keyboard.DOWN:
              case Keyboard.PAGE_DOWN:
                  return Keyboard.DOWN;
                  break;
              default:
                  return NaN;
                  break;                              
              }
              return code;
          }
      

      【讨论】:

      • 这部分有效。它似乎没有考虑到列表何时可滚动。例如,您在列表的集合/数据提供者中有 20 个项目,并且列表 rowCount(可查看的行)为 10。因此,呈现了一个滚动条。然后让我们说您的集合中的索引 9(第一次查看列表时最后一个可见的行项目)是一个分隔符。如果使用箭头键在列表中向下移动,则索引 9 处的分隔符将被列表选中。
      • 很好——到目前为止,我们还没有在可滚动列表中使用它。它也没有处理连续的分隔符(不太可能用于分隔符的使用,但用于合理的不可选择的使用)。仍然不能很好地处理不可选择的第一个/最后一个项目。可以说 ListBase 中存在一个错误——isItemSelectable() 存在并且是可覆盖的,因此键盘导航应该更好地关注其结果。
      【解决方案4】:

      只是想我会添加我的两种感觉。我想知道同样的事情(如何将列表设置为不可选择),我意识到 spark 组件数据组可以做到这一点。当然你需要使用 flex 4,但如果你是,并且想知道我是否可以将我的列表设置为不可选择,我建议使用数据组。

      【讨论】:

        【解决方案5】:

        我自己也在寻找解决方案,这就是我想出的解决方案。请注意,我使用的是火花列表。我希望有人觉得这很有帮助。

        1. 实现更改和更改的事件处理程序
        2. 将选择设置为 -1 并将 requireSelection 设置为 false,以便不选择任何内容
        3. 在构建数据提供程序时,根据需要启用/禁用项目
        4. 在更改处理程序中提供一些逻辑,以便在事件未启用或不应选择时调用“preventDefault”。

        示例:抄袭自我的实现,我在其中构建自己的项目并使用平铺布局

        <s:List id="myListView"
            itemRenderer="spark.skins.spark.DefaultComplexItemRenderer"
            horizontalCenter="0"
            verticalCenter="0"
            borderVisible="false"
            dataProvider="{myItems}"
            change="changeHandler(event)" changing="changingHandler(event)"
            requireSelection="false"
            selectedIndex="-1" >
            <s:layout>
                <s:TileLayout verticalGap="0" />
            </s:layout>
        </s:List>
        <fx:script>
            <![CDATA[
                import mx.collections.ArrayCollection;            
                import spark.events.IndexChangeEvent;
        
                [Bindable]
                public var myItems = new ArrayCollection;
        
        
                protected function startup():void {
                    // Here's where you'd build up your items if they
                    // need to be built dynamically.
                }
        
                protected function changeHandler(event:IndexChangeEvent):void
                {
                    var currentIndx:int = event.currentTarget.selectedIndex;
                    var selectedItem:UIComponent = event.currentTarget.selectedItem as UIComponent;
        
                    // Do whatever you need to do on selection here
                }
        
                protected function canMicrophoneChange(event:IndexChangeEvent):void
                {
                    var currentIndx:int = event.currentTarget.selectedIndex;
                    var selectedItem:UIComponent = event.currentTarget.selectedItem as UIComponent;
        
                    // This will cancel the select if the item was not enabled.
                    if (selectedItem.enabled == false) event.preventDefault();
                }
            ]]>
        </fx:script>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-03-29
          • 1970-01-01
          • 2022-01-01
          • 1970-01-01
          • 2014-10-14
          • 1970-01-01
          • 1970-01-01
          • 2010-11-24
          相关资源
          最近更新 更多