257 lines
9.9 KiB
C#
257 lines
9.9 KiB
C#
#nullable enable
|
|
using DG.Tweening;
|
|
using Gpm.Ui;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
|
|
namespace UVC.UI.List.ComponentList
|
|
{
|
|
/// <summary>
|
|
/// InfiniteScroll에 표시될 개별 아이템을 정의하는 클래스입니다.
|
|
/// 이 아이템은 '카테고리' 또는 '일반 항목' 두 가지 상태를 가질 수 있으며,
|
|
/// ComponentListItemData의 isCategory 값에 따라 UI가 동적으로 변경됩니다.
|
|
/// </summary>
|
|
public class ComponentListItem : InfiniteScrollItem
|
|
{
|
|
// ComponentList 참조
|
|
private ComponentList? _componentList;
|
|
// [카테고리 UI 요소]
|
|
[Header("Category UI")]
|
|
[SerializeField]
|
|
protected GameObject categoryRoot; // 카테리 UI의 최상위 GameObject
|
|
|
|
[SerializeField]
|
|
protected TMPro.TextMeshProUGUI categoryText; // 카테고리 이름을 표시할 텍스트
|
|
|
|
[SerializeField]
|
|
protected TMPro.TextMeshProUGUI categoryBageText; // 카테고리에 속한 항목 수를 표시할 텍스트
|
|
|
|
[SerializeField]
|
|
protected Button categoryExtendButton; // 카테고리 확장/축소 버튼
|
|
|
|
// [일반 항목 UI 요소]
|
|
[Header("General Item UI")]
|
|
[SerializeField]
|
|
protected GameObject generalRoot; // 일반 항목 UI의 최상위 GameObject
|
|
|
|
[SerializeField]
|
|
protected TMPro.TMP_InputField generalText; // 일반 항목의 이름을 표시할 입력 필드
|
|
|
|
[SerializeField]
|
|
protected TMPro.TextMeshProUGUI generalOptionText; // 일반 항목의 옵션을 표시할 텍스트
|
|
|
|
[SerializeField]
|
|
protected Button showButton; // 항목을 씬에 표시하는 버튼
|
|
|
|
[SerializeField]
|
|
protected Button hideButton; // 항목을 씬에서 숨기는 버튼
|
|
|
|
// 애니메이션 중복 실행을 방지하기 위한 플래그
|
|
protected bool isAnimating = false;
|
|
|
|
private void Awake()
|
|
{
|
|
// ComponentList 참조 캐싱
|
|
if (_componentList == null)
|
|
{
|
|
_componentList = GetComponentInParent<ComponentList>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// InfiniteScroll에 의해 데이터가 이 아이템에 할당될 때 호출되는 핵심 메서드입니다.
|
|
/// 스크롤 시 아이템이 재활용될 때마다 새로운 데이터로 이 메서드가 호출되어 UI를 갱신합니다.
|
|
/// </summary>
|
|
/// <param name="scrollData">이 아이템에 표시할 데이터입니다. `InfiniteScrollData`를 상속받은 `ComponentListItemData` 객체입니다.</param>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 1. 표시할 데이터를 생성합니다.
|
|
/// var categoryData = new ComponentListItemData
|
|
/// {
|
|
/// isCategory = true,
|
|
/// categoryName = "전기 설비",
|
|
/// categoryBadgeCount = 10
|
|
/// };
|
|
///
|
|
/// var generalData = new ComponentListItemData
|
|
/// {
|
|
/// isCategory = false,
|
|
/// generalName = "분전반",
|
|
/// generalOption = "옵션 A",
|
|
/// Id = "some-unique-id"
|
|
/// };
|
|
///
|
|
/// // 2. 생성한 데이터를 InfiniteScroll에 추가합니다.
|
|
/// infiniteScroll.InsertData(categoryData);
|
|
/// infiniteScroll.InsertData(generalData);
|
|
/// </code>
|
|
/// </example>
|
|
public override void UpdateData(InfiniteScrollData scrollData)
|
|
{
|
|
// 1. 부모 클래스의 UpdateData를 호출하여 기본 초기화 작업을 수행합니다.
|
|
// 이 과정에서 this.scrollData에 매개변수로 받은 scrollData가 할당됩니다.
|
|
base.UpdateData(scrollData);
|
|
|
|
// InfiniteScroll 아이템 재활용 시 애니메이션 상태 리셋
|
|
isAnimating = false;
|
|
|
|
// 2. 매개변수로 받은 scrollData를 실제 사용할 데이터 타입인 ComponentListItemData로 형변환(casting)합니다.
|
|
// 이렇게 해야 ComponentListItemData에만 정의된 속성(isCategory, categoryName 등)에 접근할 수 있습니다.
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
|
|
// 3. 데이터의 isCategory 값에 따라 카테고리 UI 또는 일반 항목 UI를 활성화/비활성화합니다.
|
|
categoryRoot.SetActive(itemData.IsCategory);
|
|
generalRoot.SetActive(!itemData.IsCategory);
|
|
|
|
// 4. 활성화된 UI에 데이터를 채워 넣습니다.
|
|
if (itemData.IsCategory)
|
|
{
|
|
// 카테고리 아이템일 경우
|
|
categoryText.text = itemData.CategoryName;
|
|
categoryBageText.text = itemData.CategoryBadgeCount.ToString();
|
|
|
|
// 애니메이션을 위해 현재 각도에서 목표 각도로 회전시킵니다.
|
|
categoryExtendButton.transform.DOKill(); // 이전 애니메이션이 있으면 종료
|
|
categoryExtendButton.transform.DORotate(new Vector3(0, 0, itemData.IsExpanded ? 0 : 90), 0.0f);
|
|
}
|
|
else
|
|
{
|
|
// 일반 아이템일 경우
|
|
generalText.text = itemData.Name;
|
|
generalOptionText.text = itemData.Option;
|
|
|
|
// 버튼 상태는 외부 이벤트 핸들러에서 처리
|
|
// 기본값: 숨기기 버튼 표시 (객체가 보이는 상태로 가정)
|
|
showButton.gameObject.SetActive(false);
|
|
hideButton.gameObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
public virtual void OnClickItem()
|
|
{
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleClickItem(itemData);
|
|
}
|
|
}
|
|
|
|
public virtual void OnRightClickItem()
|
|
{
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleRightClickItem(itemData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 카테고리 아이템의 '확장/축소' 버튼을 클릭했을 때 호출됩니다.
|
|
/// </summary>
|
|
public virtual void OnExpendButtonClick()
|
|
{
|
|
// 애니메이션이 진행 중이면 중복 호출을 방지합니다.
|
|
if (isAnimating) return;
|
|
isAnimating = true;
|
|
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
|
|
// 토글 후의 상태를 기준으로 목표 각도 계산
|
|
// 현재 isExpanded=true(펼쳐진 상태)이면 접을 것이므로 90도로 (화살표 우측 방향)
|
|
// 현재 isExpanded=false(접힌 상태)이면 펼칠 것이므로 0도로 (화살표 아래 방향)
|
|
float targetAngle = itemData.IsExpanded ? 90 : 0;
|
|
|
|
// 이전 애니메이션이 있으면 종료
|
|
categoryExtendButton.transform.DOKill();
|
|
categoryExtendButton.transform.DORotate(new Vector3(0, 0, targetAngle), 0.3f)
|
|
.SetUpdate(true) // TimeScale 영향 받지 않도록 설정
|
|
.OnComplete(() =>
|
|
{
|
|
isAnimating = false;
|
|
});
|
|
|
|
// ComponentList의 이벤트를 통해 확장/축소 처리
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleCategoryExpand(itemData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 카테고리 아이템의 '설정' 버튼을 클릭했을 때 호출됩니다.
|
|
/// </summary>
|
|
public virtual void OnSettingButtonClick()
|
|
{
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleSettingButtonClick(itemData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 일반 아이템의 '보이기' 버튼을 클릭했을 때 호출됩니다.
|
|
/// </summary>
|
|
public virtual void OnShowButtonClick()
|
|
{
|
|
showButton.gameObject.SetActive(false);
|
|
hideButton.gameObject.SetActive(true);
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleShowButtonClick(itemData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 일반 아이템의 '숨기기' 버튼을 클릭했을 때 호출됩니다.
|
|
/// </summary>
|
|
public virtual void OnHideButtonClick()
|
|
{
|
|
showButton.gameObject.SetActive(true);
|
|
hideButton.gameObject.SetActive(false);
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleHideButtonClick(itemData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 일반 아이템의 '찾기/이동' 버튼을 클릭했을 때 호출됩니다.
|
|
/// </summary>
|
|
public virtual void OnSearchButtonClick()
|
|
{
|
|
ComponentListItemData itemData = (ComponentListItemData)scrollData;
|
|
if (_componentList != null)
|
|
{
|
|
_componentList.HandleSearchButtonClick(itemData);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDestroy()
|
|
{
|
|
// 애니메이션 정리
|
|
if (categoryExtendButton != null)
|
|
{
|
|
categoryExtendButton.transform.DOKill();
|
|
}
|
|
|
|
// 참조 정리
|
|
_componentList = null;
|
|
|
|
// UI 참조 정리
|
|
categoryRoot = null!;
|
|
categoryText = null!;
|
|
categoryBageText = null!;
|
|
categoryExtendButton = null!;
|
|
generalRoot = null!;
|
|
generalText = null!;
|
|
generalOptionText = null!;
|
|
showButton = null!;
|
|
hideButton = null!;
|
|
}
|
|
}
|
|
}
|