2x 新版本

This commit is contained in:
o.o.c 2025-01-12 12:10:11 +08:00
parent 27a48bd270
commit d92d2222a3
4 changed files with 1108 additions and 564 deletions

View File

@ -73,18 +73,24 @@
}, },
{ {
"__id__": 5 "__id__": 5
},
{
"__id__": 8
},
{
"__id__": 12
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 8 "__id__": 16
}, },
{ {
"__id__": 9 "__id__": 17
}, },
{ {
"__id__": 10 "__id__": 18
} }
], ],
"_prefab": null, "_prefab": null,
@ -235,7 +241,7 @@
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "list", "_name": "list1",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 2 "__id__": 2
@ -258,8 +264,102 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 400, "width": 310,
"height": 600 "height": 640
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-325,
0,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": "37KB4+AFFHxrAaBW5L4Ycp"
},
{
"__type__": "62dc08kS7dIiIYJEawwSV8U",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 5
},
"_enabled": true,
"mask": true,
"scrollEnabled": true,
"wheelScrollEnabled": true,
"scrollDirection": 1,
"mode": 0,
"preloadNodesLimitPerFrame": 2,
"frameInterval": 1,
"recycleInterval": 1,
"registerCellForEditor": [
{
"__id__": 7
}
],
"registerSupplementaryForEditor": [],
"_id": "d7ZzsT1NNNuKRUYTA6KIhf"
},
{
"__type__": "_yx_editor_register_element_info",
"prefab": {
"__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8"
},
"identifier": "cell",
"comp": ""
},
{
"__type__": "cc.Node",
"_name": "list2",
"_objFlags": 0,
"_parent": {
"__id__": 2
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
}
],
"_prefab": null,
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 310,
"height": 640
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@ -293,14 +393,14 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "0783nLyzRLIb74nyA86bgq" "_id": "316iCgSztKvpYfUuRpjZpB"
}, },
{ {
"__type__": "62dc08kS7dIiIYJEawwSV8U", "__type__": "62dc08kS7dIiIYJEawwSV8U",
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 5 "__id__": 8
}, },
"_enabled": true, "_enabled": true,
"mask": true, "mask": true,
@ -313,19 +413,138 @@
"recycleInterval": 1, "recycleInterval": 1,
"registerCellForEditor": [ "registerCellForEditor": [
{ {
"__id__": 7 "__id__": 10
} }
], ],
"_id": "c6OeMxzjlE/okCBJxHaOEk" "registerSupplementaryForEditor": [
{
"__id__": 11
}
],
"_id": "6168pMrAdHy5egsiy1RWAl"
}, },
{ {
"__type__": "_yx_editor_register_cell_info", "__type__": "_yx_editor_register_element_info",
"prefab": { "prefab": {
"__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8" "__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8"
}, },
"identifier": "cell", "identifier": "cell",
"comp": "" "comp": ""
}, },
{
"__type__": "_yx_editor_register_element_info",
"prefab": {
"__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8"
},
"identifier": "supplementary",
"comp": ""
},
{
"__type__": "cc.Node",
"_name": "list3",
"_objFlags": 0,
"_parent": {
"__id__": 2
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 13
}
],
"_prefab": null,
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 310,
"height": 640
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
325,
0,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": "99jY+AojdA0YZq4ysmw84S"
},
{
"__type__": "62dc08kS7dIiIYJEawwSV8U",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 12
},
"_enabled": true,
"mask": true,
"scrollEnabled": true,
"wheelScrollEnabled": true,
"scrollDirection": 1,
"mode": 0,
"preloadNodesLimitPerFrame": 2,
"frameInterval": 1,
"recycleInterval": 1,
"registerCellForEditor": [
{
"__id__": 14
}
],
"registerSupplementaryForEditor": [
{
"__id__": 15
}
],
"_id": "4bts8zampKvaCz5ILMmZJA"
},
{
"__type__": "_yx_editor_register_element_info",
"prefab": {
"__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8"
},
"identifier": "cell",
"comp": ""
},
{
"__type__": "_yx_editor_register_element_info",
"prefab": {
"__uuid__": "8fa9c17d-2552-411c-9848-7b16bf0208a8"
},
"identifier": "supplementary",
"comp": ""
},
{ {
"__type__": "cc.Canvas", "__type__": "cc.Canvas",
"_name": "", "_name": "",
@ -378,9 +597,6 @@
"__id__": 2 "__id__": 2
}, },
"_enabled": true, "_enabled": true,
"listComp": {
"__id__": 6
},
"_id": "560cKL+1lFIZFZSgoBz8At" "_id": "560cKL+1lFIZFZSgoBz8At"
} }
] ]

View File

@ -10,50 +10,115 @@ import { YXTableLayout } from "../lib/yx-table-layout";
const { ccclass, property } = cc._decorator; const { ccclass, property } = cc._decorator;
class Data {
id: number
}
@ccclass @ccclass
export default class NewClass extends cc.Component { export default class NewClass extends cc.Component {
@property(YXCollectionView)
listComp: YXCollectionView = null
testData: Data[] = []
protected start(): void { protected start(): void {
this.setup_list1()
this.setup_list2()
this.setup_list3()
}
// 绑定数据源 setup_list1() {
this.listComp.numberOfItems = () => this.testData.length const listComp = this.node.getChildByName('list1').getComponent(YXCollectionView)
this.listComp.cellForItemAt = (indexPath, collectionView) => {
const rowData = this.testData[indexPath.item] listComp.numberOfItems = () => 10000
listComp.cellForItemAt = (indexPath, collectionView) => {
const cell = collectionView.dequeueReusableCell(`cell`) const cell = collectionView.dequeueReusableCell(`cell`)
cell.getChildByName('label').getComponent(cc.Label).string = `${indexPath}` cell.getChildByName('label').getComponent(cc.Label).string = `${indexPath}`
return cell return cell
} }
// 确定布局方案
let layout = new YXTableLayout() let layout = new YXTableLayout()
layout.spacing = 20 layout.spacing = 20
layout.itemSize = new cc.Size(400, 100) layout.rowHeight = 100
this.listComp.layout = layout listComp.layout = layout
this.receivedData() listComp.reloadData()
} }
/** setup_list2() {
* const listComp = this.node.getChildByName('list2').getComponent(YXCollectionView)
*/
receivedData() { listComp.numberOfSections = () => 100
this.testData = [] listComp.supplementaryForItemAt = (indexPath, collectionView, kinds) => {
for (let index = 0; index < 1000; index++) { if (kinds === YXTableLayout.SupplementaryKinds.HEADER) {
let data = new Data() const supplementary = collectionView.dequeueReusableSupplementary('supplementary')
data.id = index supplementary.getChildByName('label').getComponent(cc.Label).string = `header ${indexPath}`
this.testData.push(data) const shape = supplementary.getChildByName('shape')
shape.color = new cc.Color(100, 100, 150)
return supplementary
}
if (kinds === YXTableLayout.SupplementaryKinds.FOOTER) {
const supplementary = collectionView.dequeueReusableSupplementary('supplementary')
supplementary.getChildByName('label').getComponent(cc.Label).string = `footer ${indexPath}`
const shape = supplementary.getChildByName('shape')
shape.color = new cc.Color(150, 100, 100)
return supplementary
}
return null
} }
// 刷新列表 listComp.numberOfItems = () => 20
this.listComp.reloadData() listComp.cellForItemAt = (indexPath, collectionView) => {
const cell = collectionView.dequeueReusableCell(`cell`)
cell.getChildByName('label').getComponent(cc.Label).string = `${indexPath}`
return cell
}
let layout = new YXTableLayout()
layout.spacing = 20
layout.top = 20
layout.bottom = 20
layout.rowHeight = 100
layout.sectionHeaderHeight = 120
layout.sectionFooterHeight = 120
listComp.layout = layout
listComp.reloadData()
}
setup_list3() {
const listComp = this.node.getChildByName('list3').getComponent(YXCollectionView)
listComp.numberOfSections = () => 100
listComp.supplementaryForItemAt = (indexPath, collectionView, kinds) => {
if (kinds === YXTableLayout.SupplementaryKinds.HEADER) {
const supplementary = collectionView.dequeueReusableSupplementary('supplementary')
supplementary.getChildByName('label').getComponent(cc.Label).string = `header ${indexPath}`
const shape = supplementary.getChildByName('shape')
shape.color = new cc.Color(100, 100, 150)
return supplementary
}
if (kinds === YXTableLayout.SupplementaryKinds.FOOTER) {
const supplementary = collectionView.dequeueReusableSupplementary('supplementary')
supplementary.getChildByName('label').getComponent(cc.Label).string = `footer ${indexPath}`
const shape = supplementary.getChildByName('shape')
shape.color = new cc.Color(150, 100, 100)
return supplementary
}
return null
}
listComp.numberOfItems = () => 20
listComp.cellForItemAt = (indexPath, collectionView) => {
const cell = collectionView.dequeueReusableCell(`cell`)
cell.getChildByName('label').getComponent(cc.Label).string = `${indexPath}`
return cell
}
let layout = new YXTableLayout()
layout.spacing = 20
layout.top = 20
layout.bottom = 20
layout.rowHeight = 100
layout.sectionHeaderHeight = 120
layout.sectionFooterHeight = 120
layout.sectionHeadersPinToVisibleBounds = true
layout.sectionFootersPinToVisibleBounds = true
listComp.layout = layout
listComp.reloadData()
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,114 +1,349 @@
import { YXBinaryLayout, YXCollectionView, YXIndexPath, YXLayoutAttributes } from "./yx-collection-view"; import { YXCollectionView, YXIndexPath, YXLayout, YXLayoutAttributes } from "./yx-collection-view";
enum _yx_table_layout_supplementary_kinds {
enum _yx_table_layout_alignment { HEADER = 'header',
FOOTER = 'footer',
/**
*
*/
CENTER,
/**
*
*/
LEFT,
/**
*
*/
RIGHT,
} }
/** export class YXTableLayout extends YXLayout {
* table view
*
* -
* -
* -
* -
* -
* - /
*/
export class YXTableLayout extends YXBinaryLayout {
/** /**
* *
*/ */
itemSize: cc.Size | ((indexPath: YXIndexPath, layout: YXTableLayout, collectionView: YXCollectionView) => cc.Size) = new cc.Size(100, 100) rowHeight: number | ((indexPath: YXIndexPath) => number) = 100
/** /**
* *
*/
spacing: number = 0
/**
*
*/ */
top: number = 0 top: number = 0
/** /**
* *
*/ */
bottom: number = 0 bottom: number = 0
/** /**
* *
*/ */
alignment: _yx_table_layout_alignment = YXTableLayout.Alignment.CENTER spacing: number = 0
static Alignment = _yx_table_layout_alignment
/**
*
*/
sectionHeaderHeight: number | ((section: number) => number) = null
/**
*
*/
sectionFooterHeight: number | ((section: number) => number) = null
/**
* header ( header )
*/
sectionHeadersPinToVisibleBounds: boolean = false
/**
* footer ( footer )
*/
sectionFootersPinToVisibleBounds: boolean = false
/**
* /
*/
static SupplementaryKinds = _yx_table_layout_supplementary_kinds
protected originalHeaderRect: Map<number, cc.Rect> = new Map() // 保存所有 header 的原始位置
protected originalFooterRect: Map<number, cc.Rect> = new Map() // 保存所有 footer 的原始位置
// 为了优化查找,额外维护几个数组按类别管理所有的布局属性,空间换时间
protected allCellAttributes: YXLayoutAttributes[] = []
protected allHeaderAttributes: YXLayoutAttributes[] = []
protected allFooterAttributes: YXLayoutAttributes[] = []
prepare(collectionView: YXCollectionView): void { prepare(collectionView: YXCollectionView): void {
// 设置列表的滚动方向 // 设置列表的滚动方向(这套布局固定为垂直方向滚动)
if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.HORIZONTAL) {
cc.warn(`YXTableLayout 只支持垂直方向排列`)
}
collectionView.scrollView.horizontal = false collectionView.scrollView.horizontal = false
collectionView.scrollView.vertical = true collectionView.scrollView.vertical = true
if (collectionView.scrollDirection === YXCollectionView.ScrollDirection.HORIZONTAL) {
let contentSize = collectionView.node.getContentSize() // 由于这套布局规则只支持垂直方向布局,当外部配置了水平方向滚动时这里可以给个警告
let attrs = [] cc.warn(`YXTableLayout 仅支持垂直方向排列`)
let maxY = this.top
// 获取列表内一共需要展示多少数据
let numberOfItems = collectionView.getNumberOfItems(0)
for (let row = 0; row < numberOfItems; row++) {
// 生成对应的 indexPath并通过 indexPath 获取节点大小
// 这里是不支持分区所以不考虑 section 的情况section 默认就是 0支持的分区的情况可以回头看 flow-layout 的实现
let indexPath = new YXIndexPath(0, row)
let itemSize = this.itemSize instanceof Function ? this.itemSize(indexPath, this, collectionView) : this.itemSize
// 生成布局属性对象,并按照 table view 的规则确定好节点的位置
let attributes = new YXLayoutAttributes(indexPath)
attributes.frame = new cc.Rect()
attributes.frame.size = itemSize
attributes.frame.y = maxY + (row > 0 ? this.spacing : 0)
attributes.frame.x = 0
if (this.alignment == _yx_table_layout_alignment.RIGHT) {
attributes.frame.x = (contentSize.width - attributes.frame.width)
}
if (this.alignment == _yx_table_layout_alignment.CENTER) {
attributes.frame.x = (contentSize.width - attributes.frame.width) * 0.5
}
attrs.push(attributes)
maxY = attributes.frame.yMax
} }
maxY += this.bottom // 清空一下布局属性数组
this.attributes = []
this.allCellAttributes = []
this.allHeaderAttributes = []
this.allFooterAttributes = []
this.originalHeaderRect.clear()
this.originalFooterRect.clear()
// 保存起来给列表组件使用 // 获取列表宽度
this.attributes = attrs const contentWidth = collectionView.node.width
// 确定滚动范围的总大小 // 声明一个临时变量,用来记录当前所有内容的总高度
contentSize.height = Math.max(contentSize.height, maxY) let contentHeight = 0
this.contentSize = contentSize
// 获取列表一共分多少个区
let numberOfSections = collectionView.getNumberOfSections()
// 为每条数据对应的生成一个布局属性
for (let section = 0; section < numberOfSections; section++) {
// 创建一个区索引
let sectionIndexPath = new YXIndexPath(section, 0)
// 通过区索引创建一个区头节点布局属性
let sectionHeaderHeight = 0
if (this.sectionHeaderHeight) {
sectionHeaderHeight = this.sectionHeaderHeight instanceof Function ? this.sectionHeaderHeight(section) : this.sectionHeaderHeight
}
if (sectionHeaderHeight > 0) {
let headerAttr = YXLayoutAttributes.layoutAttributesForSupplementary(sectionIndexPath, YXTableLayout.SupplementaryKinds.HEADER)
// 确定这个节点的位置
headerAttr.frame.x = 0
headerAttr.frame.width = contentWidth
headerAttr.frame.height = sectionHeaderHeight
headerAttr.frame.y = contentHeight
// 调整层级
headerAttr.zIndex = 1
// 重要: 保存布局属性
this.attributes.push(headerAttr)
this.originalHeaderRect.set(section, headerAttr.frame.clone())
this.allHeaderAttributes.push(headerAttr)
// 更新整体内容高度
contentHeight = headerAttr.frame.yMax
}
// 将 top 配置应用到每个区
contentHeight = contentHeight + this.top
// 获取这个区内的内容数量,注意这里传入的是 section
let numberOfItems = collectionView.getNumberOfItems(section)
for (let item = 0; item < numberOfItems; item++) {
// 创建索引,注意这里的 section 已经改为正确的 section 了
let indexPath = new YXIndexPath(section, item)
// 通过索引创建一个 cell 节点的布局属性
let attr = YXLayoutAttributes.layoutAttributesForCell(indexPath)
// 通过索引获取这个节点的高度
let rowHeight = this.rowHeight instanceof Function ? this.rowHeight(indexPath) : this.rowHeight
// 确定这个节点的位置
attr.frame.x = 0
attr.frame.width = contentWidth
attr.frame.height = rowHeight
attr.frame.y = contentHeight + (item > 0 ? this.spacing : 0)
// 重要: 保存布局属性
this.attributes.push(attr)
this.allCellAttributes.push(attr)
// 更新当前内容高度
contentHeight = attr.frame.yMax
}
// 高度补一个底部间距,跟 top 一样,也是应用到每个区
contentHeight = contentHeight + this.bottom
// 通过区索引创建一个区尾节点布局属性
let sectionFooterHeight = 0
if (this.sectionFooterHeight) {
sectionFooterHeight = this.sectionFooterHeight instanceof Function ? this.sectionFooterHeight(section) : this.sectionFooterHeight
}
if (sectionFooterHeight > 0) {
let footerAttr = YXLayoutAttributes.layoutAttributesForSupplementary(sectionIndexPath, YXTableLayout.SupplementaryKinds.FOOTER)
// 确定这个节点的位置
footerAttr.frame.x = 0
footerAttr.frame.width = contentWidth
footerAttr.frame.height = sectionFooterHeight
footerAttr.frame.y = contentHeight
// 调整层级
footerAttr.zIndex = 1
// 重要: 保存布局属性
this.attributes.push(footerAttr)
this.originalFooterRect.set(section, footerAttr.frame.clone())
this.allFooterAttributes.push(footerAttr)
// 更新整体内容高度
contentHeight = footerAttr.frame.yMax
}
}
// 重要: 设置内容区域总大小,只有确定了滚动区域的大小列表才能滚动
this.contentSize = new cc.Size(contentWidth, contentHeight)
} }
initOffset(collectionView: YXCollectionView): void { initOffset(collectionView: YXCollectionView): void {
// 首次更新数据,滚动至列表顶部 // 列表首次刷新时,调整一下列表的偏移位置
collectionView.scrollView.scrollToTop() collectionView.scrollView.scrollToTop()
} }
layoutAttributesForElementsInRect(rect: cc.Rect, collectionView: YXCollectionView): YXLayoutAttributes[] {
let result = this.visibleElementsInRect(rect, collectionView)
if (this.sectionHeadersPinToVisibleBounds == false && this.sectionFootersPinToVisibleBounds == false) {
return result // 不需要调整节点位置,直接返回就好
}
let numberOfSections = collectionView.getNumberOfSections()
let scrollOffset = collectionView.scrollView.getScrollOffset()
for (let index = 0; index < result.length; index++) {
const element = result[index];
if (element.elementCategory === 'Supplementary') {
if (this.sectionHeadersPinToVisibleBounds && element.supplementaryKinds === YXTableLayout.SupplementaryKinds.HEADER) {
const originalFrame = this.originalHeaderRect.get(element.indexPath.section)
element.frame.y = originalFrame.y
if (scrollOffset.y > originalFrame.y) {
element.frame.y = scrollOffset.y
}
const nextOriginalFrame = this.getNextOriginalFrame(element.indexPath.section, YXTableLayout.SupplementaryKinds.FOOTER, numberOfSections)
if (nextOriginalFrame) {
if (element.frame.yMax > nextOriginalFrame.y) {
element.frame.y = nextOriginalFrame.y - element.frame.height
}
}
}
if (this.sectionFootersPinToVisibleBounds && element.supplementaryKinds === YXTableLayout.SupplementaryKinds.FOOTER) {
let bottom = scrollOffset.y + collectionView.scrollView.node.height
const originalFrame = this.originalFooterRect.get(element.indexPath.section)
const previousOriginalFrame = this.getPreviousOriginalFrame(element.indexPath.section, YXTableLayout.SupplementaryKinds.HEADER)
element.frame.y = originalFrame.y
if (bottom < originalFrame.yMax) {
element.frame.y = bottom - element.frame.height
if (previousOriginalFrame) {
if (element.frame.y < previousOriginalFrame.yMax) {
element.frame.y = previousOriginalFrame.yMax
}
}
}
}
}
}
return result
}
shouldUpdateAttributesZIndex(): boolean {
return this.sectionHeadersPinToVisibleBounds || this.sectionFootersPinToVisibleBounds
}
shouldUpdateAttributesForBoundsChange(): boolean {
return this.sectionHeadersPinToVisibleBounds || this.sectionFootersPinToVisibleBounds
}
/**
* `section` header footer
*/
protected getNextOriginalFrame(section: number, kinds: _yx_table_layout_supplementary_kinds, total: number) {
if (section >= total) { return null }
if (kinds === YXTableLayout.SupplementaryKinds.HEADER) {
let result = this.originalHeaderRect.get(section)
if (result) { return result }
return this.getNextOriginalFrame(section, YXTableLayout.SupplementaryKinds.FOOTER, total)
}
if (kinds === YXTableLayout.SupplementaryKinds.FOOTER) {
let result = this.originalFooterRect.get(section)
if (result) { return result }
return this.getNextOriginalFrame(section + 1, YXTableLayout.SupplementaryKinds.HEADER, total)
}
return null
}
/**
* `section` header footer
*/
protected getPreviousOriginalFrame(section: number, kinds: _yx_table_layout_supplementary_kinds) {
if (section < 0) { return null }
if (kinds === YXTableLayout.SupplementaryKinds.HEADER) {
let result = this.originalHeaderRect.get(section)
if (result) { return result }
return this.getPreviousOriginalFrame(section - 1, YXTableLayout.SupplementaryKinds.FOOTER)
}
if (kinds === YXTableLayout.SupplementaryKinds.FOOTER) {
let result = this.originalFooterRect.get(section)
if (result) { return result }
return this.getPreviousOriginalFrame(section, YXTableLayout.SupplementaryKinds.HEADER)
}
return null
}
/**
*
* @see YXLayout.layoutAttributesForElementsInRect
*
*/
protected visibleElementsInRect(rect: cc.Rect, collectionView: YXCollectionView) {
if (this.attributes.length <= 100) { return this.attributes } // 少量数据就不查了,直接返回全部
let result: YXLayoutAttributes[] = []
// header 跟 footer 暂时不考虑,数据相对来说不算很多,直接全部返回
result.push(...this.allHeaderAttributes)
result.push(...this.allFooterAttributes)
// 关于 cell这里用二分查找来优化一下
// 首先通过二分先查出个大概位置
let midIdx = -1
let left = 0
let right = this.allCellAttributes.length - 1
while (left <= right && right >= 0) {
let mid = left + (right - left) / 2
mid = Math.floor(mid)
let attr = this.allCellAttributes[mid]
if (rect.intersects(attr.frame)) {
midIdx = mid
break
}
if (rect.yMax < attr.frame.yMin || rect.xMax < attr.frame.xMin) {
right = mid - 1
} else {
left = mid + 1
}
}
// 二分查找出错了,返回全部的布局属性
if (midIdx < 0) {
return this.attributes
}
// 把模糊查到这个先加进来
result.push(this.allCellAttributes[midIdx])
// 然后依次往前检查,直到超出当前的显示范围
let startIdx = midIdx
while (startIdx > 0) {
let idx = startIdx - 1
let attr = this.allCellAttributes[idx]
if (rect.intersects(attr.frame) == false) {
break
}
result.push(attr)
startIdx = idx
}
// 依次往后检查,直到超出当前的显示范围
let endIdx = midIdx
while (endIdx < this.allCellAttributes.length - 1) {
let idx = endIdx + 1
let attr = this.allCellAttributes[idx]
if (rect.intersects(attr.frame) == false) {
break
}
result.push(attr)
endIdx = idx
}
return result
}
} }