2026-08-19 09:47:44 +08:00
|
|
|
|
using DG.Tweening;
|
|
|
|
|
|
using Kill.Managers;
|
2026-05-11 08:39:33 +08:00
|
|
|
|
using UnityEngine;
|
2026-08-19 09:47:44 +08:00
|
|
|
|
using UnityEngine.EventSystems;
|
2026-05-11 08:39:33 +08:00
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Kill.UI.Pages
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 首页设备列表项 - 显示单个设备信息
|
2026-08-19 09:47:44 +08:00
|
|
|
|
/// 支持左滑手势:左滑时菜单向左滑出并显示高斯模糊覆盖层,
|
|
|
|
|
|
/// 滑动超过菜单宽度1/3松手则完整展开,否则缩回并隐藏模糊层
|
2026-05-11 08:39:33 +08:00
|
|
|
|
/// </summary>
|
2026-08-19 09:47:44 +08:00
|
|
|
|
public class HomePageDeviceItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
2026-05-11 08:39:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
public Text deviceNameText;
|
|
|
|
|
|
public GameObject selectedIndicator;
|
2026-08-19 09:47:44 +08:00
|
|
|
|
/// <summary>菜单(子物体,锚点位于item最右侧),左滑时向左滑出</summary>
|
|
|
|
|
|
public RectTransform menuRect;
|
|
|
|
|
|
/// <summary>高斯模糊覆盖层(子物体,覆盖其他内容),菜单出现时显示,缩回时隐藏</summary>
|
|
|
|
|
|
public GameObject blurOverlay;
|
|
|
|
|
|
|
2026-05-11 08:39:33 +08:00
|
|
|
|
// 当前设备信息
|
|
|
|
|
|
public DeviceInfo deviceInfo;
|
2026-08-19 09:47:44 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>当前展开菜单的item(全局仅允许一个菜单展开)</summary>
|
|
|
|
|
|
private static HomePageDeviceItem openItem;
|
|
|
|
|
|
|
|
|
|
|
|
private float menuWidth;
|
|
|
|
|
|
private float currentOffset;
|
|
|
|
|
|
private float dragStartOffset;
|
|
|
|
|
|
private bool isMenuOpen;
|
|
|
|
|
|
private bool isDragging;
|
|
|
|
|
|
private Vector3 menuInitPos;
|
|
|
|
|
|
private Tweener tweener;
|
|
|
|
|
|
private Button button;
|
|
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
button = GetComponent<Button>();
|
|
|
|
|
|
InitSwipe();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OnDisable()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 防止拖拽中被禁用且未恢复的情况
|
|
|
|
|
|
if (button != null) button.interactable = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 销毁时释放全局展开引用
|
|
|
|
|
|
if (openItem == this)
|
|
|
|
|
|
openItem = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 08:39:33 +08:00
|
|
|
|
public void InitDeviceItem(DeviceInfo device)
|
|
|
|
|
|
{
|
|
|
|
|
|
deviceInfo = device;
|
|
|
|
|
|
deviceNameText.text = device.device_name;
|
|
|
|
|
|
selectedIndicator.SetActive(false);
|
2026-08-19 09:47:44 +08:00
|
|
|
|
InitSwipe();
|
2026-05-11 08:39:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SetSelectedState(bool isSelected)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置选中状态
|
|
|
|
|
|
selectedIndicator.SetActive(isSelected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-19 09:47:44 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化滑动数据:记录菜单初始位置、菜单宽度,重置为收起状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void InitSwipe()
|
|
|
|
|
|
{
|
|
|
|
|
|
tweener?.Kill();
|
|
|
|
|
|
if (menuRect == null) return;
|
|
|
|
|
|
menuWidth = menuRect.sizeDelta.x;
|
|
|
|
|
|
menuInitPos = menuRect.anchoredPosition3D;
|
|
|
|
|
|
isMenuOpen = false;
|
|
|
|
|
|
currentOffset = 0;
|
|
|
|
|
|
ApplyMenuOffset(0);
|
|
|
|
|
|
if (blurOverlay != null) blurOverlay.SetActive(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (menuRect == null || menuWidth <= 0) return;
|
|
|
|
|
|
// 拖拽滑动时禁用按钮点击,避免与菜单滑动同时触发
|
|
|
|
|
|
if (button != null) button.interactable = false;
|
|
|
|
|
|
// 其他item的菜单展开时,先收起,保证全局只有一个菜单
|
|
|
|
|
|
if (openItem != null && openItem != this)
|
|
|
|
|
|
openItem.CloseMenu();
|
|
|
|
|
|
isDragging = true;
|
|
|
|
|
|
// 菜单开始出现,显示高斯模糊覆盖层
|
|
|
|
|
|
if (blurOverlay != null) blurOverlay.SetActive(true);
|
|
|
|
|
|
currentOffset = isMenuOpen ? -menuWidth : 0;
|
|
|
|
|
|
dragStartOffset = currentOffset;
|
|
|
|
|
|
ApplyMenuOffset(currentOffset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isDragging) return;
|
|
|
|
|
|
// 累加位移并限制在 [-菜单宽度, 0],只允许左滑露出菜单
|
|
|
|
|
|
currentOffset += eventData.delta.x;
|
|
|
|
|
|
currentOffset = Mathf.Clamp(currentOffset, -menuWidth, 0);
|
|
|
|
|
|
ApplyMenuOffset(currentOffset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isDragging) return;
|
|
|
|
|
|
isDragging = false;
|
|
|
|
|
|
// 恢复按钮点击
|
|
|
|
|
|
if (button != null) button.interactable = true;
|
|
|
|
|
|
// 右滑超过菜单宽度的1/5则直接缩回(方便关闭已展开的菜单)
|
|
|
|
|
|
float dragDistance = currentOffset - dragStartOffset;
|
|
|
|
|
|
if (dragDistance > menuWidth / 5f)
|
|
|
|
|
|
{
|
|
|
|
|
|
AnimateTo(0);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 左滑展示超过菜单宽度的1/3则完整滑出,否则缩回
|
|
|
|
|
|
float target = currentOffset < -menuWidth / 3f ? -menuWidth : 0;
|
|
|
|
|
|
AnimateTo(target);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 收起菜单(供菜单按钮点击等外部调用)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void CloseMenu()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isMenuOpen) return;
|
|
|
|
|
|
AnimateTo(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将菜单平移到指定偏移
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void ApplyMenuOffset(float offset)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 pos = menuInitPos;
|
|
|
|
|
|
pos.x += offset;
|
|
|
|
|
|
menuRect.anchoredPosition3D = pos;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 平滑动画到目标偏移
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void AnimateTo(float target)
|
|
|
|
|
|
{
|
|
|
|
|
|
tweener?.Kill();
|
|
|
|
|
|
bool open = target < 0;
|
|
|
|
|
|
if (open)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 已有其他item的菜单展开时,先收起,保证全局只有一个菜单
|
|
|
|
|
|
if (openItem != null && openItem != this)
|
|
|
|
|
|
openItem.CloseMenu();
|
|
|
|
|
|
openItem = this;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (openItem == this)
|
|
|
|
|
|
{
|
|
|
|
|
|
openItem = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
isMenuOpen = open;
|
|
|
|
|
|
if (!isMenuOpen && blurOverlay != null)
|
|
|
|
|
|
blurOverlay.SetActive(false); // 菜单缩回时隐藏模糊层
|
|
|
|
|
|
tweener = DOTween.To(() => currentOffset, v =>
|
|
|
|
|
|
{
|
|
|
|
|
|
currentOffset = v;
|
|
|
|
|
|
ApplyMenuOffset(v);
|
|
|
|
|
|
}, target, 0.25f).SetEase(Ease.OutCubic);
|
|
|
|
|
|
}
|
2026-05-11 08:39:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|