| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- 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;
- }
- /// <summary>
- /// 预设头像网格:点击项更新 <see cref="targetImage"/>,并可通过 <see cref="OnAvatarSelected"/> 与 <see cref="AppUI.View.RegisterView"/> 等串联。
- /// </summary>
- public class AvatarGroup : MonoBehaviour
- {
- [SerializeField]
- Sprite[] _avatars;
- [Tooltip("可选:与 _avatars 一一对应的服务端 avatarID;未配置或长度不一致时用 RoleManager.PresetGridIndexToAvatarId")]
- [SerializeField]
- int[] _presetAvatarIds;
- /// <summary>与 Inspector 中配置的头像 Sprite 数组同源,供 <see cref="AppUI.View.RegisterView"/> 等读取,避免重复配置。</summary>
- public Sprite[] Avatars => _avatars;
- /// <summary>头像数量,与 <see cref="Avatars"/> 长度一致。</summary>
- public int AvatarCount => _avatars != null ? _avatars.Length : 0;
- List<AvatarItem> _avatarItems;
- public GameObject imagePanel;
- public GameObject imageObj;
- /// <summary>选中后写入的 Image;<see cref="AppUI.View.RegisterView"/> 可在运行时赋值为 <c>avatarPreviewImage</c> 以共用同一预览图。</summary>
- 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;
- /// <summary>当前选中下标,与 <see cref="_avatars"/> 一致。</summary>
- public int SelectedIndex { get; private set; }
- /// <summary>用户点击或通过 <see cref="SelectByIndex"/> 选中时触发(含索引与 Sprite)。</summary>
- public event Action<int, Sprite> 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();
- }
- /// <summary>
- /// 根据 <see cref="linkedInputField"/> 是否有内容:更新 <see cref="linkedLabelText"/> 颜色、
- /// <see cref="linkedStateImage"/> 的 Sprite(有值 / 空 两套)。
- /// </summary>
- 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<AvatarItem>();
- 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<Image>();
- 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<Button>();
- if (btn != null)
- btn.onClick.AddListener(() => OnAvatarItemClick(index));
- }
- }
- void OnAvatarItemClick(int index)
- {
- SelectByIndex(index, notify: true);
- if (targetImage != null)
- {
- var p = targetImage.transform.parent;
- if (p != null && p.parent != null)
- p.parent.gameObject.SetActive(true);
- }
- HideObj();
- }
- /// <summary>代码侧选中(与点击一致),用于与外部列表或 <see cref="AppUI.View.RegisterView.OnSelectPresetAvatar"/> 同步。</summary>
- public void SelectByIndex(int index, bool notify = true)
- {
- BuildListIfNeeded();
- if (_avatars == null || index < 0 || index >= _avatars.Length)
- return;
- SelectedIndex = index;
- if (targetImage != null)
- targetImage.sprite = _avatars[index];
- if (_avatarItems != null)
- {
- foreach (var avatarItem in _avatarItems)
- {
- if (avatarItem.avatarLine != null)
- avatarItem.avatarLine.gameObject.SetActive(avatarItem.id == index);
- }
- }
- if (notify)
- OnAvatarSelected?.Invoke(index, _avatars[index]);
- }
- public Sprite GetAvatarSprite(int index)
- {
- if (_avatars == null || index < 0 || index >= _avatars.Length)
- return null;
- return _avatars[index];
- }
- public Sprite GetSelectedSprite()
- {
- return GetAvatarSprite(SelectedIndex);
- }
- /// <summary>当前选中项对应的服务端 avatarID(与 <see cref="RoleManager.SetAvatarToImage"/> 资源约定一致)。</summary>
- public int GetSelectedAvatarId()
- {
- if (_presetAvatarIds != null
- && SelectedIndex >= 0
- && SelectedIndex < _presetAvatarIds.Length)
- {
- return _presetAvatarIds[SelectedIndex];
- }
- return RoleManager.PresetGridIndexToAvatarId(SelectedIndex);
- }
- public void HideObj()
- {
- if (imagePanel != null)
- imagePanel.SetActive(false);
- }
- public void ShowObj()
- {
- if (imagePanel != null)
- imagePanel.SetActive(true);
- }
- public void ToggleObj()
- {
- if (imagePanel != null)
- imagePanel.SetActive(!imagePanel.activeSelf);
- }
- }
- }
|