2025-11-08 14:03:17 +08:00
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
|
using UnityEngine.UI;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using TMPro;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SceneView
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct RectTransformConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public Vector2 AnchorMin;
|
|
|
|
|
|
public Vector2 AnchorMax;
|
|
|
|
|
|
public Vector2 AnchoredPosition;
|
|
|
|
|
|
public Vector2 SizeDelta;
|
|
|
|
|
|
public Vector2 OffsetMin;
|
|
|
|
|
|
public Vector2 OffsetMax;
|
|
|
|
|
|
public Vector2 Pivot;
|
|
|
|
|
|
|
|
|
|
|
|
// 默认配置
|
|
|
|
|
|
public static readonly RectTransformConfig Default = new RectTransformConfig(
|
2025-11-13 16:24:49 +08:00
|
|
|
|
Vector2.up, // 锚点最小:左上角 (0, 1)
|
|
|
|
|
|
Vector2.up, // 锚点最大:左上角 (0, 1)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 0.5f) // 默认居中轴心点
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 填充父级的配置
|
|
|
|
|
|
public static readonly RectTransformConfig FillParent = new RectTransformConfig(
|
|
|
|
|
|
Vector2.zero, // 锚点最小:左下角 (0, 0)
|
|
|
|
|
|
Vector2.one, // 锚点最大:右上角 (1, 1)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero, // sizeDelta为零表示通过offsetMin/Max来控制尺寸
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 0.5f)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public RectTransformConfig(
|
|
|
|
|
|
Vector2 anchorMin,
|
|
|
|
|
|
Vector2 anchorMax,
|
|
|
|
|
|
Vector2 anchoredPosition,
|
|
|
|
|
|
Vector2 sizeDelta,
|
|
|
|
|
|
Vector2 offsetMin,
|
|
|
|
|
|
Vector2 offsetMax,
|
|
|
|
|
|
Vector2 pivot)
|
|
|
|
|
|
{
|
|
|
|
|
|
AnchorMin = anchorMin;
|
|
|
|
|
|
AnchorMax = anchorMax;
|
|
|
|
|
|
AnchoredPosition = anchoredPosition;
|
|
|
|
|
|
SizeDelta = sizeDelta;
|
|
|
|
|
|
OffsetMin = offsetMin;
|
|
|
|
|
|
OffsetMax = offsetMax;
|
|
|
|
|
|
Pivot = pivot;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct ButtonConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public Color BackgroundColor;
|
|
|
|
|
|
public string Text;
|
|
|
|
|
|
public int FontSize;
|
|
|
|
|
|
public Color TextColor;
|
|
|
|
|
|
public bool RaycastTarget;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly ButtonConfig Default = new ButtonConfig(
|
2025-11-13 16:24:49 +08:00
|
|
|
|
RectTransformConfig.Default,
|
|
|
|
|
|
new Color(0.2f, 0.2f, 0.2f, 1f),
|
|
|
|
|
|
"Button",
|
|
|
|
|
|
18,
|
|
|
|
|
|
Color.white,
|
|
|
|
|
|
true
|
2025-11-08 14:03:17 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public ButtonConfig(
|
|
|
|
|
|
RectTransformConfig rectConfig,
|
|
|
|
|
|
Color backgroundColor,
|
|
|
|
|
|
string text,
|
|
|
|
|
|
int fontSize,
|
|
|
|
|
|
Color textColor,
|
|
|
|
|
|
bool raycastTarget = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = rectConfig;
|
|
|
|
|
|
BackgroundColor = backgroundColor;
|
|
|
|
|
|
Text = text;
|
|
|
|
|
|
FontSize = fontSize;
|
|
|
|
|
|
TextColor = textColor;
|
|
|
|
|
|
RaycastTarget = raycastTarget;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct TextConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public string Text;
|
|
|
|
|
|
public int FontSize;
|
|
|
|
|
|
public Color TextColor;
|
|
|
|
|
|
public TextAlignmentOptions Alignment;
|
|
|
|
|
|
public bool RaycastTarget;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly TextConfig Default = new TextConfig(
|
|
|
|
|
|
rectConfig: RectTransformConfig.Default,
|
|
|
|
|
|
text: "New Text",
|
|
|
|
|
|
fontSize: 18,
|
|
|
|
|
|
textColor: Color.white,
|
|
|
|
|
|
alignment: TextAlignmentOptions.Center,
|
|
|
|
|
|
raycastTarget: false
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public TextConfig(
|
|
|
|
|
|
string text,
|
|
|
|
|
|
int fontSize,
|
|
|
|
|
|
Color textColor,
|
|
|
|
|
|
TextAlignmentOptions alignment,
|
|
|
|
|
|
bool raycastTarget,
|
|
|
|
|
|
RectTransformConfig rectConfig)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = rectConfig;
|
|
|
|
|
|
Text = text;
|
|
|
|
|
|
FontSize = fontSize;
|
|
|
|
|
|
TextColor = textColor;
|
|
|
|
|
|
Alignment = alignment;
|
|
|
|
|
|
RaycastTarget = raycastTarget;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct ScrollViewConfig
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
public RectTransformConfig RectConfig; // 新增:ScrollView自身的RectTransform配置
|
2025-11-08 14:03:17 +08:00
|
|
|
|
public bool Vertical;
|
|
|
|
|
|
public bool Horizontal;
|
|
|
|
|
|
public Color BackgroundColor;
|
|
|
|
|
|
public Vector2 ContentPadding; // 内容区域的内边距(上下左右)
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly ScrollViewConfig Default = new ScrollViewConfig
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
RectConfig = new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0.5f, 0.5f), // 锚点最小:中心 (0.5, 0.5)
|
|
|
|
|
|
new Vector2(0.5f, 0.5f), // 锚点最大:中心 (0.5, 0.5)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(400, 300), // 默认尺寸
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 0.5f)
|
|
|
|
|
|
),
|
2025-11-08 14:03:17 +08:00
|
|
|
|
Vertical = true,
|
|
|
|
|
|
Horizontal = false,
|
|
|
|
|
|
BackgroundColor = new Color(0.1f, 0.1f, 0.1f, 0.8f),
|
|
|
|
|
|
ContentPadding = new Vector2(10, 10) // (horizontal, vertical)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct InputFieldConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public Color BackgroundColor;
|
|
|
|
|
|
public string PlaceholderText;
|
|
|
|
|
|
public int PlaceholderFontSize;
|
|
|
|
|
|
public Color PlaceholderTextColor;
|
|
|
|
|
|
public Color TextColor;
|
|
|
|
|
|
public int FontSize;
|
|
|
|
|
|
public TextAlignmentOptions TextAlignment;
|
|
|
|
|
|
public TMP_InputField.CharacterValidation CharacterValidation;
|
|
|
|
|
|
public int CharacterLimit;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
public static readonly InputFieldConfig Default = new InputFieldConfig(
|
2025-11-13 16:24:49 +08:00
|
|
|
|
RectTransformConfig.Default,
|
|
|
|
|
|
new Color(0.2f, 0.2f, 0.2f, 1f),
|
|
|
|
|
|
"Enter text here",
|
|
|
|
|
|
14,
|
|
|
|
|
|
new Color(0.7f, 0.7f, 0.7f, 1f),
|
|
|
|
|
|
Color.white,
|
|
|
|
|
|
18,
|
|
|
|
|
|
TextAlignmentOptions.Left,
|
|
|
|
|
|
TMP_InputField.CharacterValidation.None,
|
|
|
|
|
|
0
|
2025-11-08 14:03:17 +08:00
|
|
|
|
);
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
public InputFieldConfig(
|
|
|
|
|
|
RectTransformConfig rectConfig,
|
|
|
|
|
|
Color backgroundColor,
|
|
|
|
|
|
string placeholderText,
|
|
|
|
|
|
int placeholderFontSize,
|
|
|
|
|
|
Color placeholderTextColor,
|
|
|
|
|
|
Color textColor,
|
|
|
|
|
|
int fontSize,
|
|
|
|
|
|
TextAlignmentOptions textAlignment,
|
|
|
|
|
|
TMP_InputField.CharacterValidation characterValidation = TMP_InputField.CharacterValidation.None,
|
|
|
|
|
|
int characterLimit = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = rectConfig;
|
|
|
|
|
|
BackgroundColor = backgroundColor;
|
|
|
|
|
|
PlaceholderText = placeholderText;
|
|
|
|
|
|
PlaceholderFontSize = placeholderFontSize;
|
|
|
|
|
|
PlaceholderTextColor = placeholderTextColor;
|
|
|
|
|
|
TextColor = textColor;
|
|
|
|
|
|
FontSize = fontSize;
|
|
|
|
|
|
TextAlignment = textAlignment;
|
|
|
|
|
|
CharacterValidation = characterValidation;
|
|
|
|
|
|
CharacterLimit = characterLimit;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct LabeledInputFieldConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig; // 整个控件(标签+输入框)的配置
|
|
|
|
|
|
public string LabelText;
|
|
|
|
|
|
public int LabelFontSize;
|
|
|
|
|
|
public Color LabelTextColor;
|
|
|
|
|
|
public float LabelWidth; // 标签部分的固定宽度
|
|
|
|
|
|
public float Spacing; // 标签和输入框之间的间距
|
|
|
|
|
|
public InputFieldConfig InputFieldConfig; // 复用已有的输入框配置
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly LabeledInputFieldConfig Default = new LabeledInputFieldConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = new RectTransformConfig(
|
|
|
|
|
|
Vector2.up, // 锚点最小:左上角 (0, 1)
|
|
|
|
|
|
Vector2.one, // 锚点最大:右上角 (1, 1),默认水平拉伸
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0, 30), // 默认高度30
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 1) // 轴心点:顶部居中
|
|
|
|
|
|
),
|
|
|
|
|
|
LabelText = "Label",
|
|
|
|
|
|
LabelFontSize = 18,
|
|
|
|
|
|
LabelTextColor = Color.white,
|
|
|
|
|
|
LabelWidth = 100f,
|
|
|
|
|
|
Spacing = 10f,
|
|
|
|
|
|
InputFieldConfig = InputFieldConfig.Default
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct DropdownConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public List<string> Options;
|
|
|
|
|
|
public Color BackgroundColor;
|
|
|
|
|
|
public int CaptionFontSize; // 下拉框当前选中项的文本大小
|
|
|
|
|
|
public Color CaptionTextColor;
|
|
|
|
|
|
public int ItemFontSize; // 下拉列表每一项的文本大小
|
|
|
|
|
|
public Color ItemTextColor;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DropdownConfig Default = new DropdownConfig(
|
|
|
|
|
|
new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0.5f, 0.5f), // 锚点最小:中心 (0.5, 0.5)
|
|
|
|
|
|
new Vector2(0.5f, 0.5f), // 锚点最大:中心 (0.5, 0.5)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(160, 30),
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 0.5f)
|
|
|
|
|
|
),
|
|
|
|
|
|
new List<string> { "Option A", "Option B", "Option C" },
|
|
|
|
|
|
new Color(0.2f, 0.2f, 0.2f, 1f),
|
|
|
|
|
|
18,
|
|
|
|
|
|
Color.white,
|
|
|
|
|
|
16,
|
|
|
|
|
|
Color.white
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public DropdownConfig(RectTransformConfig rectConfig, List<string> options, Color backgroundColor,
|
|
|
|
|
|
int captionFontSize, Color captionTextColor, int itemFontSize, Color itemTextColor)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = rectConfig;
|
|
|
|
|
|
Options = options;
|
|
|
|
|
|
BackgroundColor = backgroundColor;
|
|
|
|
|
|
CaptionFontSize = captionFontSize;
|
|
|
|
|
|
CaptionTextColor = captionTextColor;
|
|
|
|
|
|
ItemFontSize = itemFontSize;
|
|
|
|
|
|
ItemTextColor = itemTextColor;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct LabeledDropdownConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public string LabelText;
|
|
|
|
|
|
public int LabelFontSize;
|
|
|
|
|
|
public Color LabelTextColor;
|
|
|
|
|
|
public float LabelWidth;
|
|
|
|
|
|
public float Spacing;
|
|
|
|
|
|
public DropdownConfig DropdownConfig;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly LabeledDropdownConfig Default = new LabeledDropdownConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = new RectTransformConfig(
|
|
|
|
|
|
Vector2.up, // 锚点最小:左上角 (0, 1)
|
|
|
|
|
|
Vector2.one, // 锚点最大:右上角 (1, 1)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0, 30),
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 1)
|
|
|
|
|
|
),
|
|
|
|
|
|
LabelText = "Label",
|
|
|
|
|
|
LabelFontSize = 18,
|
|
|
|
|
|
LabelTextColor = Color.white,
|
|
|
|
|
|
LabelWidth = 100f,
|
|
|
|
|
|
Spacing = 10f,
|
|
|
|
|
|
DropdownConfig = DropdownConfig.Default
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public struct ToggleConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public RectTransformConfig RectConfig;
|
|
|
|
|
|
public string LabelText;
|
|
|
|
|
|
public int LabelFontSize;
|
|
|
|
|
|
public Color LabelTextColor;
|
|
|
|
|
|
public Color BackgroundColor;
|
|
|
|
|
|
public Color CheckmarkColor;
|
|
|
|
|
|
public float Spacing; // 开关图形和标签之间的间距
|
|
|
|
|
|
public bool IsOnByDefault;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly ToggleConfig Default = new ToggleConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
RectConfig = new RectTransformConfig(
|
|
|
|
|
|
Vector2.up, // 锚点最小:左上角 (0, 1)
|
|
|
|
|
|
Vector2.up, // 锚点最大:左上角 (0, 1)
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(160, 20),
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 0.5f)
|
|
|
|
|
|
),
|
|
|
|
|
|
LabelText = "Toggle",
|
|
|
|
|
|
LabelFontSize = 18,
|
|
|
|
|
|
LabelTextColor = Color.white,
|
|
|
|
|
|
BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 1f),
|
|
|
|
|
|
CheckmarkColor = new Color(0.1f, 0.6f, 1f, 1f),
|
|
|
|
|
|
Spacing = 10f,
|
|
|
|
|
|
IsOnByDefault = false
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
public static class ControlUtilities
|
|
|
|
|
|
{
|
|
|
|
|
|
// 通用方法:将 RectTransformConfig 应用于 RectTransform
|
|
|
|
|
|
private static void ApplyRectTransformConfig(RectTransform rectTransform, RectTransformConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
rectTransform.anchorMin = config.AnchorMin;
|
|
|
|
|
|
rectTransform.anchorMax = config.AnchorMax;
|
|
|
|
|
|
rectTransform.pivot = config.Pivot;
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 当sizeDelta为Vector2.zero时,我们假定用户希望通过offsetMin/Max来拉伸元素
|
|
|
|
|
|
// 否则使用anchoredPosition和sizeDelta来定位和设置尺寸
|
|
|
|
|
|
if (config.SizeDelta == Vector2.zero && (config.OffsetMin != Vector2.zero ||
|
|
|
|
|
|
config.OffsetMax != Vector2.zero ||
|
|
|
|
|
|
(config.AnchorMin == Vector2.zero &&
|
|
|
|
|
|
config.AnchorMax == Vector2.one)))
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
|
|
|
|
|
rectTransform.offsetMin = config.OffsetMin;
|
|
|
|
|
|
rectTransform.offsetMax = config.OffsetMax;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
rectTransform.anchoredPosition = config.AnchoredPosition;
|
|
|
|
|
|
rectTransform.sizeDelta = config.SizeDelta;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// ========================
|
|
|
|
|
|
// 矩形对象创建
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个带有 RectTransform 组件的空 GameObject。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="name">GameObject 的名称。</param>
|
|
|
|
|
|
/// <param name="config">RectTransform 的配置。</param>
|
|
|
|
|
|
/// <returns>创建的 RectTransform 组件。</returns>
|
|
|
|
|
|
public static RectTransform CreateRect(Transform parent, string name, RectTransformConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
var obj = new GameObject(name);
|
|
|
|
|
|
var rect = obj.AddComponent<RectTransform>();
|
|
|
|
|
|
rect.SetParent(parent, false); // false表示不保留世界坐标,而是以父级为基准
|
|
|
|
|
|
ApplyRectTransformConfig(rect, config);
|
|
|
|
|
|
return rect;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
// ========================
|
|
|
|
|
|
// 按钮创建
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
public static (Button? button, TextMeshProUGUI? text) CreateButton(RectTransform? parent, ButtonConfig config,
|
|
|
|
|
|
UnityAction? onClick)
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 使用 CreateRect 创建按钮根对象并应用配置
|
|
|
|
|
|
var btnRect = CreateRect(parent, config.Text + "Button", config.RectConfig);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var button = btnRect.gameObject.AddComponent<Button>();
|
|
|
|
|
|
var image = btnRect.gameObject.AddComponent<Image>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
image.color = config.BackgroundColor;
|
|
|
|
|
|
button.image = image;
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 创建文本子对象,并使其填充按钮
|
|
|
|
|
|
var txtRect = CreateRect(btnRect, "Text (TMP)", RectTransformConfig.FillParent);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var tmpText = txtRect.gameObject.AddComponent<TextMeshProUGUI>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
tmpText.text = config.Text;
|
|
|
|
|
|
tmpText.color = config.TextColor;
|
|
|
|
|
|
tmpText.alignment = TextAlignmentOptions.Center;
|
|
|
|
|
|
tmpText.fontSize = config.FontSize;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
tmpText.raycastTarget = config.RaycastTarget; // 文本RaycastTarget通常为false,除非文本本身需要互动
|
2025-11-08 14:03:17 +08:00
|
|
|
|
if (onClick != null)
|
|
|
|
|
|
button.onClick.AddListener(onClick);
|
|
|
|
|
|
return (button, tmpText);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
// 文本创建(重载)
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
public static TextMeshProUGUI CreateText(Transform parent, string text)
|
|
|
|
|
|
{
|
|
|
|
|
|
var config = TextConfig.Default;
|
|
|
|
|
|
config.Text = text;
|
|
|
|
|
|
return CreateText(parent, config);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static TextMeshProUGUI CreateText(Transform parent, TextConfig config)
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 使用 CreateRect 创建文本对象并应用配置
|
|
|
|
|
|
var textRect = CreateRect(parent, config.Text + "Text", config.RectConfig);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var tmpText = textRect.gameObject.AddComponent<TextMeshProUGUI>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
tmpText.text = config.Text;
|
|
|
|
|
|
tmpText.color = config.TextColor;
|
|
|
|
|
|
tmpText.alignment = config.Alignment;
|
|
|
|
|
|
tmpText.fontSize = config.FontSize;
|
|
|
|
|
|
tmpText.raycastTarget = config.RaycastTarget;
|
|
|
|
|
|
|
|
|
|
|
|
return tmpText;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
// 滚动视图创建
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
public static (ScrollRect scrollRect, RectTransform content) CreateScrollView(
|
|
|
|
|
|
Transform parent,
|
|
|
|
|
|
ScrollViewConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. ScrollView 根对象
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var scrollViewRect = CreateRect(parent, "ScrollView", config.RectConfig);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var scrollView = scrollViewRect.gameObject.AddComponent<ScrollRect>();
|
|
|
|
|
|
var scrollViewImage = scrollViewRect.gameObject.AddComponent<Image>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
scrollViewImage.color = config.BackgroundColor;
|
|
|
|
|
|
scrollViewImage.raycastTarget = true;
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 2. Viewport 子对象 (始终填充 ScrollView)
|
|
|
|
|
|
var viewportRect = CreateRect(scrollViewRect, "Viewport", RectTransformConfig.FillParent);
|
|
|
|
|
|
|
|
|
|
|
|
viewportRect.gameObject.AddComponent<RectMask2D>(); // 或 Mask,但 RectMask2D 性能更好
|
|
|
|
|
|
var viewportImage = viewportRect.gameObject.AddComponent<Image>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
viewportImage.color = Color.clear; // 透明背景
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Content 子对象
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var contentRect =
|
|
|
|
|
|
CreateRect(viewportRect, "Content", RectTransformConfig.Default); // 初始使用Default,后续会根据滚动方向调整
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置 Content 的锚点:根据滚动方向决定
|
|
|
|
|
|
if (config.Vertical && !config.Horizontal)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 垂直滚动:宽度拉满,高度自适应
|
|
|
|
|
|
contentRect.anchorMin = new Vector2(0, 1);
|
|
|
|
|
|
contentRect.anchorMax = new Vector2(1, 1);
|
|
|
|
|
|
contentRect.pivot = new Vector2(0.5f, 1);
|
|
|
|
|
|
contentRect.anchoredPosition = new Vector2(0, -config.ContentPadding.y);
|
|
|
|
|
|
contentRect.sizeDelta = new Vector2(-2 * config.ContentPadding.x, 0); // 左右留边距
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 添加 VerticalLayoutGroup 通常是需要的,但这里只创建基础结构
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (config.Horizontal && !config.Vertical)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 水平滚动:高度拉满,宽度自适应
|
|
|
|
|
|
contentRect.anchorMin = new Vector2(0, 0);
|
|
|
|
|
|
contentRect.anchorMax = new Vector2(0, 1);
|
|
|
|
|
|
contentRect.pivot = new Vector2(0, 0.5f);
|
|
|
|
|
|
contentRect.anchoredPosition = new Vector2(config.ContentPadding.x, 0);
|
|
|
|
|
|
contentRect.sizeDelta = new Vector2(0, -2 * config.ContentPadding.y);
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 添加 HorizontalLayoutGroup 通常是需要的
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 双向滚动:自由布局,通常锚点设为左上角
|
|
|
|
|
|
contentRect.anchorMin = new Vector2(0, 1);
|
|
|
|
|
|
contentRect.anchorMax = new Vector2(0, 1);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
contentRect.pivot = new Vector2(0, 1);
|
2025-11-13 16:24:49 +08:00
|
|
|
|
contentRect.anchoredPosition = new Vector2(config.ContentPadding.x, -config.ContentPadding.y);
|
|
|
|
|
|
contentRect.sizeDelta = new Vector2(0, 0); // 自适应
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 关联 ScrollRect
|
|
|
|
|
|
scrollView.viewport = viewportRect;
|
|
|
|
|
|
scrollView.content = contentRect;
|
|
|
|
|
|
scrollView.vertical = config.Vertical;
|
|
|
|
|
|
scrollView.horizontal = config.Horizontal;
|
|
|
|
|
|
scrollView.movementType = ScrollRect.MovementType.Elastic;
|
|
|
|
|
|
scrollView.inertia = true;
|
|
|
|
|
|
scrollView.decelerationRate = 0.135f; // 默认值
|
|
|
|
|
|
|
|
|
|
|
|
return (scrollView, contentRect);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
// 文本编辑器创建
|
|
|
|
|
|
// ========================
|
|
|
|
|
|
public static (TMP_InputField inputField, TextMeshProUGUI text) CreateInputField(Transform parent,
|
|
|
|
|
|
InputFieldConfig config)
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// 使用 CreateRect 创建输入框根对象并应用配置
|
|
|
|
|
|
var inputFieldRect = CreateRect(parent, "InputField", config.RectConfig);
|
|
|
|
|
|
|
|
|
|
|
|
var inputField = inputFieldRect.gameObject.AddComponent<TMP_InputField>();
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
// 背景图像
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var backgroundImage = inputFieldRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
// 注意:Resources.Load 会在运行时加载,推荐通过 Inspector 赋值或使用 Addressables
|
|
|
|
|
|
// 为了保持原有功能,暂时保留,如果提示找不到,请确保路径正确或导入默认UI资源
|
2025-11-08 14:03:17 +08:00
|
|
|
|
backgroundImage.sprite = Resources.Load<Sprite>("UI/Skins/Background");
|
|
|
|
|
|
backgroundImage.type = Image.Type.Sliced;
|
|
|
|
|
|
backgroundImage.color = config.BackgroundColor;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
inputField.image = backgroundImage; // 设置TMP_InputField的图片引用
|
|
|
|
|
|
|
|
|
|
|
|
// 输入框文本组件 (始终填充输入框)
|
|
|
|
|
|
var textRect = CreateRect(inputFieldRect, "Text (TMP)", RectTransformConfig.FillParent);
|
|
|
|
|
|
|
|
|
|
|
|
var tmpText = textRect.gameObject.AddComponent<TextMeshProUGUI>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
tmpText.text = "";
|
|
|
|
|
|
tmpText.color = config.TextColor;
|
|
|
|
|
|
tmpText.alignment = config.TextAlignment;
|
|
|
|
|
|
tmpText.fontSize = config.FontSize;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
tmpText.raycastTarget = false; // 输入框内的文本通常不需要射线检测
|
|
|
|
|
|
inputField.textComponent = tmpText; // 设置TMP_InputField的文字组件引用
|
|
|
|
|
|
|
|
|
|
|
|
// 占位符文本组件 (始终填充输入框)
|
|
|
|
|
|
var placeholderRect = CreateRect(inputFieldRect, "Placeholder", RectTransformConfig.FillParent);
|
|
|
|
|
|
|
|
|
|
|
|
var placeholderText = placeholderRect.gameObject.AddComponent<TextMeshProUGUI>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
placeholderText.text = config.PlaceholderText;
|
|
|
|
|
|
placeholderText.color = config.PlaceholderTextColor;
|
|
|
|
|
|
placeholderText.alignment = config.TextAlignment;
|
|
|
|
|
|
placeholderText.fontSize = config.PlaceholderFontSize;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
placeholderText.raycastTarget = false; // 占位符通常不需要射线检测
|
|
|
|
|
|
inputField.placeholder = placeholderText; // 设置TMP_InputField的占位符引用
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
// 配置输入字段属性
|
|
|
|
|
|
inputField.characterValidation = config.CharacterValidation;
|
|
|
|
|
|
inputField.characterLimit = config.CharacterLimit;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
return (inputField, tmpText);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个网格布局容器,用于自动排列子对象。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="name">GameObject 名称。</param>
|
|
|
|
|
|
/// <param name="rectConfig">容器的 RectTransform 配置。</param>
|
|
|
|
|
|
/// <param name="constraintCount">每行或每列的元素数量。</param>
|
|
|
|
|
|
/// <param name="cellSize">每个单元格的大小。</param>
|
|
|
|
|
|
/// <param name="spacing">单元格之间的间距。</param>
|
|
|
|
|
|
/// <param name="constraint">约束类型(按行数或列数)。</param>
|
|
|
|
|
|
/// <returns>创建的网格容器的 RectTransform。</returns>
|
|
|
|
|
|
public static RectTransform CreateGridLayoutContainer(
|
|
|
|
|
|
Transform parent,
|
|
|
|
|
|
string name,
|
|
|
|
|
|
RectTransformConfig rectConfig,
|
|
|
|
|
|
int constraintCount,
|
|
|
|
|
|
Vector2 cellSize,
|
|
|
|
|
|
Vector2 spacing,
|
|
|
|
|
|
GridLayoutGroup.Constraint constraint = GridLayoutGroup.Constraint.FixedColumnCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
var containerRect = CreateRect(parent, name, rectConfig);
|
|
|
|
|
|
var gridLayout = containerRect.gameObject.AddComponent<GridLayoutGroup>();
|
|
|
|
|
|
|
|
|
|
|
|
gridLayout.constraint = constraint;
|
|
|
|
|
|
if (constraint == GridLayoutGroup.Constraint.FixedColumnCount)
|
|
|
|
|
|
gridLayout.constraintCount = constraintCount;
|
|
|
|
|
|
else if (constraint == GridLayoutGroup.Constraint.FixedRowCount)
|
|
|
|
|
|
gridLayout.constraintCount = constraintCount;
|
|
|
|
|
|
|
|
|
|
|
|
gridLayout.cellSize = cellSize;
|
|
|
|
|
|
gridLayout.spacing = spacing;
|
|
|
|
|
|
|
|
|
|
|
|
return containerRect;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个带标签的输入框(左边文字,右边输入)。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="config">控件配置。</param>
|
|
|
|
|
|
/// <returns>包含根对象、标签和输入框的元组。</returns>
|
|
|
|
|
|
public static (RectTransform root, TextMeshProUGUI label, TMP_InputField inputField) CreateLabeledInputField(
|
|
|
|
|
|
Transform parent, LabeledInputFieldConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 创建根容器并添加水平布局
|
|
|
|
|
|
var rootRect = CreateRect(parent, config.LabelText + " LabeledInput", config.RectConfig);
|
|
|
|
|
|
var layoutGroup = rootRect.gameObject.AddComponent<HorizontalLayoutGroup>();
|
|
|
|
|
|
layoutGroup.childControlWidth = true;
|
|
|
|
|
|
layoutGroup.childControlHeight = true;
|
|
|
|
|
|
layoutGroup.childForceExpandWidth = false;
|
|
|
|
|
|
layoutGroup.spacing = config.Spacing;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 创建标签
|
|
|
|
|
|
var labelConfig = new TextConfig(
|
|
|
|
|
|
config.LabelText,
|
|
|
|
|
|
config.LabelFontSize,
|
|
|
|
|
|
config.LabelTextColor,
|
|
|
|
|
|
TextAlignmentOptions.Left,
|
|
|
|
|
|
false,
|
|
|
|
|
|
RectTransformConfig.Default // RectTransform由LayoutGroup控制
|
|
|
|
|
|
);
|
|
|
|
|
|
var label = CreateText(rootRect, labelConfig);
|
|
|
|
|
|
var labelLayout = label.gameObject.AddComponent<LayoutElement>();
|
|
|
|
|
|
labelLayout.preferredWidth = config.LabelWidth;
|
|
|
|
|
|
labelLayout.flexibleWidth = 0; // 不参与弹性宽度分配
|
|
|
|
|
|
// 3. 创建输入框
|
|
|
|
|
|
var (inputField, _) = CreateInputField(rootRect, config.InputFieldConfig);
|
|
|
|
|
|
var inputLayout = inputField.gameObject.AddComponent<LayoutElement>();
|
|
|
|
|
|
inputLayout.flexibleWidth = 1; // 占据剩余所有宽度
|
|
|
|
|
|
return (rootRect, label, inputField);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个下拉框控件。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="config">控件配置。</param>
|
|
|
|
|
|
/// <returns>包含下拉框组件和其主标签的元组。</returns>
|
|
|
|
|
|
public static (TMP_Dropdown dropdown, TextMeshProUGUI captionText) CreateDropdown(Transform parent,
|
|
|
|
|
|
DropdownConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Unity 从代码创建 Dropdown 比较繁琐,因为它依赖于一个预设的模板结构。
|
|
|
|
|
|
// 以下代码将手动构建这个结构。
|
|
|
|
|
|
|
|
|
|
|
|
// 1. Root Dropdown Object
|
|
|
|
|
|
var dropdownRect = CreateRect(parent, "Dropdown", config.RectConfig);
|
|
|
|
|
|
var dropdownImage = dropdownRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
dropdownImage.color = config.BackgroundColor;
|
|
|
|
|
|
var dropdown = dropdownRect.gameObject.AddComponent<TMP_Dropdown>();
|
|
|
|
|
|
// 2. Label (Caption Text)
|
|
|
|
|
|
var labelRect = CreateRect(dropdownRect, "Label", RectTransformConfig.FillParent);
|
|
|
|
|
|
labelRect.offsetMin = new Vector2(10, 0);
|
|
|
|
|
|
labelRect.offsetMax = new Vector2(-25, 0);
|
|
|
|
|
|
var labelText = labelRect.gameObject.AddComponent<TextMeshProUGUI>();
|
|
|
|
|
|
labelText.alignment = TextAlignmentOptions.Left;
|
|
|
|
|
|
labelText.color = config.CaptionTextColor;
|
|
|
|
|
|
labelText.fontSize = config.CaptionFontSize;
|
|
|
|
|
|
dropdown.captionText = labelText;
|
|
|
|
|
|
// 3. Arrow
|
|
|
|
|
|
var arrowRect = CreateRect(dropdownRect, "Arrow", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(1, 0.5f), new Vector2(1, 0.5f), new Vector2(-15, 0), new Vector2(20, 20), Vector2.zero,
|
|
|
|
|
|
Vector2.zero, new Vector2(0.5f, 0.5f)
|
|
|
|
|
|
));
|
|
|
|
|
|
var arrowImage = arrowRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
arrowImage.color = new Color(0.8f, 0.8f, 0.8f); // 默认箭头颜色
|
|
|
|
|
|
// 4. Template (Scroll View, the dropdown list) - 必须默认禁用
|
|
|
|
|
|
var templateRect = CreateRect(dropdownRect, "Template", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 2), new Vector2(0, 150), Vector2.zero,
|
|
|
|
|
|
Vector2.zero, new Vector2(0.5f, 1)
|
|
|
|
|
|
));
|
|
|
|
|
|
var templateImage = templateRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
templateImage.color = config.BackgroundColor;
|
|
|
|
|
|
var scrollRect = templateRect.gameObject.AddComponent<ScrollRect>();
|
|
|
|
|
|
scrollRect.movementType = ScrollRect.MovementType.Clamped;
|
|
|
|
|
|
templateRect.gameObject.SetActive(false);
|
|
|
|
|
|
dropdown.template = templateRect;
|
|
|
|
|
|
|
|
|
|
|
|
// 5. Viewport
|
|
|
|
|
|
var viewportRect = CreateRect(templateRect, "Viewport", RectTransformConfig.FillParent);
|
|
|
|
|
|
viewportRect.gameObject.AddComponent<RectMask2D>();
|
|
|
|
|
|
scrollRect.viewport = viewportRect;
|
|
|
|
|
|
|
|
|
|
|
|
// 6. Content
|
|
|
|
|
|
var contentRect = CreateRect(viewportRect, "Content", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0, 1), new Vector2(1, 1), Vector2.zero, new Vector2(0, 28), Vector2.zero, Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 1)
|
|
|
|
|
|
));
|
|
|
|
|
|
scrollRect.content = contentRect;
|
|
|
|
|
|
|
|
|
|
|
|
// 7. Item (The template for each option)
|
|
|
|
|
|
var itemRect = CreateRect(contentRect, "Item", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0, 1), new Vector2(1, 1), Vector2.zero, new Vector2(0, 20), Vector2.zero, Vector2.zero,
|
|
|
|
|
|
new Vector2(0.5f, 1)
|
|
|
|
|
|
));
|
|
|
|
|
|
var itemToggle = itemRect.gameObject.AddComponent<Toggle>();
|
|
|
|
|
|
itemToggle.targetGraphic = itemRect.gameObject.AddComponent<Image>(); // Add an image to be the background
|
|
|
|
|
|
|
|
|
|
|
|
var itemLabelRect = CreateRect(itemRect, "Item Label", RectTransformConfig.FillParent);
|
|
|
|
|
|
itemLabelRect.offsetMin = new Vector2(10, 0);
|
|
|
|
|
|
itemLabelRect.offsetMax = new Vector2(-10, 0);
|
|
|
|
|
|
var itemLabel = itemLabelRect.gameObject.AddComponent<TextMeshProUGUI>();
|
|
|
|
|
|
itemLabel.color = config.ItemTextColor;
|
|
|
|
|
|
itemLabel.fontSize = config.ItemFontSize;
|
|
|
|
|
|
dropdown.itemText = itemLabel;
|
|
|
|
|
|
// 8. Populate options
|
|
|
|
|
|
dropdown.ClearOptions();
|
|
|
|
|
|
dropdown.AddOptions(config.Options);
|
|
|
|
|
|
return (dropdown, labelText);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个带标签的下拉框(左边文字,右边下拉)。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="config">控件配置。</param>
|
|
|
|
|
|
/// <returns>包含根对象、标签和下拉框的元组。</returns>
|
|
|
|
|
|
public static (RectTransform root, TextMeshProUGUI label, TMP_Dropdown dropdown) CreateLabeledDropdown(
|
|
|
|
|
|
Transform parent, LabeledDropdownConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 创建根容器并添加水平布局
|
|
|
|
|
|
var rootRect = CreateRect(parent, config.LabelText + " LabeledDropdown", config.RectConfig);
|
|
|
|
|
|
var layoutGroup = rootRect.gameObject.AddComponent<HorizontalLayoutGroup>();
|
|
|
|
|
|
layoutGroup.childControlWidth = true;
|
|
|
|
|
|
layoutGroup.childControlHeight = true;
|
|
|
|
|
|
layoutGroup.childForceExpandWidth = true;
|
|
|
|
|
|
layoutGroup.spacing = config.Spacing;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 创建标签
|
|
|
|
|
|
var labelConfig = new TextConfig(
|
|
|
|
|
|
config.LabelText,
|
|
|
|
|
|
config.LabelFontSize,
|
|
|
|
|
|
config.LabelTextColor,
|
|
|
|
|
|
TextAlignmentOptions.Left,
|
|
|
|
|
|
false,
|
|
|
|
|
|
RectTransformConfig.Default
|
|
|
|
|
|
);
|
|
|
|
|
|
var label = CreateText(rootRect, labelConfig);
|
|
|
|
|
|
var labelLayout = label.gameObject.AddComponent<LayoutElement>();
|
|
|
|
|
|
labelLayout.preferredWidth = config.LabelWidth;
|
|
|
|
|
|
labelLayout.flexibleWidth = 0;
|
|
|
|
|
|
// 3. 创建下拉框
|
|
|
|
|
|
var (dropdown, _) = CreateDropdown(rootRect, config.DropdownConfig);
|
|
|
|
|
|
var dropdownLayout = dropdown.gameObject.AddComponent<LayoutElement>();
|
|
|
|
|
|
dropdownLayout.flexibleWidth = 1;
|
|
|
|
|
|
return (rootRect, label, dropdown);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个切换开关控件。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="parent">父级 Transform。</param>
|
|
|
|
|
|
/// <param name="config">控件配置。</param>
|
|
|
|
|
|
/// <returns>包含Toggle组件、标签和勾选标记图像的元组。</returns>
|
|
|
|
|
|
public static (Toggle toggle, TextMeshProUGUI label, Image checkmark) CreateToggle(Transform parent,
|
|
|
|
|
|
ToggleConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. Root Toggle Object
|
|
|
|
|
|
var toggleRect = CreateRect(parent, "Toggle", config.RectConfig);
|
|
|
|
|
|
var toggle = toggleRect.gameObject.AddComponent<Toggle>();
|
|
|
|
|
|
toggle.isOn = config.IsOnByDefault;
|
|
|
|
|
|
// 2. Background
|
|
|
|
|
|
var backgroundRect = CreateRect(toggleRect, "Background", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0, 0.5f), new Vector2(0, 0.5f), Vector2.zero, new Vector2(20, 20), Vector2.zero,
|
|
|
|
|
|
Vector2.zero, new Vector2(0, 0.5f)
|
|
|
|
|
|
));
|
|
|
|
|
|
var backgroundImage = backgroundRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
backgroundImage.color = config.BackgroundColor;
|
|
|
|
|
|
toggle.targetGraphic = backgroundImage;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Checkmark
|
|
|
|
|
|
var checkmarkRect = CreateRect(backgroundRect, "Checkmark", RectTransformConfig.FillParent);
|
|
|
|
|
|
checkmarkRect.offsetMin = new Vector2(3, 3);
|
|
|
|
|
|
checkmarkRect.offsetMax = new Vector2(-3, -3);
|
|
|
|
|
|
var checkmarkImage = checkmarkRect.gameObject.AddComponent<Image>();
|
|
|
|
|
|
checkmarkImage.color = config.CheckmarkColor;
|
|
|
|
|
|
toggle.graphic = checkmarkImage;
|
|
|
|
|
|
|
|
|
|
|
|
// 4. Label
|
|
|
|
|
|
var labelRect = CreateRect(toggleRect, "Label", new RectTransformConfig(
|
|
|
|
|
|
new Vector2(0, 0), new Vector2(1, 1), Vector2.zero, new Vector2(-config.Spacing - 20, 0),
|
|
|
|
|
|
new Vector2(config.Spacing + 20, 0), Vector2.zero, new Vector2(0, 0.5f)
|
|
|
|
|
|
));
|
|
|
|
|
|
var label = labelRect.gameObject.AddComponent<TextMeshProUGUI>();
|
|
|
|
|
|
label.text = config.LabelText;
|
|
|
|
|
|
label.color = config.LabelTextColor;
|
|
|
|
|
|
label.fontSize = config.LabelFontSize;
|
|
|
|
|
|
label.alignment = TextAlignmentOptions.Left;
|
|
|
|
|
|
|
|
|
|
|
|
return (toggle, label, checkmarkImage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|