当前位置:网站首页>[unity ugui] scrollrect dynamically scales the grid size and automatically locates the middle grid
[unity ugui] scrollrect dynamically scales the grid size and automatically locates the middle grid
2022-07-04 17:30:00 【InfoQ】
Instructions :
Effect demonstration :
Realization principle :
Implementation code :
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));
// Initialize invariant fields
private ScrollRect scrollRect;
private RectTransform contentRectTrans;
private Vector2 scrollHalfSize; // List size
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;
// Dynamically changing fields
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(" Currently, only horizontal lists from left to right are supported ");
contentRectTrans = scrollRect.content;
if(contentRectTrans.pivot.x > 0)
Debug.LogError(" Currently, only horizontal lists from left to right are supported ");
//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;
// The first grid coordinate
Vector2 gridInitPos = gridList[0].anchoredPosition;
gridInitPos.x = scrollHalfSize.x - gridSize.x * 0.5f;
// Grid spacing
Vector2 gridOffset = Vector2.zero;
gridOffset.x = gridSize.x + gridSpace;
// Calculate the canvas size
Vector2 contentSize = contentRectTrans.rect.size;
contentSize.x = gridSize.x * gridList.Count + gridSpace * (gridList.Count - 1) + scrollHalfSize.x * 2 - gridSize.x;
// Set the canvas size
contentRectTrans.sizeDelta = contentSize;
contentRectTrans.anchoredPosition = new Vector2(0,contentRectTrans.anchoredPosition.y);
// Set the coordinates of each grid
for(int i = 0; i < gridList.Count; i++)
{
gridList[i].anchoredPosition = gridInitPos + gridOffset * i;
gridList[i].anchorMin = new Vector2(0,1);
gridList[i].anchorMax = new Vector2(0,1);
gridList[i].pivot = new Vector2(0,1);
gridCenterList.Add(gridList[i].anchoredPosition + gridSize * 0.5f);
}
if(isScale)
UpdateScale();
isInited = true;
curSelectIndex = 0;
}
#region --- Snap ---
private Vector2 snapTargetPos;
private void StartSnap()
{
if(isSnap)
{
if(gridList.Count > 0)
{
snapState = SnapState.Inertia;
}
}
}
private void UpdateSnapInertia()
{
if(scrollRect.velocity.x > -snapReverseSpeed && scrollRect.velocity.x < snapReverseSpeed)
{
// reverse
StartSnapReverse();
return;
}
}
private void StartSnapReverse()
{
snapState = SnapState.Reverse;
scrollRect.StopMovement();
// Canvas coordinates of the center of the current screen
float centerPos = Mathf.Abs(contentRectTrans.anchoredPosition.x) + scrollHalfSize.x;
float temOffset;
float minOffet = float.MaxValue;
for(int i = 0; i < gridCenterList.Count; i++)
{
if(!gridList[i].gameObject.activeSelf)
continue;
// Grid center coordinates
temOffset = centerPos - gridCenterList[i].x;
// Compare the minimum distance
if(Mathf.Abs(temOffset) < Mathf.Abs(minOffet))
{
minOffet = temOffset;
// The grid is in the middle , Reverses the coordinates of the canvas
snapTargetPos.x = -(gridCenterList[i].x - scrollHalfSize.x);
}
}
snapTargetPos.y = contentRectTrans.anchoredPosition.y;
}
private void UpdateSnapReverse()
{
if(Mathf.Abs(contentRectTrans.anchoredPosition.x - snapTargetPos.x) < 1)
{
contentRectTrans.anchoredPosition = snapTargetPos;
EndSnap();
return;
}
contentRectTrans.anchoredPosition = Vector2.Lerp(contentRectTrans.anchoredPosition,snapTargetPos,snapDecelerate);
}
private void EndSnap()
{
if(snapState == SnapState.None)
return;
scrollRect.StopMovement();
snapState = SnapState.None;
if(isScale)
UpdateScale();
OnScrollEndDrag?.Invoke(curSelectIndex);
}
private void BreakSnap()
{
if(snapState != SnapState.None)
snapState = SnapState.None;
}
#endregion
#region --- Scale ---
int tempIndex;
float tempCenter;
float tempOffset;
float minDistance;
Vector3 tempScale;
Vector2 tempAnPos;
private void UpdateScale()
{
minDistance = float.MaxValue;
tempCenter = Mathf.Abs(contentRectTrans.anchoredPosition.x) + scrollHalfSize.x;
for(int i = 0; i < gridCenterList.Count; i++)
{
if(!gridList[i].gameObject.activeSelf)
continue;
// Distance from grid center to screen center
tempOffset = Mathf.Abs(tempCenter - gridCenterList[i].x);
if(tempOffset > scrollHalfSize.x + gridSize.x)
continue;
// Calculate the scaling value
tempScale.x = scaleCurve.Evaluate(tempOffset / scrollHalfSize.x);
tempScale.y = tempScale.x;
tempScale.z = 1;
// Modify zoom
gridList[i].localScale = tempScale;
// Change location ( The anchor is in the upper left corner , Make sure the grid is still in the middle after scaling )
tempAnPos.x = gridCenterList[i].x - gridSize.x * 0.5f * tempScale.x;
tempAnPos.y = gridCenterList[i].y + gridSize.y * (0.5f * tempScale.y - 1);
gridList[i].anchoredPosition = tempAnPos;
// Compare the minimum distance
if(tempOffset < minDistance)
{
minDistance = tempOffset;
tempIndex = i;
}
}
if(curSelectIndex != tempIndex)
{
curSelectIndex = tempIndex;
OnSelectGridChanged?.Invoke(curSelectIndex);
}
}
private void UpdateSelectGrid()
{
minDistance = float.MaxValue;
tempCenter = Mathf.Abs(contentRectTrans.anchoredPosition.x) + scrollHalfSize.x;
for(int i = 0; i < gridCenterList.Count; i++)
{
if(!gridList[i].gameObject.activeSelf)
continue;
// Distance from grid center to screen center
tempOffset = Mathf.Abs(tempCenter - gridCenterList[i].x);
if(tempOffset > scrollHalfSize.x + gridSize.x)
continue;
// Compare the minimum distance
if(tempOffset < minDistance)
{
minDistance = tempOffset;
tempIndex = i;
}
}
if(curSelectIndex != tempIndex)
{
curSelectIndex = tempIndex;
OnSelectGridChanged?.Invoke(curSelectIndex);
}
}
#endregion
}
Demo link :
边栏推荐
- Is it safe for CITIC Securities to open an account online? Is the account opening fee charged
- Image retrieval
- Is it safe for Bank of China Securities to open an account online?
- 51 single chip microcomputer temperature alarm based on WiFi control
- It's too convenient. You can complete the code release and approval by nailing it!
- 昆明三环闭合工程将经过这些地方,有在你家附近的吗?
- 线性时间排序
- Visual studio 2019 (localdb) mssqllocaldb SQL Server 2014 database version is 852 and cannot be opened. This server supports 782
- 安信证券排名 网上开户安全吗
- 电子元器件B2B商城系统开发:赋能企业构建进销存标准化流程实例
猜你喜欢
整理混乱的头文件,我用include what you use
VMware Tools和open-vm-tools的安装与使用:解决虚拟机不全屏和无法传输文件的问题
World Environment Day | Chow Tai Fook serves wholeheartedly to promote carbon reduction and environmental protection
斑马识别成狗,AI犯错的原因被斯坦福找到了丨开源
The winning rate against people is 84%, and deepmind AI has reached the level of human experts in army chess for the first time
VB cannot access database stocks
Implementation of super large-scale warehouse clusters in large commercial banks
7 RSA密码体制
2022PMP考试基本情况详情了解
昆明三环闭合工程将经过这些地方,有在你家附近的吗?
随机推荐
2022年国内云管平台厂商哪家好?为什么?
Smart Logistics Park supply chain management system solution: digital intelligent supply chain enables a new supply chain model for the logistics transportation industry
ble HCI 流控机制
新享科技发布小程序UniPro小优 满足客户移动办公场景
Can you really use MySQL explain?
Object. Usage of keys()
OPPO小布推出预训练大模型OBERT,晋升KgCLUE榜首
电子元器件B2B商城系统开发:赋能企业构建进销存标准化流程实例
Analysis of abnormal frequency of minor GC in container environment
VMware Tools和open-vm-tools的安装与使用:解决虚拟机不全屏和无法传输文件的问题
Solution of dealer collaboration system in building materials industry: empowering enterprises to build core competitiveness
To sort out messy header files, I use include what you use
CANN算子:利用迭代器高效实现Tensor数据切割分块处理
Linear time sequencing
Congratulations to Mr. Zhang Pengfei, chief data scientist of artefact, for winning the campaign Asia tech MVP 2022
"Cannot initialize Photoshop because the temporary storage disk is full" graphic solution
Is it safe for Great Wall Securities to open an account? How to open a securities account
2022PMP考试基本情况详情了解
安信证券排名 网上开户安全吗
GO开发:如何利用Go单例模式保障流媒体高并发的安全性?