Unity UGUIScrollRect 动态缩放格子大小,自动定位到中间的格子
Posted 萧然CS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity UGUIScrollRect 动态缩放格子大小,自动定位到中间的格子相关的知识,希望对你有一定的参考价值。
实现效果:ScrollRect,格子动态缩放大小,滑动结束自动定位中间格子
使用说明:
目前只支持横向从左往右列表,需要设置ScrollRect仅横向滑动,ScrollViewExtras挂到ScrollRect组件所在节点,ScrollRect的格子锚点、中心点设置在左上角,Content,设置好Y坐标,运行时自动修改X坐标。
GridSpace:格子间距
IsSnap:是否开启自动定位
IsScale:是否开启自动缩放
ScaleCueve:缩放曲线
效果演示:
关闭自动定位,关闭自动缩放:
开启自动定位,关闭自动缩放:
关闭自动定位,开启自动缩放:
开启自动定位,开启自动缩放:
实现原理:
- 动态缩放功能实现:Transform改变时,计算列表可视区域内所有格子与列表中心的偏移量,根据偏移量缩放格子。
- 自动定位功能实现:初始化计算每个格子的位置,滑动结束后,计算每个格子到列表中心的偏移量,偏移量最小的格子就是列表最中间的格子,再把它自动移动到列表中心的位置,实现定位。
实现代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
[RequireComponent(typeof(ScrollRect))]
public class ScrollViewExtras : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
private enum SnapState
None,
Inertia,
Reverse,
public Action OnScrollStartDrag;
public Action<int> OnScrollEndDrag;
public Action<int> OnSelectGridChanged;
[SerializeField] private float gridSpace = 20;
[SerializeField] private bool isSnap;
[SerializeField] private bool isScale;
[SerializeField] private AnimationCurve scaleCurve = new AnimationCurve(new Keyframe(0,1),new Keyframe(1,0.5f));
//初始化不变字段
private ScrollRect scrollRect;
private RectTransform contentRectTrans;
private Vector2 scrollHalfSize; //列表尺寸
private Vector2 gridSize;
private List<RectTransform> gridList = new List<RectTransform>();
private List<Vector2> gridCenterList = new List<Vector2>();
private float snapDecelerate;
private const float snapReverseSpeed = 500;
private bool isInited = false;
//动态变化字段
private SnapState snapState = SnapState.None;
private int curSelectIndex;
//----------
private void Start()
Init();
private void Update()
if(isInited)
switch(snapState)
case SnapState.Inertia:
UpdateSnapInertia();
break;
case SnapState.Reverse:
UpdateSnapReverse();
break;
default:
break;
if(contentRectTrans.hasChanged)
if(isScale)
UpdateScale();
else
UpdateSelectGrid();
#region --- Drag Event
public void OnBeginDrag(PointerEventData eventData)
OnScrollStartDrag?.Invoke();
BreakSnap();
public void OnDrag(PointerEventData eventData)
public void OnEndDrag(PointerEventData eventData)
StartSnap();
#endregion
public void Init()
scrollRect = GetComponent<ScrollRect>();
if(!scrollRect.horizontal)
Debug.LogError("目前只支持横向从左往右列表");
contentRectTrans = scrollRect.content;
if(contentRectTrans.pivot.x > 0)
Debug.LogError("目前只支持横向从左往右列表");
//scrollCenter = scrollRect.viewport.rect.center;
scrollHalfSize = scrollRect.viewport.rect.size * 0.5f;
for(int i = 0; i < contentRectTrans.childCount; i++)
gridList.Add(contentRectTrans.GetChild(i) as RectTransform);
if(gridList.Count > 0)
gridSize = gridList[0].rect.size;
snapDecelerate = scrollRect.decelerationRate;
//if(snapDecelerate < 0.1f)
// snapDecelerate = 0.1f;
if(gridList.Count == 0)
return;
//第一个格子坐标
Vector2 gridInitPos = gridList[0].anchoredPosition;
gridInitPos.x = scrollHalfSize.x - gridSize.x * 0.5f;
//格子间隔
Vector2 gridOffset = Vector2.zero;
gridOffset.x = gridSize.x + gridSpace;
//计算画布尺寸
Vector2 contentSize = Unity 降低 Batch