适配到3.x后CCMPicker滚动有问题,跟诡异,相见视频
Opened this issue · 0 comments
shi-xintao commented
2022-10-17.14.22.06.mov
适配到3.x后CCMPicker滚动有问题,CCMCategoryView没问题,相见视频。
跟进了一下,设置的index没问题了。
这是适配后的代码CCMPicker
import { _decorator, ScrollView, Component, Prefab, Layout, error, instantiate, v2, sys, Node, Touch, Vec3, v3, UITransform } from "cc";
const EPSILON = 1e-4;
const MINIMUM_VELOCITY = 30;
const { ccclass, property } = _decorator;
export interface Adapter {
dataSource: any[],
onPick?: (index: number) => void,
bindView?: (node: Node, data: any, index: number) => void,
transform?: (node: Node, ratio: number) => void
}
@ccclass
export class CCMPicker extends ScrollView {
@property({
override: true,
visible: false
})
public horizontal: boolean = false;
@property({
override: true,
visible: false
})
public vertical: boolean = true;
@property({
override: true,
visible: false
})
public inertia: boolean = true;
@property({
override: true,
visible: false
})
public elastic: boolean = true;
@property({
override: true,
visible: false
})
public cancelInnerEvents: boolean = true;
@property({
override: true,
visible: false
})
get verticalScrollBar(): any {
return null;
};
set verticalScrollBar(scrollbar: any) {
// nothing to do
}
@property({
override: true,
visible: false
})
get horizontalScrollBar(): any {
return null;
};
set horizontalScrollBar(scrollbar: any) {
// nothing to do
}
@property({
override: true,
visible: false,
type: [Component.EventHandler]
})
public scrollEvents: any[] = [];
@property(Prefab)
private itemPrefab: Prefab = null;
private itemHeight = 0;
private currentIndex = 0;
private hasLocated = false;
private adapter: Adapter = null;
private pickCallback = () => {
if (!this.adapter || !this.adapter.onPick) return;
this.adapter.onPick(this.getCurrentIndex());
};
public onLoad() {
this.itemHeight = this.itemPrefab.data.getComponent(UITransform).height;
var layout = this.content.getComponent(Layout);
if (!!layout) {
layout.paddingTop = (this.node.getComponent(UITransform).height - this.itemHeight) / 2;
layout.paddingBottom = layout.paddingTop + this.content.parent.getComponent(UITransform).height - this.node.getComponent(UITransform).height;
}
}
private getBaseline(): number {
return - this.getScrollOffset().y - this.node.getComponent(UITransform).height / 2;
}
protected _moveContent(deltaMove: any, canStartBounceBack: boolean) {
// @ts-ignore
super._moveContent(deltaMove, canStartBounceBack);
if (!this.adapter || !this.adapter.transform) return;
let children = this.content.children;
if (!children || !children.length) return;
let baseline = this.getBaseline();
for (let i = 0, ii = children.length; i < ii; i++) {
let child = children[i];
let offset = child.position.y - baseline;
let ratio = offset / this.itemHeight;
this.adapter.transform(child, ratio);
}
}
public setAdapter(adapter: Adapter) {
if (!adapter) {
error('adapter can not be undefined!');
return;
}
this.adapter = adapter;
let { dataSource, bindView } = adapter;
for (let i = 0, ii = dataSource.length; i < ii; i++) {
let child = instantiate(this.itemPrefab);
if (bindView) bindView(child, dataSource[i], i);
this.content.addChild(child);
}
}
// override disable wheel event
protected _onMouseWheel() {
}
public setCurrentIndex(index: number) {
this.currentIndex = index;
this.hasLocated = true;
let targetY = index * this.itemHeight;
let offsetY = Math.abs(this.getScrollOffset().y);
let deltaY = Math.abs(targetY - offsetY);
let duration = Math.min(0.5 * deltaY / this.itemHeight, 0.8);
console.log(`targetY:`, targetY)
this.unschedule(this.pickCallback);
this.scrollToOffset(v2(0, targetY), duration);
}
private scrollToClosestLocation() {
let { y: currentOffset } = this.getScrollOffset();
let remainder = currentOffset % this.itemHeight;
let delta = Math.abs(remainder) > this.itemHeight / 2 ? (this.itemHeight - Math.abs(remainder)) : (-Math.abs(remainder));
let targetOffset = currentOffset + delta;
let duration = 0.5;
this.hasLocated = true;
this.scrollToOffset(v2(0, targetOffset), duration);
let index = Math.round(Math.abs(targetOffset) / this.itemHeight);
this.unschedule(this.pickCallback);
if (this.currentIndex == index) return;
this.currentIndex = index;
this.scheduleOnce(this.pickCallback, duration);
}
protected _handleReleaseLogic(touch: Touch) {
let vec2 = touch.getDelta();
this._gatherTouchMove(v3(vec2.x, vec2.y));
let bounceBackStarted = this._startBounceBackIfNeeded();
if (!bounceBackStarted && this.inertia) {
let velocity: Vec3 = this._calculateTouchMoveVelocity();
let needFling = sys.OS.ANDROID == sys.os ? Math.abs(velocity.y) > MINIMUM_VELOCITY : !velocity.equals(v3(0, 0), EPSILON);
if (needFling && this.brake < 1) {
this.hasLocated = false;
this._startInertiaScroll(velocity);
} else if (this._touchMoved) {
this.scrollToClosestLocation();
}
}
this._onScrollBarTouchEnded();
if (this._autoScrolling) return;
this.scrollToClosestLocation();
}
private getCurrentIndex(): number {
return this.currentIndex || 0;
}
private getCurrentData(): any {
if (!this.adapter || !this.adapter.dataSource) return undefined;
return this.adapter.dataSource[this.getCurrentIndex()];
}
protected _startAutoScroll(deltaMove, timeInSecond, attenuated) {
let adjustedDeltaMove = this._flattenVectorByDirection(deltaMove);
if (!this.hasLocated) {
timeInSecond *= 0.2;
let vec2 = this.getScrollOffset()
let scrollOffset = v3(vec2.x, vec2.y);
let autoScrollEndOffset = adjustedDeltaMove.add(scrollOffset);
let remainder = autoScrollEndOffset.y % this.itemHeight;
if (Math.abs(remainder) > this.itemHeight / 2) {
adjustedDeltaMove.y += (this.itemHeight - Math.abs(remainder));
} else {
adjustedDeltaMove.y -= Math.abs(remainder);
}
let { y: offsetY } = adjustedDeltaMove.add(scrollOffset);
let { y: maxoffsetY } = this.getMaxScrollOffset();
if (offsetY < 0) {
offsetY = 0;
} else if (offsetY > maxoffsetY) {
offsetY = maxoffsetY;
}
this.currentIndex = Math.round(Math.abs(offsetY) / this.itemHeight);
this.unschedule(this.pickCallback);
this.scheduleOnce(this.pickCallback, timeInSecond * 0.5);
}
this._autoScrolling = true;
this._autoScrollTargetDelta = adjustedDeltaMove;
this._autoScrollAttenuate = attenuated;
this._autoScrollStartPosition = this.getContentPosition();
this._autoScrollTotalTime = timeInSecond;
this._autoScrollAccumulatedTime = 0;
this._autoScrollBraking = false;
this._isScrollEndedWithThresholdEventFired = false;
this._autoScrollBrakingStartPosition = v3(0, 0);
let currentOutOfBoundary: Vec3 = this._getHowMuchOutOfBoundary();
if (!currentOutOfBoundary.equals(v3(0, 0), EPSILON)) {
this._autoScrollCurrentlyOutOfBoundary = true;
let afterOutOfBoundary = this._getHowMuchOutOfBoundary(adjustedDeltaMove);
if (currentOutOfBoundary.x * afterOutOfBoundary.x > 0 ||
currentOutOfBoundary.y * afterOutOfBoundary.y > 0) {
this._autoScrollBraking = true;
}
}
}
}