之前在開發 Flex Bottom Bleeding DataGrid 時
連帶發現 Flex DataGrid 有好幾項 Bug
經過一段時間的測試修改
終於將大部份的問題修好
特別將這些 Fix 與之前的 Bottom Bleeding DataGrid 整合在一起
本次主要修復的問題:
- DataGrid offscreenExtraRowsOrColumns Bug
- Flex DataGrid Header and Column Bgs Bug
- Header 設為透明時,Item 會露出馬腳
- 使用鍵盤捲動時,HighlightIndicator 顯示錯誤的問題
BleedingDataGrid 2 Class:
package {
import flash.display.*;
import flash.events.*;
import flash.utils.*;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.*;
import mx.controls.listClasses.*;
import mx.core.*;
import mx.events.*;
use namespace mx_internal;
public class BleedingDataGrid extends DataGrid {
protected var _bottomBleed_:int = 0;
[Bindable]
public function get bottomBleed():int{
return _bottomBleed_;
}
public function set bottomBleed(value:int):void{
_bottomBleed_ = value;
offscreenExtraRowsOrColumns = Math.ceil(Math.abs(value) / rowHeight);
// trace(value, rowHeight, offscreenExtraRowsOrColumns);
}
public function BleedingDataGrid() {
super();
}
// Force item renderer text to be masked.
override protected function createChildren():void {
super.createChildren();
listContent.blendMode = "layer";
this.addEventListener(ScrollEvent.SCROLL, adjustColumnBackground);
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
// trace("BleedingDataGrid.updateDisplayList();");
var h:int = unscaledHeight - viewMetrics.top - viewMetrics.bottom;
if (bottomBleed < 0) {
// Reduced ScrollBar Mode
super.updateDisplayList(unscaledWidth, unscaledHeight + ((h + bottomBleed <= minHeight)
? 0 : bottomBleed));
maskShape.height = h;
} else {
// Bleeding Content Mode
super.updateDisplayList(unscaledWidth, unscaledHeight);
maskShape.height = (h <= minHeight) ? h : h + bottomBleed;
}
fixSortScrollPosition();
adjustColumnBackground();
}
// From makeRowsAndColumnsWithExtraRows, fix sorting issue
public function fixSortScrollPosition():void {
var index:int = scrollPositionToIndex(horizontalScrollPosition, verticalScrollPosition - offscreenExtraRowsTop);
seekPositionSafely(index);
}
// Force column background do not overlap on header.
protected function adjustColumnBackground(evtObj:ScrollEvent = null):void {
var colBGs:FlexSprite = listContent.getChildByName("colBGs") as FlexSprite;
if (colBGs) {
if (showHeaders) {
colBGs.y = headerHeight - listContent.y + borderMetrics.top + 2;
} else {
colBGs.y = -listContent.y + borderMetrics.top;
}
}
}
// Force hide overlapping HighlightIndicator when keyboard scroll down.
override protected function drawHighlightIndicator(indicator:Sprite, x:Number, y:Number,
width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void{
super.drawHighlightIndicator(indicator, x, y, width, height, color, itemRenderer);
var topOffset:int = listContent.topOffset;
if ((y + topOffset) < 0 && (y + height + topOffset) > -headerHeight) {
indicator.visible = false;
} else {
indicator.visible = true;
}
}
override protected function adjustListContent(unscaledWidth:Number = -1, unscaledHeight:Number = -1):void {
// trace("adjustListContent();");
super.adjustListContent(unscaledWidth, unscaledHeight);
var itemClass:Class = itemRenderer["generator"];
var topOffset:int = listContent.topOffset;
var child:DisplayObject, i:int;
// Force top offscreen selectionLayer invisible
for (i = 0; i < selectionLayer.numChildren; ++i) {
child = selectionLayer.getChildAt(i);
// child.visible = (child.y < Math.abs(topOffset) && topOffset < 0) ? false : true;
// trace(child.name, child.y, topOffset, listContent.y);
if ((child.y + topOffset) < 0 && (child.y + child.height + topOffset) > -headerHeight) {
child.visible = false;
} else {
child.visible = true;
}
}
// Force top offscreen ItemRenderer invisible
for (i = 0; i < listContent.numChildren; ++i) {
child = listContent.getChildAt(i);
if (child is itemClass) {
// trace(child.y, listContent.y, headerHeight, topOffset);
// Warning, use visible property will cause item position disorder!
child.alpha = (child.y < Math.abs(topOffset) && topOffset < 0) ? 0 : 1;
// Another way to make it invisible
// child.scrollRect = (child.y < Math.abs(topOffset) && topOffset < 0) ? new Rectangle() : null;
}
}
}
// Force column background bottom bleeding.
override protected function drawColumnBackground(s:Sprite, columnIndex:int, color:uint
, column:DataGridColumn):void {
// trace("drawColumnBackground();");
// super.drawColumnBackground(s, columnIndex, color, column);
// adjustColumnBackground();
var background:Shape;
background = Shape(s.getChildByName(columnIndex.toString()));
if (!background) {
background = new FlexShape();
s.addChild(background);
background.name = columnIndex.toString();
}
var g:Graphics = background.graphics;
g.clear();
g.beginFill(color, 1);
var lastRow:Object = rowInfo[listItems.length - 1];
var columnHeader:DataGridHeader = (s.parent == lockedColumnContent) ?
DataGridHeader(lockedColumnHeader) : DataGridHeader(header);
// trace(columns[columnIndex].width);
var xx:Number = 0;
if (showHeaders) {
xx = columnHeader.rendererArray[columnIndex].x;
} else {
for (var i:Number = 0 ; i < columnIndex ; ++i) {
xx += columns[columnIndex].width;
}
}
var yy:Number = rowInfo[0].y;
// Height is usually as tall is the items in the row, but not if
// it would extend below the bottom of listContent
// var height:Number = Math.min(lastRow.y + lastRow.height, listContent.height - yy);
var height:Number = 0;
height = Math.max(lastRow.y + lastRow.height, listContent.height) + (bottomBleed > 0 ? bottomBleed : 0);
// trace(xx, yy);
// yy += headerHeight - s.parent.y + borderMetrics.top + 2;
if (showHeaders) {
g.drawRect(xx, yy, visibleColumns[columnIndex].width, height + headerHeight);
} else {
g.drawRect(xx, yy, visibleColumns[columnIndex].width, height);
}
g.endFill();
}
}
}
// Ticore's Blog - http://ticore.blogspot.com
Flex MXML 範例程式與之前差不多,就不貼上來了
底部出血 DataGrid 線上範例:
捲軸內縮 DataGrid 線上範例:
相關連結:
Flex DataGrid Header and Column Bgs Bug
DataGrid offscreenExtraRowsOrColumns Bug
Flex Bottom Bleeding DataGrid
Flex - 不規則底部形狀的 DataGrid






