using AppUI.Manager.Role; using System; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; namespace AppUI.Util.Avatar { [Serializable] public struct AvatarItem { public int id; public Sprite avatar; public string name; public Transform avatarLine; } /// /// 预设头像网格:点击项更新 ,并可通过 等串联。 /// public class AvatarGroup : MonoBehaviour { [SerializeField] Sprite[] _avatars; [Tooltip("可选:与 _avatars 一一对应的服务端 avatarID;未配置或长度不一致时用 RoleManager.PresetGridIndexToAvatarId")] [SerializeField] int[] _presetAvatarIds; /// 与 Inspector 中配置的头像 Sprite 数组同源,供 等读取,避免重复配置。 public Sprite[] Avatars => _avatars; /// 头像数量,与 长度一致。 public int AvatarCount => _avatars != null ? _avatars.Length : 0; List _avatarItems; public GameObject imagePanel; public GameObject imageObj; /// 选中后写入的 Image; 可在运行时赋值为 avatarPreviewImage 以共用同一预览图。 public Image targetImage; [Header("关联输入框文案颜色(可选)")] [SerializeField] TMP_InputField linkedInputField; [SerializeField] TMP_Text linkedLabelText; [SerializeField] Color textColorWhenHasValue = Color.black; [SerializeField] Color textColorWhenEmpty = new Color(0.5f, 0.5f, 0.5f, 1f); [Header("关联输入框图标(可选,与上面同一套 hasValue 逻辑)")] [SerializeField] Image linkedStateImage; [SerializeField] Sprite spriteWhenHasValue; [SerializeField] Sprite spriteWhenEmpty; /// 当前选中下标,与 一致。 public int SelectedIndex { get; private set; } /// 用户点击或通过 选中时触发(含索引与 Sprite)。 public event Action OnAvatarSelected; void OnEnable() { BindLinkedInputField(); } void OnDisable() { UnbindLinkedInputField(); } void Start() { BuildListIfNeeded(); if (_avatarItems != null && _avatarItems.Count > 0 && _avatars != null && _avatars.Length > 0) SelectByIndex(0, notify: false); RefreshLinkedLabelTextColor(); } void BindLinkedInputField() { if (linkedInputField == null) return; linkedInputField.onValueChanged.RemoveListener(OnLinkedInputValueChanged); linkedInputField.onValueChanged.AddListener(OnLinkedInputValueChanged); RefreshLinkedLabelTextColor(); } void UnbindLinkedInputField() { if (linkedInputField == null) return; linkedInputField.onValueChanged.RemoveListener(OnLinkedInputValueChanged); } void OnLinkedInputValueChanged(string _) { RefreshLinkedLabelTextColor(); } /// /// 根据 是否有内容:更新 颜色、 /// 的 Sprite(有值 / 空 两套)。 /// public void RefreshLinkedLabelTextColor() { var hasValue = linkedInputField != null && linkedInputField.text.Trim().Length > 0; if (linkedLabelText != null) linkedLabelText.color = hasValue ? textColorWhenHasValue : textColorWhenEmpty; if (linkedStateImage == null) return; var sp = hasValue ? spriteWhenHasValue : spriteWhenEmpty; if (sp != null) linkedStateImage.sprite = sp; } void BuildListIfNeeded() { if (_avatarItems != null) return; _avatarItems = new List(); if (_avatars == null || _avatars.Length == 0 || imagePanel == null || imageObj == null) return; for (var i = 0; i < _avatars.Length; i++) { var item = new AvatarItem { id = i, avatar = _avatars[i], name = $"Avatar {i}" }; var o = Instantiate(imageObj, imagePanel.transform); var img = o.GetComponent(); if (img != null) img.sprite = item.avatar; var lineTr = o.transform.Find("AvatarLine"); if (lineTr != null) item.avatarLine = lineTr; _avatarItems.Add(item); o.SetActive(true); var index = i; var btn = o.GetComponent