클래스 생성

This commit is contained in:
logonkhi
2025-11-04 20:09:18 +09:00
parent 68c5d51884
commit 0885f02871
20 changed files with 1634 additions and 3 deletions

View File

@@ -0,0 +1,57 @@
using UnityEngine;
using UVC.UI.Window;
using UVC.UI.List.Accordion;
public class AccordionSample : MonoBehaviour
{
[SerializeField]
private AccordionWindow accordionWindow;
void Start()
{
if (accordionWindow == null)
{
accordionWindow = FindObjectOfType<AccordionWindow>();
}
var data = new AccordionData();
// Horizontal section
var sec1 = new AccordionSectionData
{
Title = "Settings",
IsExpanded = true,
LayoutType = AccordionItemLayoutType.Horizontal
};
sec1.Items.Add(new AccordionHorizontalItemData
{
Head = AccordionContentSpec.FromImage(null),
Content = AccordionContentSpec.FromText("Graphics"),
Tail = AccordionContentSpec.FromIconButton(null, () => Debug.Log("Edit Graphics"))
});
sec1.Items.Add(new AccordionHorizontalItemData
{
Head = AccordionContentSpec.FromImage(null),
Content = AccordionContentSpec.FromText("Audio"),
Tail = AccordionContentSpec.FromIconButton(null, () => Debug.Log("Edit Audio"))
});
data.Sections.Add(sec1);
// Grid section
var sec2 = new AccordionSectionData
{
Title = "Presets",
IsExpanded = true,
LayoutType = AccordionItemLayoutType.Grid
};
sec2.Items.Add(new AccordionGridItemData { Caption = "Low" });
sec2.Items.Add(new AccordionGridItemData { Caption = "Medium" });
sec2.Items.Add(new AccordionGridItemData { Caption = "High" });
data.Sections.Add(sec2);
if (accordionWindow != null)
{
accordionWindow.SetData(data);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 93a668387eec1bd4e90555099bc02b42

View File

@@ -0,0 +1,746 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 13
m_BakeOnSceneLoad: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 1
m_PVRFilteringGaussRadiusAO: 1
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!224 &651880472 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
m_PrefabInstance: {fileID: 2860332021081550125}
m_PrefabAsset: {fileID: 0}
--- !u!114 &651880475 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 8327823890420627479, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
m_PrefabInstance: {fileID: 2860332021081550125}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 73be4d2e3822cba4a85e1cfb52f6b737, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1097328750
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1097328752}
- component: {fileID: 1097328751}
m_Layer: 0
m_Name: HierarchySample
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1097328751
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1097328750}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4af85cefd4077b1438d936111ae34f9b, type: 3}
m_Name:
m_EditorClassIdentifier:
hierarchyWindow: {fileID: 651880475}
--- !u!4 &1097328752
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1097328750}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1218340761
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1218340765}
- component: {fileID: 1218340764}
- component: {fileID: 1218340763}
- component: {fileID: 1218340762}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1218340762
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1218340761}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &1218340763
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1218340761}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &1218340764
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1218340761}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 25
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!224 &1218340765
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1218340761}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 651880472}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1 &1331954412
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1331954415}
- component: {fileID: 1331954414}
- component: {fileID: 1331954413}
m_Layer: 0
m_Name: EventSystem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1331954413
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1331954412}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 01614664b831546d2ae94a42149d80ac, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_MoveRepeatDelay: 0.5
m_MoveRepeatRate: 0.1
m_XRTrackingOrigin: {fileID: 0}
m_ActionsAsset: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_PointAction: {fileID: -1654692200621890270, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_MoveAction: {fileID: -8784545083839296357, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_SubmitAction: {fileID: 392368643174621059, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_CancelAction: {fileID: 7727032971491509709, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_LeftClickAction: {fileID: 3001919216989983466, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_MiddleClickAction: {fileID: -2185481485913320682, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_RightClickAction: {fileID: -4090225696740746782, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_ScrollWheelAction: {fileID: 6240969308177333660, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_TrackedDevicePositionAction: {fileID: 6564999863303420839, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_TrackedDeviceOrientationAction: {fileID: 7970375526676320489, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
m_DeselectOnBackgroundClick: 1
m_PointerBehavior: 0
m_CursorLockBehavior: 0
m_ScrollDeltaPerTick: 6
--- !u!114 &1331954414
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1331954412}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_FirstSelected: {fileID: 0}
m_sendNavigationEvents: 1
m_DragThreshold: 10
--- !u!4 &1331954415
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1331954412}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1414861612
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1414861614}
- component: {fileID: 1414861613}
- component: {fileID: 1414861615}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &1414861613
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1414861612}
m_Enabled: 1
serializedVersion: 11
m_Type: 1
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!4 &1414861614
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1414861612}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!114 &1414861615
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1414861612}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Version: 3
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_LightLayerMask: 1
m_RenderingLayers: 1
m_CustomShadowLayers: 0
m_ShadowLayerMask: 1
m_ShadowRenderingLayers: 1
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
--- !u!1 &2136621999
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2136622002}
- component: {fileID: 2136622001}
- component: {fileID: 2136622000}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &2136622000
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2136621999}
m_Enabled: 1
--- !u!20 &2136622001
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2136621999}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &2136622002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2136621999}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &2860332021081550125
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1218340765}
m_Modifications:
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_Pivot.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_Pivot.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.x
value: 300
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.y
value: -64
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -64
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1765160980165362397, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1765160980165362397, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1765160980165362397, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1765160980165362397, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1883121240313448487, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1883121240313448487, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1913501843011813999, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_Name
value: HierarchyWindow
objectReference: {fileID: 0}
- target: {fileID: 4429635802794036160, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4429635802794036160, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4629025237416871861, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4629025237416871861, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4817867488375858252, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4817867488375858252, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7315968355667519403, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7315968355667519403, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7450804729565234258, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7450804729565234258, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 55334174237ec37438ae05ee0b89079a, type: 3}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 2136622002}
- {fileID: 1414861614}
- {fileID: 1218340765}
- {fileID: 1331954415}
- {fileID: 1097328752}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 62d2e84d8c7ec934c9e720b45d9a8eab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2b427b9e85de96047aa7cfd700a09a2e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,145 @@
#nullable enable
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UVC.UI.List.Accordion
{
/// <summary>
/// 섹션 내 아이템 배치 타입.
/// Horizontal: head-content-tail3영역 수평 배치
/// Grid: 이미지+캡션2열 그리드
/// </summary>
public enum AccordionItemLayoutType
{
Horizontal,
Grid
}
/// <summary>
/// 수평 아이템 영역에 들어갈 콘텐츠 종류.
/// </summary>
public enum AccordionContentKind
{
None,
Image,
Text,
IconButton
}
/// <summary>
/// 수평 아이템의 단일 영역(head/content/tail)을 기술하는 데이터.
/// </summary>
[Serializable]
public class AccordionContentSpec
{
public AccordionContentKind Kind = AccordionContentKind.None;
// Text
public string? Text;
public UnityEngine.Object? Font; // TMP_FontAsset 또는 Font
public Color TextColor = Color.white;
public int FontSize = 22;
// Image
public Sprite? Sprite;
public Color ImageColor = Color.white;
// IconButton
public Sprite? Icon;
public Action? OnClick;
public string? Tooltip;
public static AccordionContentSpec FromText(string text, Color? color = null, int fontSize = 22, UnityEngine.Object? font = null)
=> new AccordionContentSpec
{
Kind = AccordionContentKind.Text,
Text = text,
TextColor = color ?? Color.white,
FontSize = fontSize,
Font = font
};
public static AccordionContentSpec FromImage(Sprite? sprite, Color? color = null)
=> new AccordionContentSpec
{
Kind = AccordionContentKind.Image,
Sprite = sprite,
ImageColor = color ?? Color.white
};
public static AccordionContentSpec FromIconButton(Sprite? icon, Action onClick, string? tooltip = null)
=> new AccordionContentSpec
{
Kind = AccordionContentKind.IconButton,
Icon = icon,
OnClick = onClick,
Tooltip = tooltip
};
}
/// <summary>
/// 아코디언 항목 데이터 인터페이스.
/// </summary>
public interface IAccordionItemData
{
AccordionItemLayoutType LayoutType { get; }
}
/// <summary>
/// head-content-tail 수평 아이템 데이터.
/// </summary>
[Serializable]
public class AccordionHorizontalItemData : IAccordionItemData
{
public AccordionItemLayoutType LayoutType => AccordionItemLayoutType.Horizontal;
public AccordionContentSpec Head = new AccordionContentSpec();
public AccordionContentSpec Content = new AccordionContentSpec();
public AccordionContentSpec Tail = new AccordionContentSpec();
/// <summary>
/// 임의의 태그/키 값.
/// </summary>
public string? Tag;
}
/// <summary>
/// 그리드 셀(이미지+캡션) 데이터.
/// </summary>
[Serializable]
public class AccordionGridItemData : IAccordionItemData
{
public AccordionItemLayoutType LayoutType => AccordionItemLayoutType.Grid;
public Sprite? Image;
public string Caption = string.Empty;
public Color CaptionColor = Color.white;
public int CaptionSize = 20;
public Action? OnClick;
public string? Tag;
}
/// <summary>
/// 단일 섹션 데이터(제목/펼침/아이템 컬렉션).
/// </summary>
[Serializable]
public class AccordionSectionData
{
public string Title = string.Empty;
public bool IsExpanded = false;
public AccordionItemLayoutType LayoutType = AccordionItemLayoutType.Horizontal;
// 아이템 리스트. LayoutType에 따라 타입을 일치시켜 사용합니다.
public List<IAccordionItemData> Items = new List<IAccordionItemData>();
}
/// <summary>
/// 아코디언 전체 데이터 루트.
/// </summary>
[Serializable]
public class AccordionData
{
public List<AccordionSectionData> Sections = new List<AccordionSectionData>();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 29fe5d846fc771e418d6d0090157dbfd

View File

@@ -0,0 +1,65 @@
#nullable enable
using UnityEngine;
using UnityEngine.UI;
namespace UVC.UI.List.Accordion
{
/// <summary>
/// 그리드 셀 항목(이미지+캡션). 셀 크기는 상위 GridLayoutGroup에서 결정.
/// </summary>
public class AccordionGridItemView : MonoBehaviour
{
[SerializeField] private Image image = default!;
[SerializeField] private Component caption = default!; // TMP or Text
[SerializeField] private Button button = default!;
private void Reset()
{
EnsureLayout();
}
private void Awake()
{
EnsureLayout();
}
private void EnsureLayout()
{
if (image == null)
{
var imgGO = new GameObject("Image", typeof(RectTransform), typeof(Image));
imgGO.transform.SetParent(transform, false);
image = imgGO.GetComponent<Image>();
image.preserveAspect = true;
}
if (caption == null)
{
caption = TMPProxy.CreateTextGO(transform, "Caption");
TMPProxy.SetAlignment(caption, "TopLeft");
}
if (button == null)
{
var btn = gameObject.GetComponent<Button>();
if (btn == null) btn = gameObject.AddComponent<Button>();
button = btn;
}
var v = GetComponent<VerticalLayoutGroup>();
if (v == null) v = gameObject.AddComponent<VerticalLayoutGroup>();
v.childControlHeight = true;
v.childForceExpandHeight = true;
v.spacing = 2f;
var pad = 4;
v.padding = new RectOffset(pad, pad, pad, pad);
}
public void Initialize(AccordionGridItemData data)
{
image.sprite = data.Image;
TMPProxy.SetText(caption, data.Caption);
TMPProxy.SetColor(caption, data.CaptionColor);
TMPProxy.SetFontSize(caption, data.CaptionSize);
button.onClick.RemoveAllListeners();
if (data.OnClick != null) button.onClick.AddListener(() => data.OnClick());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bbb82949b2c1f134dbb493c71bbec615

View File

@@ -0,0 +1,132 @@
#nullable enable
using UnityEngine;
using UnityEngine.UI;
namespace UVC.UI.List.Accordion
{
/// <summary>
/// 수평 아이템(Head-Content-Tail) 뷰. 고정 높이35.
/// 각 영역은 Text, Image, IconButton를 지원합니다.
/// </summary>
public class AccordionItemView : MonoBehaviour
{
[SerializeField] private RectTransform headRoot = default!;
[SerializeField] private RectTransform contentRoot = default!;
[SerializeField] private RectTransform tailRoot = default!;
private void Reset()
{
EnsureLayout();
}
private void Awake()
{
EnsureLayout();
}
private void EnsureLayout()
{
var rt = (RectTransform)transform;
rt.sizeDelta = new Vector2(AccordionList.Width, AccordionList.ItemHeight);
var h = GetComponent<HorizontalLayoutGroup>();
if (h == null) h = gameObject.AddComponent<HorizontalLayoutGroup>();
h.childControlHeight = true;
h.childForceExpandHeight = true;
h.childControlWidth = true;
h.childForceExpandWidth = true;
h.spacing = 4f;
h.padding = new RectOffset(6, 6, 0, 0);
if (headRoot == null)
{
headRoot = CreateSlot("Head", 0.25f);
}
if (contentRoot == null)
{
contentRoot = CreateSlot("Content", 0.5f);
}
if (tailRoot == null)
{
tailRoot = CreateSlot("Tail", 0.25f);
}
}
private RectTransform CreateSlot(string name, float flexible)
{
var go = new GameObject(name, typeof(RectTransform));
go.transform.SetParent(transform, false);
var layout = go.AddComponent<LayoutElement>();
layout.flexibleWidth = flexible;
layout.minHeight = AccordionList.ItemHeight;
var rt = (RectTransform)go.transform;
return rt;
}
public void Initialize(AccordionHorizontalItemData data)
{
BuildArea(headRoot, data.Head);
BuildArea(contentRoot, data.Content);
BuildArea(tailRoot, data.Tail);
}
private void BuildArea(RectTransform parent, AccordionContentSpec spec)
{
// clear
for (int i = parent.childCount - 1; i >= 0; i--)
{
Destroy(parent.GetChild(i).gameObject);
}
switch (spec.Kind)
{
case AccordionContentKind.Text:
BuildText(parent, spec.Text ?? string.Empty, spec.Font, spec.TextColor, spec.FontSize);
break;
case AccordionContentKind.Image:
BuildImage(parent, spec.Sprite, spec.ImageColor);
break;
case AccordionContentKind.IconButton:
BuildIconButton(parent, spec.Icon, spec.OnClick);
break;
default:
break;
}
}
private void BuildText(RectTransform parent, string text, UnityEngine.Object? fontAsset, Color color, int size)
{
var comp = TMPProxy.CreateTextGO(parent, "Text");
TMPProxy.SetText(comp, text);
TMPProxy.SetColor(comp, color);
TMPProxy.SetFontSize(comp, size);
TMPProxy.SetFont(comp, fontAsset);
TMPProxy.SetAlignment(comp, "MidlineLeft");
}
private void BuildImage(RectTransform parent, Sprite? sprite, Color color)
{
var go = new GameObject("Image", typeof(RectTransform), typeof(Image));
go.transform.SetParent(parent, false);
var img = go.GetComponent<Image>();
img.sprite = sprite;
img.color = color;
img.preserveAspect = true;
var le = go.AddComponent<LayoutElement>();
le.minHeight = AccordionList.ItemHeight;
}
private void BuildIconButton(RectTransform parent, Sprite? icon, System.Action? onClick)
{
var go = new GameObject("IconButton", typeof(RectTransform), typeof(Image), typeof(Button));
go.transform.SetParent(parent, false);
var img = go.GetComponent<Image>();
img.sprite = icon;
img.preserveAspect = true;
var btn = go.GetComponent<Button>();
btn.onClick.RemoveAllListeners();
if (onClick != null) btn.onClick.AddListener(() => onClick());
var le = go.AddComponent<LayoutElement>();
le.minHeight = AccordionList.ItemHeight;
le.minWidth = AccordionList.ItemHeight;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3c7296b1c3a691547ac7714fde688237

View File

@@ -0,0 +1,124 @@
#nullable enable
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace UVC.UI.List.Accordion
{
/// <summary>
/// 아코디언 전체 리스트 뷰. 섹션 헤더(48)와 항목(35)을 생성/관리합니다.
/// 가로 너비는250으로 고정합니다.
/// </summary>
[DisallowMultipleComponent]
public class AccordionList : MonoBehaviour
{
// Layout constants
public const float Width = 250f;
public const float HeaderHeight = 48f;
public const float ItemHeight = 35f;
public const int GridColumns = 2;
[Header("Prefabs")]
[SerializeField] private AccordionSection sectionPrefab = default!;
[SerializeField] private AccordionItemView horizontalItemPrefab = default!;
[SerializeField] private AccordionGridItemView gridItemPrefab = default!;
[Header("Root")]
[SerializeField] private RectTransform contentRoot = default!; // VerticalLayoutGroup 권장
[Header("Style")]
[SerializeField] private Color sectionHeaderColor = new Color(0.16f, 0.16f, 0.16f);
[SerializeField] private Color itemBgColor = new Color(0.10f, 0.10f, 0.10f);
public AccordionData? Data { get; private set; }
private readonly List<AccordionSection> _sections = new();
private void Reset()
{
EnsureRootLayout();
EnsurePrefabs();
}
private void Awake()
{
EnsureRootLayout();
EnsurePrefabs();
}
private void EnsureRootLayout()
{
if (contentRoot == null)
{
var go = new GameObject("ContentRoot", typeof(RectTransform));
go.transform.SetParent(transform, false);
contentRoot = (RectTransform)go.transform;
}
var rt = (RectTransform)transform;
rt.sizeDelta = new Vector2(Width, rt.sizeDelta.y);
var v = contentRoot.GetComponent<VerticalLayoutGroup>();
if (v == null) v = contentRoot.gameObject.AddComponent<VerticalLayoutGroup>();
v.childForceExpandHeight = false;
v.childControlHeight = true;
v.childForceExpandWidth = true;
v.childControlWidth = true;
v.spacing = 0f;
var fitter = contentRoot.GetComponent<ContentSizeFitter>();
if (fitter == null) fitter = contentRoot.gameObject.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
}
private void EnsurePrefabs()
{
if (sectionPrefab == null)
{
var proto = new GameObject("SectionPrototype", typeof(RectTransform), typeof(AccordionSection));
proto.transform.SetParent(transform, false);
proto.SetActive(false);
sectionPrefab = proto.GetComponent<AccordionSection>();
}
if (horizontalItemPrefab == null)
{
var proto = new GameObject("HorizontalItemPrototype", typeof(RectTransform), typeof(AccordionItemView));
proto.transform.SetParent(transform, false);
proto.SetActive(false);
horizontalItemPrefab = proto.GetComponent<AccordionItemView>();
}
if (gridItemPrefab == null)
{
var proto = new GameObject("GridItemPrototype", typeof(RectTransform), typeof(AccordionGridItemView));
proto.transform.SetParent(transform, false);
proto.SetActive(false);
gridItemPrefab = proto.GetComponent<AccordionGridItemView>();
}
}
public void SetData(AccordionData data)
{
EnsureRootLayout();
EnsurePrefabs();
Clear();
Data = data;
foreach (var sectionData in data.Sections)
{
var section = Instantiate(sectionPrefab, contentRoot);
section.gameObject.SetActive(true);
section.Initialize(sectionData, this, horizontalItemPrefab, gridItemPrefab);
_sections.Add(section);
}
}
public void Clear()
{
foreach (var s in _sections)
{
if (s != null) Destroy(s.gameObject);
}
_sections.Clear();
Data = null;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3da2a3205a856104cbeff1d2a234d19f

View File

@@ -0,0 +1,158 @@
#nullable enable
using UnityEngine;
using UnityEngine.UI;
namespace UVC.UI.List.Accordion
{
/// <summary>
/// 단일 섹션 헤더(48높이)와 본문을 관리합니다.
/// </summary>
public class AccordionSection : MonoBehaviour
{
[SerializeField] private Button headerButton = default!;
[SerializeField] private Image headerBg = default!;
[SerializeField] private Component titleText = default!; // TMP or Text
[SerializeField] private RectTransform bodyRoot = default!; // items parent
[SerializeField] private GameObject bodyContainer = default!; // active toggle
private AccordionSectionData? _data;
private AccordionList? _list;
private AccordionItemView? _horizontalItemPrefab;
private AccordionGridItemView? _gridItemPrefab;
private void Reset()
{
EnsureRuntimeComponents();
}
private void Awake()
{
EnsureRuntimeComponents();
}
private void EnsureRuntimeComponents()
{
var rt = (RectTransform)transform;
if (headerButton == null)
{
var headerGO = new GameObject("Header", typeof(RectTransform), typeof(Image), typeof(Button));
headerGO.transform.SetParent(transform, false);
var headerRT = (RectTransform)headerGO.transform;
headerRT.anchorMin = new Vector2(0, 1);
headerRT.anchorMax = new Vector2(1, 1);
headerRT.pivot = new Vector2(0.5f, 1);
headerRT.sizeDelta = new Vector2(0, AccordionList.HeaderHeight);
headerBg = headerGO.GetComponent<Image>();
headerButton = headerGO.GetComponent<Button>();
var textComp = TMPProxy.CreateTextGO(headerGO.transform, "Title");
var textRT = (RectTransform)textComp.transform;
textRT.anchorMin = new Vector2(0, 0);
textRT.anchorMax = new Vector2(1, 1);
textRT.offsetMin = new Vector2(12, 0);
textRT.offsetMax = new Vector2(-12, 0);
titleText = textComp;
TMPProxy.SetAlignment(titleText, "MidlineLeft");
}
if (bodyContainer == null)
{
var bodyGO = new GameObject("BodyContainer", typeof(RectTransform));
bodyGO.transform.SetParent(transform, false);
bodyContainer = bodyGO;
bodyRoot = (RectTransform)bodyGO.transform;
var v = bodyGO.AddComponent<VerticalLayoutGroup>();
v.childControlHeight = true;
v.childForceExpandHeight = false;
v.spacing = 0f;
var fitter = bodyGO.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
}
var layout = GetComponent<VerticalLayoutGroup>();
if (layout == null) layout = gameObject.AddComponent<VerticalLayoutGroup>();
layout.childControlHeight = true;
layout.childForceExpandHeight = false;
layout.spacing = 0f;
}
public void Initialize(AccordionSectionData data, AccordionList list, AccordionItemView horizontalItemPrefab, AccordionGridItemView gridItemPrefab)
{
_data = data;
_list = list;
_horizontalItemPrefab = horizontalItemPrefab;
_gridItemPrefab = gridItemPrefab;
// Appearance
var rt = (RectTransform)transform;
rt.sizeDelta = new Vector2(AccordionList.Width, rt.sizeDelta.y);
headerBg.color = new Color(0.18f, 0.18f, 0.18f);
TMPProxy.SetText(titleText, data.Title);
headerButton.onClick.RemoveAllListeners();
headerButton.onClick.AddListener(() => Toggle());
bodyContainer.SetActive(_data.IsExpanded);
BuildItems();
}
private void Toggle()
{
if (_data == null) return;
_data.IsExpanded = !_data.IsExpanded;
bodyContainer.SetActive(_data.IsExpanded);
}
private void ClearItems()
{
for (int i = bodyRoot.childCount - 1; i >= 0; i--)
{
var ch = bodyRoot.GetChild(i);
Destroy(ch.gameObject);
}
}
private void BuildItems()
{
if (_data == null || _list == null) return;
ClearItems();
if (_data.LayoutType == AccordionItemLayoutType.Horizontal)
{
foreach (var item in _data.Items)
{
if (item is AccordionHorizontalItemData h)
{
var view = Object.Instantiate(_horizontalItemPrefab!, bodyRoot);
view.Initialize(h);
}
}
}
else // Grid
{
// Wrap to2 columns using GridLayoutGroup
var containerGO = new GameObject("Grid", typeof(RectTransform), typeof(GridLayoutGroup), typeof(ContentSizeFitter));
containerGO.transform.SetParent(bodyRoot, false);
var gridRT = (RectTransform)containerGO.transform;
gridRT.sizeDelta = new Vector2(AccordionList.Width, gridRT.sizeDelta.y);
var grid = containerGO.GetComponent<GridLayoutGroup>();
float padding = 6f;
grid.cellSize = new Vector2((AccordionList.Width - padding * 3) / 2f, AccordionList.ItemHeight * 2f);
grid.spacing = new Vector2(padding, padding);
grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
grid.constraintCount = AccordionList.GridColumns;
var fitter = containerGO.GetComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
foreach (var item in _data.Items)
{
if (item is AccordionGridItemData g)
{
var view = Object.Instantiate(_gridItemPrefab!, gridRT);
view.Initialize(g);
}
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 17ca068f38574f84a969ad833b66e699

View File

@@ -0,0 +1,105 @@
#nullable enable
using System;
using UnityEngine;
using UnityEngine.UI;
namespace UVC.UI.List.Accordion
{
internal static class TMPProxy
{
private static Type? _tmpTextType;
private static Type? _tmpFontType;
private static Type? _tmpAlignType;
private static Type? TMPTextType => _tmpTextType ??= Type.GetType("TMPro.TextMeshProUGUI, Unity.TextMeshPro");
private static Type? TMPFontType => _tmpFontType ??= Type.GetType("TMPro.TMP_FontAsset, Unity.TextMeshPro");
private static Type? TMPAlignType => _tmpAlignType ??= Type.GetType("TMPro.TextAlignmentOptions, Unity.TextMeshPro");
public static Component CreateTextGO(Transform parent, string name)
{
var go = new GameObject(name, typeof(RectTransform));
go.transform.SetParent(parent, false);
if (TMPTextType != null)
{
go.AddComponent(TMPTextType);
return (Component)go.GetComponent(TMPTextType);
}
else
{
var text = go.AddComponent<Text>();
text.alignment = TextAnchor.MiddleLeft;
text.text = string.Empty;
return text;
}
}
public static void SetText(Component comp, string text)
{
if (TMPTextType != null && TMPTextType.IsInstanceOfType(comp))
{
TMPTextType.GetProperty("text")?.SetValue(comp, text);
}
else if (comp is Text uText)
{
uText.text = text;
}
}
public static void SetColor(Component comp, Color color)
{
if (TMPTextType != null && TMPTextType.IsInstanceOfType(comp))
{
TMPTextType.GetProperty("color")?.SetValue(comp, color);
}
else if (comp is Text uText)
{
uText.color = color;
}
}
public static void SetFontSize(Component comp, int size)
{
if (TMPTextType != null && TMPTextType.IsInstanceOfType(comp))
{
TMPTextType.GetProperty("fontSize")?.SetValue(comp, (float)size);
}
else if (comp is Text uText)
{
uText.fontSize = size;
}
}
public static void SetFont(Component comp, UnityEngine.Object? fontAsset)
{
if (fontAsset == null) return;
if (TMPTextType != null && TMPTextType.IsInstanceOfType(comp) && TMPFontType != null && TMPFontType.IsInstanceOfType(fontAsset))
{
TMPTextType.GetProperty("font")?.SetValue(comp, fontAsset);
}
else if (comp is Text uText && fontAsset is Font uFont)
{
uText.font = uFont;
}
}
public static void SetAlignment(Component comp, string alignment)
{
if (TMPTextType != null && TMPTextType.IsInstanceOfType(comp) && TMPAlignType != null)
{
try
{
var enumVal = Enum.Parse(TMPAlignType, alignment);
TMPTextType.GetProperty("alignment")?.SetValue(comp, enumVal);
}
catch { }
}
else if (comp is Text uText)
{
if (string.Equals(alignment, "TopLeft", StringComparison.OrdinalIgnoreCase))
uText.alignment = TextAnchor.UpperLeft;
else
uText.alignment = TextAnchor.MiddleLeft;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d2968af399993f94f8aa265253691829

View File

@@ -0,0 +1,68 @@
#nullable enable
using System;
using UnityEngine;
using UnityEngine.UI;
using UVC.UI.List.Accordion;
namespace UVC.UI.Window
{
public class AccordionWindow : MonoBehaviour
{
[SerializeField] private RectTransform root = default!;
[SerializeField] private AccordionList? accordionListPrefab = null;
private AccordionList? _instance;
private void Reset()
{
EnsureRoot();
EnsureInstance();
}
private void Awake()
{
EnsureRoot();
EnsureInstance();
}
private void EnsureRoot()
{
if (root == null)
{
var go = new GameObject("AccordionRoot", typeof(RectTransform));
go.transform.SetParent(transform, false);
root = (RectTransform)go.transform;
var v = go.AddComponent<VerticalLayoutGroup>();
v.childControlHeight = true;
v.childForceExpandHeight = false;
v.spacing = 0f;
var fitter = go.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
}
}
private void EnsureInstance()
{
if (_instance == null)
{
if (accordionListPrefab != null)
{
_instance = Instantiate(accordionListPrefab, root);
_instance.gameObject.SetActive(true);
}
else
{
var go = new GameObject("AccordionList", typeof(RectTransform), typeof(AccordionList));
go.transform.SetParent(root, false);
_instance = go.GetComponent<AccordionList>();
}
}
}
public void SetData(AccordionData data)
{
EnsureRoot();
EnsureInstance();
_instance!.SetData(data);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6ad50e65d5080f04c99dd7606a8a4d70

View File

@@ -24,9 +24,9 @@ namespace UVC.UI.Window
/// <example>
/// <![CDATA[
/// // 외부에서 창을 참조했다고 가정
/// hierarchyWindow.OnItemSelected += item => Debug.Log($"Selected: {item.Name}");
/// hierarchyWindow.AddItem(new TreeListItemData("Root A"));
/// hierarchyWindow.AddItemAt(new TreeListItemData("Root B"),0);
/// accordionWindow.OnItemSelected += item => Debug.Log($"Selected: {item.Name}");
/// accordionWindow.AddItem(new TreeListItemData("Root A"));
/// accordionWindow.AddItemAt(new TreeListItemData("Root B"),0);
/// ]]>
/// </example>
/// </summary>