【muzzik教程】50行代码,教你优化列表draw call!【网格、横、纵 全包揽】

调整透明度不会影响流畅,应该是其他原因造成的

我刚刚在项目中用你说的方法试了一下,drawCall确实会降低很多,电脑上很流畅android打包后列表移动就感觉流畅的不如之前了

虽然我想说用循环做更好

不过这个思路不错

怎么加入群阿 想进群

请教一下cocos creator3.1.2 调用不了_calculWorldMatrix 这个方法,没这个api, 求教一下,cocos creator3.1.2应该 怎么实现_calculWorldMatrix 这个方法

3.x 实现

import {
	Color,
	color,
	Component,
	error,
	mat4,
	Mat4,
	Node,
	Rect,
	Renderable2D,
	ScrollView,
	UIOpacity,
	UITransform,
	_decorator,
} from "cc";

const { ccclass, property, menu } = _decorator;

/**列表draw call优化组件 */
@ccclass
@menu("tool/list_optimize")
export default class list_optimize extends Component {
	/* ***************private*************** */
	private _scroll_view: ScrollView;
	private _ui_transform: UITransform;
	private _temp1_color = color();
	private _temp1_m4 = mat4();
	private _temp2_m4 = mat4();
	/* --------------------------------segmentation-------------------------------- */
	onLoad() {
		this._scroll_view = this.node.getComponent(ScrollView);
		this._ui_transform = this.node.getComponent(UITransform);
		if (!this._scroll_view) {
			error("不存在ScrollView组件!");
			return;
		}
		this._event_update_opacity();
		// 事件监听
		{
			this.node.on("scrolling", this._event_update_opacity, this);
			this._scroll_view.content.on(
				Node.EventType.CHILD_REMOVED,
				this._event_update_opacity,
				this
			);
			this._scroll_view.content.on(
				Node.EventType.CHILD_ADDED,
				this._event_update_opacity,
				this
			);
		}
	}
	/* ***************功能函数*************** */
	/**获取在世界坐标系下的节点包围盒(不包含自身激活的子节点范围) */
	private _get_bounding_box_to_world(node_: any): Rect {
		node_.getWorldMatrix(this._temp2_m4);
		Mat4.fromRTS(
			this._temp1_m4,
			this.node.getRotation(),
			this.node.getPosition(),
			this.node.getScale()
		);
		let width = this._ui_transform.contentSize.width;
		let height = this._ui_transform.contentSize.height;
		let rect = new Rect(
			-this._ui_transform.anchorPoint.x * width,
			-this._ui_transform.anchorPoint.y * height,
			width,
			height
		);
		Mat4.multiply(this._temp2_m4, this._temp2_m4, this._temp1_m4);
		rect.transformMat4(this._temp2_m4); // query child's BoundingBox
		return rect;
	}
	/**检测碰撞 */
	private _check_collision(node_: Node): boolean {
		let rect1 = this._get_bounding_box_to_world(this._scroll_view.content.parent);
		let rect2 = this._get_bounding_box_to_world(node_);
		// 保险范围
		{
			rect1.width += rect1.width * 0.5;
			rect1.height += rect1.height * 0.5;
			rect1.x -= rect1.width * 0.25;
			rect1.y -= rect1.height * 0.25;
		}
		return rect1.intersects(rect2);
	}
	/**设置节点透明度 */
	private set_node_opacity(node_: Node, opacity_n_: number): void {
		let rander_comp = node_.getComponent(Renderable2D);
		if (rander_comp) {
			Color.copy(this._temp1_color, rander_comp.color);
			this._temp1_color.a = opacity_n_;
			rander_comp.color = this._temp1_color;
		} else {
			(node_.getComponent(UIOpacity) || node_.addComponent(UIOpacity)).opacity = opacity_n_;
		}
	}
	/* ***************自定义事件*************** */
	private _event_update_opacity(): void {
		this._scroll_view.content.children.forEach(v1 => {
			this.set_node_opacity(v1, this._check_collision(v1) ? 255 : 0);
		});
	}
}

@xhzth70911 @1321519915

2赞

是真好用!!!

1赞

不知道是不是我的使用方式不对,我挂在scrollview节点上,刚打卡页面初始会透明度全 为0,要有滑动才显示内容,是哪里不对吗?cocos版本是2.4.6。

onLoad内执行的首次更新,如果更新时scrollView内的item不在可视区域内那么就会这样,检查下item的坐标

噢噢,我关闭的时候没有还原item的坐标,现在设置了scrollToTop就可以了,谢谢!

先mark一下。。

循环列表不得行呀,scrollview 抖动腻害,再动态修改位置 就更厉害了

这是说 不在可视范围内 的组件为完全透明,这样可以提高显示帧率?
那这个功能应该做到引擎层面呀!

1.x 时代是这样的,但是对于一些项目,要的就是实时渲染,所以2.x时代,官方修改了,个人认为这才是正确的,如果不需要,就自己设置就好了。

碰撞检测的思路点赞

大佬,新手一枚,用了你的插件,纵向是可以减少dc了,但是横向貌似没用,dc没减少,求解

  1. item 数量不够多
  2. this.node.scroll_view.content.parent 尺寸错误

感谢,我用力拉出屏幕dc可以下降,回弹回来又恢复了,数量刚好超出屏幕80多个像素吧

mark一下

有个疑问啊,难道滚动子控件的循环利用 不会比你这种方法好吗?例如 可视区域内最多显示8个item ,我用10个item 通过修改位置 数据刷新的方式 达到和tableview一样的效果,这种方式不会更好吗 ?,你这样隐藏显示的 实际上还是创建了,我有100条数据,难道就一定要创建100个item?